mirror of
https://github.com/realmicrosoft/windows.git
synced 2024-08-14 22:46:44 +00:00
need to figure out a better way for memory mapping
This commit is contained in:
parent
be015d1967
commit
50970fa2cc
13 changed files with 457 additions and 113 deletions
|
@ -11,12 +11,14 @@ spin = "0.9.1"
|
|||
x86_64 = "0.14.10"
|
||||
rlibc = "1.0"
|
||||
multiboot2 = { version = "0.14.0", optional = true }
|
||||
acpi = { version = "4.1.1", optional = true }
|
||||
linked_list_allocator = { version = "0.9.0", optional = true }
|
||||
[dependencies.lazy_static]
|
||||
version = "1.4.0"
|
||||
features = ["spin_no_std"]
|
||||
|
||||
[features]
|
||||
default = ["f_multiboot2", "f_ll_alloc"]
|
||||
f_multiboot2 = ["dep:multiboot2"]
|
||||
default = ["f_multiboot2", "f_ll_alloc", "f_debug_verbose"]
|
||||
f_debug_verbose = []
|
||||
f_multiboot2 = ["dep:multiboot2", "dep:acpi"]
|
||||
f_ll_alloc = ["dep:linked_list_allocator"]
|
32
serial.log
32
serial.log
|
@ -7,6 +7,12 @@ BdsDxe: starting Boot0001 "UEFI QEMU DVD-ROM QM00003 " from PciRoot(0x0)/Pci(0x1
|
|||
WARNING: no console will be available to OS
|
||||
error: no suitable video mode found.
|
||||
using serial port 0 as console
|
||||
debug: setup GDT
|
||||
debug: GDT loaded
|
||||
debug: CS set
|
||||
debug: SS set
|
||||
debug: TSS loaded
|
||||
debug: IDT loaded
|
||||
|
||||
|
||||
|
||||
|
@ -16,3 +22,29 @@ initialising mapper...[OK]
|
|||
initialising frame allocator...[OK]
|
||||
initialising heap...[OK]
|
||||
testing heap...[OK]
|
||||
checking for apic compatibility...[OK]
|
||||
disabling PIC...[OK]
|
||||
initialising apic...[debug] read_phys_memory32: addr fee000f0 not mapped
|
||||
[debug] allocated frame: PhysFrame[4KiB](0x1c000)
|
||||
[debug] mapped page: Page[4KiB](0xfee00000)
|
||||
[debug] map_to_result: Ok(MapperFlush(Page[4KiB](0xfee00000)))
|
||||
[OK]
|
||||
setting up apic interrupts...[debug] write_phys_memory32: addr fec00000 not mapped
|
||||
[debug] allocated frame: PhysFrame[4KiB](0x1f000)
|
||||
[debug] mapped page: Page[4KiB](0xfec00000)
|
||||
[debug] map_to_result: Ok(MapperFlush(Page[4KiB](0xfec00000)))
|
||||
[OK]
|
||||
[debug] keyboard interrupt
|
||||
---KERNEL FUCKY WUKKY UWU---
|
||||
double fault!
|
||||
stack frame: InterruptStackFrame {
|
||||
instruction_pointer: VirtAddr(
|
||||
0x120ef1,
|
||||
),
|
||||
code_segment: 8,
|
||||
cpu_flags: 0x200002,
|
||||
stack_pointer: VirtAddr(
|
||||
0x140c00,
|
||||
),
|
||||
stack_segment: 16,
|
||||
}
|
||||
|
|
|
@ -1,8 +1,12 @@
|
|||
use alloc::sync::Arc;
|
||||
use core::marker::PhantomData;
|
||||
use crate::KernelArgs;
|
||||
use acpi::{AcpiHandler, PhysicalMapping};
|
||||
use crate::{debug, KernelArgs};
|
||||
|
||||
#[cfg(feature = "f_multiboot2")]
|
||||
use multiboot2::{load, MemoryMapTag, BootInformation};
|
||||
use x86_64::structures::paging::{FrameAllocator, OffsetPageTable};
|
||||
use crate::memory::BootInfoFrameAllocator;
|
||||
|
||||
pub struct KernelInfo {
|
||||
kernel_start: u64,
|
||||
|
@ -51,4 +55,65 @@ impl KernelInfo {
|
|||
pub fn safe_memory_start(&self) -> u64 {
|
||||
self.safe_mem_start
|
||||
}
|
||||
|
||||
pub fn acpi_get_ioapic_addr(&self, mem_mapper: &mut OffsetPageTable, frame_allocator: &mut BootInfoFrameAllocator) -> u64 {
|
||||
#[cfg(feature = "f_multiboot2")]
|
||||
{
|
||||
let acpi_tag = self.boot_info.rsdp_v1_tag().expect("no acpi tag");
|
||||
let rsdp = acpi_tag;
|
||||
let rsdp = unsafe { &*rsdp };
|
||||
let rsdt = rsdp.rsdt_address();
|
||||
#[derive(Clone)]
|
||||
struct Handler<'a> {
|
||||
mem_mapper: Arc<&'a mut OffsetPageTable<'a>>,
|
||||
frame_allocator: Arc<&'a mut BootInfoFrameAllocator>,
|
||||
}
|
||||
impl<'a> AcpiHandler for Handler<'a> {
|
||||
unsafe fn map_physical_region<T>(&self, physical_address: usize, size: usize) -> PhysicalMapping<Self, T> {
|
||||
let frame_allocator = self.frame_allocator.clone();
|
||||
debug!("read_phys_memory32: addr {:x} not mapped", physical_address);
|
||||
// map the page
|
||||
let frame = frame_allocator.allocate_frame().unwrap();
|
||||
debug!("allocated frame: {:?}", frame);
|
||||
let flags = x86_64::structures::paging::PageTableFlags::PRESENT | x86_64::structures::paging::PageTableFlags::WRITABLE;
|
||||
let page = x86_64::structures::paging::Page::containing_address(initaladdr);
|
||||
debug!("mapped page: {:?}", page);
|
||||
let map_to_result = unsafe { mem_mapper.map_to(page, frame, flags, frame_allocator) };
|
||||
debug!("map_to_result: {:?}", map_to_result);
|
||||
if map_to_result.is_err() {
|
||||
panic!("Failed to map page");
|
||||
}
|
||||
let addr = unsafe { mem_mapper.translate_addr(initaladdr) };
|
||||
if let Some(addr) = addr {
|
||||
let addr = addr.as_u64() as *const u32;
|
||||
unsafe { *addr }
|
||||
} else {
|
||||
panic!("Failed to map page");
|
||||
}
|
||||
}
|
||||
|
||||
fn unmap_physical_region<T>(region: &PhysicalMapping<Self, T>) {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
let rsdt = acpi::AcpiTables::from_rsdt(rsdt).expect("failed to get acpi tables");
|
||||
let mut ioapic_addr = 0;
|
||||
for entry in rsdt.entries() {
|
||||
let entry = unsafe { &*entry };
|
||||
if entry.signature() == *b"APIC" {
|
||||
let apic = entry.as_apic();
|
||||
let apic = unsafe { &*apic };
|
||||
for entry in apic.entries() {
|
||||
let entry = unsafe { &*entry };
|
||||
if entry.signature() == *b"IOAP" {
|
||||
let ioapic = entry.as_ioapic();
|
||||
let ioapic = unsafe { &*ioapic };
|
||||
ioapic_addr = ioapic.address();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ioapic_addr
|
||||
}
|
||||
}
|
||||
}
|
142
src/internals/cpu.rs
Normal file
142
src/internals/cpu.rs
Normal file
|
@ -0,0 +1,142 @@
|
|||
use core::arch::asm;
|
||||
use x86_64::{PhysAddr, VirtAddr};
|
||||
use x86_64::structures::idt::InterruptStackFrame;
|
||||
use x86_64::structures::paging::OffsetPageTable;
|
||||
use crate::{debug, print, println};
|
||||
use crate::memory::{BootInfoFrameAllocator, read_phys_memory32, write_phys_memory32};
|
||||
use crate::serial::{command, read};
|
||||
|
||||
// todo! maybe abstract this into different sections for different parts of cpu func?
|
||||
|
||||
pub fn check_apic_compat() -> bool {
|
||||
unsafe {
|
||||
let mut eax: u32;
|
||||
let mut edx: u32;
|
||||
asm!("cpuid",
|
||||
in("eax") 1,
|
||||
lateout("eax") eax,
|
||||
lateout("edx") edx,
|
||||
);
|
||||
edx & (1 << 9) != 0
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_apic_base(apic: usize) {
|
||||
const IA32_APIC_BASE_MSR_ENABLE: u32 = 0x800;
|
||||
let mut edx = 0u32;
|
||||
let mut eax = (apic & 0xfffff0000) as u32 | IA32_APIC_BASE_MSR_ENABLE;
|
||||
unsafe {
|
||||
asm!("wrmsr",
|
||||
in("ecx") 0x1b,
|
||||
in("eax") eax,
|
||||
in("edx") edx,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_apic_base() -> usize {
|
||||
let mut edx = 0u32;
|
||||
let mut eax = 0u32;
|
||||
unsafe {
|
||||
asm!("rdmsr",
|
||||
in("ecx") 0x1b,
|
||||
lateout("eax") eax,
|
||||
lateout("edx") edx,
|
||||
);
|
||||
}
|
||||
((edx as usize) << 32) | (eax as usize)
|
||||
}
|
||||
|
||||
pub fn enable_apic(mem_mapper: &mut OffsetPageTable, frame_alloc: &mut BootInfoFrameAllocator) {
|
||||
// PIC should be disabled by now
|
||||
// now enable local apic
|
||||
// 1. set bit 8 of spurious interrupt vector register
|
||||
let sivr_addr = 0xfee000f0;
|
||||
let sivr = read_phys_memory32(mem_mapper, frame_alloc, sivr_addr);
|
||||
write_phys_memory32(mem_mapper, frame_alloc, sivr_addr, sivr | (1 << 8));
|
||||
}
|
||||
|
||||
pub fn apic_read_io(mem_mapper: &mut OffsetPageTable, frame_alloc: &mut BootInfoFrameAllocator, ioapicaddr: usize, reg: u32) -> u32 {
|
||||
write_phys_memory32(mem_mapper, frame_alloc, ioapicaddr as u32, reg);
|
||||
read_phys_memory32(mem_mapper, frame_alloc, ioapicaddr as u32 + 0x10)
|
||||
}
|
||||
|
||||
pub fn apic_write_io(mem_mapper: &mut OffsetPageTable, frame_alloc: &mut BootInfoFrameAllocator, ioapicaddr: usize, reg: u32, val: u32) {
|
||||
write_phys_memory32(mem_mapper, frame_alloc, ioapicaddr as u32, reg);
|
||||
write_phys_memory32(mem_mapper, frame_alloc, ioapicaddr as u32 + 0x10, val);
|
||||
}
|
||||
|
||||
pub fn disable_pic() {
|
||||
command(0x20, 0x11);
|
||||
command(0xa0, 0x11);
|
||||
|
||||
command(0x21, 0xe0);
|
||||
command(0xa1, 0xe8);
|
||||
|
||||
command(0x21, 0x04);
|
||||
command(0xa1, 0x02);
|
||||
|
||||
command(0x21, 0x01);
|
||||
command(0xa1, 0x01);
|
||||
|
||||
command(0x21, 0xff);
|
||||
command(0xa1, 0xff);
|
||||
}
|
||||
|
||||
pub fn ioapic_set_irq(mem_mapper: &mut OffsetPageTable, frame_alloc: &mut BootInfoFrameAllocator, ioapicaddr: usize, irq: u8, apic_id: u64, vector:u8) {
|
||||
let lo_index: u32 = (0x10 + irq*2 ) as u32;
|
||||
let hi_index: u32 = (0x10 + irq*2 + 1) as u32;
|
||||
|
||||
let mut high = apic_read_io(mem_mapper, frame_alloc, ioapicaddr, hi_index);
|
||||
// set apic id
|
||||
high &= !(0xff000000);
|
||||
high |= (apic_id as u32) << 24;
|
||||
apic_write_io(mem_mapper, frame_alloc, ioapicaddr, hi_index, high);
|
||||
|
||||
let mut low = apic_read_io(mem_mapper, frame_alloc, ioapicaddr, lo_index);
|
||||
|
||||
// unmask
|
||||
low &= !(1 << 16);
|
||||
// set to physical delivery
|
||||
low &= !(1 << 11);
|
||||
// set to fixed delivery
|
||||
low &= !(0x700);
|
||||
// set vector
|
||||
low &= !(0xff);
|
||||
low |= vector as u32;
|
||||
|
||||
apic_write_io(mem_mapper, frame_alloc, ioapicaddr, lo_index, low);
|
||||
}
|
||||
|
||||
pub fn apic_eoi() {
|
||||
unsafe {
|
||||
asm!("mov eax, 0",
|
||||
"mov ecx, 0xb0",
|
||||
"wrmsr",
|
||||
in("ecx") 0x80b,
|
||||
in("eax") 0,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// todo! in the future this will be removed, it is only for testing basic apic functionality
|
||||
pub extern "x86-interrupt" fn keyboard_irq(stack_frame: InterruptStackFrame) {
|
||||
debug!("keyboard interrupt");
|
||||
unsafe { asm!("iretq"); }
|
||||
let scancode = read(0x60);
|
||||
|
||||
print!("ksc: {},", scancode);
|
||||
|
||||
// reset keyboard controller
|
||||
let mut a = read(0x61);
|
||||
a |= 0x82;
|
||||
command(0x61, a);
|
||||
a &= 0x7f;
|
||||
command(0x61, a);
|
||||
}
|
||||
|
||||
// todo! we should abstract this away
|
||||
pub fn setup_apic_interrupts(mem_mapper: &mut OffsetPageTable, frame_alloc: &mut BootInfoFrameAllocator, ioapicaddr: usize) {
|
||||
// set keyboard irq to interrupt 40
|
||||
ioapic_set_irq(mem_mapper, frame_alloc, ioapicaddr, 1, 0, 40);
|
||||
}
|
|
@ -1,8 +1,8 @@
|
|||
pub mod errors;
|
||||
pub mod interrupts;
|
||||
pub mod cpu;
|
||||
|
||||
pub mod WhyDoTheyCallItOvenWhenYouOfInTheColdFoodOfOutHotEatTheFood {
|
||||
use core::arch::asm;
|
||||
use core::marker::PhantomData;
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct Point {
|
||||
|
|
135
src/lib.rs
135
src/lib.rs
|
@ -12,12 +12,16 @@ extern crate alloc;
|
|||
|
||||
use alloc::rc::Rc;
|
||||
use alloc::vec;
|
||||
use core::arch::asm;
|
||||
use lazy_static::lazy_static;
|
||||
use core::panic::PanicInfo;
|
||||
use multiboot2::MemoryAreaType;
|
||||
use spin::Mutex;
|
||||
use x86_64::structures::idt::{InterruptDescriptorTable, InterruptStackFrame};
|
||||
use x86_64::structures::gdt::{GlobalDescriptorTable, Descriptor};
|
||||
use x86_64::structures::tss::TaskStateSegment;
|
||||
use x86_64::{PhysAddr, VirtAddr};
|
||||
use x86_64::registers::segmentation::{CS, Segment, SS};
|
||||
use x86_64::structures::paging::Translate;
|
||||
use crate::boot::KernelInfo;
|
||||
use crate::internals::WhyDoTheyCallItOvenWhenYouOfInTheColdFoodOfOutHotEatTheFood::*;
|
||||
|
@ -32,11 +36,16 @@ mod memory;
|
|||
mod macros;
|
||||
|
||||
lazy_static! {
|
||||
static ref GDT: Mutex<GlobalDescriptorTable> = {
|
||||
let mut gdt = GlobalDescriptorTable::new();
|
||||
Mutex::new(gdt)
|
||||
};
|
||||
static ref IDT: InterruptDescriptorTable = {
|
||||
let mut idt = InterruptDescriptorTable::new();
|
||||
idt.breakpoint.set_handler_fn(internals::errors::breakpoint_exception);
|
||||
idt.double_fault.set_handler_fn(internals::errors::double_fault);
|
||||
idt.page_fault.set_handler_fn(internals::errors::page_fault);
|
||||
idt[40].set_handler_fn(internals::cpu::keyboard_irq);
|
||||
idt
|
||||
};
|
||||
}
|
||||
|
@ -93,6 +102,60 @@ pub extern fn kernel_main(args: KernelArgs) -> ! {
|
|||
println!("using serial port {} as console", i);
|
||||
}
|
||||
|
||||
// temporarily disable interrupts
|
||||
x86_64::instructions::interrupts::disable();
|
||||
println!("debug: setup GDT");
|
||||
// load TSS
|
||||
static mut tss: TaskStateSegment = TaskStateSegment::new();
|
||||
{
|
||||
unsafe {
|
||||
tss.interrupt_stack_table[0] = {
|
||||
const STACK_SIZE: usize = 4096 * 5;
|
||||
static mut STACK: [u8; STACK_SIZE] = [0; STACK_SIZE];
|
||||
let stack_start = VirtAddr::from_ptr(unsafe { &STACK });
|
||||
let stack_end = stack_start + STACK_SIZE;
|
||||
stack_end
|
||||
};
|
||||
// set word at offset 102 to 0x68 and last two bytes of the tss to 0xffff
|
||||
// this is a hack to make the tss valid
|
||||
let tss_ptr = &tss as *const TaskStateSegment as *mut u8;
|
||||
unsafe {
|
||||
*tss_ptr.add(102) = 0x68;
|
||||
*tss_ptr.add(104) = 0xff;
|
||||
*tss_ptr.add(105) = 0xff;
|
||||
}
|
||||
}
|
||||
let kcs = GDT.lock().add_entry(Descriptor::kernel_code_segment());
|
||||
let kds = GDT.lock().add_entry(Descriptor::kernel_data_segment());
|
||||
let tsss = unsafe { GDT.lock().add_entry(Descriptor::tss_segment(&tss)) };
|
||||
// load GDT
|
||||
unsafe {
|
||||
GDT.lock().load_unsafe();
|
||||
}
|
||||
println!("debug: GDT loaded");
|
||||
// set code segment to kernel code segment
|
||||
unsafe {
|
||||
CS::set_reg(kcs);
|
||||
}
|
||||
println!("debug: CS set");
|
||||
// set data segment to kernel data segment
|
||||
unsafe {
|
||||
SS::set_reg(kds);
|
||||
}
|
||||
println!("debug: SS set");
|
||||
// load TSS
|
||||
unsafe {
|
||||
x86_64::instructions::tables::load_tss(tsss);
|
||||
}
|
||||
println!("debug: TSS loaded");
|
||||
|
||||
// load IDT
|
||||
IDT.load();
|
||||
println!("debug: IDT loaded");
|
||||
// enable interrupts
|
||||
x86_64::instructions::interrupts::enable();
|
||||
}
|
||||
|
||||
|
||||
println!();
|
||||
println!();
|
||||
|
@ -100,28 +163,58 @@ pub extern fn kernel_main(args: KernelArgs) -> ! {
|
|||
println!("welcome to wukkOS!");
|
||||
println!("(c) 2022 Real Microsoft, LLC");
|
||||
let kern_info = Mutex::new(KernelInfo::init_from_kernel_args(args));
|
||||
print!("initialising mapper...");
|
||||
let mut mapper = unsafe { memory::init(VirtAddr::new(0)) };
|
||||
println!("[OK]");
|
||||
print!("initialising frame allocator...");
|
||||
let mut frame_allocator = unsafe { memory::BootInfoFrameAllocator::init(kern_info) };
|
||||
println!("[OK]");
|
||||
print!("initialising heap...");
|
||||
memory::allocator::init_heap(&mut mapper, &mut frame_allocator).expect("heap init failed");
|
||||
println!("[OK]");
|
||||
|
||||
print!("testing heap...");
|
||||
let reference_counted = Rc::new(vec![1, 2, 3]);
|
||||
let cloned = reference_counted.clone();
|
||||
let test_1 = Rc::strong_count(&reference_counted) == 2;
|
||||
drop(cloned);
|
||||
let test_2 = Rc::strong_count(&reference_counted) == 1;
|
||||
if test_1 && test_2 {
|
||||
// memory stuff
|
||||
let mut mapper = None;
|
||||
let mut frame_allocator = None;
|
||||
{
|
||||
print!("initialising mapper...");
|
||||
mapper = Some(unsafe { memory::init(VirtAddr::new(0)) });
|
||||
println!("[OK]");
|
||||
print!("initialising frame allocator...");
|
||||
frame_allocator = Some(unsafe { memory::BootInfoFrameAllocator::init(kern_info) });
|
||||
println!("[OK]");
|
||||
print!("initialising heap...");
|
||||
memory::allocator::init_heap(mapper.as_mut().unwrap(), frame_allocator.as_mut().unwrap()).expect("heap init failed");
|
||||
println!("[OK]");
|
||||
} else {
|
||||
println!("[FAIL]");
|
||||
}
|
||||
drop(reference_counted);
|
||||
|
||||
loop {}
|
||||
print!("testing heap...");
|
||||
let reference_counted = Rc::new(vec![1, 2, 3]);
|
||||
let cloned = reference_counted.clone();
|
||||
let test_1 = Rc::strong_count(&reference_counted) == 2;
|
||||
drop(cloned);
|
||||
let test_2 = Rc::strong_count(&reference_counted) == 1;
|
||||
if test_1 && test_2 {
|
||||
println!("[OK]");
|
||||
} else {
|
||||
println!("[FAIL]");
|
||||
}
|
||||
drop(reference_counted);
|
||||
}
|
||||
|
||||
// apic stuff
|
||||
{
|
||||
print!("checking for apic compatibility...");
|
||||
let apic_compatible = unsafe { internals::cpu::check_apic_compat() };
|
||||
if apic_compatible {
|
||||
println!("[OK]");
|
||||
} else {
|
||||
println!("[FAIL]");
|
||||
panic!("apic required at the moment");
|
||||
}
|
||||
print!("disabling PIC...");
|
||||
unsafe { internals::cpu::disable_pic() };
|
||||
println!("[OK]");
|
||||
print!("initialising apic...");
|
||||
unsafe { internals::cpu::enable_apic(mapper.as_mut().unwrap(), frame_allocator.as_mut().unwrap()) };
|
||||
println!("[OK]");
|
||||
print!("setting up apic interrupts...");
|
||||
unsafe { internals::cpu::setup_apic_interrupts(mapper.as_mut().unwrap(), frame_allocator.as_mut().unwrap()) };
|
||||
println!("[OK]");
|
||||
// enable interrupts
|
||||
x86_64::instructions::interrupts::enable();
|
||||
}
|
||||
|
||||
loop {
|
||||
}
|
||||
}
|
|
@ -12,8 +12,24 @@ macro_rules! println {
|
|||
($($arg:tt)*) => ($crate::print!("{}\n", format_args!($($arg)*)));
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! debug {
|
||||
($($arg:tt)*) => ($crate::macros::_debug(format_args!($($arg)*)));
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub fn _print(args: fmt::Arguments) {
|
||||
use core::fmt::Write;
|
||||
ST.writer.lock().write_fmt(args).unwrap();
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub fn _debug(args: fmt::Arguments) {
|
||||
use core::fmt::Write;
|
||||
#[cfg(feature = "f_debug_verbose")]
|
||||
{
|
||||
ST.log("[debug] ");
|
||||
ST.writer.lock().write_fmt(args).unwrap();
|
||||
ST.logln("");
|
||||
}
|
||||
}
|
|
@ -1,6 +1,8 @@
|
|||
pub mod allocator;
|
||||
|
||||
use x86_64::structures::paging::{FrameAllocator, OffsetPageTable, PageTable, PhysFrame, Size4KiB};
|
||||
use alloc::boxed::Box;
|
||||
use alloc::sync::Arc;
|
||||
use x86_64::structures::paging::{FrameAllocator, Mapper, OffsetPageTable, PageTable, PhysFrame, Size4KiB, Translate};
|
||||
use x86_64::{PhysAddr, VirtAddr};
|
||||
|
||||
pub struct Locked<A> {
|
||||
|
@ -40,6 +42,7 @@ unsafe fn active_level_4_table(phys_mem_offset: VirtAddr) -> &'static mut PageTa
|
|||
use multiboot2::{MemoryMapTag, BootInformation};
|
||||
use spin::Mutex;
|
||||
use crate::boot::KernelInfo;
|
||||
use crate::{debug, print, println};
|
||||
|
||||
pub struct BootInfoFrameAllocator {
|
||||
kern_info: Mutex<KernelInfo>,
|
||||
|
@ -82,3 +85,61 @@ unsafe impl FrameAllocator<Size4KiB> for BootInfoFrameAllocator {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn read_phys_memory32(mem_mapper: &mut OffsetPageTable, frame_allocator: &mut BootInfoFrameAllocator, addr: u32) -> u32 {
|
||||
let initaladdr = VirtAddr::new(addr as u64);
|
||||
let addr = unsafe { mem_mapper.translate_addr(initaladdr) };
|
||||
if let Some(addr) = addr {
|
||||
let addr = addr.as_u64() as *const u32;
|
||||
unsafe { *addr }
|
||||
} else {
|
||||
debug!("read_phys_memory32: addr {:x} not mapped", initaladdr.as_u64());
|
||||
// map the page
|
||||
let frame = frame_allocator.allocate_frame().unwrap();
|
||||
debug!("allocated frame: {:?}", frame);
|
||||
let flags = x86_64::structures::paging::PageTableFlags::PRESENT | x86_64::structures::paging::PageTableFlags::WRITABLE;
|
||||
let page = x86_64::structures::paging::Page::containing_address(initaladdr);
|
||||
debug!("mapped page: {:?}", page);
|
||||
let map_to_result = unsafe { mem_mapper.map_to(page, frame, flags, frame_allocator) };
|
||||
debug!("map_to_result: {:?}", map_to_result);
|
||||
if map_to_result.is_err() {
|
||||
panic!("Failed to map page");
|
||||
}
|
||||
let addr = unsafe { mem_mapper.translate_addr(initaladdr) };
|
||||
if let Some(addr) = addr {
|
||||
let addr = addr.as_u64() as *const u32;
|
||||
unsafe { *addr }
|
||||
} else {
|
||||
panic!("Failed to map page");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn write_phys_memory32(mem_mapper: &mut OffsetPageTable, frame_allocator: &mut BootInfoFrameAllocator, addr: u32, value: u32) {
|
||||
let initaladdr = VirtAddr::new(addr as u64);
|
||||
let addr = unsafe { mem_mapper.translate_addr(initaladdr) };
|
||||
if let Some(addr) = addr {
|
||||
let addr = addr.as_u64() as *mut u32;
|
||||
unsafe { *addr = value };
|
||||
} else {
|
||||
debug!("write_phys_memory32: addr {:x} not mapped", initaladdr.as_u64());
|
||||
// map the page
|
||||
let frame = frame_allocator.allocate_frame().unwrap();
|
||||
debug!("allocated frame: {:?}", frame);
|
||||
let flags = x86_64::structures::paging::PageTableFlags::PRESENT | x86_64::structures::paging::PageTableFlags::WRITABLE;
|
||||
let page = x86_64::structures::paging::Page::containing_address(initaladdr);
|
||||
debug!("mapped page: {:?}", page);
|
||||
let map_to_result = unsafe { mem_mapper.map_to(page, frame, flags, frame_allocator) };
|
||||
debug!("map_to_result: {:?}", map_to_result);
|
||||
if map_to_result.is_err() {
|
||||
panic!("Failed to map page");
|
||||
}
|
||||
let addr = unsafe { mem_mapper.translate_addr(initaladdr) };
|
||||
if let Some(addr) = addr {
|
||||
let addr = addr.as_u64() as *mut u32;
|
||||
unsafe { *addr = value };
|
||||
} else {
|
||||
panic!("Failed to map page");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,7 +4,6 @@ use core::arch::asm;
|
|||
use core::borrow::{Borrow, BorrowMut};
|
||||
use core::ops::Deref;
|
||||
|
||||
pub mod ps2;
|
||||
pub mod terminal_helpers;
|
||||
pub mod terminal;
|
||||
|
||||
|
@ -60,14 +59,14 @@ pub struct SerialPorts {
|
|||
}
|
||||
|
||||
#[cfg(any(target_arch="x86", target_arch="x86_64"))]
|
||||
fn command(port: u16, data: u8) {
|
||||
pub fn command(port: u16, data: u8) {
|
||||
unsafe {
|
||||
asm!("out dx, al", in("al") data, in("dx") port);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(target_arch="x86", target_arch="x86_64"))]
|
||||
fn read(port: u16) -> u8 {
|
||||
pub fn read(port: u16) -> u8 {
|
||||
let mut data: u8;
|
||||
unsafe {
|
||||
asm!("in al, dx", out("al") data, in("dx") port);
|
||||
|
|
|
@ -1,70 +0,0 @@
|
|||
use super::*;
|
||||
use crate::internals::WhyDoTheyCallItOvenWhenYouOfInTheColdFoodOfOutHotEatTheFood::{KernelError, ErrorKind, ErrorLevel};
|
||||
|
||||
pub enum PS2Type {
|
||||
AncientKeyboard,
|
||||
Keyboard,
|
||||
Mouse,
|
||||
FiveButtonMouse,
|
||||
ScrollWheelMouse,
|
||||
Unknown,
|
||||
}
|
||||
|
||||
enum Messages {
|
||||
MSGDisableScanning = 0xF5,
|
||||
MSGIdentify = 0xF2,
|
||||
MSGACK = 0xFA,
|
||||
}
|
||||
|
||||
pub fn probePort(port : Port) -> Result<PS2Type, KernelError> {
|
||||
let mut response : u8;
|
||||
response = port.transrecv(Messages::MSGDisableScanning as u8);
|
||||
// check for ACK
|
||||
if response != Messages::MSGACK as u8 {
|
||||
return Err(KernelError::new(ErrorKind::HardwareFuckUp, ErrorLevel::Warning, "Did not receive ACK", port.base.to_string()));
|
||||
}
|
||||
response = port.transrecv(Messages::MSGIdentify as u8);
|
||||
// check for ACK
|
||||
if response != Messages::MSGACK as u8 {
|
||||
return Err(KernelError::new(ErrorKind::HardwareFuckUp, ErrorLevel::MinorFuckUp, "Did not receive ACK after asking port to identify", port.base.to_string()));
|
||||
}
|
||||
// read the response with a timeout of x cpu cycles, this can be quite low as it will only matter on slow machines
|
||||
response = port.receive(0xFFFF);
|
||||
// if there's no response, it's a really old keyboard (IBM or whoever, why did you have to do this??)\
|
||||
if response == 0 {
|
||||
return Ok(PS2Type::AncientKeyboard);
|
||||
} else {
|
||||
// switch on the response
|
||||
match response {
|
||||
0x00 => { // standard mouse
|
||||
return Ok(PS2Type::Mouse);
|
||||
},
|
||||
0x03 => { // mouse with scroll wheel
|
||||
return Ok(PS2Type::ScrollWheelMouse);
|
||||
},
|
||||
0x04 => { // 5 button mouse
|
||||
return Ok(PS2Type::FiveButtonMouse);
|
||||
},
|
||||
0xAB => { // some type of keyboard, we'll need to read another byte to be sure
|
||||
response = port.receive(0xFFFF);
|
||||
match response {
|
||||
0x41 => { // some keyboard idfk
|
||||
return Ok(PS2Type::Keyboard);
|
||||
},
|
||||
0xC1 => { // same as above
|
||||
return Ok(PS2Type::Keyboard);
|
||||
},
|
||||
0x83 => { // keyboard after taking normal pills
|
||||
return Ok(PS2Type::Keyboard);
|
||||
},
|
||||
_ => { // what?
|
||||
return Ok(PS2Type::Unknown);
|
||||
}
|
||||
}
|
||||
},
|
||||
_ => { // some other device idk
|
||||
return Ok(PS2Type::Unknown);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,3 +0,0 @@
|
|||
static DATA_PORT: u16 = 0x60;
|
||||
static COMMAND_PORT: u16 = 0x64;
|
||||
|
|
@ -2,6 +2,7 @@ use core::fmt;
|
|||
use core::ops::Deref;
|
||||
use lazy_static::lazy_static;
|
||||
use spin::Mutex;
|
||||
use x86_64::instructions::interrupts::without_interrupts;
|
||||
use crate::serial::Port;
|
||||
|
||||
pub struct SerialTerminal {
|
||||
|
@ -32,24 +33,30 @@ impl SerialTerminal {
|
|||
}
|
||||
|
||||
pub fn log(&self, message: &str) {
|
||||
if let Some(port) = self.port.lock().deref() {
|
||||
port.transmit_string(message);
|
||||
}
|
||||
without_interrupts(|| {
|
||||
if let Some(port) = self.port.lock().deref() {
|
||||
port.transmit_string(message);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
pub fn logln(&self, message: &str) {
|
||||
if let Some(port) = self.port.lock().deref() {
|
||||
port.transmit_string(message);
|
||||
port.transmit_string("\r\n");
|
||||
}
|
||||
without_interrupts(|| {
|
||||
if let Some(port) = self.port.lock().deref() {
|
||||
port.transmit_string(message);
|
||||
port.transmit_string("\r\n");
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Write for SerialTerminalWriter {
|
||||
fn write_str(&mut self, s: &str) -> fmt::Result {
|
||||
if let Some(port) = self.port.lock().deref() {
|
||||
port.transmit_string(s);
|
||||
}
|
||||
without_interrupts(|| {
|
||||
if let Some(port) = self.port.lock().deref() {
|
||||
port.transmit_string(s);
|
||||
}
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue