From bc42931a5fc7858d08a1bcb3efec47c7e7ad637e Mon Sep 17 00:00:00 2001 From: Deniz-Mersinlioglu Date: Wed, 26 Jun 2019 17:40:11 +0300 Subject: [PATCH 01/18] Added keyboard support (but not really) --- src/cpu/idt.rs | 3 +- src/drivers/keyboard.rs | 58 +++++++++++++++++++++++++++++++++++++++ src/drivers/mod.rs | 2 +- src/drivers/vga/ransid.rs | 2 +- src/kernel.rs | 3 +- src/main.rs | 1 - 6 files changed, 63 insertions(+), 6 deletions(-) create mode 100644 src/drivers/keyboard.rs diff --git a/src/cpu/idt.rs b/src/cpu/idt.rs index a40cf37..79954ca 100644 --- a/src/cpu/idt.rs +++ b/src/cpu/idt.rs @@ -1,7 +1,7 @@ #![rustfmt::skip] use lazy_static::lazy_static; use x86_64::structures::idt; - +use crate::drivers::keyboard::keyboard_interrupt_handler; lazy_static! { static ref IDT: idt::InterruptDescriptorTable = { let mut idt = idt::InterruptDescriptorTable::new(); @@ -25,6 +25,7 @@ lazy_static! { idt.simd_floating_point.set_handler_fn(simd_floating_point_handler); idt.virtualization.set_handler_fn(virtualization_handler); idt.security_exception.set_handler_fn(security_exception_handler); + idt[33].set_handler_fn(keyboard_interrupt_handler); idt }; } diff --git a/src/drivers/keyboard.rs b/src/drivers/keyboard.rs new file mode 100644 index 0000000..2d17984 --- /dev/null +++ b/src/drivers/keyboard.rs @@ -0,0 +1,58 @@ +use x86_64::instructions::port::{PortRead, PortWrite}; +use crate::drivers::keyboard::Ports::STATUS_COMMAND; +use crate::drivers::keyboard::StatusMasks::{INBUF_STATUS, OUTBUF_STATUS}; +use x86_64::structures::idt; +//for now, we're just going to support one layout +#[allow(non_camel_case_types)] +enum Ports { + DATA = 0x60, + //status register when read, command register when written to + STATUS_COMMAND = 0x64 +} +#[allow(dead_code)] +#[allow(non_camel_case_types)] +enum StatusMasks { + OUTBUF_STATUS = 0x01, + INBUF_STATUS = 0x02, + SYSFLAG = 0x04, + COMM_DATA = 0x08, + UNK1 = 0x10, + UNK2 = 0x20, + TIMEOUT_ERR = 0x40, + PARITY_ERR = 0x80 +} +unsafe fn keyboard_output_withwait(p:Ports, data:u8) { + loop { + let sbyte:u8 = PortRead::read_from_port(STATUS_COMMAND as u16); + if (sbyte & (INBUF_STATUS as u8)) == 0 { + break; + } + } + PortWrite::write_to_port(p as u16,data); +} +unsafe fn keyboard_input_withwait() -> u8 { + loop { + let sbyte:u8 = PortRead::read_from_port(STATUS_COMMAND as u16); + if (sbyte & (OUTBUF_STATUS as u8)) != 0 { + break; + } + } + return PortRead::read_from_port(Ports::DATA as u16); +} +pub fn init() { + unsafe { + keyboard_output_withwait(STATUS_COMMAND, 0xAE); + keyboard_output_withwait(STATUS_COMMAND, 0x20); + let mut response_byte:u8 = keyboard_input_withwait(); + response_byte |= 1; + keyboard_output_withwait(STATUS_COMMAND , 0x60); + keyboard_output_withwait(Ports::DATA, response_byte); + } +} +#[allow(unused_variables)] +pub extern "x86-interrupt" fn keyboard_interrupt_handler(frame: &mut idt::InterruptStackFrame) { + unsafe { + let incoming_byte: u8 = keyboard_input_withwait(); + info!("Key recieved: {}", incoming_byte); + } +} \ No newline at end of file diff --git a/src/drivers/mod.rs b/src/drivers/mod.rs index 8d00214..b933396 100644 --- a/src/drivers/mod.rs +++ b/src/drivers/mod.rs @@ -1,4 +1,4 @@ #[macro_use] pub mod vga; - +pub mod keyboard; pub mod serial; diff --git a/src/drivers/vga/ransid.rs b/src/drivers/vga/ransid.rs index 2ab1e70..3e99c4e 100644 --- a/src/drivers/vga/ransid.rs +++ b/src/drivers/vga/ransid.rs @@ -41,7 +41,7 @@ pub struct ColorChar { pub style: u8, pub ascii: u8, } - +#[allow(dead_code)] fn create_style(bg: Color, fg: Color) -> u8 { let background = (bg as u8) << 4u8; let forground = fg as u8; diff --git a/src/kernel.rs b/src/kernel.rs index b24aade..6f1db93 100644 --- a/src/kernel.rs +++ b/src/kernel.rs @@ -1,11 +1,10 @@ #![rustfmt::skip] use crate::cpu; use crate::drivers; - pub fn kernel_main() { drivers::serial::init(); drivers::vga::text_mode::init().unwrap(); - + drivers::keyboard::init(); println!(" _____ _ _ _ Join us at discord.gg/vnyVmAE"); println!(" / ____| | | | | (_) Developed by members:"); println!("| (___ ___ | |___| |_ _ ___ ___ {:11} {:11} {:11}", "vinc", "TBA", "TBA"); diff --git a/src/main.rs b/src/main.rs index 95b84c0..6e5166b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -39,7 +39,6 @@ pub extern "C" fn _start(boot_info: &'static BootInfo) -> ! { test_main(); info!("nothing to do, halting..."); - abort(); } From 382e9b64d23f446b56613142e15024834c0e1722 Mon Sep 17 00:00:00 2001 From: trashcognito <44940491+bash-the-trash@users.noreply.github.com> Date: Wed, 26 Jun 2019 17:47:08 +0300 Subject: [PATCH 02/18] Add files via upload --- src/src/cpu/gdt.rs | 41 ++++++++ src/src/cpu/idt.rs | 116 +++++++++++++++++++++ src/src/cpu/mod.rs | 2 + src/src/drivers/keyboard.rs | 58 +++++++++++ src/src/drivers/mod.rs | 4 + src/src/drivers/serial.rs | 37 +++++++ src/src/drivers/vga/mod.rs | 4 + src/src/drivers/vga/ransid.rs | 161 ++++++++++++++++++++++++++++ src/src/drivers/vga/text_mode.rs | 173 +++++++++++++++++++++++++++++++ src/src/ds/mod.rs | 2 + src/src/ds/sync.rs | 98 +++++++++++++++++ src/src/kernel.rs | 18 ++++ src/src/macros.rs | 110 ++++++++++++++++++++ src/src/main.rs | 63 +++++++++++ src/src/qemu.rs | 18 ++++ src/src/testing.rs | 29 ++++++ 16 files changed, 934 insertions(+) create mode 100644 src/src/cpu/gdt.rs create mode 100644 src/src/cpu/idt.rs create mode 100644 src/src/cpu/mod.rs create mode 100644 src/src/drivers/keyboard.rs create mode 100644 src/src/drivers/mod.rs create mode 100644 src/src/drivers/serial.rs create mode 100644 src/src/drivers/vga/mod.rs create mode 100644 src/src/drivers/vga/ransid.rs create mode 100644 src/src/drivers/vga/text_mode.rs create mode 100644 src/src/ds/mod.rs create mode 100644 src/src/ds/sync.rs create mode 100644 src/src/kernel.rs create mode 100644 src/src/macros.rs create mode 100644 src/src/main.rs create mode 100644 src/src/qemu.rs create mode 100644 src/src/testing.rs diff --git a/src/src/cpu/gdt.rs b/src/src/cpu/gdt.rs new file mode 100644 index 0000000..adb628a --- /dev/null +++ b/src/src/cpu/gdt.rs @@ -0,0 +1,41 @@ +use lazy_static::lazy_static; +use x86_64::structures::gdt::{Descriptor, DescriptorFlags, GlobalDescriptorTable}; + +lazy_static! { + static ref GDT: GlobalDescriptorTable = { + let mut gdt = GlobalDescriptorTable::new(); + + // Kernel code segment + gdt.add_entry(Descriptor::kernel_code_segment()); + + // Kernel data segment + let flags = DescriptorFlags::USER_SEGMENT | DescriptorFlags::PRESENT; + gdt.add_entry(Descriptor::UserSegment(flags.bits() | (1 << 41))); + + gdt + }; +} + +pub fn load() { + GDT.load(); + + unsafe { + use x86_64::{ + instructions::segmentation as seg, + structures::gdt::SegmentSelector, + PrivilegeLevel, + }; + + let code_segment = SegmentSelector::new(1, PrivilegeLevel::Ring0); + let data_segment = SegmentSelector::new(2, PrivilegeLevel::Ring0); + + seg::load_ds(data_segment); + seg::load_es(data_segment); + seg::load_fs(data_segment); + seg::load_gs(data_segment); + seg::load_ss(data_segment); + seg::set_cs(code_segment); + } + + info!("GDT loaded"); +} diff --git a/src/src/cpu/idt.rs b/src/src/cpu/idt.rs new file mode 100644 index 0000000..79954ca --- /dev/null +++ b/src/src/cpu/idt.rs @@ -0,0 +1,116 @@ +#![rustfmt::skip] +use lazy_static::lazy_static; +use x86_64::structures::idt; +use crate::drivers::keyboard::keyboard_interrupt_handler; +lazy_static! { + static ref IDT: idt::InterruptDescriptorTable = { + let mut idt = idt::InterruptDescriptorTable::new(); + idt.divide_by_zero.set_handler_fn(divide_by_zero_handler); + idt.debug.set_handler_fn(debug_handler); + idt.non_maskable_interrupt.set_handler_fn(non_maskable_interrupt_handler); + idt.breakpoint.set_handler_fn(breakpoint_handler); + idt.overflow.set_handler_fn(overflow_handler); + idt.bound_range_exceeded.set_handler_fn(bound_range_exceeded_handler); + idt.invalid_opcode.set_handler_fn(invalid_opcode_handler); + idt.device_not_available.set_handler_fn(device_not_available_handler); + idt.double_fault.set_handler_fn(double_fault_handler); + idt.invalid_tss.set_handler_fn(invalid_tss_handler); + idt.segment_not_present.set_handler_fn(segment_not_present_handler); + idt.stack_segment_fault.set_handler_fn(stack_segment_fault_handler); + idt.general_protection_fault.set_handler_fn(general_protection_fault_handler); + idt.page_fault.set_handler_fn(page_fault_handler); + idt.x87_floating_point.set_handler_fn(x87_floating_point_handler); + idt.alignment_check.set_handler_fn(alignment_check_handler); + idt.machine_check.set_handler_fn(machine_check_handler); + idt.simd_floating_point.set_handler_fn(simd_floating_point_handler); + idt.virtualization.set_handler_fn(virtualization_handler); + idt.security_exception.set_handler_fn(security_exception_handler); + idt[33].set_handler_fn(keyboard_interrupt_handler); + idt + }; +} + +pub fn load() { + IDT.load(); + info!("IDT loaded"); +} + +extern "x86-interrupt" fn divide_by_zero_handler(frame: &mut idt::InterruptStackFrame) { + panic!("EXCEPTION: Zero Division\n{:#?}", frame); +} + +extern "x86-interrupt" fn debug_handler(frame: &mut idt::InterruptStackFrame) { + panic!("EXCEPTION: Debug\n{:#?}", frame); +} + +extern "x86-interrupt" fn non_maskable_interrupt_handler(frame: &mut idt::InterruptStackFrame) { + panic!("EXCEPTION: Non-Maskable Interrupt\n{:#?}", frame); +} + +extern "x86-interrupt" fn breakpoint_handler(frame: &mut idt::InterruptStackFrame) { + panic!("EXCEPTION: Breakpoint\n{:#?}", frame); +} + +extern "x86-interrupt" fn overflow_handler(frame: &mut idt::InterruptStackFrame) { + panic!("EXCEPTION: Overflow\n{:#?}", frame); +} + +extern "x86-interrupt" fn bound_range_exceeded_handler(frame: &mut idt::InterruptStackFrame) { + panic!("EXCEPTION: Bound Range Exceeded\n{:#?}", frame); +} + +extern "x86-interrupt" fn invalid_opcode_handler(frame: &mut idt::InterruptStackFrame) { + panic!("EXCEPTION: Invalid Opcode\n{:#?}", frame); +} + +extern "x86-interrupt" fn device_not_available_handler(frame: &mut idt::InterruptStackFrame) { + panic!("EXCEPTION: Device Not Available\n{:#?}", frame); +} + +extern "x86-interrupt" fn double_fault_handler(frame: &mut idt::InterruptStackFrame, error_code: u64) { + panic!("EXCEPTION: Double Fault with error code {}\n{:#?}", error_code, frame); +} + +extern "x86-interrupt" fn invalid_tss_handler(frame: &mut idt::InterruptStackFrame, error_code: u64) { + panic!("EXCEPTION: Invalid TSS with error code {}\n{:#?}", error_code, frame); +} + +extern "x86-interrupt" fn segment_not_present_handler(frame: &mut idt::InterruptStackFrame, error_code: u64) { + panic!("EXCEPTION: Segment Not Present with error code {}\n{:#?}", error_code, frame); +} + +extern "x86-interrupt" fn stack_segment_fault_handler(frame: &mut idt::InterruptStackFrame, error_code: u64) { + panic!("EXCEPTION: Stack Segment Fault with error code {}\n{:#?}", error_code, frame); +} + +extern "x86-interrupt" fn general_protection_fault_handler(frame: &mut idt::InterruptStackFrame, error_code: u64) { + panic!("EXCEPTION: General Protection Fault with error code {}\n{:#?}", error_code, frame); +} + +extern "x86-interrupt" fn page_fault_handler(frame: &mut idt::InterruptStackFrame, error_code: idt::PageFaultErrorCode) { + panic!("EXCEPTION: Page Fault with error code {:#?}\n{:#?}", error_code, frame); +} + +extern "x86-interrupt" fn x87_floating_point_handler(frame: &mut idt::InterruptStackFrame) { + panic!("EXCEPTION: x87 Floating Point\n{:#?}", frame); +} + +extern "x86-interrupt" fn alignment_check_handler(frame: &mut idt::InterruptStackFrame, error_code: u64) { + panic!("EXCEPTION: Alignment Check with error code {}\n{:#?}", error_code, frame); +} + +extern "x86-interrupt" fn machine_check_handler(frame: &mut idt::InterruptStackFrame) { + panic!("EXCEPTION: Machine Check\n{:#?}", frame); +} + +extern "x86-interrupt" fn simd_floating_point_handler(frame: &mut idt::InterruptStackFrame) { + panic!("EXCEPTION: SIMD Floating Point\n{:#?}", frame); +} + +extern "x86-interrupt" fn virtualization_handler(frame: &mut idt::InterruptStackFrame) { + panic!("EXCEPTION: Virtualization\n{:#?}", frame); +} + +extern "x86-interrupt" fn security_exception_handler(frame: &mut idt::InterruptStackFrame, error_code: u64, ) { + panic!("EXCEPTION: Security Exception with error code {}\n{:#?}", error_code, frame); +} diff --git a/src/src/cpu/mod.rs b/src/src/cpu/mod.rs new file mode 100644 index 0000000..ba7d073 --- /dev/null +++ b/src/src/cpu/mod.rs @@ -0,0 +1,2 @@ +pub mod gdt; +pub mod idt; diff --git a/src/src/drivers/keyboard.rs b/src/src/drivers/keyboard.rs new file mode 100644 index 0000000..2d17984 --- /dev/null +++ b/src/src/drivers/keyboard.rs @@ -0,0 +1,58 @@ +use x86_64::instructions::port::{PortRead, PortWrite}; +use crate::drivers::keyboard::Ports::STATUS_COMMAND; +use crate::drivers::keyboard::StatusMasks::{INBUF_STATUS, OUTBUF_STATUS}; +use x86_64::structures::idt; +//for now, we're just going to support one layout +#[allow(non_camel_case_types)] +enum Ports { + DATA = 0x60, + //status register when read, command register when written to + STATUS_COMMAND = 0x64 +} +#[allow(dead_code)] +#[allow(non_camel_case_types)] +enum StatusMasks { + OUTBUF_STATUS = 0x01, + INBUF_STATUS = 0x02, + SYSFLAG = 0x04, + COMM_DATA = 0x08, + UNK1 = 0x10, + UNK2 = 0x20, + TIMEOUT_ERR = 0x40, + PARITY_ERR = 0x80 +} +unsafe fn keyboard_output_withwait(p:Ports, data:u8) { + loop { + let sbyte:u8 = PortRead::read_from_port(STATUS_COMMAND as u16); + if (sbyte & (INBUF_STATUS as u8)) == 0 { + break; + } + } + PortWrite::write_to_port(p as u16,data); +} +unsafe fn keyboard_input_withwait() -> u8 { + loop { + let sbyte:u8 = PortRead::read_from_port(STATUS_COMMAND as u16); + if (sbyte & (OUTBUF_STATUS as u8)) != 0 { + break; + } + } + return PortRead::read_from_port(Ports::DATA as u16); +} +pub fn init() { + unsafe { + keyboard_output_withwait(STATUS_COMMAND, 0xAE); + keyboard_output_withwait(STATUS_COMMAND, 0x20); + let mut response_byte:u8 = keyboard_input_withwait(); + response_byte |= 1; + keyboard_output_withwait(STATUS_COMMAND , 0x60); + keyboard_output_withwait(Ports::DATA, response_byte); + } +} +#[allow(unused_variables)] +pub extern "x86-interrupt" fn keyboard_interrupt_handler(frame: &mut idt::InterruptStackFrame) { + unsafe { + let incoming_byte: u8 = keyboard_input_withwait(); + info!("Key recieved: {}", incoming_byte); + } +} \ No newline at end of file diff --git a/src/src/drivers/mod.rs b/src/src/drivers/mod.rs new file mode 100644 index 0000000..b933396 --- /dev/null +++ b/src/src/drivers/mod.rs @@ -0,0 +1,4 @@ +#[macro_use] +pub mod vga; +pub mod keyboard; +pub mod serial; diff --git a/src/src/drivers/serial.rs b/src/src/drivers/serial.rs new file mode 100644 index 0000000..2bf4cf8 --- /dev/null +++ b/src/src/drivers/serial.rs @@ -0,0 +1,37 @@ +use x86_64::instructions::port::PortWrite; + +#[repr(u16)] +#[allow(unused)] +enum Port { + COM1 = 0x3F8, + COM2 = 0x2F8, + COM3 = 0x3E8, + COM4 = 0x2E8, +} + +const PORT: u16 = Port::COM1 as u16; + +pub fn init() { + #[allow(clippy::identity_op)] + unsafe { + PortWrite::write_to_port(PORT + 1, 0x00 as u8); + PortWrite::write_to_port(PORT + 3, 0x80 as u8); + PortWrite::write_to_port(PORT + 0, 0x03 as u8); + PortWrite::write_to_port(PORT + 1, 0x00 as u8); + PortWrite::write_to_port(PORT + 3, 0x03 as u8); + PortWrite::write_to_port(PORT + 2, 0xC7 as u8); + PortWrite::write_to_port(PORT + 4, 0x0B as u8); + } +} + +fn write_byte(ch: u8) { + unsafe { + PortWrite::write_to_port(PORT as u16, ch); + } +} + +pub fn write_str(s: &str) { + for byte in s.bytes() { + write_byte(byte); + } +} diff --git a/src/src/drivers/vga/mod.rs b/src/src/drivers/vga/mod.rs new file mode 100644 index 0000000..6aff40c --- /dev/null +++ b/src/src/drivers/vga/mod.rs @@ -0,0 +1,4 @@ +#[macro_use] +pub mod text_mode; + +mod ransid; diff --git a/src/src/drivers/vga/ransid.rs b/src/src/drivers/vga/ransid.rs new file mode 100644 index 0000000..3e99c4e --- /dev/null +++ b/src/src/drivers/vga/ransid.rs @@ -0,0 +1,161 @@ +const ESC: u8 = b'\x1B'; + +pub enum State { + Esc, + Bracket, + Parse, + BgColor, + FgColor, + Equals, + EndVal, +} + +#[repr(u8)] +#[allow(unused)] +enum Color { + Black = 0x00, + Blue = 0x01, + Green = 0x02, + Cyan = 0x03, + Red = 0x04, + Magenta = 0x05, + Brown = 0x06, + LightGrey = 0x07, + DarkGrey = 0x08, + LightBlue = 0x09, + LightGreen = 0x0A, + LightCyan = 0x0B, + LightRed = 0x0C, + LightMagenta = 0x0D, + LightBrown = 0x0E, + White = 0x0F, +} + +pub struct RansidState { + pub state: State, + pub style: u8, + pub next_style: u8, +} + +pub struct ColorChar { + pub style: u8, + pub ascii: u8, +} +#[allow(dead_code)] +fn create_style(bg: Color, fg: Color) -> u8 { + let background = (bg as u8) << 4u8; + let forground = fg as u8; + background | forground +} + +fn convert_color(color: u8) -> u8 { + let lookup_table: [u8; 8] = [0, 4, 2, 6, 1, 5, 3, 7]; + lookup_table[color as usize] +} + +impl RansidState { + pub fn new() -> Self { + let mut state = Self { + state: State::Esc, + style: 0, + next_style: 0, + }; + + for ch in "\x1B[0m".chars() { + state.ransid_process(ch as u8); + } + + state + } + + pub fn ransid_process(&mut self, x: u8) -> Option { + let mut rv = ColorChar { + style: self.style, + ascii: b'\0', + }; + match self.state { + State::Esc => { + if x == ESC { + self.state = State::Bracket; + } else { + rv.ascii = x; + } + } + State::Bracket => { + if x == b'[' { + self.state = State::Parse; + } else { + self.state = State::Esc; + rv.ascii = x; + } + } + State::Parse => { + if x == b'3' { + self.state = State::FgColor; + } else if x == b'4' { + self.state = State::BgColor; + } else if x == b'0' { + self.state = State::EndVal; + self.next_style = 0x0F; + } else if x == b'1' { + self.state = State::EndVal; + self.next_style |= 1 << 3; + } else if x == b'=' { + self.state = State::Equals; + } else { + self.state = State::Esc; + self.next_style = self.style; + rv.ascii = x; + } + } + State::BgColor => { + if x >= b'0' && x <= b'7' { + self.state = State::EndVal; + self.next_style &= 0x1F; + self.next_style |= convert_color(x - b'0') << 4; + } else { + self.state = State::Esc; + self.next_style = self.style; + rv.ascii = x; + } + } + State::FgColor => { + if x >= b'0' && x <= b'7' { + self.state = State::EndVal; + self.next_style &= 0xF8; + self.next_style |= convert_color(x - b'0'); + } else { + self.state = State::Esc; + self.next_style = self.style; + rv.ascii = x; + } + } + State::Equals => { + if x == b'1' { + self.state = State::EndVal; + self.next_style &= !(1 << 3); + } else { + self.state = State::Esc; + self.next_style = self.style; + rv.ascii = x; + } + } + State::EndVal => { + if x == b';' { + self.state = State::Parse; + } else if x == b'm' { + self.state = State::Esc; + self.style = self.next_style; + } else { + self.state = State::Esc; + self.next_style = self.style; + } + } + }; + + match rv.ascii { + b'\0' => None, + _ => Some(rv), + } + } +} diff --git a/src/src/drivers/vga/text_mode.rs b/src/src/drivers/vga/text_mode.rs new file mode 100644 index 0000000..d4feaa9 --- /dev/null +++ b/src/src/drivers/vga/text_mode.rs @@ -0,0 +1,173 @@ +use log::{LevelFilter, SetLoggerError}; +use volatile::Volatile; +use x86_64::instructions::port::{PortRead, PortWrite}; +use crate::{drivers::vga::ransid::RansidState, macros}; + +const TERMINAL_BUFFER: usize = 0xB8000; +const WIDTH: usize = 80; +const HEIGHT: usize = 25; + +pub struct Writer { + state: RansidState, + buf: &'static mut [Volatile], + x: usize, + y: usize, +} + +impl Writer { + /// Handles escape characters for writing to the screen. + /// + /// Done: \n, \t + /// TODO: All the other escape characters (\r, etc...) + /// + /// Returns true if the character is an escape character, false if it's not. + /// If it's an escape character, then the `x` and `y` positions do not + /// have to be incremented because that's handled inside this function. + pub fn handle_escapes(&mut self, ch: u8) -> bool { + match ch { + b'\n' => { + self.y += 1; + self.x = 0; + true + } + b'\t' => { + self.write_str(" "); + true + } + _ => false, + } + } + + /// Handles scrolling + /// In essence this just pushes everything up by decrementing their `y` + /// position by 1 This overwrites row 0 + pub fn handle_scrolling(&mut self) { + if self.y < HEIGHT { + return; + } + + unsafe { + // Moves old memory up + core::intrinsics::volatile_copy_memory( + self.buf.as_mut_ptr(), + self.buf[WIDTH..].as_mut_ptr(), + WIDTH * (HEIGHT - 1), + ); + + // Clears bottom row + core::intrinsics::volatile_set_memory( + self.buf[(WIDTH * (HEIGHT - 1))..].as_mut_ptr(), + 0, + WIDTH, + ); + } + + self.y = HEIGHT - 1; + self.x = 0; + } + + /// Handles position of the cursor, does not handle scrolling. + pub fn update_cursor_position(&mut self) { + self.x += 1; + + if self.x >= WIDTH { + self.x = 0; + self.y += 1; + } + } + + /// Write a byte to the screen, handles escape characters and updates + /// positions. + /// Returns position of most recently written character + pub fn write_byte(&mut self, ch: u8) -> u16 { + match self.state.ransid_process(ch) { + Some(char) => { + if self.handle_escapes(ch) { + return 0; + } + + self.handle_scrolling(); + + // Actually write the character to the screen, escapes have been handled + // previously no need to worry about those anymore. + let pos: u16 = (self.y * WIDTH + self.x) as u16; + let byte: u16 = ((char.style as u16) << 8) | u16::from(char.ascii); + self.buf[self.y * WIDTH + self.x].write(byte); + + self.update_cursor_position(); + + pos + } + None => return 0, + } + } + + pub fn write_str(&mut self, s: &str) { + let mut pos: u16 = 0; + for byte in s.bytes() { + // TODO: Handle non-ascii chars + pos = self.write_byte(byte); + } + + if pos != 0 { + update_cursor(pos); + } + } +} + +impl Default for Writer { + fn default() -> Self { + Writer { + state: RansidState::new(), + buf: unsafe { + core::slice::from_raw_parts_mut(TERMINAL_BUFFER as *mut Volatile, 80 * 25) + }, + x: 0, + y: 0, + } + } +} + +pub fn init() -> Result<(), SetLoggerError> { + enable_cursor(); + + log::set_logger(&*macros::SCREEN).map(|()| { + #[cfg(debug_assertions)] + log::set_max_level(LevelFilter::Debug); + + #[cfg(not(debug_assertions))] + log::set_max_level(LevelFilter::Info); + }) +} + +fn update_cursor(pos: u16) { + unsafe { + PortWrite::write_to_port(0x3D4 as u16, 0x0F as u8); + PortWrite::write_to_port(0x3D5 as u16, (pos & 0xFF) as u16); + PortWrite::write_to_port(0x3D4 as u16, 0x0E as u8); + PortWrite::write_to_port(0x3D5 as u16, ((pos >> 8) & 0xFF) as u16); + } +} + +fn enable_cursor() { + const BEGIN_SCANLINE: u16 = 0; + const END_SCANLINE: u16 = 15; + + unsafe { + PortWrite::write_to_port(0x3D4 as u16, 0x0A as u8); + let old: u16 = PortRead::read_from_port(0x3D5); + PortWrite::write_to_port(0x3D5 as u16, ((old & 0xC0) | BEGIN_SCANLINE) as u8); + + PortWrite::write_to_port(0x3D4 as u16, 0x0B as u8); + let old: u16 = PortRead::read_from_port(0x3D5); + PortWrite::write_to_port(0x3D5 as u16, ((old & 0xE0) | END_SCANLINE) as u8); + } +} + +#[allow(dead_code)] +fn disable_cursor() { + unsafe { + PortWrite::write_to_port(0x3D4 as u16, 0x0A as u8); + PortWrite::write_to_port(0x3D5 as u16, 0x20 as u8); + } +} diff --git a/src/src/ds/mod.rs b/src/src/ds/mod.rs new file mode 100644 index 0000000..91a9acc --- /dev/null +++ b/src/src/ds/mod.rs @@ -0,0 +1,2 @@ +pub mod sync; +pub use sync::SpinLock; diff --git a/src/src/ds/sync.rs b/src/src/ds/sync.rs new file mode 100644 index 0000000..877e403 --- /dev/null +++ b/src/src/ds/sync.rs @@ -0,0 +1,98 @@ +use core::{ + cell::UnsafeCell, + ops::{Deref, DerefMut}, + sync::atomic::{spin_loop_hint, AtomicBool, Ordering}, +}; + +pub struct SpinLock { + locked: AtomicBool, + data: UnsafeCell, +} + +unsafe impl Sync for SpinLock {} +unsafe impl Send for SpinLock {} + +impl SpinLock { + pub fn new(data: T) -> Self { + Self { + locked: AtomicBool::new(false), + data: UnsafeCell::new(data), + } + } + + pub fn lock(&self) -> SpinLockGuard { + // Acquire the lock + while self.locked.compare_and_swap(false, true, Ordering::Acquire) { + while self.locked.load(Ordering::Relaxed) { + spin_loop_hint(); + } + } + + SpinLockGuard { + locked: &self.locked, + data: unsafe { &mut *self.data.get() }, + } + } + + pub fn try_lock(&self) -> Option> { + if !self.locked.compare_and_swap(false, true, Ordering::Acquire) { + Some(SpinLockGuard { + locked: &self.locked, + data: unsafe { &mut *self.data.get() }, + }) + } else { + None + } + } +} + +impl Default for SpinLock { + fn default() -> Self { + Self::new(T::default()) + } +} + +impl core::fmt::Debug for SpinLock { + fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { + match self.try_lock() { + Some(temp) => f + .debug_struct("SpinLock") + .field("data", &temp.data) + .finish(), + None => f + .debug_struct("SpinLock") + .field("data", b"") + .finish(), + } + } +} + +pub struct SpinLockGuard<'a, T> { + locked: &'a AtomicBool, + data: &'a mut T, +} + +impl Deref for SpinLockGuard<'_, T> { + type Target = T; + + fn deref(&self) -> &T { + &*self.data + } +} + +impl DerefMut for SpinLockGuard<'_, T> { + fn deref_mut(&mut self) -> &mut T { + self.data + } +} + +impl Drop for SpinLockGuard<'_, T> { + fn drop(&mut self) { + self.locked.store(false, Ordering::Release); + } +} + +// TODO: Add proper tests +test_case!(spin_lock, { + assert_eq!(1, 1); +}); diff --git a/src/src/kernel.rs b/src/src/kernel.rs new file mode 100644 index 0000000..6f1db93 --- /dev/null +++ b/src/src/kernel.rs @@ -0,0 +1,18 @@ +#![rustfmt::skip] +use crate::cpu; +use crate::drivers; +pub fn kernel_main() { + drivers::serial::init(); + drivers::vga::text_mode::init().unwrap(); + drivers::keyboard::init(); + println!(" _____ _ _ _ Join us at discord.gg/vnyVmAE"); + println!(" / ____| | | | | (_) Developed by members:"); + println!("| (___ ___ | |___| |_ _ ___ ___ {:11} {:11} {:11}", "vinc", "TBA", "TBA"); + println!(" \\___ \\ / _ \\| / __| __| |/ __/ _ \\ {:11} {:11} {:11}", "Crally", "TBA", "TBA"); + println!(" ____) | (_) | \\__ \\ |_| | (_| __/ {:11} {:11} {:11}", "Mehodin", "TBA", "TBA"); + println!("|_____/ \\___/|_|___/\\__|_|\\___\\___| {:11} {:11} {:11}", "Alex8675", "TBA", "TBA"); + println!(); + + cpu::gdt::load(); + cpu::idt::load(); +} diff --git a/src/src/macros.rs b/src/src/macros.rs new file mode 100644 index 0000000..47798f2 --- /dev/null +++ b/src/src/macros.rs @@ -0,0 +1,110 @@ +// TODO: Move into macros/ folder + +use crate::{ + drivers::{serial, vga::text_mode::Writer}, + ds::SpinLock, +}; +use core::fmt; +use lazy_static::lazy_static; +use log::{Level, Log, Metadata, Record}; + +// Need a separate struct so we can implement Log trait +pub struct ScreenLocker(SpinLock); + +pub struct ScreenWriter(Writer); + +impl fmt::Write for ScreenWriter { + fn write_str(&mut self, s: &str) -> fmt::Result { + #[cfg(debug_assertions)] + serial::write_str(s); + + self.0.write_str(s); + + Ok(()) + } +} + +lazy_static! { + pub static ref SCREEN: ScreenLocker = + ScreenLocker(SpinLock::new(ScreenWriter(Writer::default()))); +} + +macro_rules! print { + ($($arg:tt)*) => ($crate::macros::_print(format_args!($($arg)*))); +} + +macro_rules! println { + () => (print!("\n")); + ($($arg:tt)*) => (print!("{}\n", format_args!($($arg)*))); +} + +// Lifted from standard library +#[allow(unused_macros)] +macro_rules! dbg { + () => { + println!("[DEBUG {}:{}]", file!(), line!()); + }; + ($val:expr) => { + // Use of `match` here is intentional because it affects the lifetimes + // of temporaries - https://stackoverflow.com/a/48732525/1063961 + match $val { + tmp => { + println!( + "[DEBUG {}:{}] {} = {:#?}", + file!(), + line!(), + stringify!($val), + &tmp + ); + tmp + } + } + }; +} + +#[doc(hidden)] +pub fn _print(args: fmt::Arguments) { + use core::fmt::Write; + x86_64::instructions::interrupts::without_interrupts(|| { + SCREEN.0.lock().write_fmt(args).unwrap(); + }); +} + +impl Log for ScreenLocker { + fn enabled(&self, metadata: &Metadata) -> bool { + metadata.level() <= log::max_level() + } + + fn log(&self, record: &Record) { + if self.enabled(record.metadata()) { + let color = match record.level() { + Level::Info => "\x1B[32m", + Level::Error => "\x1B[31m", + Level::Warn => "\x1B[33m", + Level::Debug => "\x1B[36m", + Level::Trace => "\x1B[35m", + }; + + println!( + "[{}{}{}] {}", + color, + record.level(), + "\x1B[0m", + record.args() + ); + } + } + + fn flush(&self) {} +} + +macro_rules! test_case { + ($test_name:ident, $body:expr) => { + #[test_case] + fn $test_name() { + print!("{}::{}... ", module_path!(), stringify!($test_name)); + $body; + println!("[ok]"); + } + }; +} diff --git a/src/src/main.rs b/src/src/main.rs new file mode 100644 index 0000000..6e5166b --- /dev/null +++ b/src/src/main.rs @@ -0,0 +1,63 @@ +#![no_std] +#![no_main] +#![test_runner(crate::testing::test_runner)] +#![reexport_test_harness_main = "test_main"] +#![feature(custom_test_frameworks)] +#![feature(abi_x86_interrupt)] +#![feature(custom_inner_attributes)] +#![feature(core_intrinsics)] +#![feature(asm)] + +#[macro_use] +extern crate log; + +#[macro_use] +mod macros; + +mod cpu; +mod drivers; +mod ds; +mod testing; +mod kernel; +mod qemu; + +use bootloader::BootInfo; +#[allow(unused_imports)] +use core::panic::PanicInfo; + +#[no_mangle] +pub extern "C" fn _start(boot_info: &'static BootInfo) -> ! { + kernel::kernel_main(); + + info!( + "Physical memory offset: 0x{:x}", + boot_info.physical_memory_offset + ); + + // Run tests + #[cfg(test)] + test_main(); + + info!("nothing to do, halting..."); + abort(); +} + +#[panic_handler] +#[cfg(not(test))] +#[allow(clippy::empty_loop)] +fn panic(info: &PanicInfo) -> ! { + error!("{}", info); + + // Halt CPU + loop { + x86_64::instructions::interrupts::disable(); + x86_64::instructions::hlt(); + } +} + +fn abort() -> ! { + loop { + x86_64::instructions::interrupts::disable(); + x86_64::instructions::hlt(); + } +} diff --git a/src/src/qemu.rs b/src/src/qemu.rs new file mode 100644 index 0000000..028bc65 --- /dev/null +++ b/src/src/qemu.rs @@ -0,0 +1,18 @@ +#![allow(dead_code)] + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[repr(u32)] +pub enum ExitCode { + Success = 0x10, + Failure = 0x11, +} + +pub fn exit(exit_code: ExitCode) { + use x86_64::instructions::port::Port; + + let mut port = Port::new(0xF4); + + unsafe { + port.write(exit_code as u32); + } +} diff --git a/src/src/testing.rs b/src/src/testing.rs new file mode 100644 index 0000000..941cff6 --- /dev/null +++ b/src/src/testing.rs @@ -0,0 +1,29 @@ +#![allow(unused_imports)] +use crate::qemu; + +use core::panic::PanicInfo; + +#[panic_handler] +#[cfg(test)] +fn panic(info: &PanicInfo) -> ! { + println!("[failed] {}", info); + qemu::exit(qemu::ExitCode::Failure); + loop {} +} + +#[cfg(test)] +pub fn test_runner(tests: &[&dyn Fn()]) { + info!("Running {} tests", tests.len()); + println!("-----------------------"); + + for test in tests { + test(); + } + + qemu::exit(qemu::ExitCode::Success); +} + +// Example test +test_case!(basic_test, { + assert_eq!(1, 1); +}); From 50ef3f96f6c84aaa14cc4db8fd6fa5dcabfaa2ad Mon Sep 17 00:00:00 2001 From: Deniz-Mersinlioglu Date: Wed, 26 Jun 2019 17:59:09 +0300 Subject: [PATCH 03/18] Added keyboard support (but not really) --- src/src/cpu/gdt.rs | 41 -------- src/src/cpu/idt.rs | 116 --------------------- src/src/cpu/mod.rs | 2 - src/src/drivers/keyboard.rs | 58 ----------- src/src/drivers/mod.rs | 4 - src/src/drivers/serial.rs | 37 ------- src/src/drivers/vga/mod.rs | 4 - src/src/drivers/vga/ransid.rs | 161 ---------------------------- src/src/drivers/vga/text_mode.rs | 173 ------------------------------- src/src/ds/mod.rs | 2 - src/src/ds/sync.rs | 98 ----------------- src/src/kernel.rs | 18 ---- src/src/macros.rs | 110 -------------------- src/src/main.rs | 63 ----------- src/src/qemu.rs | 18 ---- src/src/testing.rs | 29 ------ 16 files changed, 934 deletions(-) delete mode 100644 src/src/cpu/gdt.rs delete mode 100644 src/src/cpu/idt.rs delete mode 100644 src/src/cpu/mod.rs delete mode 100644 src/src/drivers/keyboard.rs delete mode 100644 src/src/drivers/mod.rs delete mode 100644 src/src/drivers/serial.rs delete mode 100644 src/src/drivers/vga/mod.rs delete mode 100644 src/src/drivers/vga/ransid.rs delete mode 100644 src/src/drivers/vga/text_mode.rs delete mode 100644 src/src/ds/mod.rs delete mode 100644 src/src/ds/sync.rs delete mode 100644 src/src/kernel.rs delete mode 100644 src/src/macros.rs delete mode 100644 src/src/main.rs delete mode 100644 src/src/qemu.rs delete mode 100644 src/src/testing.rs diff --git a/src/src/cpu/gdt.rs b/src/src/cpu/gdt.rs deleted file mode 100644 index adb628a..0000000 --- a/src/src/cpu/gdt.rs +++ /dev/null @@ -1,41 +0,0 @@ -use lazy_static::lazy_static; -use x86_64::structures::gdt::{Descriptor, DescriptorFlags, GlobalDescriptorTable}; - -lazy_static! { - static ref GDT: GlobalDescriptorTable = { - let mut gdt = GlobalDescriptorTable::new(); - - // Kernel code segment - gdt.add_entry(Descriptor::kernel_code_segment()); - - // Kernel data segment - let flags = DescriptorFlags::USER_SEGMENT | DescriptorFlags::PRESENT; - gdt.add_entry(Descriptor::UserSegment(flags.bits() | (1 << 41))); - - gdt - }; -} - -pub fn load() { - GDT.load(); - - unsafe { - use x86_64::{ - instructions::segmentation as seg, - structures::gdt::SegmentSelector, - PrivilegeLevel, - }; - - let code_segment = SegmentSelector::new(1, PrivilegeLevel::Ring0); - let data_segment = SegmentSelector::new(2, PrivilegeLevel::Ring0); - - seg::load_ds(data_segment); - seg::load_es(data_segment); - seg::load_fs(data_segment); - seg::load_gs(data_segment); - seg::load_ss(data_segment); - seg::set_cs(code_segment); - } - - info!("GDT loaded"); -} diff --git a/src/src/cpu/idt.rs b/src/src/cpu/idt.rs deleted file mode 100644 index 79954ca..0000000 --- a/src/src/cpu/idt.rs +++ /dev/null @@ -1,116 +0,0 @@ -#![rustfmt::skip] -use lazy_static::lazy_static; -use x86_64::structures::idt; -use crate::drivers::keyboard::keyboard_interrupt_handler; -lazy_static! { - static ref IDT: idt::InterruptDescriptorTable = { - let mut idt = idt::InterruptDescriptorTable::new(); - idt.divide_by_zero.set_handler_fn(divide_by_zero_handler); - idt.debug.set_handler_fn(debug_handler); - idt.non_maskable_interrupt.set_handler_fn(non_maskable_interrupt_handler); - idt.breakpoint.set_handler_fn(breakpoint_handler); - idt.overflow.set_handler_fn(overflow_handler); - idt.bound_range_exceeded.set_handler_fn(bound_range_exceeded_handler); - idt.invalid_opcode.set_handler_fn(invalid_opcode_handler); - idt.device_not_available.set_handler_fn(device_not_available_handler); - idt.double_fault.set_handler_fn(double_fault_handler); - idt.invalid_tss.set_handler_fn(invalid_tss_handler); - idt.segment_not_present.set_handler_fn(segment_not_present_handler); - idt.stack_segment_fault.set_handler_fn(stack_segment_fault_handler); - idt.general_protection_fault.set_handler_fn(general_protection_fault_handler); - idt.page_fault.set_handler_fn(page_fault_handler); - idt.x87_floating_point.set_handler_fn(x87_floating_point_handler); - idt.alignment_check.set_handler_fn(alignment_check_handler); - idt.machine_check.set_handler_fn(machine_check_handler); - idt.simd_floating_point.set_handler_fn(simd_floating_point_handler); - idt.virtualization.set_handler_fn(virtualization_handler); - idt.security_exception.set_handler_fn(security_exception_handler); - idt[33].set_handler_fn(keyboard_interrupt_handler); - idt - }; -} - -pub fn load() { - IDT.load(); - info!("IDT loaded"); -} - -extern "x86-interrupt" fn divide_by_zero_handler(frame: &mut idt::InterruptStackFrame) { - panic!("EXCEPTION: Zero Division\n{:#?}", frame); -} - -extern "x86-interrupt" fn debug_handler(frame: &mut idt::InterruptStackFrame) { - panic!("EXCEPTION: Debug\n{:#?}", frame); -} - -extern "x86-interrupt" fn non_maskable_interrupt_handler(frame: &mut idt::InterruptStackFrame) { - panic!("EXCEPTION: Non-Maskable Interrupt\n{:#?}", frame); -} - -extern "x86-interrupt" fn breakpoint_handler(frame: &mut idt::InterruptStackFrame) { - panic!("EXCEPTION: Breakpoint\n{:#?}", frame); -} - -extern "x86-interrupt" fn overflow_handler(frame: &mut idt::InterruptStackFrame) { - panic!("EXCEPTION: Overflow\n{:#?}", frame); -} - -extern "x86-interrupt" fn bound_range_exceeded_handler(frame: &mut idt::InterruptStackFrame) { - panic!("EXCEPTION: Bound Range Exceeded\n{:#?}", frame); -} - -extern "x86-interrupt" fn invalid_opcode_handler(frame: &mut idt::InterruptStackFrame) { - panic!("EXCEPTION: Invalid Opcode\n{:#?}", frame); -} - -extern "x86-interrupt" fn device_not_available_handler(frame: &mut idt::InterruptStackFrame) { - panic!("EXCEPTION: Device Not Available\n{:#?}", frame); -} - -extern "x86-interrupt" fn double_fault_handler(frame: &mut idt::InterruptStackFrame, error_code: u64) { - panic!("EXCEPTION: Double Fault with error code {}\n{:#?}", error_code, frame); -} - -extern "x86-interrupt" fn invalid_tss_handler(frame: &mut idt::InterruptStackFrame, error_code: u64) { - panic!("EXCEPTION: Invalid TSS with error code {}\n{:#?}", error_code, frame); -} - -extern "x86-interrupt" fn segment_not_present_handler(frame: &mut idt::InterruptStackFrame, error_code: u64) { - panic!("EXCEPTION: Segment Not Present with error code {}\n{:#?}", error_code, frame); -} - -extern "x86-interrupt" fn stack_segment_fault_handler(frame: &mut idt::InterruptStackFrame, error_code: u64) { - panic!("EXCEPTION: Stack Segment Fault with error code {}\n{:#?}", error_code, frame); -} - -extern "x86-interrupt" fn general_protection_fault_handler(frame: &mut idt::InterruptStackFrame, error_code: u64) { - panic!("EXCEPTION: General Protection Fault with error code {}\n{:#?}", error_code, frame); -} - -extern "x86-interrupt" fn page_fault_handler(frame: &mut idt::InterruptStackFrame, error_code: idt::PageFaultErrorCode) { - panic!("EXCEPTION: Page Fault with error code {:#?}\n{:#?}", error_code, frame); -} - -extern "x86-interrupt" fn x87_floating_point_handler(frame: &mut idt::InterruptStackFrame) { - panic!("EXCEPTION: x87 Floating Point\n{:#?}", frame); -} - -extern "x86-interrupt" fn alignment_check_handler(frame: &mut idt::InterruptStackFrame, error_code: u64) { - panic!("EXCEPTION: Alignment Check with error code {}\n{:#?}", error_code, frame); -} - -extern "x86-interrupt" fn machine_check_handler(frame: &mut idt::InterruptStackFrame) { - panic!("EXCEPTION: Machine Check\n{:#?}", frame); -} - -extern "x86-interrupt" fn simd_floating_point_handler(frame: &mut idt::InterruptStackFrame) { - panic!("EXCEPTION: SIMD Floating Point\n{:#?}", frame); -} - -extern "x86-interrupt" fn virtualization_handler(frame: &mut idt::InterruptStackFrame) { - panic!("EXCEPTION: Virtualization\n{:#?}", frame); -} - -extern "x86-interrupt" fn security_exception_handler(frame: &mut idt::InterruptStackFrame, error_code: u64, ) { - panic!("EXCEPTION: Security Exception with error code {}\n{:#?}", error_code, frame); -} diff --git a/src/src/cpu/mod.rs b/src/src/cpu/mod.rs deleted file mode 100644 index ba7d073..0000000 --- a/src/src/cpu/mod.rs +++ /dev/null @@ -1,2 +0,0 @@ -pub mod gdt; -pub mod idt; diff --git a/src/src/drivers/keyboard.rs b/src/src/drivers/keyboard.rs deleted file mode 100644 index 2d17984..0000000 --- a/src/src/drivers/keyboard.rs +++ /dev/null @@ -1,58 +0,0 @@ -use x86_64::instructions::port::{PortRead, PortWrite}; -use crate::drivers::keyboard::Ports::STATUS_COMMAND; -use crate::drivers::keyboard::StatusMasks::{INBUF_STATUS, OUTBUF_STATUS}; -use x86_64::structures::idt; -//for now, we're just going to support one layout -#[allow(non_camel_case_types)] -enum Ports { - DATA = 0x60, - //status register when read, command register when written to - STATUS_COMMAND = 0x64 -} -#[allow(dead_code)] -#[allow(non_camel_case_types)] -enum StatusMasks { - OUTBUF_STATUS = 0x01, - INBUF_STATUS = 0x02, - SYSFLAG = 0x04, - COMM_DATA = 0x08, - UNK1 = 0x10, - UNK2 = 0x20, - TIMEOUT_ERR = 0x40, - PARITY_ERR = 0x80 -} -unsafe fn keyboard_output_withwait(p:Ports, data:u8) { - loop { - let sbyte:u8 = PortRead::read_from_port(STATUS_COMMAND as u16); - if (sbyte & (INBUF_STATUS as u8)) == 0 { - break; - } - } - PortWrite::write_to_port(p as u16,data); -} -unsafe fn keyboard_input_withwait() -> u8 { - loop { - let sbyte:u8 = PortRead::read_from_port(STATUS_COMMAND as u16); - if (sbyte & (OUTBUF_STATUS as u8)) != 0 { - break; - } - } - return PortRead::read_from_port(Ports::DATA as u16); -} -pub fn init() { - unsafe { - keyboard_output_withwait(STATUS_COMMAND, 0xAE); - keyboard_output_withwait(STATUS_COMMAND, 0x20); - let mut response_byte:u8 = keyboard_input_withwait(); - response_byte |= 1; - keyboard_output_withwait(STATUS_COMMAND , 0x60); - keyboard_output_withwait(Ports::DATA, response_byte); - } -} -#[allow(unused_variables)] -pub extern "x86-interrupt" fn keyboard_interrupt_handler(frame: &mut idt::InterruptStackFrame) { - unsafe { - let incoming_byte: u8 = keyboard_input_withwait(); - info!("Key recieved: {}", incoming_byte); - } -} \ No newline at end of file diff --git a/src/src/drivers/mod.rs b/src/src/drivers/mod.rs deleted file mode 100644 index b933396..0000000 --- a/src/src/drivers/mod.rs +++ /dev/null @@ -1,4 +0,0 @@ -#[macro_use] -pub mod vga; -pub mod keyboard; -pub mod serial; diff --git a/src/src/drivers/serial.rs b/src/src/drivers/serial.rs deleted file mode 100644 index 2bf4cf8..0000000 --- a/src/src/drivers/serial.rs +++ /dev/null @@ -1,37 +0,0 @@ -use x86_64::instructions::port::PortWrite; - -#[repr(u16)] -#[allow(unused)] -enum Port { - COM1 = 0x3F8, - COM2 = 0x2F8, - COM3 = 0x3E8, - COM4 = 0x2E8, -} - -const PORT: u16 = Port::COM1 as u16; - -pub fn init() { - #[allow(clippy::identity_op)] - unsafe { - PortWrite::write_to_port(PORT + 1, 0x00 as u8); - PortWrite::write_to_port(PORT + 3, 0x80 as u8); - PortWrite::write_to_port(PORT + 0, 0x03 as u8); - PortWrite::write_to_port(PORT + 1, 0x00 as u8); - PortWrite::write_to_port(PORT + 3, 0x03 as u8); - PortWrite::write_to_port(PORT + 2, 0xC7 as u8); - PortWrite::write_to_port(PORT + 4, 0x0B as u8); - } -} - -fn write_byte(ch: u8) { - unsafe { - PortWrite::write_to_port(PORT as u16, ch); - } -} - -pub fn write_str(s: &str) { - for byte in s.bytes() { - write_byte(byte); - } -} diff --git a/src/src/drivers/vga/mod.rs b/src/src/drivers/vga/mod.rs deleted file mode 100644 index 6aff40c..0000000 --- a/src/src/drivers/vga/mod.rs +++ /dev/null @@ -1,4 +0,0 @@ -#[macro_use] -pub mod text_mode; - -mod ransid; diff --git a/src/src/drivers/vga/ransid.rs b/src/src/drivers/vga/ransid.rs deleted file mode 100644 index 3e99c4e..0000000 --- a/src/src/drivers/vga/ransid.rs +++ /dev/null @@ -1,161 +0,0 @@ -const ESC: u8 = b'\x1B'; - -pub enum State { - Esc, - Bracket, - Parse, - BgColor, - FgColor, - Equals, - EndVal, -} - -#[repr(u8)] -#[allow(unused)] -enum Color { - Black = 0x00, - Blue = 0x01, - Green = 0x02, - Cyan = 0x03, - Red = 0x04, - Magenta = 0x05, - Brown = 0x06, - LightGrey = 0x07, - DarkGrey = 0x08, - LightBlue = 0x09, - LightGreen = 0x0A, - LightCyan = 0x0B, - LightRed = 0x0C, - LightMagenta = 0x0D, - LightBrown = 0x0E, - White = 0x0F, -} - -pub struct RansidState { - pub state: State, - pub style: u8, - pub next_style: u8, -} - -pub struct ColorChar { - pub style: u8, - pub ascii: u8, -} -#[allow(dead_code)] -fn create_style(bg: Color, fg: Color) -> u8 { - let background = (bg as u8) << 4u8; - let forground = fg as u8; - background | forground -} - -fn convert_color(color: u8) -> u8 { - let lookup_table: [u8; 8] = [0, 4, 2, 6, 1, 5, 3, 7]; - lookup_table[color as usize] -} - -impl RansidState { - pub fn new() -> Self { - let mut state = Self { - state: State::Esc, - style: 0, - next_style: 0, - }; - - for ch in "\x1B[0m".chars() { - state.ransid_process(ch as u8); - } - - state - } - - pub fn ransid_process(&mut self, x: u8) -> Option { - let mut rv = ColorChar { - style: self.style, - ascii: b'\0', - }; - match self.state { - State::Esc => { - if x == ESC { - self.state = State::Bracket; - } else { - rv.ascii = x; - } - } - State::Bracket => { - if x == b'[' { - self.state = State::Parse; - } else { - self.state = State::Esc; - rv.ascii = x; - } - } - State::Parse => { - if x == b'3' { - self.state = State::FgColor; - } else if x == b'4' { - self.state = State::BgColor; - } else if x == b'0' { - self.state = State::EndVal; - self.next_style = 0x0F; - } else if x == b'1' { - self.state = State::EndVal; - self.next_style |= 1 << 3; - } else if x == b'=' { - self.state = State::Equals; - } else { - self.state = State::Esc; - self.next_style = self.style; - rv.ascii = x; - } - } - State::BgColor => { - if x >= b'0' && x <= b'7' { - self.state = State::EndVal; - self.next_style &= 0x1F; - self.next_style |= convert_color(x - b'0') << 4; - } else { - self.state = State::Esc; - self.next_style = self.style; - rv.ascii = x; - } - } - State::FgColor => { - if x >= b'0' && x <= b'7' { - self.state = State::EndVal; - self.next_style &= 0xF8; - self.next_style |= convert_color(x - b'0'); - } else { - self.state = State::Esc; - self.next_style = self.style; - rv.ascii = x; - } - } - State::Equals => { - if x == b'1' { - self.state = State::EndVal; - self.next_style &= !(1 << 3); - } else { - self.state = State::Esc; - self.next_style = self.style; - rv.ascii = x; - } - } - State::EndVal => { - if x == b';' { - self.state = State::Parse; - } else if x == b'm' { - self.state = State::Esc; - self.style = self.next_style; - } else { - self.state = State::Esc; - self.next_style = self.style; - } - } - }; - - match rv.ascii { - b'\0' => None, - _ => Some(rv), - } - } -} diff --git a/src/src/drivers/vga/text_mode.rs b/src/src/drivers/vga/text_mode.rs deleted file mode 100644 index d4feaa9..0000000 --- a/src/src/drivers/vga/text_mode.rs +++ /dev/null @@ -1,173 +0,0 @@ -use log::{LevelFilter, SetLoggerError}; -use volatile::Volatile; -use x86_64::instructions::port::{PortRead, PortWrite}; -use crate::{drivers::vga::ransid::RansidState, macros}; - -const TERMINAL_BUFFER: usize = 0xB8000; -const WIDTH: usize = 80; -const HEIGHT: usize = 25; - -pub struct Writer { - state: RansidState, - buf: &'static mut [Volatile], - x: usize, - y: usize, -} - -impl Writer { - /// Handles escape characters for writing to the screen. - /// - /// Done: \n, \t - /// TODO: All the other escape characters (\r, etc...) - /// - /// Returns true if the character is an escape character, false if it's not. - /// If it's an escape character, then the `x` and `y` positions do not - /// have to be incremented because that's handled inside this function. - pub fn handle_escapes(&mut self, ch: u8) -> bool { - match ch { - b'\n' => { - self.y += 1; - self.x = 0; - true - } - b'\t' => { - self.write_str(" "); - true - } - _ => false, - } - } - - /// Handles scrolling - /// In essence this just pushes everything up by decrementing their `y` - /// position by 1 This overwrites row 0 - pub fn handle_scrolling(&mut self) { - if self.y < HEIGHT { - return; - } - - unsafe { - // Moves old memory up - core::intrinsics::volatile_copy_memory( - self.buf.as_mut_ptr(), - self.buf[WIDTH..].as_mut_ptr(), - WIDTH * (HEIGHT - 1), - ); - - // Clears bottom row - core::intrinsics::volatile_set_memory( - self.buf[(WIDTH * (HEIGHT - 1))..].as_mut_ptr(), - 0, - WIDTH, - ); - } - - self.y = HEIGHT - 1; - self.x = 0; - } - - /// Handles position of the cursor, does not handle scrolling. - pub fn update_cursor_position(&mut self) { - self.x += 1; - - if self.x >= WIDTH { - self.x = 0; - self.y += 1; - } - } - - /// Write a byte to the screen, handles escape characters and updates - /// positions. - /// Returns position of most recently written character - pub fn write_byte(&mut self, ch: u8) -> u16 { - match self.state.ransid_process(ch) { - Some(char) => { - if self.handle_escapes(ch) { - return 0; - } - - self.handle_scrolling(); - - // Actually write the character to the screen, escapes have been handled - // previously no need to worry about those anymore. - let pos: u16 = (self.y * WIDTH + self.x) as u16; - let byte: u16 = ((char.style as u16) << 8) | u16::from(char.ascii); - self.buf[self.y * WIDTH + self.x].write(byte); - - self.update_cursor_position(); - - pos - } - None => return 0, - } - } - - pub fn write_str(&mut self, s: &str) { - let mut pos: u16 = 0; - for byte in s.bytes() { - // TODO: Handle non-ascii chars - pos = self.write_byte(byte); - } - - if pos != 0 { - update_cursor(pos); - } - } -} - -impl Default for Writer { - fn default() -> Self { - Writer { - state: RansidState::new(), - buf: unsafe { - core::slice::from_raw_parts_mut(TERMINAL_BUFFER as *mut Volatile, 80 * 25) - }, - x: 0, - y: 0, - } - } -} - -pub fn init() -> Result<(), SetLoggerError> { - enable_cursor(); - - log::set_logger(&*macros::SCREEN).map(|()| { - #[cfg(debug_assertions)] - log::set_max_level(LevelFilter::Debug); - - #[cfg(not(debug_assertions))] - log::set_max_level(LevelFilter::Info); - }) -} - -fn update_cursor(pos: u16) { - unsafe { - PortWrite::write_to_port(0x3D4 as u16, 0x0F as u8); - PortWrite::write_to_port(0x3D5 as u16, (pos & 0xFF) as u16); - PortWrite::write_to_port(0x3D4 as u16, 0x0E as u8); - PortWrite::write_to_port(0x3D5 as u16, ((pos >> 8) & 0xFF) as u16); - } -} - -fn enable_cursor() { - const BEGIN_SCANLINE: u16 = 0; - const END_SCANLINE: u16 = 15; - - unsafe { - PortWrite::write_to_port(0x3D4 as u16, 0x0A as u8); - let old: u16 = PortRead::read_from_port(0x3D5); - PortWrite::write_to_port(0x3D5 as u16, ((old & 0xC0) | BEGIN_SCANLINE) as u8); - - PortWrite::write_to_port(0x3D4 as u16, 0x0B as u8); - let old: u16 = PortRead::read_from_port(0x3D5); - PortWrite::write_to_port(0x3D5 as u16, ((old & 0xE0) | END_SCANLINE) as u8); - } -} - -#[allow(dead_code)] -fn disable_cursor() { - unsafe { - PortWrite::write_to_port(0x3D4 as u16, 0x0A as u8); - PortWrite::write_to_port(0x3D5 as u16, 0x20 as u8); - } -} diff --git a/src/src/ds/mod.rs b/src/src/ds/mod.rs deleted file mode 100644 index 91a9acc..0000000 --- a/src/src/ds/mod.rs +++ /dev/null @@ -1,2 +0,0 @@ -pub mod sync; -pub use sync::SpinLock; diff --git a/src/src/ds/sync.rs b/src/src/ds/sync.rs deleted file mode 100644 index 877e403..0000000 --- a/src/src/ds/sync.rs +++ /dev/null @@ -1,98 +0,0 @@ -use core::{ - cell::UnsafeCell, - ops::{Deref, DerefMut}, - sync::atomic::{spin_loop_hint, AtomicBool, Ordering}, -}; - -pub struct SpinLock { - locked: AtomicBool, - data: UnsafeCell, -} - -unsafe impl Sync for SpinLock {} -unsafe impl Send for SpinLock {} - -impl SpinLock { - pub fn new(data: T) -> Self { - Self { - locked: AtomicBool::new(false), - data: UnsafeCell::new(data), - } - } - - pub fn lock(&self) -> SpinLockGuard { - // Acquire the lock - while self.locked.compare_and_swap(false, true, Ordering::Acquire) { - while self.locked.load(Ordering::Relaxed) { - spin_loop_hint(); - } - } - - SpinLockGuard { - locked: &self.locked, - data: unsafe { &mut *self.data.get() }, - } - } - - pub fn try_lock(&self) -> Option> { - if !self.locked.compare_and_swap(false, true, Ordering::Acquire) { - Some(SpinLockGuard { - locked: &self.locked, - data: unsafe { &mut *self.data.get() }, - }) - } else { - None - } - } -} - -impl Default for SpinLock { - fn default() -> Self { - Self::new(T::default()) - } -} - -impl core::fmt::Debug for SpinLock { - fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { - match self.try_lock() { - Some(temp) => f - .debug_struct("SpinLock") - .field("data", &temp.data) - .finish(), - None => f - .debug_struct("SpinLock") - .field("data", b"") - .finish(), - } - } -} - -pub struct SpinLockGuard<'a, T> { - locked: &'a AtomicBool, - data: &'a mut T, -} - -impl Deref for SpinLockGuard<'_, T> { - type Target = T; - - fn deref(&self) -> &T { - &*self.data - } -} - -impl DerefMut for SpinLockGuard<'_, T> { - fn deref_mut(&mut self) -> &mut T { - self.data - } -} - -impl Drop for SpinLockGuard<'_, T> { - fn drop(&mut self) { - self.locked.store(false, Ordering::Release); - } -} - -// TODO: Add proper tests -test_case!(spin_lock, { - assert_eq!(1, 1); -}); diff --git a/src/src/kernel.rs b/src/src/kernel.rs deleted file mode 100644 index 6f1db93..0000000 --- a/src/src/kernel.rs +++ /dev/null @@ -1,18 +0,0 @@ -#![rustfmt::skip] -use crate::cpu; -use crate::drivers; -pub fn kernel_main() { - drivers::serial::init(); - drivers::vga::text_mode::init().unwrap(); - drivers::keyboard::init(); - println!(" _____ _ _ _ Join us at discord.gg/vnyVmAE"); - println!(" / ____| | | | | (_) Developed by members:"); - println!("| (___ ___ | |___| |_ _ ___ ___ {:11} {:11} {:11}", "vinc", "TBA", "TBA"); - println!(" \\___ \\ / _ \\| / __| __| |/ __/ _ \\ {:11} {:11} {:11}", "Crally", "TBA", "TBA"); - println!(" ____) | (_) | \\__ \\ |_| | (_| __/ {:11} {:11} {:11}", "Mehodin", "TBA", "TBA"); - println!("|_____/ \\___/|_|___/\\__|_|\\___\\___| {:11} {:11} {:11}", "Alex8675", "TBA", "TBA"); - println!(); - - cpu::gdt::load(); - cpu::idt::load(); -} diff --git a/src/src/macros.rs b/src/src/macros.rs deleted file mode 100644 index 47798f2..0000000 --- a/src/src/macros.rs +++ /dev/null @@ -1,110 +0,0 @@ -// TODO: Move into macros/ folder - -use crate::{ - drivers::{serial, vga::text_mode::Writer}, - ds::SpinLock, -}; -use core::fmt; -use lazy_static::lazy_static; -use log::{Level, Log, Metadata, Record}; - -// Need a separate struct so we can implement Log trait -pub struct ScreenLocker(SpinLock); - -pub struct ScreenWriter(Writer); - -impl fmt::Write for ScreenWriter { - fn write_str(&mut self, s: &str) -> fmt::Result { - #[cfg(debug_assertions)] - serial::write_str(s); - - self.0.write_str(s); - - Ok(()) - } -} - -lazy_static! { - pub static ref SCREEN: ScreenLocker = - ScreenLocker(SpinLock::new(ScreenWriter(Writer::default()))); -} - -macro_rules! print { - ($($arg:tt)*) => ($crate::macros::_print(format_args!($($arg)*))); -} - -macro_rules! println { - () => (print!("\n")); - ($($arg:tt)*) => (print!("{}\n", format_args!($($arg)*))); -} - -// Lifted from standard library -#[allow(unused_macros)] -macro_rules! dbg { - () => { - println!("[DEBUG {}:{}]", file!(), line!()); - }; - ($val:expr) => { - // Use of `match` here is intentional because it affects the lifetimes - // of temporaries - https://stackoverflow.com/a/48732525/1063961 - match $val { - tmp => { - println!( - "[DEBUG {}:{}] {} = {:#?}", - file!(), - line!(), - stringify!($val), - &tmp - ); - tmp - } - } - }; -} - -#[doc(hidden)] -pub fn _print(args: fmt::Arguments) { - use core::fmt::Write; - x86_64::instructions::interrupts::without_interrupts(|| { - SCREEN.0.lock().write_fmt(args).unwrap(); - }); -} - -impl Log for ScreenLocker { - fn enabled(&self, metadata: &Metadata) -> bool { - metadata.level() <= log::max_level() - } - - fn log(&self, record: &Record) { - if self.enabled(record.metadata()) { - let color = match record.level() { - Level::Info => "\x1B[32m", - Level::Error => "\x1B[31m", - Level::Warn => "\x1B[33m", - Level::Debug => "\x1B[36m", - Level::Trace => "\x1B[35m", - }; - - println!( - "[{}{}{}] {}", - color, - record.level(), - "\x1B[0m", - record.args() - ); - } - } - - fn flush(&self) {} -} - -macro_rules! test_case { - ($test_name:ident, $body:expr) => { - #[test_case] - fn $test_name() { - print!("{}::{}... ", module_path!(), stringify!($test_name)); - $body; - println!("[ok]"); - } - }; -} diff --git a/src/src/main.rs b/src/src/main.rs deleted file mode 100644 index 6e5166b..0000000 --- a/src/src/main.rs +++ /dev/null @@ -1,63 +0,0 @@ -#![no_std] -#![no_main] -#![test_runner(crate::testing::test_runner)] -#![reexport_test_harness_main = "test_main"] -#![feature(custom_test_frameworks)] -#![feature(abi_x86_interrupt)] -#![feature(custom_inner_attributes)] -#![feature(core_intrinsics)] -#![feature(asm)] - -#[macro_use] -extern crate log; - -#[macro_use] -mod macros; - -mod cpu; -mod drivers; -mod ds; -mod testing; -mod kernel; -mod qemu; - -use bootloader::BootInfo; -#[allow(unused_imports)] -use core::panic::PanicInfo; - -#[no_mangle] -pub extern "C" fn _start(boot_info: &'static BootInfo) -> ! { - kernel::kernel_main(); - - info!( - "Physical memory offset: 0x{:x}", - boot_info.physical_memory_offset - ); - - // Run tests - #[cfg(test)] - test_main(); - - info!("nothing to do, halting..."); - abort(); -} - -#[panic_handler] -#[cfg(not(test))] -#[allow(clippy::empty_loop)] -fn panic(info: &PanicInfo) -> ! { - error!("{}", info); - - // Halt CPU - loop { - x86_64::instructions::interrupts::disable(); - x86_64::instructions::hlt(); - } -} - -fn abort() -> ! { - loop { - x86_64::instructions::interrupts::disable(); - x86_64::instructions::hlt(); - } -} diff --git a/src/src/qemu.rs b/src/src/qemu.rs deleted file mode 100644 index 028bc65..0000000 --- a/src/src/qemu.rs +++ /dev/null @@ -1,18 +0,0 @@ -#![allow(dead_code)] - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -#[repr(u32)] -pub enum ExitCode { - Success = 0x10, - Failure = 0x11, -} - -pub fn exit(exit_code: ExitCode) { - use x86_64::instructions::port::Port; - - let mut port = Port::new(0xF4); - - unsafe { - port.write(exit_code as u32); - } -} diff --git a/src/src/testing.rs b/src/src/testing.rs deleted file mode 100644 index 941cff6..0000000 --- a/src/src/testing.rs +++ /dev/null @@ -1,29 +0,0 @@ -#![allow(unused_imports)] -use crate::qemu; - -use core::panic::PanicInfo; - -#[panic_handler] -#[cfg(test)] -fn panic(info: &PanicInfo) -> ! { - println!("[failed] {}", info); - qemu::exit(qemu::ExitCode::Failure); - loop {} -} - -#[cfg(test)] -pub fn test_runner(tests: &[&dyn Fn()]) { - info!("Running {} tests", tests.len()); - println!("-----------------------"); - - for test in tests { - test(); - } - - qemu::exit(qemu::ExitCode::Success); -} - -// Example test -test_case!(basic_test, { - assert_eq!(1, 1); -}); From 290e0543d3f7f35ed3dbe08331e5b043d43381ec Mon Sep 17 00:00:00 2001 From: Deniz-Mersinlioglu Date: Sun, 18 Aug 2019 22:36:20 +0300 Subject: [PATCH 04/18] SLP_TYPa parsed --- src/drivers/acpi.rs | 32 ++++++++++++++++++++++++++++---- src/kernel.rs | 1 - 2 files changed, 28 insertions(+), 5 deletions(-) diff --git a/src/drivers/acpi.rs b/src/drivers/acpi.rs index 4751fa3..8ea218f 100644 --- a/src/drivers/acpi.rs +++ b/src/drivers/acpi.rs @@ -1,13 +1,14 @@ use acpi::{AcpiHandler, AmlTable, PhysicalMapping}; -use aml::{AmlContext, AmlError}; +use aml::{AmlContext, AmlError, AmlValue}; use core::ptr::NonNull; use x86_64::{PhysAddr, VirtAddr}; - +use aml::value::AmlValue::Package; +use aml::value::AmlType; +use lazy_static::__Deref; pub fn init() { let acpi = unsafe { acpi::search_for_rsdp_bios(&mut Acpi).expect("ACPI table parsing failed") }; - debug!("acpi: found tables"); - + debug!("acpi: found tables {:#?}", acpi); let mut ctx = AmlContext::new(); if let Some(dsdt) = &acpi.dsdt { @@ -20,6 +21,29 @@ pub fn init() { debug!("acpi: parsed ssdt {}", i); } + + let mut name = aml::AmlName::from_str("_S5_").expect("Could not get AmlName"); + let root = aml::AmlName::root(); + let mut name = ctx.namespace.search(&name, &root).expect("Could not get actual name"); + let v = ctx.namespace.get(name).expect("Could not get AmlValue"); + let mut SLP_TYPa:u64 = 52; + match v { + AmlValue::Name(p) => { + match p.deref() { + AmlValue::Package(v) => { + debug!("acpi: getting SLP_TYPa"); + SLP_TYPa = v[0].as_integer().unwrap(); + } + _ => { + unreachable!(); + } + } + }, + _ => { + unreachable!(); + } + } + debug!("acpi: done!"); } diff --git a/src/kernel.rs b/src/kernel.rs index 557d78f..aca18ed 100644 --- a/src/kernel.rs +++ b/src/kernel.rs @@ -24,7 +24,6 @@ pub fn kernel_main(info: &BootInfo) { cpu::idt::load(); let map = MemoryMap::new(&info.memory_map); - PhysAllocator::init(map); drivers::acpi::init(); From 8e53b25beeca0418cee430bbf99d364c7e364d54 Mon Sep 17 00:00:00 2001 From: Deniz-Mersinlioglu Date: Mon, 19 Aug 2019 11:40:06 +0300 Subject: [PATCH 05/18] ACPI Shutdown (or some error maybe idk) --- Cargo.lock | 8 ++----- Cargo.toml | 4 ++-- acpi | 1 + src/drivers/acpi.rs | 53 +++++++++++++++++++++++++++++++++++++++------ src/kernel.rs | 2 ++ 5 files changed, 53 insertions(+), 15 deletions(-) create mode 160000 acpi diff --git a/Cargo.lock b/Cargo.lock index 95c0864..42e7818 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3,7 +3,6 @@ [[package]] name = "acpi" version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bit_field 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", @@ -13,7 +12,6 @@ dependencies = [ [[package]] name = "aml" version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bit_field 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", @@ -81,8 +79,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" name = "solstice" version = "0.1.0" dependencies = [ - "acpi 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "aml 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "acpi 0.4.0", + "aml 0.4.0", "arrayvec 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", "bootloader 0.6.1", "intrusive-collections 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -123,8 +121,6 @@ dependencies = [ ] [metadata] -"checksum acpi 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2c18d706bdc322dd4f8f7930a5879ad8df3d78d4452a678d5419c72f9f69acea" -"checksum aml 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b7669e841017880c2710777c46ec654272163379bbe55de6e17a2a2388d44d92" "checksum arrayvec 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)" = "b8d73f9beda665eaa98ab9e4f7442bd4e7de6652587de55b2525e52e29c1b0ba" "checksum bit_field 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ed8765909f9009617974ab6b7d332625b320b33c326b1e9321382ef1999b5d56" "checksum bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3d155346769a6855b86399e9bc3814ab343cd3d62c7e985113d46a0ec3c281fd" diff --git a/Cargo.toml b/Cargo.toml index 595aca9..fb89a4e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -38,5 +38,5 @@ volatile = "0.2.6" lazy_static = { version = "1", features = ["spin_no_std"] } intrusive-collections = { version = "0.8.1", features = ["nightly"] } arrayvec = { version = "0.4.10", default-features = false } -acpi = "0.4.0" -aml = "0.4.0" +acpi = {path = "acpi/acpi"} +aml = {path = "acpi/aml"} diff --git a/acpi b/acpi new file mode 160000 index 0000000..0df085f --- /dev/null +++ b/acpi @@ -0,0 +1 @@ +Subproject commit 0df085fa6ccb3585d7b7ae95d68e588ae4912bc3 diff --git a/src/drivers/acpi.rs b/src/drivers/acpi.rs index 8ea218f..d8f8c64 100644 --- a/src/drivers/acpi.rs +++ b/src/drivers/acpi.rs @@ -1,12 +1,17 @@ -use acpi::{AcpiHandler, AmlTable, PhysicalMapping}; +use acpi::{AcpiHandler, AmlTable, PhysicalMapping, Fadt}; use aml::{AmlContext, AmlError, AmlValue}; use core::ptr::NonNull; -use x86_64::{PhysAddr, VirtAddr}; +use x86_64::{PhysAddr, VirtAddr, instructions::port::{PortRead,PortWrite}}; use aml::value::AmlValue::Package; use aml::value::AmlType; use lazy_static::__Deref; +use intrusive_collections::IntrusivePointer; +use core::borrow::BorrowMut; + +static mut SLP_TYPa:u64 = 0; +static mut acpip: *mut acpi::Acpi = 0 as *mut acpi::Acpi; pub fn init() { - let acpi = unsafe { acpi::search_for_rsdp_bios(&mut Acpi).expect("ACPI table parsing failed") }; + let mut acpi = unsafe { acpi::search_for_rsdp_bios(&mut Acpi).expect("ACPI table parsing failed") }; debug!("acpi: found tables {:#?}", acpi); let mut ctx = AmlContext::new(); @@ -26,13 +31,14 @@ pub fn init() { let root = aml::AmlName::root(); let mut name = ctx.namespace.search(&name, &root).expect("Could not get actual name"); let v = ctx.namespace.get(name).expect("Could not get AmlValue"); - let mut SLP_TYPa:u64 = 52; match v { AmlValue::Name(p) => { match p.deref() { AmlValue::Package(v) => { debug!("acpi: getting SLP_TYPa"); - SLP_TYPa = v[0].as_integer().unwrap(); + unsafe { + SLP_TYPa = v[0].as_integer().unwrap(); + } } _ => { unreachable!(); @@ -43,10 +49,43 @@ pub fn init() { unreachable!(); } } - - debug!("acpi: done!"); + unsafe { + acpip = acpi.borrow_mut(); + } + debug!("acpi: done"); } +pub fn enable() { + let fadt = unsafe { (*acpip).fadt.unwrap() }; + let fadt = unsafe { fadt.as_ref() }; + let mut readval:u16 = 0; + // SCI_EN is 1 + readval = unsafe { PortRead::read_from_port(fadt.pm1a_control_block as u16) }; + if (readval & 1 == 0) { + if (fadt.smi_cmd_port != 0 && fadt.acpi_enable != 0) { + unsafe { PortWrite::write_to_port(fadt.smi_cmd_port as u16, fadt.acpi_enable); } + readval = unsafe { PortRead::read_from_port(fadt.pm1a_control_block as u16) }; + while (readval & 1 == 0) { + readval = unsafe { PortRead::read_from_port(fadt.pm1a_control_block as u16) }; + } + if (fadt.pm1b_control_block != 0) { + readval = unsafe { PortRead::read_from_port(fadt.pm1b_control_block as u16) }; + while (readval & 1 == 0) { + readval = unsafe { PortRead::read_from_port(fadt.pm1b_control_block as u16) }; + } + } + return; + } + } +} +pub fn shutdown() { + let fadt = unsafe { (*acpip).fadt.unwrap() }; + let fadt = unsafe { fadt.as_ref() }; + unsafe { PortWrite::write_to_port(fadt.pm1a_control_block as u16, (SLP_TYPa | 1 << 13) as u16); } + if (fadt.pm1b_control_block != 0) { + unsafe { PortWrite::write_to_port(fadt.pm1b_control_block as u16, (SLP_TYPa | 1 << 13) as u16); } + } +} fn parse_table(ctx: &mut AmlContext, table: &AmlTable) -> Result<(), AmlError> { let virt = VirtAddr::from(PhysAddr::new(table.address)); diff --git a/src/kernel.rs b/src/kernel.rs index aca18ed..28acd99 100644 --- a/src/kernel.rs +++ b/src/kernel.rs @@ -27,4 +27,6 @@ pub fn kernel_main(info: &BootInfo) { PhysAllocator::init(map); drivers::acpi::init(); + drivers::acpi::enable(); + drivers::acpi::shutdown(); } From 6606388b0f88770fa0f07ca53e5177be94dd5206 Mon Sep 17 00:00:00 2001 From: Deniz-Mersinlioglu Date: Mon, 19 Aug 2019 11:41:51 +0300 Subject: [PATCH 06/18] Added self to developers list --- src/kernel.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/kernel.rs b/src/kernel.rs index 28acd99..02994f8 100644 --- a/src/kernel.rs +++ b/src/kernel.rs @@ -16,7 +16,7 @@ pub fn kernel_main(info: &BootInfo) { println!("| (___ ___ | |___| |_ _ ___ ___ - Crally"); println!(" \\___ \\ / _ \\| / __| __| |/ __/ _ \\ - Mehodin"); println!(" ____) | (_) | \\__ \\ |_| | (_| __/ - Alex8675"); - println!("|_____/ \\___/|_|___/\\__|_|\\___\\___|"); + println!("|_____/ \\___/|_|___/\\__|_|\\___\\___| -trash"); println!(); }; From b6d821b3049c5602412bc66574fdd998f9875039 Mon Sep 17 00:00:00 2001 From: Deniz-Mersinlioglu Date: Thu, 29 Aug 2019 10:36:47 +0300 Subject: [PATCH 07/18] ACPI shutdown actually works now --- Cargo.toml | 2 +- acpi | 2 +- src/drivers/acpi.rs | 66 ++++++++++++++++++++++++++------------------- src/kernel.rs | 11 +++++--- src/main.rs | 7 ++--- 5 files changed, 52 insertions(+), 36 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index fb89a4e..660926a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -39,4 +39,4 @@ lazy_static = { version = "1", features = ["spin_no_std"] } intrusive-collections = { version = "0.8.1", features = ["nightly"] } arrayvec = { version = "0.4.10", default-features = false } acpi = {path = "acpi/acpi"} -aml = {path = "acpi/aml"} +aml = {path = "acpi/aml"} \ No newline at end of file diff --git a/acpi b/acpi index 0df085f..5bf81d6 160000 --- a/acpi +++ b/acpi @@ -1 +1 @@ -Subproject commit 0df085fa6ccb3585d7b7ae95d68e588ae4912bc3 +Subproject commit 5bf81d63074ff0667cb4d64c53fc554bb186848b diff --git a/src/drivers/acpi.rs b/src/drivers/acpi.rs index d8f8c64..40c947a 100644 --- a/src/drivers/acpi.rs +++ b/src/drivers/acpi.rs @@ -1,4 +1,4 @@ -use acpi::{AcpiHandler, AmlTable, PhysicalMapping, Fadt}; +use ::acpi::{AcpiHandler, AmlTable, PhysicalMapping, Fadt, Processor}; use aml::{AmlContext, AmlError, AmlValue}; use core::ptr::NonNull; use x86_64::{PhysAddr, VirtAddr, instructions::port::{PortRead,PortWrite}}; @@ -6,22 +6,26 @@ use aml::value::AmlValue::Package; use aml::value::AmlType; use lazy_static::__Deref; use intrusive_collections::IntrusivePointer; -use core::borrow::BorrowMut; +use core::borrow::{BorrowMut, Borrow}; +use alloc::vec::Vec; +use core::marker::PhantomData; -static mut SLP_TYPa:u64 = 0; -static mut acpip: *mut acpi::Acpi = 0 as *mut acpi::Acpi; -pub fn init() { - let mut acpi = unsafe { acpi::search_for_rsdp_bios(&mut Acpi).expect("ACPI table parsing failed") }; +static mut SLP_TYPA:u64 = 0; +pub fn init() -> ::acpi::Acpi { + let mut our_acpi = unsafe {acpi::search_for_rsdp_bios(&mut Acpi).expect("ACPI table parsing failed")}; - debug!("acpi: found tables {:#?}", acpi); + debug!("acpi: found tables"); let mut ctx = AmlContext::new(); - - if let Some(dsdt) = &acpi.dsdt { - parse_table(&mut ctx, dsdt).expect("AML DSDT parsing failed"); - debug!("acpi: parsed dsdt"); + match unsafe {core::ptr::read(&our_acpi.dsdt)} { + Some(dsdt) => { + parse_table(&mut ctx, &dsdt); + debug!("acpi: parsed dsdt"); + } + None => { + warn!("acpi: DSDT not found!"); + } } - - for (i, ssdt) in acpi.ssdts.iter().enumerate() { + for (i, ssdt) in our_acpi.ssdts.iter().enumerate() { parse_table(&mut ctx, ssdt).expect("AML SSDT parsing failed"); debug!("acpi: parsed ssdt {}", i); } @@ -35,9 +39,9 @@ pub fn init() { AmlValue::Name(p) => { match p.deref() { AmlValue::Package(v) => { - debug!("acpi: getting SLP_TYPa"); + debug!("acpi: getting SLP_TYPA"); unsafe { - SLP_TYPa = v[0].as_integer().unwrap(); + SLP_TYPA = v[0].as_integer().unwrap() << 10; } } _ => { @@ -49,14 +53,12 @@ pub fn init() { unreachable!(); } } - unsafe { - acpip = acpi.borrow_mut(); - } - debug!("acpi: done"); + return our_acpi; } -pub fn enable() { - let fadt = unsafe { (*acpip).fadt.unwrap() }; - let fadt = unsafe { fadt.as_ref() }; +pub fn enable(acpi: &mut ::acpi::Acpi) { + + let fadt = unsafe { acpi.fadt.unwrap().as_ptr() }; + let mut fadt = unsafe { fadt.clone().read() }; let mut readval:u16 = 0; // SCI_EN is 1 readval = unsafe { PortRead::read_from_port(fadt.pm1a_control_block as u16) }; @@ -75,15 +77,23 @@ pub fn enable() { } } return; + } else { + debug!("ACPI cannot be enabled"); } + } else { + warn!("ACPI already enabled"); } + } -pub fn shutdown() { - let fadt = unsafe { (*acpip).fadt.unwrap() }; - let fadt = unsafe { fadt.as_ref() }; - unsafe { PortWrite::write_to_port(fadt.pm1a_control_block as u16, (SLP_TYPa | 1 << 13) as u16); } - if (fadt.pm1b_control_block != 0) { - unsafe { PortWrite::write_to_port(fadt.pm1b_control_block as u16, (SLP_TYPa | 1 << 13) as u16); } +pub fn shutdown(acpi: &mut ::acpi::Acpi) { + let fadt = unsafe { acpi.fadt.unwrap().as_ptr() }; + let mut fadt = unsafe { fadt.clone().read() }; + loop { + unsafe { PortWrite::write_to_port(fadt.pm1a_control_block as u16, (SLP_TYPA | (1 << 13)) as u16); } + if (fadt.pm1b_control_block != 0) { + unsafe { PortWrite::write_to_port(fadt.pm1b_control_block as u16, (SLP_TYPA | (1 << 13)) as u16); } + } + //wait till dead } } fn parse_table(ctx: &mut AmlContext, table: &AmlTable) -> Result<(), AmlError> { diff --git a/src/kernel.rs b/src/kernel.rs index 02994f8..ed8b31e 100644 --- a/src/kernel.rs +++ b/src/kernel.rs @@ -26,7 +26,12 @@ pub fn kernel_main(info: &BootInfo) { let map = MemoryMap::new(&info.memory_map); PhysAllocator::init(map); - drivers::acpi::init(); - drivers::acpi::enable(); - drivers::acpi::shutdown(); + let mut acpi = drivers::acpi::init(); + debug!("ACPI initialized"); + drivers::acpi::enable(&mut acpi); + debug!("ACPI enabled"); + debug!("Nothing to do, shutting down..."); + drivers::acpi::shutdown(&mut acpi); + debug!("SHUTDOWN FAILED"); + unreachable!(); } diff --git a/src/main.rs b/src/main.rs index 0fcb105..454400a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -9,7 +9,9 @@ #![feature(asm)] #![feature(alloc_layout_extra)] #![feature(alloc_error_handler)] - +#![feature(raw_vec_internals)] +#![feature(ptr_internals)] +#![feature(allocator_api)] #[macro_use] extern crate log; @@ -35,8 +37,7 @@ pub extern "C" fn _start(boot_info: &'static BootInfo) -> ! { kernel::kernel_main(boot_info); // Run tests - #[cfg(test)] - test_main(); + info!("nothing to do, halting..."); From 2ab1e41cba76a189a6ac84f93d61a6730260dd43 Mon Sep 17 00:00:00 2001 From: Deniz-Mersinlioglu Date: Thu, 29 Aug 2019 14:23:46 +0300 Subject: [PATCH 08/18] ACPI shutdown actually works now --- scripts/gdb.sh | 5 ++--- src/cpu/gdt.rs | 10 +++++----- src/kernel.rs | 3 --- src/main.rs | 1 - 4 files changed, 7 insertions(+), 12 deletions(-) diff --git a/scripts/gdb.sh b/scripts/gdb.sh index 68908c0..86e096d 100755 --- a/scripts/gdb.sh +++ b/scripts/gdb.sh @@ -1,7 +1,6 @@ #!/bin/sh set -me bootimage build -qemu-system-x86_64 -drive format=raw,file=target/x86_64-solstice/debug/bootimage-solstice.bin -no-reboot -S -s & +qemu-system-x86_64 -drive format=raw,file=../target/x86_64-solstice/debug/bootimage-solstice.bin -machine q35 -no-reboot -S -s & sleep 0.5 -gdb target/x86_64-solstice/debug/solstice -ex "target remote :1234" -pkill qemu +gdb ../target/x86_64-solstice/debug/solstice -ex "target remote :1234" \ No newline at end of file diff --git a/src/cpu/gdt.rs b/src/cpu/gdt.rs index bb4e6e7..c761ed4 100644 --- a/src/cpu/gdt.rs +++ b/src/cpu/gdt.rs @@ -54,14 +54,14 @@ pub fn load() { let null_segment = SegmentSelector::new(0, PrivilegeLevel::Ring0); let code_segment = SegmentSelector::new(1, PrivilegeLevel::Ring0); let tss_segment = SegmentSelector::new(2, PrivilegeLevel::Ring0); - seg::load_ds(null_segment); - seg::load_es(null_segment); - seg::load_fs(null_segment); - seg::load_gs(null_segment); - seg::load_ss(null_segment); + seg::load_es(SegmentSelector::new(0, PrivilegeLevel::Ring0)); + seg::load_fs(SegmentSelector::new(0, PrivilegeLevel::Ring0)); + seg::load_gs(SegmentSelector::new(0, PrivilegeLevel::Ring0)); + seg::load_ss(SegmentSelector::new(0, PrivilegeLevel::Ring0)); seg::set_cs(code_segment); load_tss(tss_segment); + } debug!("gdt: loaded"); diff --git a/src/kernel.rs b/src/kernel.rs index ed8b31e..05fa457 100644 --- a/src/kernel.rs +++ b/src/kernel.rs @@ -30,8 +30,5 @@ pub fn kernel_main(info: &BootInfo) { debug!("ACPI initialized"); drivers::acpi::enable(&mut acpi); debug!("ACPI enabled"); - debug!("Nothing to do, shutting down..."); drivers::acpi::shutdown(&mut acpi); - debug!("SHUTDOWN FAILED"); - unreachable!(); } diff --git a/src/main.rs b/src/main.rs index 454400a..bae933d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -29,7 +29,6 @@ mod ds; mod kernel; mod mm; mod testing; - use bootloader::BootInfo; #[no_mangle] From ba9e94e7876a5b7184e22dae8ea9ec8a3d27062b Mon Sep 17 00:00:00 2001 From: Deniz-Mersinlioglu Date: Thu, 5 Sep 2019 21:00:55 +0300 Subject: [PATCH 09/18] Wiped warnings --- src/cpu/percpu.rs | 4 ++-- src/drivers/acpi.rs | 46 +++++++++++++++++++++----------------------- src/kernel.rs | 3 +++ src/mm/addr_space.rs | 2 +- src/mm/pmm.rs | 5 +++-- src/mm/slob.rs | 3 +-- 6 files changed, 32 insertions(+), 31 deletions(-) diff --git a/src/cpu/percpu.rs b/src/cpu/percpu.rs index 8611ca5..95ead67 100644 --- a/src/cpu/percpu.rs +++ b/src/cpu/percpu.rs @@ -1,7 +1,7 @@ use crate::mm::addr_space::AddrSpace; use arrayvec::ArrayVec; use core::sync::atomic::{AtomicUsize, Ordering}; - +#[allow(dead_code)] pub struct PerCpu { addr_space: *const AddrSpace, preempt_count: AtomicUsize, @@ -24,7 +24,7 @@ lazy_static! { cpus }; } - +#[allow(dead_code)] impl PerCpu { pub fn current() -> &'static PerCpu { &CPUS[0] // TODO: SMP diff --git a/src/drivers/acpi.rs b/src/drivers/acpi.rs index 40c947a..0f3aaf2 100644 --- a/src/drivers/acpi.rs +++ b/src/drivers/acpi.rs @@ -1,24 +1,18 @@ -use ::acpi::{AcpiHandler, AmlTable, PhysicalMapping, Fadt, Processor}; +use ::acpi::{AcpiHandler, AmlTable, PhysicalMapping}; use aml::{AmlContext, AmlError, AmlValue}; use core::ptr::NonNull; use x86_64::{PhysAddr, VirtAddr, instructions::port::{PortRead,PortWrite}}; -use aml::value::AmlValue::Package; -use aml::value::AmlType; use lazy_static::__Deref; -use intrusive_collections::IntrusivePointer; -use core::borrow::{BorrowMut, Borrow}; -use alloc::vec::Vec; -use core::marker::PhantomData; static mut SLP_TYPA:u64 = 0; pub fn init() -> ::acpi::Acpi { - let mut our_acpi = unsafe {acpi::search_for_rsdp_bios(&mut Acpi).expect("ACPI table parsing failed")}; + let our_acpi = unsafe {acpi::search_for_rsdp_bios(&mut Acpi).expect("ACPI table parsing failed")}; debug!("acpi: found tables"); let mut ctx = AmlContext::new(); match unsafe {core::ptr::read(&our_acpi.dsdt)} { Some(dsdt) => { - parse_table(&mut ctx, &dsdt); + parse_table(&mut ctx, &dsdt).expect("AML DSDT parsing failed"); debug!("acpi: parsed dsdt"); } None => { @@ -31,9 +25,9 @@ pub fn init() -> ::acpi::Acpi { } - let mut name = aml::AmlName::from_str("_S5_").expect("Could not get AmlName"); + let name = aml::AmlName::from_str("_S5_").expect("Could not get AmlName"); let root = aml::AmlName::root(); - let mut name = ctx.namespace.search(&name, &root).expect("Could not get actual name"); + let name = ctx.namespace.search(&name, &root).expect("Could not get actual name"); let v = ctx.namespace.get(name).expect("Could not get AmlValue"); match v { AmlValue::Name(p) => { @@ -57,22 +51,23 @@ pub fn init() -> ::acpi::Acpi { } pub fn enable(acpi: &mut ::acpi::Acpi) { - let fadt = unsafe { acpi.fadt.unwrap().as_ptr() }; - let mut fadt = unsafe { fadt.clone().read() }; - let mut readval:u16 = 0; - // SCI_EN is 1 - readval = unsafe { PortRead::read_from_port(fadt.pm1a_control_block as u16) }; - if (readval & 1 == 0) { - if (fadt.smi_cmd_port != 0 && fadt.acpi_enable != 0) { + let fadt = acpi.fadt + .unwrap() + .as_ptr() + .clone(); + let fadt = unsafe {fadt.read()}; + let mut readval:u16 = unsafe { PortRead::read_from_port(fadt.pm1a_control_block as u16) }; + if readval & 1 == 0 { + if fadt.smi_cmd_port != 0 && fadt.acpi_enable != 0 { unsafe { PortWrite::write_to_port(fadt.smi_cmd_port as u16, fadt.acpi_enable); } readval = unsafe { PortRead::read_from_port(fadt.pm1a_control_block as u16) }; - while (readval & 1 == 0) { + while readval & 1 == 0 { readval = unsafe { PortRead::read_from_port(fadt.pm1a_control_block as u16) }; } - if (fadt.pm1b_control_block != 0) { + if fadt.pm1b_control_block != 0 { readval = unsafe { PortRead::read_from_port(fadt.pm1b_control_block as u16) }; - while (readval & 1 == 0) { + while readval & 1 == 0 { readval = unsafe { PortRead::read_from_port(fadt.pm1b_control_block as u16) }; } } @@ -86,11 +81,14 @@ pub fn enable(acpi: &mut ::acpi::Acpi) { } pub fn shutdown(acpi: &mut ::acpi::Acpi) { - let fadt = unsafe { acpi.fadt.unwrap().as_ptr() }; - let mut fadt = unsafe { fadt.clone().read() }; + let fadt = acpi.fadt + .unwrap() + .as_ptr() + .clone(); + let fadt = unsafe {fadt.read()}; loop { unsafe { PortWrite::write_to_port(fadt.pm1a_control_block as u16, (SLP_TYPA | (1 << 13)) as u16); } - if (fadt.pm1b_control_block != 0) { + if fadt.pm1b_control_block != 0 { unsafe { PortWrite::write_to_port(fadt.pm1b_control_block as u16, (SLP_TYPA | (1 << 13)) as u16); } } //wait till dead diff --git a/src/kernel.rs b/src/kernel.rs index 05fa457..41bc19a 100644 --- a/src/kernel.rs +++ b/src/kernel.rs @@ -30,5 +30,8 @@ pub fn kernel_main(info: &BootInfo) { debug!("ACPI initialized"); drivers::acpi::enable(&mut acpi); debug!("ACPI enabled"); + + debug!("Nothing to do, shutting down..."); drivers::acpi::shutdown(&mut acpi); + unreachable!(); } diff --git a/src/mm/addr_space.rs b/src/mm/addr_space.rs index 73505c0..859d15f 100644 --- a/src/mm/addr_space.rs +++ b/src/mm/addr_space.rs @@ -34,7 +34,7 @@ lazy_static! { } }; } - +#[allow(dead_code)] impl AddrSpace { pub fn kernel() -> &'static AddrSpace { &*KERNEL diff --git a/src/mm/pmm.rs b/src/mm/pmm.rs index 6edfc75..46b058e 100644 --- a/src/mm/pmm.rs +++ b/src/mm/pmm.rs @@ -23,7 +23,7 @@ struct Zone { num_pages: usize, order_list: [&'static mut [Block]; MAX_ORDER + 1], } - +#[allow(dead_code)] impl Zone { pub fn new(addr: PhysAddr, size: usize, blocks: &'static mut [Block]) -> Self { let num_pages = size / super::PAGE_SIZE; @@ -150,6 +150,7 @@ impl core::fmt::Debug for Block { fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { match self { Block::LargestFreeOrder(nzu) => { + fmt.write_fmt(format_args!("LargestFreeOrder({})", nzu.get() - 1)) } Block::Used => fmt.write_str("Used"), @@ -227,7 +228,7 @@ pub struct PhysAllocator { } pub static PMM: PhysAllocator = PhysAllocator::new(); - +#[allow(dead_code)] impl PhysAllocator { const fn new() -> Self { Self { diff --git a/src/mm/slob.rs b/src/mm/slob.rs index 374cd62..2eef2d6 100644 --- a/src/mm/slob.rs +++ b/src/mm/slob.rs @@ -73,7 +73,6 @@ unsafe fn alloc_inner(head: &mut Option>, layout: Layout) -> *mut .expect("block layout creation failed"); let alloc_len = layout.size() - offset; - let header_len = offset; debug_assert_eq!(offset, core::mem::size_of::()); @@ -182,7 +181,7 @@ impl Block { unsafe fn split_at( mut block: NonNull, - mut alloc_len: usize, + alloc_len: usize, ) -> (NonNull, NonNull) { let total_len = alloc_len + core::mem::size_of::(); debug_assert!(block.as_mut().size >= total_len); From 73ea2c8654040bcca80a720572cb96cc143b4086 Mon Sep 17 00:00:00 2001 From: trashcognito Date: Thu, 1 Jul 2021 18:00:36 +0300 Subject: [PATCH 10/18] trivial formatting --- src/kernel.rs | 1 - x86_64/src/structures/idt.rs | 1 - 2 files changed, 2 deletions(-) diff --git a/src/kernel.rs b/src/kernel.rs index 41bc19a..5fb65ea 100644 --- a/src/kernel.rs +++ b/src/kernel.rs @@ -8,7 +8,6 @@ use bootloader::bootinfo::BootInfo; pub fn kernel_main(info: &BootInfo) { drivers::serial::init(); drivers::vga::text_mode::init().unwrap(); - #[rustfmt::skip] { println!(" _____ _ _ _ Developed by:"); diff --git a/x86_64/src/structures/idt.rs b/x86_64/src/structures/idt.rs index f06bbd5..114742b 100644 --- a/x86_64/src/structures/idt.rs +++ b/x86_64/src/structures/idt.rs @@ -367,7 +367,6 @@ pub struct InterruptDescriptorTable { /// instruction pointer points to the instruction after the INTn. interrupts: [Entry; 256 - 32], } - impl InterruptDescriptorTable { /// Creates a new IDT filled with non-present entries. pub const fn new() -> InterruptDescriptorTable { From 89bfa4763bcb10e2931cd262534e7e5cf068d96d Mon Sep 17 00:00:00 2001 From: trashcognito Date: Thu, 1 Jul 2021 18:00:49 +0300 Subject: [PATCH 11/18] fixed mem allocation --- src/mm/slob.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/mm/slob.rs b/src/mm/slob.rs index 2eef2d6..ec39ca4 100644 --- a/src/mm/slob.rs +++ b/src/mm/slob.rs @@ -67,10 +67,11 @@ unsafe fn alloc_inner(head: &mut Option>, layout: Layout) -> *mut core::mem::size_of::(), core::mem::align_of::(), ) - .and_then(|l| l.pad_to_align()) + .and_then(|l| Ok(l.pad_to_align())) .and_then(|l| l.extend(layout)) - .and_then(|(l, o)| l.pad_to_align().map(|l| (l, o))) - .expect("block layout creation failed"); + .expect("block layout creation failed"); + //.and_then(|(l, o)| l.pad_to_align().map(|l| (l, o))) + let layout = layout.pad_to_align(); let alloc_len = layout.size() - offset; From bb855cb35f30e2f385c678616501a3d5f7fc2f21 Mon Sep 17 00:00:00 2001 From: trashcognito Date: Thu, 1 Jul 2021 18:01:32 +0300 Subject: [PATCH 12/18] migrate to llvm_asm --- x86_64/src/instructions/interrupts.rs | 8 ++++---- x86_64/src/instructions/mod.rs | 4 ++-- x86_64/src/instructions/port.rs | 12 ++++++------ x86_64/src/instructions/segmentation.rs | 14 +++++++------- x86_64/src/instructions/tables.rs | 6 +++--- x86_64/src/instructions/tlb.rs | 2 +- x86_64/src/lib.rs | 5 +++-- x86_64/src/registers/control.rs | 10 +++++----- x86_64/src/registers/mod.rs | 2 +- x86_64/src/registers/model_specific.rs | 6 +++--- x86_64/src/registers/rflags.rs | 4 ++-- 11 files changed, 37 insertions(+), 36 deletions(-) diff --git a/x86_64/src/instructions/interrupts.rs b/x86_64/src/instructions/interrupts.rs index 95c526e..b67ac0e 100644 --- a/x86_64/src/instructions/interrupts.rs +++ b/x86_64/src/instructions/interrupts.rs @@ -13,7 +13,7 @@ pub fn are_enabled() -> bool { #[inline] pub fn enable() { unsafe { - asm!("sti" :::: "volatile"); + llvm_asm!("sti" :::: "volatile"); } } @@ -23,7 +23,7 @@ pub fn enable() { #[inline] pub fn disable() { unsafe { - asm!("cli" :::: "volatile"); + llvm_asm!("cli" :::: "volatile"); } } @@ -75,7 +75,7 @@ where #[inline] pub fn int3() { unsafe { - asm!("int3" :::: "volatile"); + llvm_asm!("int3" :::: "volatile"); } } @@ -87,6 +87,6 @@ pub fn int3() { #[macro_export] macro_rules! software_interrupt { ($x:expr) => {{ - asm!("int $0" :: "N" ($x) :: "volatile"); + llvm_asm!("int $0" :: "N" ($x) :: "volatile"); }}; } diff --git a/x86_64/src/instructions/mod.rs b/x86_64/src/instructions/mod.rs index d8349f9..5fd0e21 100644 --- a/x86_64/src/instructions/mod.rs +++ b/x86_64/src/instructions/mod.rs @@ -13,7 +13,7 @@ pub mod tlb; #[inline] pub fn hlt() { unsafe { - asm!("hlt" :::: "volatile"); + llvm_asm!("hlt" :::: "volatile"); } } @@ -22,6 +22,6 @@ pub fn hlt() { #[inline] pub fn bochs_breakpoint() { unsafe { - asm!("xchgw %bx, %bx" :::: "volatile"); + llvm_asm!("xchgw %bx, %bx" :::: "volatile"); } } diff --git a/x86_64/src/instructions/port.rs b/x86_64/src/instructions/port.rs index c08fa1d..e046b7f 100644 --- a/x86_64/src/instructions/port.rs +++ b/x86_64/src/instructions/port.rs @@ -8,7 +8,7 @@ impl PortRead for u8 { #[inline] unsafe fn read_from_port(port: u16) -> u8 { let value: u8; - asm!("inb %dx, %al" : "={al}"(value) : "{dx}"(port) :: "volatile"); + llvm_asm!("inb %dx, %al" : "={al}"(value) : "{dx}"(port) :: "volatile"); value } } @@ -17,7 +17,7 @@ impl PortRead for u16 { #[inline] unsafe fn read_from_port(port: u16) -> u16 { let value: u16; - asm!("inw %dx, %ax" : "={ax}"(value) : "{dx}"(port) :: "volatile"); + llvm_asm!("inw %dx, %ax" : "={ax}"(value) : "{dx}"(port) :: "volatile"); value } } @@ -26,7 +26,7 @@ impl PortRead for u32 { #[inline] unsafe fn read_from_port(port: u16) -> u32 { let value: u32; - asm!("inl %dx, %eax" : "={eax}"(value) : "{dx}"(port) :: "volatile"); + llvm_asm!("inl %dx, %eax" : "={eax}"(value) : "{dx}"(port) :: "volatile"); value } } @@ -34,21 +34,21 @@ impl PortRead for u32 { impl PortWrite for u8 { #[inline] unsafe fn write_to_port(port: u16, value: u8) { - asm!("outb %al, %dx" :: "{dx}"(port), "{al}"(value) :: "volatile"); + llvm_asm!("outb %al, %dx" :: "{dx}"(port), "{al}"(value) :: "volatile"); } } impl PortWrite for u16 { #[inline] unsafe fn write_to_port(port: u16, value: u16) { - asm!("outw %ax, %dx" :: "{dx}"(port), "{ax}"(value) :: "volatile"); + llvm_asm!("outw %ax, %dx" :: "{dx}"(port), "{ax}"(value) :: "volatile"); } } impl PortWrite for u32 { #[inline] unsafe fn write_to_port(port: u16, value: u32) { - asm!("outl %eax, %dx" :: "{dx}"(port), "{eax}"(value) :: "volatile"); + llvm_asm!("outl %eax, %dx" :: "{dx}"(port), "{eax}"(value) :: "volatile"); } } diff --git a/x86_64/src/instructions/segmentation.rs b/x86_64/src/instructions/segmentation.rs index 4283fb3..fafdc14 100644 --- a/x86_64/src/instructions/segmentation.rs +++ b/x86_64/src/instructions/segmentation.rs @@ -11,7 +11,7 @@ use crate::structures::gdt::SegmentSelector; pub unsafe fn set_cs(sel: SegmentSelector) { #[inline(always)] unsafe fn inner(sel: SegmentSelector) { - asm!("pushq $0; \ + llvm_asm!("pushq $0; \ leaq 1f(%rip), %rax; \ pushq %rax; \ lretq; \ @@ -24,36 +24,36 @@ pub unsafe fn set_cs(sel: SegmentSelector) { /// Reload stack segment register. #[inline] pub unsafe fn load_ss(sel: SegmentSelector) { - asm!("movw $0, %ss " :: "r" (sel.0) : "memory"); + llvm_asm!("movw $0, %ss " :: "r" (sel.0) : "memory"); } /// Reload data segment register. #[inline] pub unsafe fn load_ds(sel: SegmentSelector) { - asm!("movw $0, %ds " :: "r" (sel.0) : "memory"); + llvm_asm!("movw $0, %ds " :: "r" (sel.0) : "memory"); } /// Reload es segment register. #[inline] pub unsafe fn load_es(sel: SegmentSelector) { - asm!("movw $0, %es " :: "r" (sel.0) : "memory"); + llvm_asm!("movw $0, %es " :: "r" (sel.0) : "memory"); } /// Reload fs segment register. #[inline] pub unsafe fn load_fs(sel: SegmentSelector) { - asm!("movw $0, %fs " :: "r" (sel.0) : "memory"); + llvm_asm!("movw $0, %fs " :: "r" (sel.0) : "memory"); } /// Reload gs segment register. #[inline] pub unsafe fn load_gs(sel: SegmentSelector) { - asm!("movw $0, %gs " :: "r" (sel.0) : "memory"); + llvm_asm!("movw $0, %gs " :: "r" (sel.0) : "memory"); } /// Returns the current value of the code segment register. pub fn cs() -> SegmentSelector { let segment: u16; - unsafe { asm!("mov %cs, $0" : "=r" (segment) ) }; + unsafe { llvm_asm!("mov %cs, $0" : "=r" (segment) ) }; SegmentSelector(segment) } diff --git a/x86_64/src/instructions/tables.rs b/x86_64/src/instructions/tables.rs index 9e582e9..dd13a60 100644 --- a/x86_64/src/instructions/tables.rs +++ b/x86_64/src/instructions/tables.rs @@ -9,7 +9,7 @@ pub use crate::structures::DescriptorTablePointer; /// interface to loading a GDT. #[inline] pub unsafe fn lgdt(gdt: &DescriptorTablePointer) { - asm!("lgdt ($0)" :: "r" (gdt) : "memory"); + llvm_asm!("lgdt ($0)" :: "r" (gdt) : "memory"); } /// Load an IDT. Use the @@ -17,11 +17,11 @@ pub unsafe fn lgdt(gdt: &DescriptorTablePointer) { /// interface to loading an IDT. #[inline] pub unsafe fn lidt(idt: &DescriptorTablePointer) { - asm!("lidt ($0)" :: "r" (idt) : "memory"); + llvm_asm!("lidt ($0)" :: "r" (idt) : "memory"); } /// Load the task state register using the `ltr` instruction. #[inline] pub unsafe fn load_tss(sel: SegmentSelector) { - asm!("ltr $0" :: "r" (sel.0)); + llvm_asm!("ltr $0" :: "r" (sel.0)); } diff --git a/x86_64/src/instructions/tlb.rs b/x86_64/src/instructions/tlb.rs index 91a3e6a..0b9589a 100644 --- a/x86_64/src/instructions/tlb.rs +++ b/x86_64/src/instructions/tlb.rs @@ -5,7 +5,7 @@ use crate::VirtAddr; /// Invalidate the given address in the TLB using the `invlpg` instruction. #[inline] pub fn flush(addr: VirtAddr) { - unsafe { asm!("invlpg ($0)" :: "r" (addr.as_usize()) : "memory") }; + unsafe { llvm_asm!("invlpg ($0)" :: "r" (addr.as_usize()) : "memory") }; } /// Invalidate the TLB completely by reloading the CR3 register. diff --git a/x86_64/src/lib.rs b/x86_64/src/lib.rs index e435400..c9fc1f1 100644 --- a/x86_64/src/lib.rs +++ b/x86_64/src/lib.rs @@ -2,11 +2,12 @@ //! and access to various system registers. #![feature(const_fn)] -#![feature(asm)] +#![feature(llvm_asm)] #![feature(abi_x86_interrupt)] #![cfg_attr(not(test), no_std)] #![deny(missing_debug_implementations)] - +#![feature(const_fn_fn_ptr_basics)] +#![feature(const_mut_refs)] /// Provides the non-standard-width integer types `u2`–`u63`. /// /// We use these integer types in various APIs, for example `u9` for page tables indices. diff --git a/x86_64/src/registers/control.rs b/x86_64/src/registers/control.rs index 05f1d0f..f911ad9 100644 --- a/x86_64/src/registers/control.rs +++ b/x86_64/src/registers/control.rs @@ -77,7 +77,7 @@ mod x86_64 { pub fn read_raw() -> u64 { let value: u64; unsafe { - asm!("mov %cr0, $0" : "=r" (value)); + llvm_asm!("mov %cr0, $0" : "=r" (value)); } value } @@ -99,7 +99,7 @@ mod x86_64 { /// Does _not_ preserve any values, including reserved fields. Unsafe because it's possible to violate memory /// safety by e.g. disabling paging. pub unsafe fn write_raw(value: u64) { - asm!("mov $0, %cr0" :: "r" (value) : "memory") + llvm_asm!("mov $0, %cr0" :: "r" (value) : "memory") } /// Updates CR0 flags. @@ -121,7 +121,7 @@ mod x86_64 { pub fn read() -> VirtAddr { let value: usize; unsafe { - asm!("mov %cr2, $0" : "=r" (value)); + llvm_asm!("mov %cr2, $0" : "=r" (value)); } VirtAddr::new(value) } @@ -132,7 +132,7 @@ mod x86_64 { pub fn read() -> (PhysFrame, Cr3Flags) { let value: usize; unsafe { - asm!("mov %cr3, $0" : "=r" (value)); + llvm_asm!("mov %cr3, $0" : "=r" (value)); } let flags = Cr3Flags::from_bits_truncate(value as u64); let addr = PhysAddr::new(value & 0x_000f_ffff_ffff_f000); @@ -148,7 +148,7 @@ mod x86_64 { pub unsafe fn write(frame: PhysFrame, flags: Cr3Flags) { let addr = frame.start_address(); let value = addr.as_usize() as u64 | flags.bits(); - asm!("mov $0, %cr3" :: "r" (value) : "memory") + llvm_asm!("mov $0, %cr3" :: "r" (value) : "memory") } } } diff --git a/x86_64/src/registers/mod.rs b/x86_64/src/registers/mod.rs index f8bb993..ddfb4dd 100644 --- a/x86_64/src/registers/mod.rs +++ b/x86_64/src/registers/mod.rs @@ -10,7 +10,7 @@ pub mod rflags; pub fn read_rip() -> u64 { let rip: u64; unsafe { - asm!( + llvm_asm!( "lea (%rip), $0" : "=r"(rip) ::: "volatile" ); diff --git a/x86_64/src/registers/model_specific.rs b/x86_64/src/registers/model_specific.rs index 3f4a959..29876be 100644 --- a/x86_64/src/registers/model_specific.rs +++ b/x86_64/src/registers/model_specific.rs @@ -52,15 +52,15 @@ mod x86_64 { /// Read 64 bits msr register. pub unsafe fn read(&self) -> u64 { let (high, low): (u32, u32); - asm!("rdmsr" : "={eax}" (low), "={edx}" (high) : "{ecx}" (self.0) : "memory" : "volatile"); + llvm_asm!("rdmsr" : "={eax}" (low), "={edx}" (high) : "{ecx}" (self.0) : "memory" : "volatile"); ((high as u64) << 32) | (low as u64) } /// Write 64 bits to msr register. pub unsafe fn write(&mut self, value: u64) { - let low = value as u32; + let low = value.clone() as u32; let high = (value >> 32) as u32; - asm!("wrmsr" :: "{ecx}" (self.0), "{eax}" (low), "{edx}" (high) : "memory" : "volatile" ); + llvm_asm!("wrmsr" :: "{ecx}" (self.0), "{eax}" (low), "{edx}" (high) : "memory" : "volatile" ); } } diff --git a/x86_64/src/registers/rflags.rs b/x86_64/src/registers/rflags.rs index b1fad31..9e55867 100644 --- a/x86_64/src/registers/rflags.rs +++ b/x86_64/src/registers/rflags.rs @@ -76,7 +76,7 @@ mod x86_64 { /// Returns the raw current value of the RFLAGS register. pub fn read_raw() -> u64 { let r: u64; - unsafe { asm!("pushfq; popq $0" : "=r"(r) :: "memory") }; + unsafe { llvm_asm!("pushfq; popq $0" : "=r"(r) :: "memory") }; r } @@ -93,6 +93,6 @@ mod x86_64 { /// /// Does not preserve any bits, including reserved bits. pub fn write_raw(val: u64) { - unsafe { asm!("pushq $0; popfq" :: "r"(val) : "memory" "flags") }; + unsafe { llvm_asm!("pushq $0; popfq" :: "r"(val) : "memory" "flags") }; } } From d59285fac1b717b8e44828b2f65df8ec5a9dbdc2 Mon Sep 17 00:00:00 2001 From: trashcognito Date: Thu, 1 Jul 2021 18:28:35 +0300 Subject: [PATCH 13/18] Wiped warnings --- .travis.yml | 3 +- Cargo.lock | 127 ++++--- Cargo.toml | 21 +- bootloader/.cargo/config | 2 - bootloader/.gitignore | 2 - bootloader/Cargo.lock | 97 ----- bootloader/Cargo.toml | 49 --- bootloader/LICENSE-MIT | 21 -- bootloader/README.md | 3 - bootloader/build.rs | 299 ---------------- bootloader/linker.ld | 50 --- bootloader/rust-toolchain | 1 - bootloader/src/boot_info.rs | 29 -- bootloader/src/bootinfo/memory_map.rs | 243 ------------- bootloader/src/bootinfo/mod.rs | 49 --- bootloader/src/e820.s | 55 --- bootloader/src/frame_allocator.rs | 128 ------- bootloader/src/level4_entries.rs | 43 --- bootloader/src/lib.rs | 34 -- bootloader/src/main.rs | 392 --------------------- bootloader/src/page_table.rs | 179 ---------- bootloader/src/printer/mod.rs | 11 - bootloader/src/printer/vga_320x200.rs | 83 ----- bootloader/src/printer/vga_text_80x25.rs | 37 -- bootloader/src/stage_1.s | 233 ------------ bootloader/src/stage_2.s | 105 ------ bootloader/src/stage_3.s | 199 ----------- bootloader/src/video_mode/vga_320x200.s | 90 ----- bootloader/src/video_mode/vga_text_80x25.s | 84 ----- bootloader/x86_64-bootloader.json | 21 -- src/cpu/idt.rs | 8 +- src/kernel.rs | 25 +- src/mm/addr_space.rs | 10 +- src/mm/map.rs | 6 +- src/mm/mod.rs | 16 +- src/mm/pmm.rs | 80 ++--- src/mm/slob.rs | 30 +- 37 files changed, 189 insertions(+), 2676 deletions(-) delete mode 100644 bootloader/.cargo/config delete mode 100644 bootloader/.gitignore delete mode 100644 bootloader/Cargo.lock delete mode 100644 bootloader/Cargo.toml delete mode 100644 bootloader/LICENSE-MIT delete mode 100644 bootloader/README.md delete mode 100644 bootloader/build.rs delete mode 100644 bootloader/linker.ld delete mode 100644 bootloader/rust-toolchain delete mode 100644 bootloader/src/boot_info.rs delete mode 100644 bootloader/src/bootinfo/memory_map.rs delete mode 100644 bootloader/src/bootinfo/mod.rs delete mode 100644 bootloader/src/e820.s delete mode 100644 bootloader/src/frame_allocator.rs delete mode 100644 bootloader/src/level4_entries.rs delete mode 100644 bootloader/src/lib.rs delete mode 100644 bootloader/src/main.rs delete mode 100644 bootloader/src/page_table.rs delete mode 100644 bootloader/src/printer/mod.rs delete mode 100644 bootloader/src/printer/vga_320x200.rs delete mode 100644 bootloader/src/printer/vga_text_80x25.rs delete mode 100644 bootloader/src/stage_1.s delete mode 100644 bootloader/src/stage_2.s delete mode 100644 bootloader/src/stage_3.s delete mode 100644 bootloader/src/video_mode/vga_320x200.s delete mode 100644 bootloader/src/video_mode/vga_text_80x25.s delete mode 100644 bootloader/x86_64-bootloader.json diff --git a/.travis.yml b/.travis.yml index b559ada..f71f19f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -23,10 +23,11 @@ addons: install: - if [ $TRAVIS_OS_NAME = windows ]; then choco install qemu; export PATH="/c/Program Files/qemu:$PATH"; fi + - qemu-system-x86_64 --version before_script: - rustup component add rust-src llvm-tools-preview - - cargo install bootimage cargo-xbuild cargo-cache --debug -Z install-upgrade + - cargo install bootimage cargo-xbuild cargo-cache --debug script: - cargo xbuild diff --git a/Cargo.lock b/Cargo.lock index 42e7818..ba08f33 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3,27 +3,26 @@ [[package]] name = "acpi" version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bit_field 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", - "typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "typenum 1.11.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "aml" version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bit_field 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "arrayvec" -version = "0.4.11" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", -] [[package]] name = "bit_field" @@ -32,77 +31,103 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "bitflags" -version = "1.1.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "bootloader" -version = "0.6.1" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "cast" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", +] [[package]] name = "cfg-if" -version = "0.1.9" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "intrusive-collections" -version = "0.8.1" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "memoffset 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", +] [[package]] name = "lazy_static" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "spin 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "spin 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "log" -version = "0.4.7" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "nodrop" -version = "0.1.13" +name = "memoffset" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rustc_version" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "semver" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "semver-parser" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "solstice" version = "0.1.0" dependencies = [ - "acpi 0.4.0", - "aml 0.4.0", - "arrayvec 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", - "bootloader 0.6.1", - "intrusive-collections 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", + "acpi 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "aml 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "arrayvec 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "bootloader 0.8.3 (registry+https://github.com/rust-lang/crates.io-index)", + "intrusive-collections 0.8.3 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "volatile 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", - "x86_64 0.7.2", + "x86_64 0.8.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "spin" -version = "0.5.0" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "typenum" -version = "1.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "ux" -version = "0.1.3" +version = "1.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -112,25 +137,31 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "x86_64" -version = "0.7.2" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bit_field 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "cast 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "ux 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "cast 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [metadata] -"checksum arrayvec 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)" = "b8d73f9beda665eaa98ab9e4f7442bd4e7de6652587de55b2525e52e29c1b0ba" +"checksum acpi 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2c18d706bdc322dd4f8f7930a5879ad8df3d78d4452a678d5419c72f9f69acea" +"checksum aml 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b7669e841017880c2710777c46ec654272163379bbe55de6e17a2a2388d44d92" +"checksum arrayvec 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cff77d8686867eceff3105329d4698d96c2391c176d5d03adc90c7389162b5b8" "checksum bit_field 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ed8765909f9009617974ab6b7d332625b320b33c326b1e9321382ef1999b5d56" -"checksum bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3d155346769a6855b86399e9bc3814ab343cd3d62c7e985113d46a0ec3c281fd" -"checksum cast 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "926013f2860c46252efceabb19f4a6b308197505082c609025aa6706c011d427" -"checksum cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "b486ce3ccf7ffd79fdeb678eac06a9e6c09fc88d33836340becb8fffe87c5e33" -"checksum intrusive-collections 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5e3f2fab470fde1a4bcefdc72b8a8eaad0074233397d3d4abb078114606f1262" -"checksum lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bc5729f27f159ddd61f4df6228e827e86643d4d3e7c32183cb30a1c08f604a14" -"checksum log 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "c275b6ad54070ac2d665eef9197db647b32239c9d244bfb6f041a766d00da5b3" -"checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945" -"checksum spin 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "44363f6f51401c34e7be73db0db371c04705d35efbe9f7d6082e03a921a32c55" -"checksum typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "612d636f949607bdf9b123b4a6f6d966dedf3ff669f7f045890d3a4a73948169" -"checksum ux 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "88dfeb711b61ce620c0cb6fd9f8e3e678622f0c971da2a63c4b3e25e88ed012f" +"checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" +"checksum bootloader 0.8.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d596849a47f28abdea62d7a6a25c4f6e69c3d9b09b0a2877db6e9cda004ca993" +"checksum cast 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "4b9434b9a5aa1450faa3f9cb14ea0e8c53bb5d2b3c1bfd1ab4fc03e9f33fbfb0" +"checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" +"checksum intrusive-collections 0.8.3 (registry+https://github.com/rust-lang/crates.io-index)" = "163ff4f05115a819d7d8dab45661a2a38d7dde7ee93690a0b84cc819b78ba8c4" +"checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +"checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" +"checksum memoffset 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "75189eb85871ea5c2e2c15abbdd541185f63b408415e5051f5cac122d8c774b9" +"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" +"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" +"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" +"checksum spin 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" +"checksum typenum 1.11.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6d2783fe2d6b8c1101136184eb41be8b1ad379e4657050b8aaff0c79ee7575f9" "checksum volatile 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "6af0edf5b4faacc31fc51159244d78d65ec580f021afcef7bd53c04aeabc7f29" +"checksum x86_64 0.8.3 (registry+https://github.com/rust-lang/crates.io-index)" = "5d9e3e26fcb51976eafa310e8f2b7a5a83ae8c185443efe50cbc6534a4fffa0d" diff --git a/Cargo.toml b/Cargo.toml index 660926a..d5e788e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,8 +8,8 @@ edition = "2018" run-command = [ "qemu-system-x86_64", "-serial", "stdio", - "-drive", "format=raw,file={}", "-machine", "q35", + "-drive", "format=raw,file={}", "-no-reboot", ] test-args = [ @@ -31,12 +31,15 @@ lto = true panic = "abort" [dependencies] -x86_64 = { path = "x86_64" } -bootloader = { path = "bootloader", features = ["map_physical_memory"] } -log = "0.4.6" +x86_64 = "0.8.3" +bootloader = { version = "0.8.3", features = ["map_physical_memory"] } +log = "0.4.8" volatile = "0.2.6" -lazy_static = { version = "1", features = ["spin_no_std"] } -intrusive-collections = { version = "0.8.1", features = ["nightly"] } -arrayvec = { version = "0.4.10", default-features = false } -acpi = {path = "acpi/acpi"} -aml = {path = "acpi/aml"} \ No newline at end of file +lazy_static = { version = "1.4.0", features = ["spin_no_std"] } +intrusive-collections = { version = "0.8.3", features = ["nightly"] } +arrayvec = { version = "0.5.1", default-features = false } +acpi = "0.4.0" +aml = "0.4.0" +#acpi = { path = "../acpi/acpi/" } +#aml = { path = "../acpi/aml/" } +#apic = { path = "../apic" } diff --git a/bootloader/.cargo/config b/bootloader/.cargo/config deleted file mode 100644 index fb871b1..0000000 --- a/bootloader/.cargo/config +++ /dev/null @@ -1,2 +0,0 @@ -[build] -target = "x86_64-bootloader.json" diff --git a/bootloader/.gitignore b/bootloader/.gitignore deleted file mode 100644 index eccd7b4..0000000 --- a/bootloader/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -/target/ -**/*.rs.bk diff --git a/bootloader/Cargo.lock b/bootloader/Cargo.lock deleted file mode 100644 index 0c63aab..0000000 --- a/bootloader/Cargo.lock +++ /dev/null @@ -1,97 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -[[package]] -name = "bit_field" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "bitflags" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "bootloader" -version = "0.6.1" -dependencies = [ - "fixedvec 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", - "font8x8 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", - "llvm-tools 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "toml 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "x86_64 0.7.2", - "xmas-elf 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "cast" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "fixedvec" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "font8x8" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "llvm-tools" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "serde" -version = "1.0.98" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "toml" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "serde 1.0.98 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "ux" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "x86_64" -version = "0.7.2" -dependencies = [ - "bit_field 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "cast 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "ux 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "xmas-elf" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "zero 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "zero" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[metadata] -"checksum bit_field 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ed8765909f9009617974ab6b7d332625b320b33c326b1e9321382ef1999b5d56" -"checksum bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3d155346769a6855b86399e9bc3814ab343cd3d62c7e985113d46a0ec3c281fd" -"checksum cast 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "926013f2860c46252efceabb19f4a6b308197505082c609025aa6706c011d427" -"checksum fixedvec 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b395ef2adf62bdeefcd1b59ad0dd2225c6c333ec79656ea79ac5285c46d051ea" -"checksum font8x8 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "44226c40489fb1d602344a1d8f1b544570c3435e396dda1eda7b5ef010d8f1be" -"checksum llvm-tools 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "955be5d0ca0465caf127165acb47964f911e2bc26073e865deb8be7189302faf" -"checksum serde 1.0.98 (registry+https://github.com/rust-lang/crates.io-index)" = "7fe5626ac617da2f2d9c48af5515a21d5a480dbd151e01bb1c355e26a3e68113" -"checksum toml 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b8c96d7873fa7ef8bdeb3a9cda3ac48389b4154f32b9803b4bc26220b677b039" -"checksum ux 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "88dfeb711b61ce620c0cb6fd9f8e3e678622f0c971da2a63c4b3e25e88ed012f" -"checksum xmas-elf 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "22678df5df766e8d1e5d609da69f0c3132d794edf6ab5e75e7abcd2270d4cf58" -"checksum zero 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5f1bc8a6b2005884962297587045002d8cfb8dcec9db332f4ca216ddc5de82c5" diff --git a/bootloader/Cargo.toml b/bootloader/Cargo.toml deleted file mode 100644 index 62af0f3..0000000 --- a/bootloader/Cargo.toml +++ /dev/null @@ -1,49 +0,0 @@ -[package] -name = "bootloader" -version = "0.6.1" -authors = ["Philipp Oppermann "] -license = "MIT/Apache-2.0" -description = "An experimental pure-Rust x86 bootloader." -repository = "https://github.com/rust-osdev/bootloader" -edition = "2018" -build = "build.rs" - -[[bin]] -name = "bootloader" -required-features = ["binary"] - -[dependencies] -xmas-elf = { version = "0.6.2", optional = true } -x86_64 = { path = "../x86_64", optional = true } -fixedvec = { version = "0.2.4", optional = true } - -[dependencies.font8x8] -version = "0.2.4" -default-features = false -features = ["unicode"] -optional = true - -[build-dependencies] -llvm-tools = { version = "0.1", optional = true } -toml = { version = "0.5.1", optional = true } - -[features] -default = [] -binary = ["xmas-elf", "x86_64", "fixedvec", "llvm-tools", "toml"] -vga_320x200 = ["font8x8"] -recursive_page_table = [] -map_physical_memory = [] - -[profile.dev] -panic = "abort" - -[profile.release] -panic = "abort" -lto = false -debug = true - -[package.metadata.bootloader] -target = "x86_64-bootloader.json" - -[package.metadata.docs.rs] -features = [ "recursive_page_table", "map_physical_memory" ] diff --git a/bootloader/LICENSE-MIT b/bootloader/LICENSE-MIT deleted file mode 100644 index 9b63948..0000000 --- a/bootloader/LICENSE-MIT +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2018 Philipp Oppermann - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/bootloader/README.md b/bootloader/README.md deleted file mode 100644 index f97f2dc..0000000 --- a/bootloader/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# solstice-bootloader - -FORKED FROM https://github.com/rust-osdev/bootloader diff --git a/bootloader/build.rs b/bootloader/build.rs deleted file mode 100644 index 8f91c90..0000000 --- a/bootloader/build.rs +++ /dev/null @@ -1,299 +0,0 @@ -#[cfg(not(feature = "binary"))] -fn main() { - #[cfg(target_arch = "x86")] - compile_error!( - "This crate currently does not support 32-bit protected mode. \ - See https://github.com/rust-osdev/bootloader/issues/70 for more information." - ); - - #[cfg(not(any(target_arch = "x86_64", target_arch = "x86")))] - compile_error!("This crate only supports the x86_64 architecture."); -} - -#[cfg(feature = "binary")] -#[derive(Default)] -struct BootloaderConfig { - physical_memory_offset: Option, - kernel_stack_address: Option, - kernel_stack_size: Option, -} - -#[cfg(feature = "binary")] -fn parse_aligned_addr(key: &str, value: &str) -> usize { - let num = if value.starts_with("0x") { - usize::from_str_radix(&value[2..], 16) - } else { - usize::from_str_radix(&value, 10) - }; - - let num = num.expect(&format!( - "`{}` in the kernel manifest must be an integer (is `{}`)", - key, value - )); - - if num % 0x1000 != 0 { - panic!( - "`{}` in the kernel manifest must be aligned to 4KiB (is `{}`)", - key, value - ); - } else { - num - } -} - -#[cfg(feature = "binary")] -fn parse_to_config(cfg: &mut BootloaderConfig, table: &toml::value::Table) { - use toml::Value; - - for (key, value) in table { - match (key.as_str(), value.clone()) { - ("kernel-stack-address", Value::Integer(i)) - | ("physical-memory-offset", Value::Integer(i)) => { - panic!( - "`{0}` in the kernel manifest must be given as a string, \ - as toml does not support unsigned 64-bit integers (try `{0} = \"{1}\"`)", - key.as_str(), - i - ); - } - ("kernel-stack-address", Value::String(s)) => { - cfg.kernel_stack_address = Some(parse_aligned_addr(key.as_str(), &s)); - } - #[cfg(not(feature = "map_physical_memory"))] - ("physical-memory-offset", Value::String(_)) => { - panic!( - "`physical-memory-offset` is only supported when the `map_physical_memory` \ - feature of the crate is enabled" - ); - } - #[cfg(feature = "map_physical_memory")] - ("physical-memory-offset", Value::String(s)) => { - cfg.physical_memory_offset = Some(parse_aligned_addr(key.as_str(), &s)); - } - ("kernel-stack-size", Value::Integer(i)) => { - if i <= 0 { - panic!("`kernel-stack-size` in kernel manifest must be positive"); - } else { - cfg.kernel_stack_size = Some(i as usize); - } - } - (s, _) => { - panic!( - "unknown key '{}' in kernel manifest \ - - you may need to update the bootloader crate", - s - ); - } - } - } -} - -#[cfg(feature = "binary")] -fn main() { - use std::{ - env, - fs::{self, File}, - io::Write, - path::{Path, PathBuf}, - process::{self, Command}, - }; - use toml::Value; - - let target = env::var("TARGET").expect("TARGET not set"); - if Path::new(&target) - .file_stem() - .expect("target has no file stem") - != "x86_64-bootloader" - { - panic!("The bootloader must be compiled for the `x86_64-bootloader.json` target."); - } - - let out_dir = PathBuf::from(env::var("OUT_DIR").expect("OUT_DIR not set")); - let kernel = PathBuf::from(match env::var("KERNEL") { - Ok(kernel) => kernel, - Err(_) => { - eprintln!( - "The KERNEL environment variable must be set for building the bootloader.\n\n\ - If you use `bootimage` for building you need at least version 0.7.0. You can \ - update `bootimage` by running `cargo install bootimage --force`." - ); - process::exit(1); - } - }); - let kernel_file_name = kernel - .file_name() - .expect("KERNEL has no valid file name") - .to_str() - .expect("kernel file name not valid utf8"); - - // check that the kernel file exists - assert!( - kernel.exists(), - format!("KERNEL does not exist: {}", kernel.display()) - ); - - // get access to llvm tools shipped in the llvm-tools-preview rustup component - let llvm_tools = match llvm_tools::LlvmTools::new() { - Ok(tools) => tools, - Err(llvm_tools::Error::NotFound) => { - eprintln!("Error: llvm-tools not found"); - eprintln!("Maybe the rustup component `llvm-tools-preview` is missing?"); - eprintln!(" Install it through: `rustup component add llvm-tools-preview`"); - process::exit(1); - } - Err(err) => { - eprintln!("Failed to retrieve llvm-tools component: {:?}", err); - process::exit(1); - } - }; - - // check that kernel executable has code in it - let llvm_size = llvm_tools - .tool(&llvm_tools::exe("llvm-size")) - .expect("llvm-size not found in llvm-tools"); - let mut cmd = Command::new(llvm_size); - cmd.arg(&kernel); - let output = cmd.output().expect("failed to run llvm-size"); - let output_str = String::from_utf8_lossy(&output.stdout); - let second_line_opt = output_str.lines().skip(1).next(); - let second_line = second_line_opt.expect("unexpected llvm-size line output"); - let text_size_opt = second_line.split_ascii_whitespace().next(); - let text_size = text_size_opt.expect("unexpected llvm-size output"); - if text_size == "0" { - panic!("Kernel executable has an empty text section. Perhaps the entry point was set incorrectly?\n\n\ - Kernel executable at `{}`\n", kernel.display()); - } - - // strip debug symbols from kernel for faster loading - let stripped_kernel_file_name = format!("kernel_stripped-{}", kernel_file_name); - let stripped_kernel = out_dir.join(&stripped_kernel_file_name); - let objcopy = llvm_tools - .tool(&llvm_tools::exe("llvm-objcopy")) - .expect("llvm-objcopy not found in llvm-tools"); - let mut cmd = Command::new(&objcopy); - cmd.arg("--strip-debug"); - cmd.arg(&kernel); - cmd.arg(&stripped_kernel); - let exit_status = cmd - .status() - .expect("failed to run objcopy to strip debug symbols"); - if !exit_status.success() { - eprintln!("Error: Stripping debug symbols failed"); - process::exit(1); - } - - // wrap the kernel executable as binary in a new ELF file - let stripped_kernel_file_name_replaced = stripped_kernel_file_name.replace('-', "_"); - let kernel_bin = out_dir.join(format!("kernel_bin-{}.o", kernel_file_name)); - let kernel_archive = out_dir.join(format!("libkernel_bin-{}.a", kernel_file_name)); - let mut cmd = Command::new(&objcopy); - cmd.arg("-I").arg("binary"); - cmd.arg("-O").arg("elf64-x86-64"); - cmd.arg("--binary-architecture=i386:x86-64"); - cmd.arg("--rename-section").arg(".data=.kernel"); - cmd.arg("--redefine-sym").arg(format!( - "_binary_{}_start=_kernel_start_addr", - stripped_kernel_file_name_replaced - )); - cmd.arg("--redefine-sym").arg(format!( - "_binary_{}_end=_kernel_end_addr", - stripped_kernel_file_name_replaced - )); - cmd.arg("--redefine-sym").arg(format!( - "_binary_{}_size=_kernel_size", - stripped_kernel_file_name_replaced - )); - cmd.current_dir(&out_dir); - cmd.arg(&stripped_kernel_file_name); - cmd.arg(&kernel_bin); - let exit_status = cmd.status().expect("failed to run objcopy"); - if !exit_status.success() { - eprintln!("Error: Running objcopy failed"); - process::exit(1); - } - - // create an archive for linking - let ar = llvm_tools - .tool(&llvm_tools::exe("llvm-ar")) - .unwrap_or_else(|| { - eprintln!("Failed to retrieve llvm-ar component"); - eprint!("This component is available since nightly-2019-03-29,"); - eprintln!("so try updating your toolchain if you're using an older nightly"); - process::exit(1); - }); - let mut cmd = Command::new(ar); - cmd.arg("crs"); - cmd.arg(&kernel_archive); - cmd.arg(&kernel_bin); - let exit_status = cmd.status().expect("failed to run ar"); - if !exit_status.success() { - eprintln!("Error: Running ar failed"); - process::exit(1); - } - - // Parse the kernel's Cargo.toml which is given to us by bootimage - let mut bootloader_config = BootloaderConfig::default(); - - match env::var("KERNEL_MANIFEST") { - Err(env::VarError::NotPresent) => { - panic!("The KERNEL_MANIFEST environment variable must be set for building the bootloader.\n\n\ - If you use `bootimage` for building you need at least version 0.7.7. You can \ - update `bootimage` by running `cargo install bootimage --force`."); - } - Err(env::VarError::NotUnicode(_)) => { - panic!("The KERNEL_MANIFEST environment variable contains invalid unicode") - } - Ok(path) => { - println!("cargo:rerun-if-changed={}", path); - - let contents = fs::read_to_string(&path).expect(&format!( - "failed to read kernel manifest file (path: {})", - path - )); - - let manifest = contents - .parse::() - .expect("failed to parse kernel's Cargo.toml"); - - let table = manifest - .get("package") - .and_then(|table| table.get("metadata")) - .and_then(|table| table.get("bootloader")) - .and_then(|table| table.as_table()); - - if let Some(table) = table { - parse_to_config(&mut bootloader_config, table); - } - } - } - - // Configure constants for the bootloader - // We leave some variables as Option rather than hardcoding their defaults so that they - // can be calculated dynamically by the bootloader. - let file_path = out_dir.join("bootloader_config.rs"); - let mut file = File::create(file_path).expect("failed to create bootloader_config.rs"); - file.write_all( - format!( - "const PHYSICAL_MEMORY_OFFSET: Option = {:?}; - const KERNEL_STACK_ADDRESS: Option = {:?}; - const KERNEL_STACK_SIZE: usize = {};", - bootloader_config.physical_memory_offset, - bootloader_config.kernel_stack_address, - bootloader_config.kernel_stack_size.unwrap_or(512), // size is in number of pages - ) - .as_bytes(), - ) - .expect("write to bootloader_config.rs failed"); - - // pass link arguments to rustc - println!("cargo:rustc-link-search=native={}", out_dir.display()); - println!( - "cargo:rustc-link-lib=static=kernel_bin-{}", - kernel_file_name - ); - - println!("cargo:rerun-if-env-changed=KERNEL"); - println!("cargo:rerun-if-env-changed=KERNEL_MANIFEST"); - println!("cargo:rerun-if-changed={}", kernel.display()); - println!("cargo:rerun-if-changed=build.rs"); -} diff --git a/bootloader/linker.ld b/bootloader/linker.ld deleted file mode 100644 index 4e58320..0000000 --- a/bootloader/linker.ld +++ /dev/null @@ -1,50 +0,0 @@ -ENTRY(_start) - -SECTIONS { - . = 0x500; - /* buffer for loading the kernel */ - _kernel_buffer = .; - . += 512; - /* page tables */ - . = ALIGN(0x1000); - __page_table_start = .; - _p4 = .; - . += 0x1000; - _p3 = .; - . += 0x1000; - _p2 = .; - . += 0x1000; - _p1 = .; - . += 0x1000; - __page_table_end = .; - __bootloader_start = .; - _memory_map = .; - . += 0x1000; - - _stack_start = .; - . = 0x7c00; - _stack_end = .; - - .bootloader : - { - /* first stage */ - *(.boot-first-stage) - - /* rest of bootloader */ - _rest_of_bootloader_start_addr = .; - *(.boot) - *(.context_switch) - *(.text .text.*) - *(.rodata .rodata.*) - *(.data .data.*) - *(.got) - . = ALIGN(512); - _rest_of_bootloader_end_addr = .; - __bootloader_end = .; - } - - .kernel : - { - KEEP(*(.kernel)) - } -} diff --git a/bootloader/rust-toolchain b/bootloader/rust-toolchain deleted file mode 100644 index 07ade69..0000000 --- a/bootloader/rust-toolchain +++ /dev/null @@ -1 +0,0 @@ -nightly \ No newline at end of file diff --git a/bootloader/src/boot_info.rs b/bootloader/src/boot_info.rs deleted file mode 100644 index 401c976..0000000 --- a/bootloader/src/boot_info.rs +++ /dev/null @@ -1,29 +0,0 @@ -use core::slice; - -use bootloader::bootinfo::{E820MemoryRegion, MemoryMap, MemoryRegion, MemoryRegionType}; -use x86_64::VirtAddr; - -pub(crate) fn create_from(memory_map_addr: VirtAddr, entry_count: usize) -> MemoryMap { - let memory_map_start_ptr = memory_map_addr.as_usize() as *const E820MemoryRegion; - let e820_memory_map = unsafe { slice::from_raw_parts(memory_map_start_ptr, entry_count) }; - - let mut memory_map = MemoryMap::new(); - for region in e820_memory_map { - memory_map.add_region(MemoryRegion::from(*region)); - } - - memory_map.sort(); - - let mut iter = memory_map.iter_mut().peekable(); - while let Some(region) = iter.next() { - if let Some(next) = iter.peek() { - if region.range.end_frame_number > next.range.start_frame_number - && region.region_type == MemoryRegionType::Usable - { - region.range.end_frame_number = next.range.start_frame_number; - } - } - } - - memory_map -} diff --git a/bootloader/src/bootinfo/memory_map.rs b/bootloader/src/bootinfo/memory_map.rs deleted file mode 100644 index 159b966..0000000 --- a/bootloader/src/bootinfo/memory_map.rs +++ /dev/null @@ -1,243 +0,0 @@ -use core::{ - fmt, - ops::{Deref, DerefMut}, -}; - -const PAGE_SIZE: usize = 4096; - -const MAX_MEMORY_MAP_SIZE: usize = 64; - -/// A map of the physical memory regions of the underlying machine. -#[repr(C)] -pub struct MemoryMap { - entries: [MemoryRegion; MAX_MEMORY_MAP_SIZE], - next_entry_index: usize, -} - -impl Default for MemoryMap { - fn default() -> Self { - Self::new() - } -} - -#[doc(hidden)] -impl MemoryMap { - pub fn new() -> Self { - MemoryMap { - entries: [MemoryRegion::empty(); MAX_MEMORY_MAP_SIZE], - next_entry_index: 0, - } - } - - pub fn add_region(&mut self, region: MemoryRegion) { - assert!( - self.next_entry_index() < MAX_MEMORY_MAP_SIZE, - "too many memory regions in memory map" - ); - self.entries[self.next_entry_index()] = region; - self.next_entry_index += 1; - self.sort(); - } - - pub fn sort(&mut self) { - use core::cmp::Ordering; - - self.entries.sort_unstable_by(|r1, r2| { - if r1.range.is_empty() { - Ordering::Greater - } else if r2.range.is_empty() { - Ordering::Less - } else { - let ordering = r1 - .range - .start_frame_number - .cmp(&r2.range.start_frame_number); - - if ordering == Ordering::Equal { - r1.range.end_frame_number.cmp(&r2.range.end_frame_number) - } else { - ordering - } - } - }); - if let Some(first_zero_index) = self.entries.iter().position(|r| r.range.is_empty()) { - self.next_entry_index = first_zero_index as usize; - } - } - - fn next_entry_index(&self) -> usize { - self.next_entry_index as usize - } -} - -impl Deref for MemoryMap { - type Target = [MemoryRegion]; - - fn deref(&self) -> &Self::Target { - &self.entries[0..self.next_entry_index()] - } -} - -impl DerefMut for MemoryMap { - fn deref_mut(&mut self) -> &mut Self::Target { - let next_index = self.next_entry_index(); - &mut self.entries[0..next_index] - } -} - -impl fmt::Debug for MemoryMap { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_list().entries(self.iter()).finish() - } -} - -/// Represents a region of physical memory. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -#[repr(C)] -pub struct MemoryRegion { - /// The range of frames that belong to the region. - pub range: FrameRange, - /// The type of the region. - pub region_type: MemoryRegionType, -} - -#[doc(hidden)] -impl MemoryRegion { - pub fn empty() -> Self { - MemoryRegion { - range: FrameRange { - start_frame_number: 0, - end_frame_number: 0, - }, - region_type: MemoryRegionType::Empty, - } - } -} - -/// A range of frames with an exclusive upper bound. -#[derive(Clone, Copy, PartialEq, Eq)] -#[repr(C)] -pub struct FrameRange { - /// The frame _number_ of the first 4KiB frame in the region. - /// - /// This convert this frame number to a physical address, multiply it with - /// the page size (4KiB). - pub start_frame_number: usize, - /// The frame _number_ of the first 4KiB frame that does no longer belong to - /// the region. - /// - /// This convert this frame number to a physical address, multiply it with - /// the page size (4KiB). - pub end_frame_number: usize, -} - -impl FrameRange { - /// Create a new FrameRange from the passed start_addr and end_addr. - /// - /// The end_addr is exclusive. - pub fn new(start_addr: usize, end_addr: usize) -> Self { - let last_byte = end_addr - 1; - FrameRange { - start_frame_number: start_addr / PAGE_SIZE, - end_frame_number: (last_byte / PAGE_SIZE) + 1, - } - } - - /// Returns true if the frame range contains no frames. - pub fn is_empty(&self) -> bool { - self.start_frame_number == self.end_frame_number - } - - /// Returns the physical start address of the memory region. - pub fn start_addr(&self) -> usize { - self.start_frame_number * PAGE_SIZE - } - - /// Returns the physical end address of the memory region. - pub fn end_addr(&self) -> usize { - self.end_frame_number * PAGE_SIZE - } -} - -impl fmt::Debug for FrameRange { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!( - f, - "FrameRange({:#x}..{:#x})", - self.start_addr(), - self.end_addr() - ) - } -} - -/// Represents possible types for memory regions. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -#[repr(C)] -pub enum MemoryRegionType { - /// Unused memory, can be freely used by the kernel. - Usable, - /// Memory that is already in use. - InUse, - /// Memory reserved by the hardware. Not usable. - Reserved, - /// ACPI reclaimable memory - AcpiReclaimable, - /// ACPI NVS memory - AcpiNvs, - /// Area containing bad memory - BadMemory, - /// Memory used for loading the kernel. - Kernel, - /// Memory used for the kernel stack. - KernelStack, - /// Memory used for creating page tables. - PageTable, - /// Memory used by the bootloader. - Bootloader, - /// Frame at address zero. - /// - /// (shouldn't be used because it's easy to make mistakes related to null - /// pointers) - FrameZero, - /// An empty region with size 0 - Empty, - /// Memory used for storing the boot information. - BootInfo, - /// Memory used for storing the supplied package - Package, - /// Additional variant to ensure that we can add more variants in the future - /// without breaking backwards compatibility. - #[doc(hidden)] - NonExhaustive, -} - -#[doc(hidden)] -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -#[repr(C)] -pub struct E820MemoryRegion { - pub start_addr: usize, - pub len: usize, - pub region_type: u32, - pub acpi_extended_attributes: u32, -} - -impl From for MemoryRegion { - fn from(region: E820MemoryRegion) -> MemoryRegion { - let region_type = match region.region_type { - 1 => MemoryRegionType::Usable, - 2 => MemoryRegionType::Reserved, - 3 => MemoryRegionType::AcpiReclaimable, - 4 => MemoryRegionType::AcpiNvs, - 5 => MemoryRegionType::BadMemory, - t => panic!("invalid region type {}", t), - }; - MemoryRegion { - range: FrameRange::new(region.start_addr, region.start_addr + region.len), - region_type, - } - } -} - -extern "C" { - fn _improper_ctypes_check(_boot_info: MemoryMap); -} diff --git a/bootloader/src/bootinfo/mod.rs b/bootloader/src/bootinfo/mod.rs deleted file mode 100644 index 0b3d909..0000000 --- a/bootloader/src/bootinfo/mod.rs +++ /dev/null @@ -1,49 +0,0 @@ -//! Provides boot information to the kernel. - -#![deny(improper_ctypes)] - -pub use self::memory_map::*; - -mod memory_map; - -/// This structure represents the information that the bootloader passes to the -/// kernel. -/// -/// The information is passed as an argument to the entry point: -/// -/// ```ignore -/// pub extern "C" fn _start(boot_info: &'static BootInfo) -> ! { -/// // […] -/// } -/// ``` -/// -/// Note that no type checking occurs for the entry point function, so be -/// careful to use the correct argument types. To ensure that the entry point -/// function has the correct signature, use the [`entry_point`] macro. -#[derive(Debug)] -#[repr(C)] -pub struct BootInfo { - pub memory_map: MemoryMap, - pub p4_addr: u64, - pub physical_memory_offset: u64, - _non_exhaustive: u8, // `()` is not FFI safe -} - -impl BootInfo { - /// Create a new boot information structure. This function is only for - /// internal purposes. - #[allow(unused_variables)] - #[doc(hidden)] - pub fn new(memory_map: MemoryMap, p4_addr: u64, physical_memory_offset: u64) -> Self { - BootInfo { - memory_map, - p4_addr, - physical_memory_offset, - _non_exhaustive: 0, - } - } -} - -extern "C" { - fn _improper_ctypes_check(_boot_info: BootInfo); -} diff --git a/bootloader/src/e820.s b/bootloader/src/e820.s deleted file mode 100644 index 114de23..0000000 --- a/bootloader/src/e820.s +++ /dev/null @@ -1,55 +0,0 @@ -.section .boot, "awx" -.intel_syntax noprefix -.code16 - -# From http://wiki.osdev.org/Detecting_Memory_(x86)#Getting_an_E820_Memory_Map - -# use the INT 0x15, eax= 0xE820 BIOS function to get a memory map -# inputs: es:di -> destination buffer for 24 byte entries -# outputs: bp = entry count, trashes all registers except esi -do_e820: - xor ebx, ebx # ebx must be 0 to start - xor bp, bp # keep an entry count in bp - mov edx, 0x0534D4150 # Place "SMAP" into edx - mov eax, 0xe820 - mov dword ptr es:[di + 20], 1 # force a valid ACPI 3.X entry - mov ecx, 24 # ask for 24 bytes - int 0x15 - jc .failed # carry set on first call means "unsupported function" - mov edx, 0x0534D4150 # Some BIOSes apparently trash this register? - cmp eax, edx # on success, eax must have been reset to "SMAP" - jne .failed - test ebx, ebx # ebx = 0 implies list is only 1 entry long (worthless) - je .failed - jmp .jmpin -.e820lp: - mov eax, 0xe820 # eax, ecx get trashed on every int 0x15 call - mov dword ptr es:[di + 20], 1 # force a valid ACPI 3.X entry - mov ecx, 24 # ask for 24 bytes again - int 0x15 - jc .e820f # carry set means "end of list already reached" - mov edx, 0x0534D4150 # repair potentially trashed register -.jmpin: - jcxz .skipent # skip any 0 length entries - cmp cl, 20 # got a 24 byte ACPI 3.X response? - jbe .notext - test byte ptr es:[di + 20], 1 # if so: is the "ignore this data" bit clear? - je .skipent -.notext: - mov ecx, es:[di + 8] # get lower uint32_t of memory region length - or ecx, es:[di + 12] # "or" it with upper uint32_t to test for zero - jz .skipent # if length uint64_t is 0, skip entry - inc bp # got a good entry: ++count, move to next storage spot - add di, 24 -.skipent: - test ebx, ebx # if ebx resets to 0, list is complete - jne .e820lp -.e820f: - mov [mmap_ent], bp # store the entry count - clc # there is "jc" on end of list to this point, so the carry must be cleared - ret -.failed: - stc # "function unsupported" error exit - ret - -mmap_ent: .word 0 diff --git a/bootloader/src/frame_allocator.rs b/bootloader/src/frame_allocator.rs deleted file mode 100644 index 13e906f..0000000 --- a/bootloader/src/frame_allocator.rs +++ /dev/null @@ -1,128 +0,0 @@ -use super::{frame_range, phys_frame_range}; -use bootloader::bootinfo::{MemoryMap, MemoryRegion, MemoryRegionType}; -use x86_64::structures::paging::{frame::PhysFrameRange, PhysFrame}; - -pub(crate) struct FrameAllocator<'a> { - pub memory_map: &'a mut MemoryMap, -} - -impl<'a> FrameAllocator<'a> { - pub(crate) fn allocate_frame(&mut self, region_type: MemoryRegionType) -> Option { - // try to find an existing region of same type that can be enlarged - let mut iter = self.memory_map.iter_mut().peekable(); - while let Some(region) = iter.next() { - if region.region_type == region_type { - if let Some(next) = iter.peek() { - if next.range.start_frame_number == region.range.end_frame_number - && next.region_type == MemoryRegionType::Usable - && !next.range.is_empty() - { - let frame = phys_frame_range(region.range).end; - region.range.end_frame_number += 1; - iter.next().unwrap().range.start_frame_number += 1; - return Some(frame); - } - } - } - } - - fn split_usable_region<'a, I>(iter: &mut I) -> Option<(PhysFrame, PhysFrameRange)> - where - I: Iterator, - { - for region in iter { - if region.region_type != MemoryRegionType::Usable { - continue; - } - if region.range.is_empty() { - continue; - } - - let frame = phys_frame_range(region.range).start; - region.range.start_frame_number += 1; - return Some((frame, PhysFrame::range(frame, frame + 1))); - } - None - } - - let result = if region_type == MemoryRegionType::PageTable { - // prevent fragmentation when page tables are allocated in between - split_usable_region(&mut self.memory_map.iter_mut().rev()) - } else { - split_usable_region(&mut self.memory_map.iter_mut()) - }; - - if let Some((frame, range)) = result { - self.memory_map.add_region(MemoryRegion { - range: frame_range(range), - region_type, - }); - Some(frame) - } else { - None - } - } - - /// Marks the passed region in the memory map. - /// - /// Panics if a non-usable region (e.g. a reserved region) overlaps with the - /// passed region. - pub(crate) fn mark_allocated_region(&mut self, region: MemoryRegion) { - for r in self.memory_map.iter_mut() { - if region.range.start_frame_number >= r.range.end_frame_number { - continue; - } - if region.range.end_frame_number <= r.range.start_frame_number { - continue; - } - - if r.region_type != MemoryRegionType::Usable { - panic!( - "region {:x?} overlaps with non-usable region {:x?}", - region, r - ); - } - - if region.range.start_frame_number == r.range.start_frame_number { - if region.range.end_frame_number < r.range.end_frame_number { - // Case: (r = `r`, R = `region`) - // ----rrrrrrrrrrr---- - // ----RRRR----------- - r.range.start_frame_number = region.range.end_frame_number; - self.memory_map.add_region(region); - } else { - // Case: (r = `r`, R = `region`) - // ----rrrrrrrrrrr---- - // ----RRRRRRRRRRRRRR- - *r = region; - } - } else if region.range.start_frame_number > r.range.start_frame_number { - if region.range.end_frame_number < r.range.end_frame_number { - // Case: (r = `r`, R = `region`) - // ----rrrrrrrrrrr---- - // ------RRRR--------- - let mut behind_r = r.clone(); - behind_r.range.start_frame_number = region.range.end_frame_number; - r.range.end_frame_number = region.range.start_frame_number; - self.memory_map.add_region(behind_r); - self.memory_map.add_region(region); - } else { - // Case: (r = `r`, R = `region`) - // ----rrrrrrrrrrr---- - // -----------RRRR---- or - // -------------RRRR-- - r.range.end_frame_number = region.range.start_frame_number; - self.memory_map.add_region(region); - } - } else { - // Case: (r = `r`, R = `region`) - // ----rrrrrrrrrrr---- - // --RRRR------------- - r.range.start_frame_number = region.range.end_frame_number; - self.memory_map.add_region(region); - } - return; - } - panic!("region {:x?} is not a usable memory region", region); - } -} diff --git a/bootloader/src/level4_entries.rs b/bootloader/src/level4_entries.rs deleted file mode 100644 index e17729f..0000000 --- a/bootloader/src/level4_entries.rs +++ /dev/null @@ -1,43 +0,0 @@ -use core::convert::TryInto; -use fixedvec::FixedVec; -use x86_64::ux; -use x86_64::{structures::paging::Page, VirtAddr}; -use xmas_elf::program::ProgramHeader64; - -pub struct UsedLevel4Entries { - entry_state: [bool; 512], // whether an entry is in use by the kernel -} - -impl UsedLevel4Entries { - pub fn new(segments: &FixedVec) -> Self { - let mut used = UsedLevel4Entries { - entry_state: [false; 512], - }; - - used.entry_state[0] = true; // TODO: Can we do this dynamically? - - for segment in segments { - let start_page: Page = Page::containing_address(VirtAddr::new(segment.virtual_addr as usize)); - let end_page: Page = - Page::containing_address(VirtAddr::new((segment.virtual_addr + segment.mem_size) as usize)); - - for p4_index in u64::from(start_page.p4_index())..=u64::from(end_page.p4_index()) { - used.entry_state[p4_index as usize] = true; - } - } - - used - } - - pub fn get_free_entry(&mut self) -> ux::u9 { - let (idx, entry) = self - .entry_state - .iter_mut() - .enumerate() - .find(|(_, &mut entry)| entry == false) - .expect("no usable level 4 entries found"); - - *entry = true; - ux::u9::new(idx.try_into().unwrap()) - } -} diff --git a/bootloader/src/lib.rs b/bootloader/src/lib.rs deleted file mode 100644 index 4f52099..0000000 --- a/bootloader/src/lib.rs +++ /dev/null @@ -1,34 +0,0 @@ -//! This library part of the bootloader allows kernels to retrieve information -//! from the bootloader. -//! -//! To combine your kernel with the bootloader crate you need a tool such -//! as [`bootimage`](https://github.com/rust-osdev/bootimage). See the -//! [_Writing an OS in Rust_](https://os.phil-opp.com/minimal-rust-kernel/#creating-a-bootimage) -//! blog for an explanation. - -#![no_std] - -pub use crate::bootinfo::BootInfo; - -pub mod bootinfo; - -/// Defines the entry point function. -/// -/// The function must have the signature `fn(&'static BootInfo) -> !`. -/// -/// This macro just creates a function named `_start`, which the linker will use -/// as the entry point. The advantage of using this macro instead of providing -/// an own `_start` function is that the macro ensures that the function and -/// argument types are correct. -#[macro_export] -macro_rules! entry_point { - ($path:path) => { - #[export_name = "_start"] - pub extern "C" fn __impl_start(boot_info: &'static $crate::bootinfo::BootInfo) -> ! { - // validate the signature of the program entry point - let f: fn(&'static $crate::bootinfo::BootInfo) -> ! = $path; - - f(boot_info) - } - }; -} diff --git a/bootloader/src/main.rs b/bootloader/src/main.rs deleted file mode 100644 index 5f08530..0000000 --- a/bootloader/src/main.rs +++ /dev/null @@ -1,392 +0,0 @@ -#![feature(lang_items)] -#![feature(global_asm)] -#![feature(step_trait)] -#![feature(asm)] -#![feature(nll)] -#![feature(const_fn)] -#![no_std] -#![no_main] - -#[cfg(not(target_os = "none"))] -compile_error!("The bootloader crate must be compiled for the `x86_64-bootloader.json` target"); - -use bootloader::bootinfo::{BootInfo, FrameRange}; -use core::convert::TryInto; -use core::panic::PanicInfo; -use core::{mem, slice}; -use fixedvec::alloc_stack; -use x86_64::instructions::tlb; -use x86_64::structures::paging::{ - frame::PhysFrameRange, page_table::PageTableEntry, Mapper, Page, PageTable, PageTableFlags, - PhysFrame, RecursivePageTable, Size2MiB, Size4KiB, -}; -use x86_64::ux::u9; -use x86_64::{PhysAddr, VirtAddr}; - -// The bootloader_config.rs file contains some configuration constants set by the build script: -// PHYSICAL_MEMORY_OFFSET: The offset into the virtual address space where the physical memory -// is mapped if the `map_physical_memory` feature is activated. -// -// KERNEL_STACK_ADDRESS: The virtual address of the kernel stack. -// -// KERNEL_STACK_SIZE: The number of pages in the kernel stack. -include!(concat!(env!("OUT_DIR"), "/bootloader_config.rs")); - -global_asm!(include_str!("stage_1.s")); -global_asm!(include_str!("stage_2.s")); -global_asm!(include_str!("e820.s")); -global_asm!(include_str!("stage_3.s")); - -#[cfg(feature = "vga_320x200")] -global_asm!(include_str!("video_mode/vga_320x200.s")); -#[cfg(not(feature = "vga_320x200"))] -global_asm!(include_str!("video_mode/vga_text_80x25.s")); - -unsafe fn context_switch(boot_info: VirtAddr, entry_point: VirtAddr, stack_pointer: VirtAddr) -> ! { - asm!("jmp $1; ${:private}.spin.${:uid}: jmp ${:private}.spin.${:uid}" :: - "{rsp}"(stack_pointer), "r"(entry_point), "{rdi}"(boot_info) :: "intel"); - ::core::hint::unreachable_unchecked() -} - -mod boot_info; -mod frame_allocator; -mod level4_entries; -mod page_table; -mod printer; - -pub struct IdentityMappedAddr(PhysAddr); - -impl IdentityMappedAddr { - fn phys(&self) -> PhysAddr { - self.0 - } - - fn virt(&self) -> VirtAddr { - VirtAddr::new(self.0.as_usize()) - } - - fn as_usize(&self) -> usize { - self.0.as_usize() - } -} - -// Symbols defined in `linker.ld` -extern "C" { - static mmap_ent: usize; - static _memory_map: usize; - static _kernel_start_addr: usize; - static _kernel_end_addr: usize; - static _kernel_size: usize; - static __page_table_start: usize; - static __page_table_end: usize; - static __bootloader_end: usize; - static __bootloader_start: usize; - static _p4: usize; -} - -#[no_mangle] -pub unsafe extern "C" fn stage_4() -> ! { - // Set stack segment - asm!("mov bx, 0x0 - mov ss, bx" ::: "bx" : "intel"); - - let kernel_start = 0x400000; - let kernel_size = &_kernel_size as *const _ as u64; - let memory_map_addr = &_memory_map as *const _ as u64; - let memory_map_entry_count = (mmap_ent & 0xff) as u64; // Extract lower 8 bits - let page_table_start = &__page_table_start as *const _ as u64; - let page_table_end = &__page_table_end as *const _ as u64; - let bootloader_start = &__bootloader_start as *const _ as u64; - let bootloader_end = &__bootloader_end as *const _ as u64; - let p4_physical = &_p4 as *const _ as u64; - - load_elf( - IdentityMappedAddr(PhysAddr::new(kernel_start)), - kernel_size as usize, - VirtAddr::new(memory_map_addr as usize), - memory_map_entry_count as usize, - PhysAddr::new(page_table_start as usize), - PhysAddr::new(page_table_end as usize), - PhysAddr::new(bootloader_start as usize), - PhysAddr::new(bootloader_end as usize), - PhysAddr::new(p4_physical as usize), - ) -} - -fn load_elf( - kernel_start: IdentityMappedAddr, - kernel_size: usize, - memory_map_addr: VirtAddr, - memory_map_entry_count: usize, - page_table_start: PhysAddr, - page_table_end: PhysAddr, - bootloader_start: PhysAddr, - bootloader_end: PhysAddr, - p4_physical: PhysAddr, -) -> ! { - use bootloader::bootinfo::{MemoryRegion, MemoryRegionType}; - use fixedvec::FixedVec; - use xmas_elf::program::{ProgramHeader, ProgramHeader64}; - - printer::Printer.clear_screen(); - - let mut memory_map = boot_info::create_from(memory_map_addr, memory_map_entry_count); - - let max_phys_addr = memory_map - .iter() - .map(|r| r.range.end_addr()) - .max() - .expect("no physical memory regions found"); - - // Extract required information from the ELF file. - let mut preallocated_space = alloc_stack!([ProgramHeader64; 32]); - let mut segments = FixedVec::new(&mut preallocated_space); - let entry_point; - { - let kernel_start_ptr = kernel_start.as_usize() as *const u8; - let kernel = unsafe { slice::from_raw_parts(kernel_start_ptr, kernel_size) }; - let elf_file = xmas_elf::ElfFile::new(kernel).unwrap(); - xmas_elf::header::sanity_check(&elf_file).unwrap(); - - entry_point = elf_file.header.pt2.entry_point(); - - for program_header in elf_file.program_iter() { - match program_header { - ProgramHeader::Ph64(header) => segments - .push(*header) - .expect("does not support more than 32 program segments"), - ProgramHeader::Ph32(_) => panic!("does not support 32 bit elf files"), - } - } - } - - // Mark used virtual addresses - let mut level4_entries = level4_entries::UsedLevel4Entries::new(&segments); - - // Enable support for the no-execute bit in page tables. - enable_nxe_bit(); - - // Create a recursive page table entry - let recursive_index = u9::new(level4_entries.get_free_entry().try_into().unwrap()); - let mut entry = PageTableEntry::new(); - entry.set_addr( - p4_physical, - PageTableFlags::PRESENT | PageTableFlags::WRITABLE, - ); - - // Write the recursive entry into the page table - let page_table = unsafe { &mut *(p4_physical.as_usize() as *mut PageTable) }; - page_table[recursive_index] = entry; - tlb::flush_all(); - - let recursive_page_table_addr = Page::from_page_table_indices( - recursive_index, - recursive_index, - recursive_index, - recursive_index, - ) - .start_address(); - let page_table = unsafe { &mut *(recursive_page_table_addr.as_mut_ptr()) }; - let mut rec_page_table = - RecursivePageTable::new(page_table).expect("recursive page table creation failed"); - - // Create a frame allocator, which marks allocated frames as used in the memory map. - let mut frame_allocator = frame_allocator::FrameAllocator { - memory_map: &mut memory_map, - }; - - // Mark already used memory areas in frame allocator. - { - let zero_frame: PhysFrame = PhysFrame::from_start_address(PhysAddr::new(0)).unwrap(); - frame_allocator.mark_allocated_region(MemoryRegion { - range: frame_range(PhysFrame::range(zero_frame, zero_frame + 1)), - region_type: MemoryRegionType::FrameZero, - }); - let bootloader_start_frame = PhysFrame::containing_address(bootloader_start); - let bootloader_end_frame = PhysFrame::containing_address(bootloader_end - 1usize); - let bootloader_memory_area = - PhysFrame::range(bootloader_start_frame, bootloader_end_frame + 1); - frame_allocator.mark_allocated_region(MemoryRegion { - range: frame_range(bootloader_memory_area), - region_type: MemoryRegionType::Bootloader, - }); - let kernel_start_frame = PhysFrame::containing_address(kernel_start.phys()); - let kernel_end_frame = - PhysFrame::containing_address(kernel_start.phys() + kernel_size - 1usize); - let kernel_memory_area = PhysFrame::range(kernel_start_frame, kernel_end_frame + 1); - frame_allocator.mark_allocated_region(MemoryRegion { - range: frame_range(kernel_memory_area), - region_type: MemoryRegionType::Kernel, - }); - let page_table_start_frame = PhysFrame::containing_address(page_table_start); - let page_table_end_frame = PhysFrame::containing_address(page_table_end - 1usize); - let page_table_memory_area = - PhysFrame::range(page_table_start_frame, page_table_end_frame + 1); - frame_allocator.mark_allocated_region(MemoryRegion { - range: frame_range(page_table_memory_area), - region_type: MemoryRegionType::PageTable, - }); - } - - // Unmap the ELF file. - let kernel_start_page: Page = Page::containing_address(kernel_start.virt()); - let kernel_end_page: Page = - Page::containing_address(kernel_start.virt() + kernel_size - 1usize); - for page in Page::range_inclusive(kernel_start_page, kernel_end_page) { - rec_page_table.unmap(page).expect("dealloc error").1.flush(); - } - - // Map a page for the boot info structure - let boot_info_page = { - let page: Page = Page::from_page_table_indices( - level4_entries.get_free_entry(), - u9::new(0), - u9::new(0), - u9::new(0), - ); - let frame = frame_allocator - .allocate_frame(MemoryRegionType::BootInfo) - .expect("frame allocation failed"); - let flags = PageTableFlags::PRESENT | PageTableFlags::WRITABLE; - unsafe { - page_table::map_page( - page, - frame, - flags, - &mut rec_page_table, - &mut frame_allocator, - ) - } - .expect("Mapping of bootinfo page failed") - .flush(); - page - }; - - // If no kernel stack address is provided, map the kernel stack after the boot info page - let kernel_stack_address = match KERNEL_STACK_ADDRESS { - Some(addr) => Page::containing_address(VirtAddr::new(addr)), - None => boot_info_page + 1, - }; - - // Map kernel segments. - let stack_end = page_table::map_kernel( - kernel_start.phys(), - kernel_stack_address, - KERNEL_STACK_SIZE, - &segments, - &mut rec_page_table, - &mut frame_allocator, - ) - .expect("kernel mapping failed"); - - let physical_memory_offset = if cfg!(feature = "map_physical_memory") { - let physical_memory_offset = PHYSICAL_MEMORY_OFFSET.unwrap_or_else(|| { - // If offset not manually provided, find a free p4 entry and map memory here. - // One level 4 entry spans 2^48/512 bytes (over 500gib) so this should suffice. - assert!(max_phys_addr < (1 << 48) / 512); - Page::from_page_table_indices_1gib(level4_entries.get_free_entry(), u9::new(0)) - .start_address() - .as_usize() - }); - - let virt_for_phys = - |phys: PhysAddr| -> VirtAddr { VirtAddr::new(phys.as_usize() + physical_memory_offset) }; - - let start_frame = PhysFrame::::containing_address(PhysAddr::new(0)); - let end_frame = PhysFrame::::containing_address(PhysAddr::new(max_phys_addr)); - - for frame in PhysFrame::range_inclusive(start_frame, end_frame) { - let page = Page::containing_address(virt_for_phys(frame.start_address())); - let flags = PageTableFlags::PRESENT | PageTableFlags::WRITABLE; - unsafe { - page_table::map_page( - page, - frame, - flags, - &mut rec_page_table, - &mut frame_allocator, - ) - } - .expect("Mapping of bootinfo page failed") - .flush(); - } - - physical_memory_offset - } else { - 0 // Value is unused by BootInfo::new, so this doesn't matter - }; - - // Construct boot info structure. - let mut boot_info = BootInfo::new( - memory_map, - recursive_page_table_addr.as_usize() as u64, - physical_memory_offset as u64, - ); - boot_info.memory_map.sort(); - - // Write boot info to boot info page. - let boot_info_addr = boot_info_page.start_address(); - unsafe { boot_info_addr.as_mut_ptr::().write(boot_info) }; - - // Make sure that the kernel respects the write-protection bits, even when in ring 0. - enable_write_protect_bit(); - - if cfg!(not(feature = "recursive_page_table")) { - // unmap recursive entry - rec_page_table - .unmap(Page::::containing_address( - recursive_page_table_addr, - )) - .expect("error deallocating recursive entry") - .1 - .flush(); - mem::drop(rec_page_table); - } - - let entry_point = VirtAddr::new(entry_point as usize); - - unsafe { context_switch(boot_info_addr, entry_point, stack_end) }; -} - -fn enable_nxe_bit() { - use x86_64::registers::control::{Efer, EferFlags}; - unsafe { Efer::update(|efer| *efer |= EferFlags::NO_EXECUTE_ENABLE) } -} - -fn enable_write_protect_bit() { - use x86_64::registers::control::{Cr0, Cr0Flags}; - unsafe { Cr0::update(|cr0| *cr0 |= Cr0Flags::WRITE_PROTECT) }; -} - -#[panic_handler] -#[no_mangle] -pub extern "C" fn panic(info: &PanicInfo) -> ! { - use core::fmt::Write; - write!(printer::Printer, "{}", info).unwrap(); - loop {} -} - -#[lang = "eh_personality"] -#[no_mangle] -pub extern "C" fn eh_personality() { - loop {} -} - -#[no_mangle] -pub extern "C" fn _Unwind_Resume() { - loop {} -} - -fn phys_frame_range(range: FrameRange) -> PhysFrameRange { - PhysFrameRange { - start: PhysFrame::from_start_address(PhysAddr::new(range.start_addr())).unwrap(), - end: PhysFrame::from_start_address(PhysAddr::new(range.end_addr())).unwrap(), - } -} - -fn frame_range(range: PhysFrameRange) -> FrameRange { - FrameRange::new( - range.start.start_address().as_usize(), - range.end.start_address().as_usize(), - ) -} diff --git a/bootloader/src/page_table.rs b/bootloader/src/page_table.rs deleted file mode 100644 index 1fb7426..0000000 --- a/bootloader/src/page_table.rs +++ /dev/null @@ -1,179 +0,0 @@ -use crate::frame_allocator::FrameAllocator; -use bootloader::bootinfo::MemoryRegionType; -use fixedvec::FixedVec; -use x86_64::structures::paging::mapper::{MapToError, MapperFlush, UnmapError}; -use x86_64::structures::paging::{ - self, Mapper, Page, PageSize, PageTableFlags, PhysFrame, RecursivePageTable, Size4KiB, -}; -use x86_64::{align_up, PhysAddr, VirtAddr}; -use xmas_elf::program::{self, ProgramHeader64}; - -pub(crate) fn map_kernel( - kernel_start: PhysAddr, - stack_start: Page, - stack_size: usize, - segments: &FixedVec, - page_table: &mut RecursivePageTable, - frame_allocator: &mut FrameAllocator, -) -> Result { - for segment in segments { - map_segment(segment, kernel_start, page_table, frame_allocator)?; - } - - // Create a stack - let stack_start = stack_start + 1; // Leave the first page unmapped as a 'guard page' - let stack_end = stack_start + stack_size; // stack_size is in pages - - let flags = PageTableFlags::PRESENT | PageTableFlags::WRITABLE; - let region_type = MemoryRegionType::KernelStack; - - for page in Page::range(stack_start, stack_end) { - let frame = frame_allocator - .allocate_frame(region_type) - .ok_or(MapToError::FrameAllocationFailed)?; - unsafe { map_page(page, frame, flags, page_table, frame_allocator)? }.flush(); - } - - Ok(stack_end.start_address()) -} - -pub(crate) fn map_segment( - segment: &ProgramHeader64, - kernel_start: PhysAddr, - page_table: &mut RecursivePageTable, - frame_allocator: &mut FrameAllocator, -) -> Result<(), MapToError> { - let typ = segment.get_type().unwrap(); - match typ { - program::Type::Load => { - let mem_size = segment.mem_size as usize; - let file_size = segment.file_size as usize; - let file_offset = segment.offset as usize; - let phys_start_addr = kernel_start + file_offset as usize; - let virt_start_addr = VirtAddr::new(segment.virtual_addr as usize); - - let start_page: Page = Page::containing_address(virt_start_addr); - let start_frame = PhysFrame::containing_address(phys_start_addr); - let end_frame = - PhysFrame::containing_address(phys_start_addr + file_size as usize - 1usize); - - let flags = segment.flags; - let mut page_table_flags = PageTableFlags::PRESENT; - if !flags.is_execute() { - page_table_flags |= PageTableFlags::NO_EXECUTE - }; - if flags.is_write() { - page_table_flags |= PageTableFlags::WRITABLE - }; - - for frame in PhysFrame::range_inclusive(start_frame, end_frame) { - let offset = frame - start_frame; - let page = start_page + offset; - unsafe { map_page(page, frame, page_table_flags, page_table, frame_allocator)? }.flush(); - } - - if mem_size > file_size { - // .bss section (or similar), which needs to be zeroed - let zero_start = virt_start_addr + file_size as usize; - let zero_end = virt_start_addr + mem_size as usize; - if zero_start.as_usize() & 0xfff != 0 { - // A part of the last mapped frame needs to be zeroed. This is - // not possible since it could already contains parts of the next - // segment. Thus, we need to copy it before zeroing. - - // TODO: search for a free page dynamically - let temp_page: Page = Page::containing_address(VirtAddr::new(0xfeeefeee000)); - let new_frame = frame_allocator - .allocate_frame(MemoryRegionType::Kernel) - .ok_or(MapToError::FrameAllocationFailed)?; - unsafe { map_page( - temp_page.clone(), - new_frame.clone(), - page_table_flags, - page_table, - frame_allocator, - )? } - .flush(); - - type PageArray = [usize; Size4KiB::SIZE as usize / 8]; - - let last_page = - Page::containing_address(virt_start_addr + file_size as usize - 1usize); - let last_page_ptr = last_page.start_address().as_ptr::(); - let temp_page_ptr = temp_page.start_address().as_mut_ptr::(); - - unsafe { - // copy contents - temp_page_ptr.write(last_page_ptr.read()); - } - - // remap last page - if let Err(e) = page_table.unmap(last_page.clone()) { - return Err(match e { - UnmapError::ParentEntryHugePage => MapToError::ParentEntryHugePage, - UnmapError::PageNotMapped => unreachable!(), - UnmapError::InvalidFrameAddress(_) => unreachable!(), - }); - } - - unsafe { map_page( - last_page, - new_frame, - page_table_flags, - page_table, - frame_allocator, - )? } - .flush(); - } - - // Map additional frames. - let start_page: Page = Page::containing_address(VirtAddr::new(align_up( - zero_start.as_usize(), - Size4KiB::SIZE, - ))); - let end_page = Page::containing_address(zero_end); - for page in Page::range_inclusive(start_page, end_page) { - let frame = frame_allocator - .allocate_frame(MemoryRegionType::Kernel) - .ok_or(MapToError::FrameAllocationFailed)?; - unsafe { map_page(page, frame, page_table_flags, page_table, frame_allocator)? }.flush(); - } - - // zero - for offset in file_size..mem_size { - let addr = virt_start_addr + offset as usize; - unsafe { addr.as_mut_ptr::().write(0) }; - } - } - } - _ => {} - } - Ok(()) -} - -pub(crate) unsafe fn map_page<'a, S>( - page: Page, - phys_frame: PhysFrame, - flags: PageTableFlags, - page_table: &mut RecursivePageTable<'a>, - frame_allocator: &mut FrameAllocator, -) -> Result, MapToError> -where - S: PageSize, - RecursivePageTable<'a>: Mapper, -{ - struct PageTableAllocator<'a, 'b: 'a>(&'a mut FrameAllocator<'b>); - - unsafe impl<'a, 'b> paging::FrameAllocator for PageTableAllocator<'a, 'b> { - fn allocate_frame(&mut self) -> Option> { - self.0.allocate_frame(MemoryRegionType::PageTable) - } - } - - page_table.map_to( - page, - phys_frame, - flags, - &mut PageTableAllocator(frame_allocator), - ) -} diff --git a/bootloader/src/printer/mod.rs b/bootloader/src/printer/mod.rs deleted file mode 100644 index 726bb76..0000000 --- a/bootloader/src/printer/mod.rs +++ /dev/null @@ -1,11 +0,0 @@ -#[cfg(not(feature = "vga_320x200"))] -pub use self::vga_text_80x25::*; - -#[cfg(feature = "vga_320x200")] -pub use self::vga_320x200::*; - -#[cfg(feature = "vga_320x200")] -mod vga_320x200; - -#[cfg(not(feature = "vga_320x200"))] -mod vga_text_80x25; diff --git a/bootloader/src/printer/vga_320x200.rs b/bootloader/src/printer/vga_320x200.rs deleted file mode 100644 index 5b83170..0000000 --- a/bootloader/src/printer/vga_320x200.rs +++ /dev/null @@ -1,83 +0,0 @@ -use core::{ - fmt::{Result, Write}, - slice, - sync::atomic::{AtomicUsize, Ordering}, -}; - -const VGA_BUFFER: *mut u8 = 0xa0000 as *mut _; -const SCREEN_WIDTH: usize = 320; -const SCREEN_HEIGHT: usize = 200; - -pub static X_POS: AtomicUsize = AtomicUsize::new(1); // must not be 0 so that we don't have a .bss section -pub static Y_POS: AtomicUsize = AtomicUsize::new(1); // must not be 0 so that we don't have a .bss section - -pub struct Printer; - -impl Printer { - pub fn clear_screen(&mut self) { - let vga_buffer = Self::vga_buffer(); - for byte in vga_buffer { - *byte = 0x00; - } - X_POS.store(0, Ordering::SeqCst); - Y_POS.store(0, Ordering::SeqCst); - } - - fn vga_buffer() -> &'static mut [u8] { - unsafe { slice::from_raw_parts_mut(VGA_BUFFER, SCREEN_WIDTH * SCREEN_HEIGHT) } - } - - fn newline(&mut self) { - let y_pos = Y_POS.fetch_add(8, Ordering::SeqCst); - X_POS.store(0, Ordering::SeqCst); - if y_pos >= SCREEN_HEIGHT { - self.clear_screen(); - } - } - - fn write_char(&mut self, c: char) { - use font8x8::UnicodeFonts; - - if c == '\n' { - self.newline(); - return; - } - - let vga_buffer = Self::vga_buffer(); - - let x_pos = X_POS.fetch_add(8, Ordering::SeqCst); - let y_pos = Y_POS.load(Ordering::SeqCst); - - match c { - ' '..='~' => { - let rendered = font8x8::BASIC_FONTS - .get(c) - .expect("character not found in basic font"); - for (y, byte) in rendered.iter().enumerate() { - for (x, bit) in (0..8).enumerate() { - if *byte & (1 << bit) == 0 { - continue; - } - let color = 0xf; - vga_buffer[(y_pos + y) * SCREEN_WIDTH + x_pos + x] = color; - } - } - } - _ => panic!("unprintable character"), - } - - if x_pos + 8 >= SCREEN_WIDTH { - self.newline(); - } - } -} - -impl Write for Printer { - fn write_str(&mut self, s: &str) -> Result { - for c in s.chars() { - self.write_char(c); - } - - Ok(()) - } -} diff --git a/bootloader/src/printer/vga_text_80x25.rs b/bootloader/src/printer/vga_text_80x25.rs deleted file mode 100644 index b0b726b..0000000 --- a/bootloader/src/printer/vga_text_80x25.rs +++ /dev/null @@ -1,37 +0,0 @@ -use core::{ - fmt::{Result, Write}, - sync::atomic::{AtomicUsize, Ordering}, -}; - -const VGA_BUFFER: *mut u16 = 0xb8000 as *mut _; -const SCREEN_SIZE: usize = 80 * 25; - -pub static CURRENT_OFFSET: AtomicUsize = AtomicUsize::new(160); - -pub struct Printer; - -impl Printer { - pub fn clear_screen(&mut self) { - for i in 0..SCREEN_SIZE { - unsafe { - VGA_BUFFER.offset(i as isize).write_volatile(0xf00); - } - } - - CURRENT_OFFSET.store(0, Ordering::Relaxed); - } -} - -impl Write for Printer { - fn write_str(&mut self, s: &str) -> Result { - for byte in s.bytes() { - let index = CURRENT_OFFSET.fetch_add(1, Ordering::Relaxed) as isize; - - unsafe { - VGA_BUFFER.offset(index).write_volatile(0x4f00 | u16::from(byte)); - } - } - - Ok(()) - } -} diff --git a/bootloader/src/stage_1.s b/bootloader/src/stage_1.s deleted file mode 100644 index ebfa1a0..0000000 --- a/bootloader/src/stage_1.s +++ /dev/null @@ -1,233 +0,0 @@ -.section .boot-first-stage, "awx" -.global _start -.intel_syntax noprefix -.code16 - -# This stage initializes the stack, enables the A20 line, loads the rest of -# the bootloader from disk, and jumps to stage_2. - -_start: - # zero segment registers - xor ax, ax - mov ds, ax - mov es, ax - mov ss, ax - mov fs, ax - mov gs, ax - - # clear the direction flag (e.g. go forward in memory when using - # instructions like lodsb) - cld - - # initialize stack - mov sp, 0x7c00 - - lea si, boot_start_str - call real_mode_println - -enable_a20: - # enable A20-Line via IO-Port 92, might not work on all motherboards - in al, 0x92 - test al, 2 - jnz enable_a20_after - or al, 2 - and al, 0xFE - out 0x92, al -enable_a20_after: - - -enter_protected_mode: - # clear interrupts - cli - push ds - push es - - lgdt [gdt32info] - - mov eax, cr0 - or al, 1 # set protected mode bit - mov cr0, eax - - jmp protected_mode # tell 386/486 to not crash - -protected_mode: - mov bx, 0x10 - mov ds, bx # set data segment - mov es, bx # set extra segment - - and al, 0xfe # clear protected mode bit - mov cr0, eax - -unreal_mode: - pop es # get back old extra segment - pop ds # get back old data segment - sti - - # back to real mode, but internal data segment register is still loaded - # with gdt segment -> we can access the full 4GiB of memory - - mov bx, 0x0f01 # attrib/char of smiley - mov eax, 0xb8f00 # note 32 bit offset - mov word ptr ds:[eax], bx - -check_int13h_extensions: - mov ah, 0x41 - mov bx, 0x55aa - # dl contains drive number - int 0x13 - jc no_int13h_extensions - -load_rest_of_bootloader_from_disk: - lea eax, _rest_of_bootloader_start_addr - - # start of memory buffer - mov [dap_buffer_addr], ax - - # number of disk blocks to load - lea ebx, _rest_of_bootloader_end_addr - sub ebx, eax # end - start - shr ebx, 9 # divide by 512 (block size) - mov [dap_blocks], bx - - # number of start block - lea ebx, _start - sub eax, ebx - shr eax, 9 # divide by 512 (block size) - mov [dap_start_lba], eax - - lea si, dap - mov ah, 0x42 - int 0x13 - jc rest_of_bootloader_load_failed - -jump_to_second_stage: - lea eax, [stage_2] - jmp eax - -spin: - jmp spin - -# print a string and a newline -# IN -# si: points at zero-terminated String -# CLOBBER -# ax -real_mode_println: - call real_mode_print - mov al, 13 # \r - call real_mode_print_char - mov al, 10 # \n - jmp real_mode_print_char - -# print a string -# IN -# si: points at zero-terminated String -# CLOBBER -# ax -real_mode_print: - cld -real_mode_print_loop: - # note: if direction flag is set (via std) - # this will DECREMENT the ptr, effectively - # reading/printing in reverse. - lodsb al, BYTE PTR [si] - test al, al - jz real_mode_print_done - call real_mode_print_char - jmp real_mode_print_loop -real_mode_print_done: - ret - -# print a character -# IN -# al: character to print -# CLOBBER -# ah -real_mode_print_char: - mov ah, 0x0e - int 0x10 - ret - -# print a number in hex -# IN -# bx: the number -# CLOBBER -# al, cx -real_mode_print_hex: - mov cx, 4 -.lp: - mov al, bh - shr al, 4 - - cmp al, 0xA - jb .below_0xA - - add al, 'A' - 0xA - '0' -.below_0xA: - add al, '0' - - call real_mode_print_char - - shl bx, 4 - loop .lp - - ret - -real_mode_error: - call real_mode_println - jmp spin - -no_int13h_extensions: - lea si, no_int13h_extensions_str - jmp real_mode_error - -rest_of_bootloader_load_failed: - lea si, rest_of_bootloader_load_failed_str - jmp real_mode_error - -boot_start_str: .asciz "Booting (first stage)..." -error_str: .asciz "Error: " -no_int13h_extensions_str: .asciz "No support for int13h extensions" -rest_of_bootloader_load_failed_str: .asciz "Failed to load rest of bootloader" - -gdt32info: - .word gdt32_end - gdt32 - 1 # last byte in table - .word gdt32 # start of table - -gdt32: - # entry 0 is always unused - .quad 0 -codedesc: - .byte 0xff - .byte 0xff - .byte 0 - .byte 0 - .byte 0 - .byte 0x9a - .byte 0xcf - .byte 0 -datadesc: - .byte 0xff - .byte 0xff - .byte 0 - .byte 0 - .byte 0 - .byte 0x92 - .byte 0xcf - .byte 0 -gdt32_end: - -dap: # disk access packet - .byte 0x10 # size of dap - .byte 0 # unused -dap_blocks: - .word 0 # number of sectors -dap_buffer_addr: - .word 0 # offset to memory buffer -dap_buffer_seg: - .word 0 # segment of memory buffer -dap_start_lba: - .quad 0 # start logical block address - -.org 510 -.word 0xaa55 # magic number for bootable disk diff --git a/bootloader/src/stage_2.s b/bootloader/src/stage_2.s deleted file mode 100644 index 5486439..0000000 --- a/bootloader/src/stage_2.s +++ /dev/null @@ -1,105 +0,0 @@ -.section .boot, "awx" -.intel_syntax noprefix -.code16 - -# This stage sets the target operating mode, loads the kernel from disk, -# creates an e820 memory map, enters protected mode, and jumps to the -# third stage. - -second_stage_start_str: .asciz "Booting (second stage)..." -kernel_load_failed_str: .asciz "Failed to load kernel from disk" - -kernel_load_failed: - lea si, [kernel_load_failed_str] - call real_mode_println -kernel_load_failed_spin: - jmp kernel_load_failed_spin - -stage_2: - lea si, [second_stage_start_str] - call real_mode_println - -set_target_operating_mode: - # Some BIOSs assume the processor will only operate in Legacy Mode. We change the Target - # Operating Mode to "Long Mode Target Only", so the firmware expects each CPU to enter Long Mode - # once and then stay in it. This allows the firmware to enable mode-specifc optimizations. - # We save the flags, because CF is set if the callback is not supported (in which case, this is - # a NOP) - pushf - mov ax, 0xec00 - mov bl, 0x2 - int 0x15 - popf - -load_kernel_from_disk: - # start of memory buffer - lea eax, _kernel_buffer - mov [dap_buffer_addr], ax - - # number of disk blocks to load - mov word ptr [dap_blocks], 1 - - # number of start block - lea eax, _kernel_start_addr - lea ebx, _start - sub eax, ebx - shr eax, 9 # divide by 512 (block size) - mov [dap_start_lba], eax - - # destination address - mov edi, 0x400000 - - # block count - lea ecx, _kernel_size - add ecx, 511 # align up - shr ecx, 9 - -load_next_kernel_block_from_disk: - # load block from disk - lea si, dap - mov ah, 0x42 - int 0x13 - jc kernel_load_failed - - # copy block to 2MiB - push ecx - push esi - mov ecx, 512 / 4 - # move with zero extension - # because we are moving a word ptr - # to esi, a 32-bit register. - movzx esi, word ptr [dap_buffer_addr] - # move from esi to edi ecx times. - rep movsd [edi], [esi] - pop esi - pop ecx - - # next block - mov eax, [dap_start_lba] - add eax, 1 - mov [dap_start_lba], eax - - sub ecx, 1 - jnz load_next_kernel_block_from_disk - -create_memory_map: - lea di, es:[_memory_map] - call do_e820 - -video_mode_config: - call config_video_mode - -enter_protected_mode_again: - cli - lgdt [gdt32info] - mov eax, cr0 - or al, 1 # set protected mode bit - mov cr0, eax - - push 0x8 - lea eax, [stage_3] - push eax - retf - -spin32: - jmp spin32 diff --git a/bootloader/src/stage_3.s b/bootloader/src/stage_3.s deleted file mode 100644 index 06d753c..0000000 --- a/bootloader/src/stage_3.s +++ /dev/null @@ -1,199 +0,0 @@ -.section .boot, "awx" -.intel_syntax noprefix -.code32 - -# This stage performs some checks on the CPU (cpuid, long mode), sets up an -# initial page table mapping (identity map the bootloader, map the P4 -# recursively, map the kernel blob to 4MB), enables paging, switches to long -# mode, and jumps to stage_4. - -stage_3: - mov bx, 0x10 - mov ds, bx # set data segment - mov es, bx # set extra segment - mov ss, bx # set stack segment - - lea si, boot_third_stage_str - call vga_println - -check_cpu: - call check_cpuid - call check_long_mode - - cli # disable interrupts - - lidt zero_idt # Load a zero length IDT so that any NMI causes a triple fault. - -# enter long mode - -set_up_page_tables: - # zero out buffer for page tables - lea edi, [__page_table_start] - lea ecx, [__page_table_end] - sub ecx, edi - shr ecx, 2 # one stosd zeros 4 bytes -> divide by 4 - xor eax, eax - rep stosd - - # p4 - lea eax, [_p3] - or eax, (1 | 2) - mov [_p4], eax - # p3 - lea eax, [_p2] - or eax, (1 | 2) - mov [_p3], eax - # p2 - lea eax, [_p1] - or eax, (1 | 2) - mov [_p2], eax - mov eax, (0x400000 | 1 | 2 | (1 << 7)) - mov ecx, 2 - lea edx, _kernel_size - add edx, 0x400000 # start address - add edx, 0x200000 - 1 # align up - shr edx, 12 + 9 # end huge page number - map_p2_table: - mov [_p2 + ecx * 8], eax - add eax, 0x200000 - add ecx, 1 - cmp ecx, edx - jb map_p2_table - # p1 - # start mapping from __page_table_start, as we need to be able to access - # the p4 table from rust. stop mapping at __bootloader_end - lea eax, __page_table_start - and eax, 0xfffff000 - or eax, (1 | 2) - lea ecx, __page_table_start - shr ecx, 12 # start page number - lea edx, __bootloader_end - add edx, 4096 - 1 # align up - shr edx, 12 # end page number - map_p1_table: - mov [_p1 + ecx * 8], eax - add eax, 4096 - add ecx, 1 - cmp ecx, edx - jb map_p1_table - map_framebuffer: - call vga_map_frame_buffer - -enable_paging: - # Write back cache and add a memory fence. I'm not sure if this is - # necessary, but better be on the safe side. - wbinvd - mfence - - # load P4 to cr3 register (cpu uses this to access the P4 table) - lea eax, [_p4] - mov cr3, eax - - # enable PAE-flag in cr4 (Physical Address Extension) - mov eax, cr4 - or eax, (1 << 5) - mov cr4, eax - - # set the long mode bit in the EFER MSR (model specific register) - mov ecx, 0xC0000080 - rdmsr - or eax, (1 << 8) - wrmsr - - # enable paging in the cr0 register - mov eax, cr0 - or eax, (1 << 31) - mov cr0, eax - -load_64bit_gdt: - lgdt gdt_64_pointer # Load GDT.Pointer defined below. - -jump_to_long_mode: - push 0x8 - lea eax, [stage_4] - push eax - retf # Load CS with 64 bit segment and flush the instruction cache - -spin_here: - jmp spin_here - -check_cpuid: - # Check if CPUID is supported by attempting to flip the ID bit (bit 21) - # in the FLAGS register. If we can flip it, CPUID is available. - - # Copy FLAGS in to EAX via stack - pushfd - pop eax - - # Copy to ECX as well for comparing later on - mov ecx, eax - - # Flip the ID bit - xor eax, (1 << 21) - - # Copy EAX to FLAGS via the stack - push eax - popfd - - # Copy FLAGS back to EAX (with the flipped bit if CPUID is supported) - pushfd - pop eax - - # Restore FLAGS from the old version stored in ECX (i.e. flipping the - # ID bit back if it was ever flipped). - push ecx - popfd - - # Compare EAX and ECX. If they are equal then that means the bit - # wasn't flipped, and CPUID isn't supported. - cmp eax, ecx - je no_cpuid - ret -no_cpuid: - lea esi, no_cpuid_str - call vga_println -no_cpuid_spin: - hlt - jmp no_cpuid_spin - -check_long_mode: - # test if extended processor info in available - mov eax, 0x80000000 # implicit argument for cpuid - cpuid # get highest supported argument - cmp eax, 0x80000001 # it needs to be at least 0x80000001 - jb no_long_mode # if it's less, the CPU is too old for long mode - - # use extended info to test if long mode is available - mov eax, 0x80000001 # argument for extended processor info - cpuid # returns various feature bits in ecx and edx - test edx, (1 << 29) # test if the LM-bit is set in the D-register - jz no_long_mode # If it's not set, there is no long mode - ret -no_long_mode: - lea esi, no_long_mode_str - call vga_println -no_long_mode_spin: - hlt - jmp no_long_mode_spin - - -.align 4 -zero_idt: - .word 0 - .byte 0 - -gdt_64: - .quad 0x0000000000000000 # Null Descriptor - should be present. - .quad 0x00209A0000000000 # 64-bit code descriptor (exec/read). - .quad 0x0000920000000000 # 64-bit data descriptor (read/write). - -.align 4 - .word 0 # Padding to make the "address of the GDT" field aligned on a 4-byte boundary - -gdt_64_pointer: - .word gdt_64_pointer - gdt_64 - 1 # 16-bit Size (Limit) of GDT. - .long gdt_64 # 32-bit Base Address of GDT. (CPU will zero extend to 64-bit) - -boot_third_stage_str: .asciz "Booting (third stage)..." -no_cpuid_str: .asciz "Error: CPU does not support CPUID" -no_long_mode_str: .asciz "Error: CPU does not support long mode" diff --git a/bootloader/src/video_mode/vga_320x200.s b/bootloader/src/video_mode/vga_320x200.s deleted file mode 100644 index e052def..0000000 --- a/bootloader/src/video_mode/vga_320x200.s +++ /dev/null @@ -1,90 +0,0 @@ -.section .boot, "awx" -.intel_syntax noprefix -.code16 - -config_video_mode: - mov ah, 0 - mov al, 0x13 # 320x200 256 color graphics - int 0x10 - ret - -.code32 - -vga_map_frame_buffer: - mov eax, 0xa0000 - or eax, (1 | 2) -vga_map_frame_buffer_loop: - mov ecx, eax - shr ecx, 12 - mov [_p1 + ecx * 8], eax - - add eax, 4096 - cmp eax, 0xa0000 + 320 * 200 - jl vga_map_frame_buffer_loop - - ret - -# print a string and a newline -# IN -# esi: points at zero-terminated String -vga_println: - push eax - push ebx - push ecx - push edx - - call vga_print - - # newline - mov edx, 0 - mov eax, vga_position - mov ecx, 80 * 2 - div ecx - add eax, 1 - mul ecx - mov vga_position, eax - - pop edx - pop ecx - pop ebx - pop eax - - ret - -# print a string -# IN -# esi: points at zero-terminated String -# CLOBBER -# ah, ebx -vga_print: - cld -vga_print_loop: - # note: if direction flag is set (via std) - # this will DECREMENT the ptr, effectively - # reading/printing in reverse. - lodsb al, BYTE PTR [esi] - test al, al - jz vga_print_done - call vga_print_char - jmp vga_print_loop -vga_print_done: - ret - - -# print a character -# IN -# al: character to print -# CLOBBER -# ah, ebx -vga_print_char: - mov ebx, vga_position - mov ah, 0x0f - mov [ebx + 0xa0000], ax - - add ebx, 2 - mov [vga_position], ebx - - ret - -vga_position: - .double 0 diff --git a/bootloader/src/video_mode/vga_text_80x25.s b/bootloader/src/video_mode/vga_text_80x25.s deleted file mode 100644 index 0720876..0000000 --- a/bootloader/src/video_mode/vga_text_80x25.s +++ /dev/null @@ -1,84 +0,0 @@ -.section .boot, "awx" -.intel_syntax noprefix -.code16 - -config_video_mode: - mov ah, 0 - mov al, 0x03 # 80x25 16 color text - int 0x10 - ret - -.code32 - -vga_map_frame_buffer: - mov eax, 0xb8000 - or eax, (1 | 2) - mov ecx, 0xb8000 - shr ecx, 12 - mov [_p1 + ecx * 8], eax - ret - -# print a string and a newline -# IN -# esi: points at zero-terminated String -vga_println: - push eax - push ebx - push ecx - push edx - - call vga_print - - # newline - mov edx, 0 - mov eax, vga_position - mov ecx, 80 * 2 - div ecx - add eax, 1 - mul ecx - mov vga_position, eax - - pop edx - pop ecx - pop ebx - pop eax - - ret - -# print a string -# IN -# esi: points at zero-terminated String -# CLOBBER -# ah, ebx -vga_print: - cld -vga_print_loop: - # note: if direction flag is set (via std) - # this will DECREMENT the ptr, effectively - # reading/printing in reverse. - lodsb al, BYTE PTR [esi] - test al, al - jz vga_print_done - call vga_print_char - jmp vga_print_loop -vga_print_done: - ret - - -# print a character -# IN -# al: character to print -# CLOBBER -# ah, ebx -vga_print_char: - mov ebx, vga_position - mov ah, 0x0f - mov [ebx + 0xb8000], ax - - add ebx, 2 - mov [vga_position], ebx - - ret - -vga_position: - .double 0 diff --git a/bootloader/x86_64-bootloader.json b/bootloader/x86_64-bootloader.json deleted file mode 100644 index 391f1c2..0000000 --- a/bootloader/x86_64-bootloader.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "llvm-target": "x86_64-unknown-none-gnu", - "data-layout": "e-m:e-i64:64-f80:128-n8:16:32:64-S128", - "linker-flavor": "ld.lld", - "linker": "rust-lld", - "pre-link-args": { - "ld.lld": [ - "--script=linker.ld" - ] - }, - "target-endian": "little", - "target-pointer-width": "64", - "target-c-int-width": "32", - "arch": "x86_64", - "os": "none", - "features": "-mmx,-sse,+soft-float", - "disable-redzone": true, - "panic": "abort", - "executables": true, - "relocation_model": "static" -} diff --git a/src/cpu/idt.rs b/src/cpu/idt.rs index 83fa4c3..ead4cb9 100644 --- a/src/cpu/idt.rs +++ b/src/cpu/idt.rs @@ -7,7 +7,7 @@ use crate::cpu::gdt::DOUBLE_FAULT_IST_INDEX; lazy_static! { static ref IDT: idt::InterruptDescriptorTable = { let mut idt = idt::InterruptDescriptorTable::new(); - idt.divide_by_zero.set_handler_fn(divide_by_zero_handler); + idt.divide_error.set_handler_fn(divide_error_handler); idt.debug.set_handler_fn(debug_handler); idt.non_maskable_interrupt.set_handler_fn(non_maskable_interrupt_handler); idt.breakpoint.set_handler_fn(breakpoint_handler); @@ -40,7 +40,7 @@ test_case!(int3_handler, { x86_64::instructions::interrupts::int3(); }); -extern "x86-interrupt" fn divide_by_zero_handler(frame: &mut idt::InterruptStackFrame) { +extern "x86-interrupt" fn divide_error_handler(frame: &mut idt::InterruptStackFrame) { panic!("EXCEPTION: Zero Division\n{:#?}", frame); } @@ -72,7 +72,7 @@ extern "x86-interrupt" fn device_not_available_handler(frame: &mut idt::Interrup panic!("EXCEPTION: Device Not Available\n{:#?}", frame); } -extern "x86-interrupt" fn double_fault_handler(frame: &mut idt::InterruptStackFrame, error_code: u64) { +extern "x86-interrupt" fn double_fault_handler(frame: &mut idt::InterruptStackFrame, error_code: u64) -> ! { panic!("EXCEPTION: Double Fault with error code {}\n{:#?}", error_code, frame); } @@ -104,7 +104,7 @@ extern "x86-interrupt" fn alignment_check_handler(frame: &mut idt::InterruptStac panic!("EXCEPTION: Alignment Check with error code {}\n{:#?}", error_code, frame); } -extern "x86-interrupt" fn machine_check_handler(frame: &mut idt::InterruptStackFrame) { +extern "x86-interrupt" fn machine_check_handler(frame: &mut idt::InterruptStackFrame) -> ! { panic!("EXCEPTION: Machine Check\n{:#?}", frame); } diff --git a/src/kernel.rs b/src/kernel.rs index 5fb65ea..eeff5c0 100644 --- a/src/kernel.rs +++ b/src/kernel.rs @@ -3,11 +3,14 @@ use crate::{ drivers, mm::{map::MemoryMap, pmm::PhysAllocator}, }; +use acpi::InterruptModel; +use apic::{LocalApic, XApic}; use bootloader::bootinfo::BootInfo; pub fn kernel_main(info: &BootInfo) { drivers::serial::init(); drivers::vga::text_mode::init().unwrap(); + #[rustfmt::skip] { println!(" _____ _ _ _ Developed by:"); @@ -15,7 +18,7 @@ pub fn kernel_main(info: &BootInfo) { println!("| (___ ___ | |___| |_ _ ___ ___ - Crally"); println!(" \\___ \\ / _ \\| / __| __| |/ __/ _ \\ - Mehodin"); println!(" ____) | (_) | \\__ \\ |_| | (_| __/ - Alex8675"); - println!("|_____/ \\___/|_|___/\\__|_|\\___\\___| -trash"); + println!("|_____/ \\___/|_|___/\\__|_|\\___\\___|"); println!(); }; @@ -23,14 +26,20 @@ pub fn kernel_main(info: &BootInfo) { cpu::idt::load(); let map = MemoryMap::new(&info.memory_map); + PhysAllocator::init(map); - let mut acpi = drivers::acpi::init(); - debug!("ACPI initialized"); - drivers::acpi::enable(&mut acpi); - debug!("ACPI enabled"); + let acpi = drivers::acpi::init(); - debug!("Nothing to do, shutting down..."); - drivers::acpi::shutdown(&mut acpi); - unreachable!(); + match acpi.interrupt_model { + None => panic!("unknown interrupt model"), + Some(InterruptModel::Pic { .. }) => panic!("unsupported acpi interrupt model"), + Some(InterruptModel::Apic { .. }) => { + if !XApic::is_supported() { + error!("apic: xapic is not supported"); + } else { + info!("apic: detected xapic support"); + } + } + }; } diff --git a/src/mm/addr_space.rs b/src/mm/addr_space.rs index 859d15f..c40c13b 100644 --- a/src/mm/addr_space.rs +++ b/src/mm/addr_space.rs @@ -2,7 +2,7 @@ use crate::{ds::RwSpinLock, mm::pmm::PhysAllocator}; use x86_64::{ registers::control::Cr3, structures::paging::{ - frame::PhysFrame, + UnusedPhysFrame, mapper::{MapToError, MapperAllSizes, MapperFlush}, page::Size4KiB, FrameAllocator, @@ -25,11 +25,11 @@ unsafe impl Sync for AddrSpace {} lazy_static! { static ref KERNEL: AddrSpace = { let (table_frame, _) = Cr3::read(); - let table_virt: VirtAddr = table_frame.start_address().into(); + let table_virt = super::phys_to_kernel_virt(table_frame.start_address()); AddrSpace { table: RwSpinLock::new(unsafe { - OffsetPageTable::new(&mut *table_virt.as_mut_ptr(), super::PHYS_OFFSET) + OffsetPageTable::new(&mut *table_virt.as_mut_ptr(), VirtAddr::new(super::PHYS_OFFSET)) }), } }; @@ -48,7 +48,7 @@ impl AddrSpace { ) -> Result, MapToError> { struct PhysAllocatorProxy; unsafe impl FrameAllocator for PhysAllocatorProxy { - fn allocate_frame(&mut self) -> Option> { + fn allocate_frame(&mut self) -> Option> { Some(PhysAllocator::alloc(0).start) } } @@ -68,7 +68,7 @@ impl AddrSpace { unsafe { self.table.write().map_to( Page::containing_address(virt), - PhysFrame::containing_address(phys), + UnusedPhysFrame::containing_address(phys), flags, alloc, ) diff --git a/src/mm/map.rs b/src/mm/map.rs index d87eba4..9df0e5f 100644 --- a/src/mm/map.rs +++ b/src/mm/map.rs @@ -7,7 +7,7 @@ use core::{ ptr::{self, NonNull}, }; use x86_64::{ - structures::paging::{FrameAllocator, PageSize, PageTableFlags, PhysFrame, Size4KiB}, + structures::paging::{FrameAllocator, PageSize, PageTableFlags, UnusedPhysFrame, PhysFrame, Size4KiB}, PhysAddr, VirtAddr, }; @@ -107,7 +107,7 @@ impl MemoryMap { } unsafe impl FrameAllocator for MemoryMap { - fn allocate_frame(&mut self) -> Option { + fn allocate_frame(&mut self) -> Option { let (idx, found_region) = self .regions .iter_mut() @@ -137,7 +137,7 @@ unsafe impl FrameAllocator for MemoryMap { ) }; - Some(out) + unsafe { Some(UnusedPhysFrame::new(out)) } } } diff --git a/src/mm/mod.rs b/src/mm/mod.rs index 2d4a9ec..6a1ff1c 100644 --- a/src/mm/mod.rs +++ b/src/mm/mod.rs @@ -1,8 +1,9 @@ -pub const PHYS_OFFSET: usize = 0xFFFF8000_00000000; -pub const PAGE_INFO_OFFSET: usize = 0xFFFF9000_00000000; -pub const PAGE_SIZE: usize = 0x1000; +pub const PHYS_OFFSET: u64 = 0xFFFF8000_00000000; +pub const PAGE_INFO_OFFSET: u64 = 0xFFFF9000_00000000; +pub const PAGE_SIZE: u64 = 0x1000; use crate::ds::RwSpinLock; +use x86_64::{VirtAddr, PhysAddr}; use x86_64::structures::paging::PhysFrame; pub mod addr_space; @@ -24,3 +25,12 @@ pub fn phys_to_page_info(frame: PhysFrame) -> *const PageInfo { out_addr as *const PageInfo } + +pub fn kernel_virt_to_phys(virt: VirtAddr) -> PhysAddr { + debug_assert!(virt.start_address() >= PHYS_OFFSET); + PhysAddr::new(virt.start_address() - PHYS_OFFSET); +} + +pub fn phys_to_kernel_virt(phys: PhysAddr) -> VirtAddr { + VirtAddr::new(phys.as_u64()) +} diff --git a/src/mm/pmm.rs b/src/mm/pmm.rs index 46b058e..4a59344 100644 --- a/src/mm/pmm.rs +++ b/src/mm/pmm.rs @@ -13,20 +13,20 @@ use x86_64::{ VirtAddr, }; -pub const MAX_ZONES: usize = 64; -pub const MAX_ORDER: usize = 11; -pub const MAX_ORDER_PAGES: usize = 1 << 11; +pub const MAX_ZONES: u64 = 64; +pub const MAX_ORDER: u64 = 11; +pub const MAX_ORDER_PAGES: u64 = 1 << 11; #[derive(Debug)] struct Zone { pages: PhysFrameRange, - num_pages: usize, - order_list: [&'static mut [Block]; MAX_ORDER + 1], + num_pages: u64, + order_list: [&'static mut [Block]; MAX_ORDER as usize + 1], } #[allow(dead_code)] impl Zone { pub fn new(addr: PhysAddr, size: usize, blocks: &'static mut [Block]) -> Self { - let num_pages = size / super::PAGE_SIZE; + let num_pages = (size / super::PAGE_SIZE as usize) as u64; let mut order_list = Self::split_region(num_pages, blocks); @@ -56,9 +56,9 @@ impl Zone { } fn split_region( - num_pages: usize, + num_pages: u64, mut blocks: &'static mut [Block], - ) -> [&'static mut [Block]; MAX_ORDER + 1] { + ) -> [&'static mut [Block]; MAX_ORDER as usize + 1] { let max_order_blocks = x86_64::align_up(num_pages, MAX_ORDER_PAGES) / MAX_ORDER_PAGES; // TODO: This whole section is a bit of a hack @@ -67,8 +67,8 @@ impl Zone { ]; for (order, block_slice) in tmp.iter_mut().rev().enumerate() { - let blocks_in_layer = max_order_blocks * 2_usize.pow(order as u32); - let (left, right) = blocks.split_at_mut(blocks_in_layer); + let blocks_in_layer = max_order_blocks * 2u64.pow(order as u32); + let (left, right) = blocks.split_at_mut(blocks_in_layer as usize); *block_slice = Some(left); blocks = right; } @@ -77,12 +77,12 @@ impl Zone { } // Iterate back up, setting parents to have the correct largest order value - fn update_tree(&mut self, start_order: u8, mut idx: usize) { + fn update_tree(&mut self, start_order: u8, mut idx: u64) { for current_order in start_order + 1..=MAX_ORDER as u8 { let left_idx = idx & !1; let left = self.order_list[current_order as usize - 1][left_idx]; let right = self.order_list[current_order as usize - 1][left_idx + 1]; - self.order_list[current_order as usize][idx / 2] = Block::parent_state(left, right); + self.order_list[current_order as usize][idx as usize / 2] = Block::parent_state(left, right); idx /= 2; } } @@ -90,37 +90,37 @@ impl Zone { fn alloc(&mut self, order: u8) -> Option { // TODO: This can be optimised quite a bit (use linked lists?) // Find top level index - let mut idx = self.order_list[MAX_ORDER] + let mut idx = self.order_list[MAX_ORDER as usize] .iter() .enumerate() .find(|(_, blk)| blk.larger_than(order))? - .0; + .0 as usize; for current_order in (order..(MAX_ORDER as u8)).rev() { idx *= 2; - idx = if self.order_list[current_order as usize][idx].larger_than(order) { + idx = if self.order_list[current_order as usize][idx as usize].larger_than(order) { idx - } else if self.order_list[current_order as usize][idx + 1].larger_than(order) { + } else if self.order_list[current_order as usize][idx as usize + 1].larger_than(order) { idx + 1 } else { unreachable!(); }; } - self.order_list[order as usize][idx] = Block::Used; + self.order_list[order as usize][idx as usize] = Block::Used; self.update_tree(order, idx); - let start_frame = self.pages.start + 2usize.pow(order as u32) * idx; - let end_frame = self.pages.start + 2usize.pow(order as u32) * (idx + 1); + let start_frame = self.pages.start + 2u64.pow(order as u32) * idx; + let end_frame = self.pages.start + 2u64.pow(order as u32) * (idx + 1); // Zero out region unsafe { - let page: *mut u8 = VirtAddr::from(start_frame.start_address()).as_mut_ptr(); + let page: *mut u8 = super::phys_to_kernel_virt(start_frame.start_address()).as_mut_ptr(); core::intrinsics::write_bytes( page, if cfg!(debug_assertions) { 0xB8 } else { 0x00 }, - super::PAGE_SIZE * 2usize.pow(order as u32), + (super::PAGE_SIZE * 2u64.pow(order as u32)) as usize, ) }; @@ -129,13 +129,13 @@ impl Zone { fn free(&mut self, range: PhysFrameRange) { let order = range.len().trailing_zeros(); - debug_assert!(order as usize <= MAX_ORDER); + debug_assert!(order <= MAX_ORDER); debug_assert!(self.pages.contains_range(range)); let idx = (range.start - self.pages.start) / range.len(); - debug_assert_eq!(self.order_list[order as usize][idx], Block::Used); + debug_assert_eq!(self.order_list[order as usize][idx as usize], Block::Used); - self.order_list[order as usize][idx] = Block::from_order(order as u8); + self.order_list[order as usize][idx as usize] = Block::from_order(order as u8); self.update_tree(order as u8, idx); } } @@ -192,14 +192,14 @@ impl Block { } } - fn new_blocks_for_region(region: Region, usable_pages: usize) -> &'static mut [Block] { + fn new_blocks_for_region(region: Region, usable_pages: u64) -> &'static mut [Block] { let block_count = blocks_in_region(usable_pages); let mut rg_allocator = RegionBumpAllocator::from(region); let ptr = rg_allocator .alloc( Layout::from_size_align( - block_count * mem::size_of::(), + block_count as usize * mem::size_of::(), mem::align_of::(), ) .unwrap(), @@ -207,14 +207,14 @@ impl Block { .expect("failed to allocate from region"); debug_assert_eq!( - ptr.as_ptr() as usize, - x86_64::align_down(ptr.as_ptr() as usize, super::PAGE_SIZE) + ptr.as_ptr() as u64, + x86_64::align_down(ptr.as_ptr() as u64, super::PAGE_SIZE) ); unsafe { // Zero out the memory, which corresponds to Block::Used - core::intrinsics::write_bytes(ptr.as_ptr(), 0, block_count); - slice::from_raw_parts_mut(ptr.as_ptr() as *mut Block, block_count) + core::intrinsics::write_bytes(ptr.as_ptr(), 0, block_count as usize); + slice::from_raw_parts_mut(ptr.as_ptr() as *mut Block, block_count as usize) } } } @@ -224,7 +224,7 @@ impl Block { // We use an option here because ArrayVec doesn't have a const constructor. This // could be done with MaybeUninit in future to avoid that check pub struct PhysAllocator { - zones: RwSpinLock; MAX_ZONES]>>>, + zones: RwSpinLock; MAX_ZONES as usize]>>>, } pub static PMM: PhysAllocator = PhysAllocator::new(); @@ -240,22 +240,22 @@ impl PhysAllocator { let mut zones = ArrayVec::new(); for rg in map { - let pages_in_rg = rg.size / super::PAGE_SIZE; + let pages_in_rg = rg.size as u64 / super::PAGE_SIZE; let usable_pages = usable_pages(pages_in_rg); if usable_pages <= 1 { continue; } - let (reserved, usable) = rg.split_at((pages_in_rg - usable_pages) * super::PAGE_SIZE); + let (reserved, usable) = rg.split_at(((pages_in_rg - usable_pages) * super::PAGE_SIZE) as usize); let zone = Zone::new( usable.addr.into(), - x86_64::align_down(usable.size, super::PAGE_SIZE), + x86_64::align_down(usable.size as u64, super::PAGE_SIZE) as usize, Block::new_blocks_for_region(reserved, usable_pages), ); zones.push(SpinLock::new(zone)); - assert_eq!(usable.addr.as_usize() & (super::PAGE_SIZE - 1), 0); // Make sure it's aligned + assert_eq!(usable.addr.as_u64() & (super::PAGE_SIZE - 1), 0); // Make sure it's aligned } *PMM.zones.write() = Some(zones); @@ -309,19 +309,19 @@ impl PhysAllocator { // Subtract one extra page, just to be safe about padding and alignment // TODO: should really be blocks_in_region(usable_pages), but this hugely // complicates the math -fn usable_pages(total_pages: usize) -> usize { - (4096 * total_pages as usize - blocks_in_region(total_pages)) - / (mem::size_of::() + 4096) +fn usable_pages(total_pages: u64) -> u64 { + (4096 * total_pages - blocks_in_region(total_pages)) + / (mem::size_of::() as u64 + 4096) - 2 } -fn blocks_in_region(pages: usize) -> usize { +fn blocks_in_region(pages: u64) -> u64 { let max_order_blocks = x86_64::align_up(pages, MAX_ORDER_PAGES) / MAX_ORDER_PAGES; // Evaluate the geometric series // a = max_order_blocks // r = 2 // n = max_order + 1 - max_order_blocks * (2usize.pow(MAX_ORDER as u32 + 1) - 1) + max_order_blocks * (2u64.pow(MAX_ORDER as u32 + 1) - 1) } #[cfg(test)] diff --git a/src/mm/slob.rs b/src/mm/slob.rs index ec39ca4..06be6ed 100644 --- a/src/mm/slob.rs +++ b/src/mm/slob.rs @@ -63,21 +63,21 @@ unsafe impl GlobalAlloc for SlobAllocator { } unsafe fn alloc_inner(head: &mut Option>, layout: Layout) -> *mut u8 { + // TODO: Clean this up (can we use padding_needed_for?) let (layout, offset) = Layout::from_size_align( core::mem::size_of::(), core::mem::align_of::(), ) - .and_then(|l| Ok(l.pad_to_align())) - .and_then(|l| l.extend(layout)) - .expect("block layout creation failed"); - //.and_then(|(l, o)| l.pad_to_align().map(|l| (l, o))) - let layout = layout.pad_to_align(); + .and_then(|l| l.pad_to_align().extend(layout)) + .map(|(l, o)| (l.pad_to_align(), o)) + .expect("block layout creation failed"); let alloc_len = layout.size() - offset; + let header_len = offset; debug_assert_eq!(offset, core::mem::size_of::()); - if layout.size() > super::PAGE_SIZE { + if layout.size() > super::PAGE_SIZE as usize { trace!("slob: large {} byte allocation", layout.size()); } @@ -106,7 +106,7 @@ unsafe fn alloc_inner(head: &mut Option>, layout: Layout) -> *mut curr_opt = curr.as_mut().next; } - morecore(head, (layout.size() + super::PAGE_SIZE) / super::PAGE_SIZE); + morecore(head, (layout.size() as u64 + super::PAGE_SIZE) / super::PAGE_SIZE); } unreachable!(); @@ -152,15 +152,13 @@ unsafe fn dealloc_inner(head: &mut Option>, ptr: *mut u8, layout: } } -fn morecore(head: &mut Option>, num_pages: usize) { +fn morecore(head: &mut Option>, num_pages: u64) { unsafe { - let addr: VirtAddr = - PhysAllocator::alloc(num_pages.next_power_of_two().trailing_zeros() as u8) - .start - .start_address() - .into(); + let addr = + super::phys_to_kernel_virt(PhysAllocator::alloc(num_pages.next_power_of_two().trailing_zeros() as u8) + .start.start_address()); let p_block = addr.as_mut_ptr::(); - let size = num_pages * super::PAGE_SIZE - core::mem::size_of::(); + let size = (num_pages * super::PAGE_SIZE) as usize - core::mem::size_of::(); (*p_block).size = size; (*p_block).next = None; @@ -182,7 +180,7 @@ impl Block { unsafe fn split_at( mut block: NonNull, - alloc_len: usize, + mut alloc_len: usize, ) -> (NonNull, NonNull) { let total_len = alloc_len + core::mem::size_of::(); debug_assert!(block.as_mut().size >= total_len); @@ -200,7 +198,7 @@ impl Block { unsafe fn try_merge(mut left: NonNull, mut right: NonNull) -> bool { debug_assert!(left < right); let mask = !(super::PAGE_SIZE - 1); - if left.as_ptr() as usize & mask != right.as_ptr() as usize & mask { + if left.as_ptr() as u64 & mask != right.as_ptr() as u64 & mask { // The blocks are in separate pages. Since we allocate each physical page as // order 0, we can't merge these. false From d1a1e5d0837b028827b3ab47b8e6dc21ae5e8d98 Mon Sep 17 00:00:00 2001 From: trashcognito Date: Thu, 1 Jul 2021 23:06:54 +0300 Subject: [PATCH 14/18] broke everything --- x86_64/.gitignore | 13 - x86_64/Cargo.toml | 41 - x86_64/LICENSE-MIT | 23 - x86_64/README.md | 3 - x86_64/src/addr.rs | 357 -------- x86_64/src/instructions/interrupts.rs | 92 --- x86_64/src/instructions/mod.rs | 27 - x86_64/src/instructions/port.rs | 144 ---- x86_64/src/instructions/random.rs | 84 -- x86_64/src/instructions/segmentation.rs | 59 -- x86_64/src/instructions/tables.rs | 27 - x86_64/src/instructions/tlb.rs | 17 - x86_64/src/lib.rs | 67 -- x86_64/src/registers/control.rs | 154 ---- x86_64/src/registers/mod.rs | 19 - x86_64/src/registers/model_specific.rs | 111 --- x86_64/src/registers/rflags.rs | 98 --- x86_64/src/structures/gdt.rs | 230 ------ x86_64/src/structures/idt.rs | 764 ------------------ x86_64/src/structures/mod.rs | 18 - x86_64/src/structures/paging/frame.rs | 194 ----- x86_64/src/structures/paging/frame_alloc.rs | 18 - .../paging/mapper/mapped_page_table.rs | 560 ------------- x86_64/src/structures/paging/mapper/mod.rs | 207 ----- .../paging/mapper/offset_page_table.rs | 151 ---- .../paging/mapper/recursive_page_table.rs | 621 -------------- x86_64/src/structures/paging/mod.rs | 18 - x86_64/src/structures/paging/page.rs | 330 -------- x86_64/src/structures/paging/page_table.rs | 236 ------ x86_64/src/structures/port.rs | 31 - x86_64/src/structures/tss.rs | 38 - 31 files changed, 4752 deletions(-) delete mode 100644 x86_64/.gitignore delete mode 100644 x86_64/Cargo.toml delete mode 100644 x86_64/LICENSE-MIT delete mode 100644 x86_64/README.md delete mode 100644 x86_64/src/addr.rs delete mode 100644 x86_64/src/instructions/interrupts.rs delete mode 100644 x86_64/src/instructions/mod.rs delete mode 100644 x86_64/src/instructions/port.rs delete mode 100644 x86_64/src/instructions/random.rs delete mode 100644 x86_64/src/instructions/segmentation.rs delete mode 100644 x86_64/src/instructions/tables.rs delete mode 100644 x86_64/src/instructions/tlb.rs delete mode 100644 x86_64/src/lib.rs delete mode 100644 x86_64/src/registers/control.rs delete mode 100644 x86_64/src/registers/mod.rs delete mode 100644 x86_64/src/registers/model_specific.rs delete mode 100644 x86_64/src/registers/rflags.rs delete mode 100644 x86_64/src/structures/gdt.rs delete mode 100644 x86_64/src/structures/idt.rs delete mode 100644 x86_64/src/structures/mod.rs delete mode 100644 x86_64/src/structures/paging/frame.rs delete mode 100644 x86_64/src/structures/paging/frame_alloc.rs delete mode 100644 x86_64/src/structures/paging/mapper/mapped_page_table.rs delete mode 100644 x86_64/src/structures/paging/mapper/mod.rs delete mode 100644 x86_64/src/structures/paging/mapper/offset_page_table.rs delete mode 100644 x86_64/src/structures/paging/mapper/recursive_page_table.rs delete mode 100644 x86_64/src/structures/paging/mod.rs delete mode 100644 x86_64/src/structures/paging/page.rs delete mode 100644 x86_64/src/structures/paging/page_table.rs delete mode 100644 x86_64/src/structures/port.rs delete mode 100644 x86_64/src/structures/tss.rs diff --git a/x86_64/.gitignore b/x86_64/.gitignore deleted file mode 100644 index b5c891e..0000000 --- a/x86_64/.gitignore +++ /dev/null @@ -1,13 +0,0 @@ -# Compiled files -*.o -*.so -*.rlib -*.dll - -# Executables -*.exe - -# Generated by Cargo -/target/ -Cargo.lock -/testing/target diff --git a/x86_64/Cargo.toml b/x86_64/Cargo.toml deleted file mode 100644 index fca3773..0000000 --- a/x86_64/Cargo.toml +++ /dev/null @@ -1,41 +0,0 @@ -[package] -authors = [ - "Gerd Zellweger ", - "Eric Kidd ", - "Philipp Oppermann ", - "Dan Schatzberg ", - "John Ericson ", - "Rex Lunae ", -] -description = "Support for x86_64 specific instructions, registers, and structures." -documentation = "https://docs.rs/x86_64" -keywords = [ - "amd64", - "x86", - "x86_64", - "no_std", -] -categories = [ - "no-std", -] -license = "MIT/Apache-2.0" -name = "x86_64" -readme = "README.md" -repository = "https://github.com/rust-osdev/x86_64" -version = "0.7.2" -edition = "2018" - -[dependencies] -bit_field = "0.9.0" -bitflags = "1.0.4" - -[dependencies.cast] -version = "0.2.2" -default-features = false - -[dependencies.ux] -default-features = false -version = "0.1.3" - -[features] -deny-warnings = [] diff --git a/x86_64/LICENSE-MIT b/x86_64/LICENSE-MIT deleted file mode 100644 index 22e2806..0000000 --- a/x86_64/LICENSE-MIT +++ /dev/null @@ -1,23 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2018 Philipp Oppermann -Copyright (c) 2015 Gerd Zellweger -Copyright (c) 2015 The libcpu Developers - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. diff --git a/x86_64/README.md b/x86_64/README.md deleted file mode 100644 index 0697e2b..0000000 --- a/x86_64/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# Solstice x86_64 library - -FORKED FROM [rust-osdev/x86_64](https://github.com/rust-osdev/x86_64) diff --git a/x86_64/src/addr.rs b/x86_64/src/addr.rs deleted file mode 100644 index 3ed0109..0000000 --- a/x86_64/src/addr.rs +++ /dev/null @@ -1,357 +0,0 @@ -use core::convert::{Into, TryInto}; -use core::fmt; -use core::ops::{Add, AddAssign, Sub, SubAssign}; - -use bit_field::BitField; -use ux::*; - -#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] -#[repr(transparent)] -pub struct VirtAddr(usize); - -#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] -#[repr(transparent)] -pub struct PhysAddr(usize); - -#[derive(Debug)] -pub struct VirtAddrNotValid(usize); - -impl From for VirtAddr { - fn from(phys: PhysAddr) -> VirtAddr { - VirtAddr::new(phys.as_usize() + 0xFFFF8000_00000000) - } -} - -impl From for PhysAddr { - fn from(virt: VirtAddr) -> PhysAddr { - PhysAddr::new(virt.as_usize() - 0xFFFF8000_00000000) - } -} - -impl VirtAddr { - pub fn new(addr: usize) -> VirtAddr { - Self::try_new(addr).expect( - "address passed to VirtAddr::new must not contain any data \ - in bits 48 to 64", - ) - } - - /// Tries to create a new canonical virtual address. - /// - /// This function tries to performs sign - /// extension of bit 47 to make the address canonical. It succeeds if bits 48 to 64 are - /// either a correct sign extension (i.e. copies of bit 47) or all null. Else, an error - /// is returned. - pub fn try_new(addr: usize) -> Result { - match addr.get_bits(47..64) { - 0 | 0x1ffff => Ok(VirtAddr(addr)), // address is canonical - 1 => Ok(VirtAddr::new_unchecked(addr)), // address needs sign extension - other => Err(VirtAddrNotValid(other)), - } - } - - /// Creates a new canonical virtual address without checks. - /// - /// This function performs sign extension of bit 47 to make the address canonical, so - /// bits 48 to 64 are overwritten. If you want to check that these bits contain no data, - /// use `new` or `try_new`. - pub fn new_unchecked(mut addr: usize) -> VirtAddr { - if addr.get_bit(47) { - addr.set_bits(48..64, 0xffff); - } else { - addr.set_bits(48..64, 0); - } - VirtAddr(addr) - } - - /// Creates a virtual address that points to `0`. - pub const fn zero() -> VirtAddr { - VirtAddr(0) - } - - pub fn as_usize(self) -> usize { - self.0 - } - - /// Creates a virtual address from the given pointer - pub fn from_ptr(ptr: *const T) -> Self { - Self::new(ptr as usize) - } - - /// Converts the address to a raw pointer. - #[cfg(target_pointer_width = "64")] - pub fn as_ptr(self) -> *const T { - cast::usize(self.as_usize()) as *const T - } - - /// Converts the address to a mutable raw pointer. - #[cfg(target_pointer_width = "64")] - pub fn as_mut_ptr(self) -> *mut T { - self.as_ptr::() as *mut T - } - - /// Aligns the virtual address upwards to the given alignment. - /// - /// See the `align_up` function for more information. - pub fn align_up(self, align: U) -> Self - where - U: Into, - { - VirtAddr(align_up(self.0, align.into())) - } - - /// Aligns the virtual address downwards to the given alignment. - /// - /// See the `align_down` function for more information. - pub fn align_down(self, align: U) -> Self - where - U: Into, - { - VirtAddr(align_down(self.0, align.into())) - } - - /// Checks whether the virtual address has the demanded alignment. - pub fn is_aligned(self, align: U) -> bool - where - U: Into, - { - self.align_down(align) == self - } - - /// Returns the 12-bit page offset of this virtual address. - pub fn page_offset(&self) -> u12 { - u12::new((self.0 & 0xfff).try_into().unwrap()) - } - - /// Returns the 9-bit level 1 page table index. - pub fn p1_index(&self) -> u9 { - u9::new(((self.0 >> 12) & 0o777).try_into().unwrap()) - } - - /// Returns the 9-bit level 2 page table index. - pub fn p2_index(&self) -> u9 { - u9::new(((self.0 >> 12 >> 9) & 0o777).try_into().unwrap()) - } - - /// Returns the 9-bit level 3 page table index. - pub fn p3_index(&self) -> u9 { - u9::new(((self.0 >> 12 >> 9 >> 9) & 0o777).try_into().unwrap()) - } - - /// Returns the 9-bit level 4 page table index. - pub fn p4_index(&self) -> u9 { - u9::new(((self.0 >> 12 >> 9 >> 9 >> 9) & 0o777).try_into().unwrap()) - } -} - -impl fmt::Debug for VirtAddr { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "VirtAddr({:#x})", self.0) - } -} - -impl Add for VirtAddr { - type Output = Self; - fn add(self, rhs: usize) -> Self::Output { - VirtAddr::new(self.0 + rhs) - } -} - -impl AddAssign for VirtAddr { - fn add_assign(&mut self, rhs: usize) { - *self = *self + rhs; - } -} - -impl Sub for VirtAddr { - type Output = Self; - fn sub(self, rhs: usize) -> Self::Output { - VirtAddr::new(self.0.checked_sub(rhs).unwrap()) - } -} - -impl SubAssign for VirtAddr { - fn sub_assign(&mut self, rhs: usize) { - *self = *self - rhs; - } -} - -impl Sub for VirtAddr { - type Output = usize; - fn sub(self, rhs: VirtAddr) -> Self::Output { - self.as_usize().checked_sub(rhs.as_usize()).unwrap() - } -} - -#[derive(Debug)] -pub struct PhysAddrNotValid(usize); - -impl PhysAddr { - /// Creates a new physical address. - /// - /// Panics if a bit in the range 52 to 64 is set. - pub fn new(addr: usize) -> PhysAddr { - assert_eq!( - addr.get_bits(52..64), - 0, - "physical addresses must not have any bits in the range 52 to 64 set" - ); - PhysAddr(addr) - } - - /// Tries to create a new physical address. - /// - /// Fails if any bits in the range 52 to 64 are set. - pub fn try_new(addr: usize) -> Result { - match addr.get_bits(52..64) { - 0 => Ok(PhysAddr(addr)), // address is valid - other => Err(PhysAddrNotValid(other)), - } - } - - /// Converts the address to an `usize`. - pub fn as_usize(self) -> usize { - self.0 - } - - /// Convenience method for checking if a physical address is null. - pub fn is_null(&self) -> bool { - self.0 == 0 - } - - /// Aligns the physical address upwards to the given alignment. - /// - /// See the `align_up` function for more information. - pub fn align_up(self, align: U) -> Self - where - U: Into, - { - PhysAddr(align_up(self.0, align.into())) - } - - /// Aligns the physical address downwards to the given alignment. - /// - /// See the `align_down` function for more information. - pub fn align_down(self, align: U) -> Self - where - U: Into, - { - PhysAddr(align_down(self.0, align.into())) - } - - /// Checks whether the physical address has the demanded alignment. - pub fn is_aligned(self, align: U) -> bool - where - U: Into, - { - self.align_down(align) == self - } -} - -impl fmt::Debug for PhysAddr { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "PhysAddr({:#x})", self.0) - } -} - -impl fmt::Binary for PhysAddr { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.0.fmt(f) - } -} - -impl fmt::LowerHex for PhysAddr { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.0.fmt(f) - } -} - -impl fmt::Octal for PhysAddr { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.0.fmt(f) - } -} - -impl fmt::UpperHex for PhysAddr { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.0.fmt(f) - } -} - -impl Add for PhysAddr { - type Output = Self; - fn add(self, rhs: usize) -> Self::Output { - PhysAddr::new(self.0 + rhs) - } -} - -impl AddAssign for PhysAddr { - fn add_assign(&mut self, rhs: usize) { - *self = *self + rhs; - } -} - -impl Sub for PhysAddr { - type Output = Self; - fn sub(self, rhs: usize) -> Self::Output { - PhysAddr::new(self.0.checked_sub(rhs).unwrap()) - } -} - -impl SubAssign for PhysAddr { - fn sub_assign(&mut self, rhs: usize) { - *self = *self - rhs; - } -} - -impl Sub for PhysAddr { - type Output = usize; - fn sub(self, rhs: PhysAddr) -> Self::Output { - self.as_usize().checked_sub(rhs.as_usize()).unwrap() - } -} - -/// Align address downwards. -/// -/// Returns the greatest x with alignment `align` so that x <= addr. The alignment must be -/// a power of 2. -pub fn align_down(addr: usize, align: usize) -> usize { - assert!(align.is_power_of_two(), "`align` must be a power of two"); - addr & !(align - 1) -} - -/// Align address upwards. -/// -/// Returns the smallest x with alignment `align` so that x >= addr. The alignment must be -/// a power of 2. -pub fn align_up(addr: usize, align: usize) -> usize { - assert!(align.is_power_of_two(), "`align` must be a power of two"); - let align_mask = align - 1; - if addr & align_mask == 0 { - addr // already aligned - } else { - (addr | align_mask) + 1 - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - pub fn test_align_up() { - // align 1 - assert_eq!(align_up(0, 1), 0); - assert_eq!(align_up(1234, 1), 1234); - assert_eq!(align_up(0xffffffffffffffff, 1), 0xffffffffffffffff); - // align 2 - assert_eq!(align_up(0, 2), 0); - assert_eq!(align_up(1233, 2), 1234); - assert_eq!(align_up(0xfffffffffffffffe, 2), 0xfffffffffffffffe); - // address 0 - assert_eq!(align_up(0, 128), 0); - assert_eq!(align_up(0, 1), 0); - assert_eq!(align_up(0, 2), 0); - assert_eq!(align_up(0, 0x8000000000000000), 0); - } -} diff --git a/x86_64/src/instructions/interrupts.rs b/x86_64/src/instructions/interrupts.rs deleted file mode 100644 index b67ac0e..0000000 --- a/x86_64/src/instructions/interrupts.rs +++ /dev/null @@ -1,92 +0,0 @@ -//! Enabling and disabling interrupts - -/// Returns whether interrupts are enabled. -pub fn are_enabled() -> bool { - use crate::registers::rflags::{self, RFlags}; - - rflags::read().contains(RFlags::INTERRUPT_FLAG) -} - -/// Enable interrupts. -/// -/// This is a wrapper around the `sti` instruction. -#[inline] -pub fn enable() { - unsafe { - llvm_asm!("sti" :::: "volatile"); - } -} - -/// Disable interrupts. -/// -/// This is a wrapper around the `cli` instruction. -#[inline] -pub fn disable() { - unsafe { - llvm_asm!("cli" :::: "volatile"); - } -} - -/// Run a closure with disabled interrupts. -/// -/// Run the given closure, disabling interrupts before running it (if they aren't already disabled). -/// Afterwards, interrupts are enabling again if they were enabled before. -/// -/// If you have other `enable` and `disable` calls _within_ the closure, things may not work as expected. -/// -/// # Examples -/// -/// ```ignore -/// // interrupts are enabled -/// without_interrupts(|| { -/// // interrupts are disabled -/// without_interrupts(|| { -/// // interrupts are disabled -/// }); -/// // interrupts are still disabled -/// }); -/// // interrupts are enabled again -/// ``` -pub fn without_interrupts(f: F) -> R -where - F: FnOnce() -> R, -{ - // true if the interrupt flag is set (i.e. interrupts are enabled) - let saved_intpt_flag = are_enabled(); - - // if interrupts are enabled, disable them for now - if saved_intpt_flag { - disable(); - } - - // do `f` while interrupts are disabled - let ret = f(); - - // re-enable interrupts if they were previously enabled - if saved_intpt_flag { - enable(); - } - - // return the result of `f` to the caller - ret -} - -/// Cause a breakpoint exception by invoking the `int3` instruction. -#[inline] -pub fn int3() { - unsafe { - llvm_asm!("int3" :::: "volatile"); - } -} - -/// Generate a software interrupt by invoking the `int` instruction. -/// -/// This currently needs to be a macro because the `int` argument needs to be an -/// immediate. This macro will be replaced by a generic function when support for -/// const generics is implemented in Rust. -#[macro_export] -macro_rules! software_interrupt { - ($x:expr) => {{ - llvm_asm!("int $0" :: "N" ($x) :: "volatile"); - }}; -} diff --git a/x86_64/src/instructions/mod.rs b/x86_64/src/instructions/mod.rs deleted file mode 100644 index 5fd0e21..0000000 --- a/x86_64/src/instructions/mod.rs +++ /dev/null @@ -1,27 +0,0 @@ -#![cfg(target_arch = "x86_64")] - -//! Special x86_64 instructions. - -pub mod interrupts; -pub mod port; -pub mod random; -pub mod segmentation; -pub mod tables; -pub mod tlb; - -/// Halts the CPU until the next interrupt arrives. -#[inline] -pub fn hlt() { - unsafe { - llvm_asm!("hlt" :::: "volatile"); - } -} - -/// Emits a '[magic breakpoint](https://wiki.osdev.org/Bochs#Magic_Breakpoint)' instruction for the [Bochs](http://bochs.sourceforge.net/) CPU -/// emulator. Make sure to set `magic_break: enabled=1` in your `.bochsrc` file. -#[inline] -pub fn bochs_breakpoint() { - unsafe { - llvm_asm!("xchgw %bx, %bx" :::: "volatile"); - } -} diff --git a/x86_64/src/instructions/port.rs b/x86_64/src/instructions/port.rs deleted file mode 100644 index e046b7f..0000000 --- a/x86_64/src/instructions/port.rs +++ /dev/null @@ -1,144 +0,0 @@ -//! Access to I/O ports - -use core::marker::PhantomData; - -pub use crate::structures::port::{PortRead, PortReadWrite, PortWrite}; - -impl PortRead for u8 { - #[inline] - unsafe fn read_from_port(port: u16) -> u8 { - let value: u8; - llvm_asm!("inb %dx, %al" : "={al}"(value) : "{dx}"(port) :: "volatile"); - value - } -} - -impl PortRead for u16 { - #[inline] - unsafe fn read_from_port(port: u16) -> u16 { - let value: u16; - llvm_asm!("inw %dx, %ax" : "={ax}"(value) : "{dx}"(port) :: "volatile"); - value - } -} - -impl PortRead for u32 { - #[inline] - unsafe fn read_from_port(port: u16) -> u32 { - let value: u32; - llvm_asm!("inl %dx, %eax" : "={eax}"(value) : "{dx}"(port) :: "volatile"); - value - } -} - -impl PortWrite for u8 { - #[inline] - unsafe fn write_to_port(port: u16, value: u8) { - llvm_asm!("outb %al, %dx" :: "{dx}"(port), "{al}"(value) :: "volatile"); - } -} - -impl PortWrite for u16 { - #[inline] - unsafe fn write_to_port(port: u16, value: u16) { - llvm_asm!("outw %ax, %dx" :: "{dx}"(port), "{ax}"(value) :: "volatile"); - } -} - -impl PortWrite for u32 { - #[inline] - unsafe fn write_to_port(port: u16, value: u32) { - llvm_asm!("outl %eax, %dx" :: "{dx}"(port), "{eax}"(value) :: "volatile"); - } -} - -impl PortReadWrite for u8 {} -impl PortReadWrite for u16 {} -impl PortReadWrite for u32 {} - -/// A read only I/O port. -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct PortReadOnly { - port: u16, - phantom: PhantomData, -} - -/// A write only I/O port. -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct PortWriteOnly { - port: u16, - phantom: PhantomData, -} - -/// An I/O port. -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct Port { - port: u16, - phantom: PhantomData, -} - -impl PortReadOnly { - /// Creates a read only I/O port with the given port number. - pub const fn new(port: u16) -> PortReadOnly { - PortReadOnly { - port: port, - phantom: PhantomData, - } - } - - /// Reads from the port. - /// - /// This function is unsafe because the I/O port could have side effects that violate memory - /// safety. - #[inline] - pub unsafe fn read(&mut self) -> T { - T::read_from_port(self.port) - } -} - -impl PortWriteOnly { - /// Creates a write only I/O port with the given port number. - pub const fn new(port: u16) -> PortWriteOnly { - PortWriteOnly { - port: port, - phantom: PhantomData, - } - } - - /// Writes to the port. - /// - /// This function is unsafe because the I/O port could have side effects that violate memory - /// safety. - #[inline] - pub unsafe fn write(&mut self, value: T) { - T::write_to_port(self.port, value) - } -} - -impl Port { - /// Creates an I/O port with the given port number. - pub const fn new(port: u16) -> Port { - Port { - port: port, - phantom: PhantomData, - } - } - - /// Reads from the port. - /// - /// This function is unsafe because the I/O port could have side effects that violate memory - /// safety. - #[inline] - pub unsafe fn read(&mut self) -> T { - T::read_from_port(self.port) - } - - /// Writes to the port. - /// - /// This function is unsafe because the I/O port could have side effects that violate memory - /// safety. - #[inline] - pub unsafe fn write(&mut self, value: T) { - T::write_to_port(self.port, value) - } -} diff --git a/x86_64/src/instructions/random.rs b/x86_64/src/instructions/random.rs deleted file mode 100644 index 17fe95b..0000000 --- a/x86_64/src/instructions/random.rs +++ /dev/null @@ -1,84 +0,0 @@ -//! Support for build-in RNGs - -#[derive(Copy, Clone, Debug)] -/// Used to obtain random numbers using x86_64's RDRAND opcode -pub struct RdRand(()); - -#[cfg(target_arch = "x86_64")] -impl RdRand { - /// Creates Some(RdRand) if RDRAND is supported, None otherwise - pub fn new() -> Option { - // RDRAND support indicated by CPUID page 01h, ecx bit 30 - // https://en.wikipedia.org/wiki/RdRand#Overview - let cpuid = unsafe { core::arch::x86_64::__cpuid(0x1) }; - if cpuid.ecx & (1 << 30) != 0 { - Some(RdRand(())) - } else { - None - } - } - - /// Uniformly sampled u64. - /// May fail in rare circumstances or heavy load. - #[inline] - pub fn get_u64(&self) -> Option { - let mut res: u64 = 0; - unsafe { - match core::arch::x86_64::_rdrand64_step(&mut res) { - 1 => Some(res), - x => { - debug_assert_eq!(x, 0, "rdrand64 returned non-binary value"); - None - } - } - } - } - /// Uniformly sampled u32. - /// May fail in rare circumstances or heavy load. - #[inline] - pub fn get_u32(&self) -> Option { - let mut res: u32 = 0; - unsafe { - match core::arch::x86_64::_rdrand32_step(&mut res) { - 1 => Some(res), - x => { - debug_assert_eq!(x, 0, "rdrand32 returned non-binary value"); - None - } - } - } - } - /// Uniformly sampled u16. - /// May fail in rare circumstances or heavy load. - #[inline] - pub fn get_u16(&self) -> Option { - let mut res: u16 = 0; - unsafe { - match core::arch::x86_64::_rdrand16_step(&mut res) { - 1 => Some(res), - x => { - debug_assert_eq!(x, 0, "rdrand16 returned non-binary value"); - None - } - } - } - } -} - -#[cfg(all(test, target_arch = "x86_64"))] -mod tests { - use super::*; - - #[test] - pub fn test_rdrand() { - let rand = RdRand::new(); - if is_x86_feature_detected!("rdrand") { - let rand = rand.unwrap(); - assert!(rand.get_u16().is_some()); - assert!(rand.get_u32().is_some()); - assert!(rand.get_u64().is_some()); - } else { - assert!(rand.is_none()); - } - } -} diff --git a/x86_64/src/instructions/segmentation.rs b/x86_64/src/instructions/segmentation.rs deleted file mode 100644 index fafdc14..0000000 --- a/x86_64/src/instructions/segmentation.rs +++ /dev/null @@ -1,59 +0,0 @@ -//! Provides functions to read and write segment registers. - -use crate::structures::gdt::SegmentSelector; - -/// Reload code segment register. -/// -/// Note this is special since we can not directly move -/// to %cs. Instead we push the new segment selector -/// and return value on the stack and use lretq -/// to reload cs and continue at 1:. -pub unsafe fn set_cs(sel: SegmentSelector) { - #[inline(always)] - unsafe fn inner(sel: SegmentSelector) { - llvm_asm!("pushq $0; \ - leaq 1f(%rip), %rax; \ - pushq %rax; \ - lretq; \ - 1:" :: "ri" (u64::from(sel.0)) : "rax" "memory"); - } - - inner(sel) -} - -/// Reload stack segment register. -#[inline] -pub unsafe fn load_ss(sel: SegmentSelector) { - llvm_asm!("movw $0, %ss " :: "r" (sel.0) : "memory"); -} - -/// Reload data segment register. -#[inline] -pub unsafe fn load_ds(sel: SegmentSelector) { - llvm_asm!("movw $0, %ds " :: "r" (sel.0) : "memory"); -} - -/// Reload es segment register. -#[inline] -pub unsafe fn load_es(sel: SegmentSelector) { - llvm_asm!("movw $0, %es " :: "r" (sel.0) : "memory"); -} - -/// Reload fs segment register. -#[inline] -pub unsafe fn load_fs(sel: SegmentSelector) { - llvm_asm!("movw $0, %fs " :: "r" (sel.0) : "memory"); -} - -/// Reload gs segment register. -#[inline] -pub unsafe fn load_gs(sel: SegmentSelector) { - llvm_asm!("movw $0, %gs " :: "r" (sel.0) : "memory"); -} - -/// Returns the current value of the code segment register. -pub fn cs() -> SegmentSelector { - let segment: u16; - unsafe { llvm_asm!("mov %cs, $0" : "=r" (segment) ) }; - SegmentSelector(segment) -} diff --git a/x86_64/src/instructions/tables.rs b/x86_64/src/instructions/tables.rs deleted file mode 100644 index dd13a60..0000000 --- a/x86_64/src/instructions/tables.rs +++ /dev/null @@ -1,27 +0,0 @@ -//! Functions to load GDT, IDT, and TSS structures. - -use crate::structures::gdt::SegmentSelector; - -pub use crate::structures::DescriptorTablePointer; - -/// Load a GDT. Use the -/// [`GlobalDescriptorTable`](crate::structures::gdt::GlobalDescriptorTable) struct for a high-level -/// interface to loading a GDT. -#[inline] -pub unsafe fn lgdt(gdt: &DescriptorTablePointer) { - llvm_asm!("lgdt ($0)" :: "r" (gdt) : "memory"); -} - -/// Load an IDT. Use the -/// [`InterruptDescriptorTable`](crate::structures::idt::InterruptDescriptorTable) struct for a high-level -/// interface to loading an IDT. -#[inline] -pub unsafe fn lidt(idt: &DescriptorTablePointer) { - llvm_asm!("lidt ($0)" :: "r" (idt) : "memory"); -} - -/// Load the task state register using the `ltr` instruction. -#[inline] -pub unsafe fn load_tss(sel: SegmentSelector) { - llvm_asm!("ltr $0" :: "r" (sel.0)); -} diff --git a/x86_64/src/instructions/tlb.rs b/x86_64/src/instructions/tlb.rs deleted file mode 100644 index 0b9589a..0000000 --- a/x86_64/src/instructions/tlb.rs +++ /dev/null @@ -1,17 +0,0 @@ -//! Functions to flush the translation lookaside buffer (TLB). - -use crate::VirtAddr; - -/// Invalidate the given address in the TLB using the `invlpg` instruction. -#[inline] -pub fn flush(addr: VirtAddr) { - unsafe { llvm_asm!("invlpg ($0)" :: "r" (addr.as_usize()) : "memory") }; -} - -/// Invalidate the TLB completely by reloading the CR3 register. -#[inline] -pub fn flush_all() { - use crate::registers::control::Cr3; - let (frame, flags) = Cr3::read(); - unsafe { Cr3::write(frame, flags) } -} diff --git a/x86_64/src/lib.rs b/x86_64/src/lib.rs deleted file mode 100644 index c9fc1f1..0000000 --- a/x86_64/src/lib.rs +++ /dev/null @@ -1,67 +0,0 @@ -//! This crate provides x86_64 specific functions and data structures, -//! and access to various system registers. - -#![feature(const_fn)] -#![feature(llvm_asm)] -#![feature(abi_x86_interrupt)] -#![cfg_attr(not(test), no_std)] -#![deny(missing_debug_implementations)] -#![feature(const_fn_fn_ptr_basics)] -#![feature(const_mut_refs)] -/// Provides the non-standard-width integer types `u2`–`u63`. -/// -/// We use these integer types in various APIs, for example `u9` for page tables indices. -pub use ux; - -pub use crate::addr::{align_down, align_up, PhysAddr, VirtAddr}; - -pub mod instructions; -pub mod registers; -pub mod structures; - -mod addr; - -/// Represents a protection ring level. -#[derive(Debug, Copy, Clone, PartialEq, Eq)] -#[repr(u8)] -pub enum PrivilegeLevel { - /// Privilege-level 0 (most privilege): This level is used by critical system-software - /// components that require direct access to, and control over, all processor and system - /// resources. This can include BIOS, memory-management functions, and interrupt handlers. - Ring0 = 0, - - /// Privilege-level 1 (moderate privilege): This level is used by less-critical system- - /// software services that can access and control a limited scope of processor and system - /// resources. Software running at these privilege levels might include some device drivers - /// and library routines. The actual privileges of this level are defined by the - /// operating system. - Ring1 = 1, - - /// Privilege-level 2 (moderate privilege): Like level 1, this level is used by - /// less-critical system-software services that can access and control a limited scope of - /// processor and system resources. The actual privileges of this level are defined by the - /// operating system. - Ring2 = 2, - - /// Privilege-level 3 (least privilege): This level is used by application software. - /// Software running at privilege-level 3 is normally prevented from directly accessing - /// most processor and system resources. Instead, applications request access to the - /// protected processor and system resources by calling more-privileged service routines - /// to perform the accesses. - Ring3 = 3, -} - -impl PrivilegeLevel { - /// Creates a `PrivilegeLevel` from a numeric value. The value must be in the range 0..4. - /// - /// This function panics if the passed value is >3. - pub fn from_u16(value: u16) -> PrivilegeLevel { - match value { - 0 => PrivilegeLevel::Ring0, - 1 => PrivilegeLevel::Ring1, - 2 => PrivilegeLevel::Ring2, - 3 => PrivilegeLevel::Ring3, - i => panic!("{} is not a valid privilege level", i), - } - } -} diff --git a/x86_64/src/registers/control.rs b/x86_64/src/registers/control.rs deleted file mode 100644 index f911ad9..0000000 --- a/x86_64/src/registers/control.rs +++ /dev/null @@ -1,154 +0,0 @@ -//! Functions to read and write control registers. - -pub use super::model_specific::{Efer, EferFlags}; - -use bitflags::bitflags; - -/// Various control flags modifying the basic operation of the CPU. -#[derive(Debug)] -pub struct Cr0; - -bitflags! { - /// Configuration flags of the Cr0 register. - pub struct Cr0Flags: u64 { - /// Enables protected mode. - const PROTECTED_MODE_ENABLE = 1 << 0; - /// Enables monitoring of the coprocessor, typical for x87 instructions. - /// - /// Controls together with the `TASK_SWITCHED` flag whether a `wait` or `fwait` - /// instruction should cause a device-not-available exception. - const MONITOR_COPROCESSOR = 1 << 1; - /// Force all x87 and MMX instructions to cause an exception. - const EMULATE_COPROCESSOR = 1 << 2; - /// Automatically set to 1 on _hardware_ task switch. - /// - /// This flags allows lazily saving x87/MMX/SSE instructions on hardware context switches. - const TASK_SWITCHED = 1 << 3; - /// Enables the native error reporting mechanism for x87 FPU errors. - const NUMERIC_ERROR = 1 << 5; - /// Controls whether supervisor-level writes to read-only pages are inhibited. - /// - /// When set, it is not possible to write to read-only pages from ring 0. - const WRITE_PROTECT = 1 << 16; - /// Enables automatic alignment checking. - const ALIGNMENT_MASK = 1 << 18; - /// Ignored. Used to control write-back/write-through cache strategy on older CPUs. - const NOT_WRITE_THROUGH = 1 << 29; - /// Disables internal caches (only for some cases). - const CACHE_DISABLE = 1 << 30; - /// Enables page translation. - const PAGING = 1 << 31; - } -} - -/// Contains the Page Fault Linear Address (PFLA). -/// -/// When page fault occurs, the CPU sets this register to the accessed address. -#[derive(Debug)] -pub struct Cr2; - -/// Contains the physical address of the level 4 page table. -#[derive(Debug)] -pub struct Cr3; - -bitflags! { - /// Controls cache settings for the level 4 page table. - pub struct Cr3Flags: u64 { - /// Use a writethrough cache policy for the P4 table (else a writeback policy is used). - const PAGE_LEVEL_WRITETHROUGH = 1 << 3; - /// Disable caching for the P4 table. - const PAGE_LEVEL_CACHE_DISABLE = 1 << 4; - } -} - -#[cfg(target_arch = "x86_64")] -mod x86_64 { - use super::*; - use crate::structures::paging::PhysFrame; - use crate::{PhysAddr, VirtAddr}; - - impl Cr0 { - /// Read the current set of CR0 flags. - pub fn read() -> Cr0Flags { - Cr0Flags::from_bits_truncate(Self::read_raw()) - } - - /// Read the current raw CR0 value. - pub fn read_raw() -> u64 { - let value: u64; - unsafe { - llvm_asm!("mov %cr0, $0" : "=r" (value)); - } - value - } - - /// Write CR0 flags. - /// - /// Preserves the value of reserved fields. Unsafe because it's possible to violate memory - /// safety by e.g. disabling paging. - pub unsafe fn write(flags: Cr0Flags) { - let old_value = Self::read_raw(); - let reserved = old_value & !(Cr0Flags::all().bits()); - let new_value = reserved | flags.bits(); - - Self::write_raw(new_value); - } - - /// Write raw CR0 flags. - /// - /// Does _not_ preserve any values, including reserved fields. Unsafe because it's possible to violate memory - /// safety by e.g. disabling paging. - pub unsafe fn write_raw(value: u64) { - llvm_asm!("mov $0, %cr0" :: "r" (value) : "memory") - } - - /// Updates CR0 flags. - /// - /// Preserves the value of reserved fields. Unsafe because it's possible to violate memory - /// safety by e.g. disabling paging. - pub unsafe fn update(f: F) - where - F: FnOnce(&mut Cr0Flags), - { - let mut flags = Self::read(); - f(&mut flags); - Self::write(flags); - } - } - - impl Cr2 { - /// Read the current page fault linear address from the CR3 register. - pub fn read() -> VirtAddr { - let value: usize; - unsafe { - llvm_asm!("mov %cr2, $0" : "=r" (value)); - } - VirtAddr::new(value) - } - } - - impl Cr3 { - /// Read the current P4 table address from the CR3 register. - pub fn read() -> (PhysFrame, Cr3Flags) { - let value: usize; - unsafe { - llvm_asm!("mov %cr3, $0" : "=r" (value)); - } - let flags = Cr3Flags::from_bits_truncate(value as u64); - let addr = PhysAddr::new(value & 0x_000f_ffff_ffff_f000); - let frame = PhysFrame::containing_address(addr); - (frame, flags) - } - - /// Write a new P4 table address into the CR3 register. - /// - /// ## Safety - /// Changing the level 4 page table is unsafe, because it's possible to violate memory safety by - /// changing the page mapping. - pub unsafe fn write(frame: PhysFrame, flags: Cr3Flags) { - let addr = frame.start_address(); - let value = addr.as_usize() as u64 | flags.bits(); - llvm_asm!("mov $0, %cr3" :: "r" (value) : "memory") - } - } -} diff --git a/x86_64/src/registers/mod.rs b/x86_64/src/registers/mod.rs deleted file mode 100644 index ddfb4dd..0000000 --- a/x86_64/src/registers/mod.rs +++ /dev/null @@ -1,19 +0,0 @@ -//! Access to various system and model specific registers. - -pub mod control; -pub mod model_specific; -pub mod rflags; - -/// Gets the current instruction pointer. Note that this is only approximate as it requires a few -/// instructions to execute. -#[inline(always)] -pub fn read_rip() -> u64 { - let rip: u64; - unsafe { - llvm_asm!( - "lea (%rip), $0" - : "=r"(rip) ::: "volatile" - ); - } - rip -} diff --git a/x86_64/src/registers/model_specific.rs b/x86_64/src/registers/model_specific.rs deleted file mode 100644 index 29876be..0000000 --- a/x86_64/src/registers/model_specific.rs +++ /dev/null @@ -1,111 +0,0 @@ -//! Functions to read and write control registers. - -use bitflags::bitflags; - -/// A model specific register. -#[derive(Debug)] -pub struct Msr(u32); - -impl Msr { - /// Create an instance from a register. - pub const fn new(reg: u32) -> Msr { - Msr(reg) - } -} - -/// The Extended Feature Enable Register. -#[derive(Debug)] -pub struct Efer; - -impl Efer { - /// The underlying model specific register. - pub const MSR: Msr = Msr(0xC0000080); -} - -bitflags! { - /// Flags of the Extended Feature Enable Register. - pub struct EferFlags: u64 { - /// Enables the `syscall` and `sysret` instructions. - const SYSTEM_CALL_EXTENSIONS = 1 << 0; - /// Activates long mode, requires activating paging. - const LONG_MODE_ENABLE = 1 << 8; - /// Indicates that long mode is active. - const LONG_MODE_ACTIVE = 1 << 10; - /// Enables the no-execute page-protection feature. - const NO_EXECUTE_ENABLE = 1 << 11; - /// Enables SVM extensions. - const SECURE_VIRTUAL_MACHINE_ENABLE = 1 << 12; - /// Enable certain limit checks in 64-bit mode. - const LONG_MODE_SEGMENT_LIMIT_ENABLE = 1 << 13; - /// Enable the `fxsave` and `fxrstor` instructions to execute faster in 64-bit mode. - const FAST_FXSAVE_FXRSTOR = 1 << 14; - /// Changes how the `invlpg` instruction operates on TLB entries of upper-level entries. - const TRANSLATION_CACHE_EXTENSION = 1 << 15; - } -} - -#[cfg(target_arch = "x86_64")] -mod x86_64 { - use super::*; - - impl Msr { - /// Read 64 bits msr register. - pub unsafe fn read(&self) -> u64 { - let (high, low): (u32, u32); - llvm_asm!("rdmsr" : "={eax}" (low), "={edx}" (high) : "{ecx}" (self.0) : "memory" : "volatile"); - ((high as u64) << 32) | (low as u64) - } - - /// Write 64 bits to msr register. - pub unsafe fn write(&mut self, value: u64) { - let low = value.clone() as u32; - let high = (value >> 32) as u32; - llvm_asm!("wrmsr" :: "{ecx}" (self.0), "{eax}" (low), "{edx}" (high) : "memory" : "volatile" ); - } - } - - impl Efer { - /// Read the current EFER flags. - pub fn read() -> EferFlags { - EferFlags::from_bits_truncate(Self::read_raw()) - } - - /// Read the current raw EFER flags. - pub fn read_raw() -> u64 { - unsafe { Self::MSR.read() } - } - - /// Write the EFER flags, preserving reserved values. - /// - /// Preserves the value of reserved fields. Unsafe because it's possible to break memory - /// safety, e.g. by disabling long mode. - pub unsafe fn write(flags: EferFlags) { - let old_value = Self::read_raw(); - let reserved = old_value & !(EferFlags::all().bits()); - let new_value = reserved | flags.bits(); - - Self::write_raw(new_value); - } - - /// Write the EFER flags. - /// - /// Does not preserve any bits, including reserved fields. Unsafe because it's possible to - /// break memory safety, e.g. by disabling long mode. - pub unsafe fn write_raw(flags: u64) { - Self::MSR.write(flags); - } - - /// Update EFER flags. - /// - /// Preserves the value of reserved fields. Unsafe because it's possible to break memory - /// safety, e.g. by disabling long mode. - pub unsafe fn update(f: F) - where - F: FnOnce(&mut EferFlags), - { - let mut flags = Self::read(); - f(&mut flags); - Self::write(flags); - } - } -} diff --git a/x86_64/src/registers/rflags.rs b/x86_64/src/registers/rflags.rs deleted file mode 100644 index 9e55867..0000000 --- a/x86_64/src/registers/rflags.rs +++ /dev/null @@ -1,98 +0,0 @@ -//! Processor state stored in the RFLAGS register. - -#[cfg(target_arch = "x86_64")] -pub use self::x86_64::*; - -use bitflags::bitflags; - -bitflags! { - /// The RFLAGS register. - pub struct RFlags: u64 { - /// Processor feature identification flag. - /// - /// If this flag is modifiable, the CPU supports CPUID. - const ID = 1 << 21; - /// Indicates that an external, maskable interrupt is pending. - /// - /// Used when virtual-8086 mode extensions (CR4.VME) or protected-mode virtual - /// interrupts (CR4.PVI) are activated. - const VIRTUAL_INTERRUPT_PENDING = 1 << 20; - /// Virtual image of the INTERRUPT_FLAG bit. - /// - /// Used when virtual-8086 mode extensions (CR4.VME) or protected-mode virtual - /// interrupts (CR4.PVI) are activated. - const VIRTUAL_INTERRUPT = 1 << 19; - /// Enable automatic alignment checking if CR0.AM is set. Only works if CPL is 3. - const ALIGNMENT_CHECK = 1 << 18; - /// Enable the virtual-8086 mode. - const VIRTUAL_8086_MODE = 1 << 17; - /// Allows to restart an instruction following an instrucion breakpoint. - const RESUME_FLAG = 1 << 16; - /// Used by `iret` in hardware task switch mode to determine if current task is nested. - const NESTED_TASK = 1 << 14; - /// The high bit of the I/O Privilege Level field. - /// - /// Specifies the privilege level required for executing I/O address-space instructions. - const IOPL_HIGH = 1 << 13; - /// The low bit of the I/O Privilege Level field. - /// - /// Specifies the privilege level required for executing I/O address-space instructions. - const IOPL_LOW = 1 << 12; - /// Set by hardware to indicate that the sign bit of the result of the last signed integer - /// operation differs from the source operands. - const OVERFLOW_FLAG = 1 << 11; - /// Determines the order in which strings are processed. - const DIRECTION_FLAG = 1 << 10; - /// Enable interrupts. - const INTERRUPT_FLAG = 1 << 9; - /// Enable single-step mode for debugging. - const TRAP_FLAG = 1 << 8; - /// Set by hardware if last arithmetic operation resulted in a negative value. - const SIGN_FLAG = 1 << 7; - /// Set by hardware if last arithmetic operation resulted in a zero value. - const ZERO_FLAG = 1 << 6; - /// Set by hardware if last arithmetic operation generated a carry ouf of bit 3 of the - /// result. - const AUXILIARY_CARRY_FLAG = 1 << 4; - /// Set by hardware if last result has an even number of 1 bits (only for some operations). - const PARITY_FLAG = 1 << 2; - /// Set by hardware if last arithmetic operation generated a carry out of the - /// most-significant bit of the result. - const CARRY_FLAG = 1 << 0; - } -} - -#[cfg(target_arch = "x86_64")] -mod x86_64 { - use super::*; - - /// Returns the current value of the RFLAGS register. - /// - /// Drops any unknown bits. - pub fn read() -> RFlags { - RFlags::from_bits_truncate(read_raw()) - } - - /// Returns the raw current value of the RFLAGS register. - pub fn read_raw() -> u64 { - let r: u64; - unsafe { llvm_asm!("pushfq; popq $0" : "=r"(r) :: "memory") }; - r - } - - /// Writes the RFLAGS register, preserves reserved bits. - pub fn write(flags: RFlags) { - let old_value = read_raw(); - let reserved = old_value & !(RFlags::all().bits()); - let new_value = reserved | flags.bits(); - - write_raw(new_value); - } - - /// Writes the RFLAGS register. - /// - /// Does not preserve any bits, including reserved bits. - pub fn write_raw(val: u64) { - unsafe { llvm_asm!("pushq $0; popfq" :: "r"(val) : "memory" "flags") }; - } -} diff --git a/x86_64/src/structures/gdt.rs b/x86_64/src/structures/gdt.rs deleted file mode 100644 index b340577..0000000 --- a/x86_64/src/structures/gdt.rs +++ /dev/null @@ -1,230 +0,0 @@ -//! Types for the Global Descriptor Table and segment selectors. - -use crate::structures::tss::TaskStateSegment; -use crate::PrivilegeLevel; -use bit_field::BitField; -use bitflags::bitflags; -use core::fmt; - -/// Specifies which element to load into a segment from -/// descriptor tables (i.e., is a index to LDT or GDT table -/// with some additional flags). -/// -/// See Intel 3a, Section 3.4.2 "Segment Selectors" -#[derive(Clone, Copy, PartialEq, Eq)] -#[repr(transparent)] -pub struct SegmentSelector(pub u16); - -impl SegmentSelector { - /// Creates a new SegmentSelector - /// - /// # Arguments - /// * `index`: index in GDT or LDT array (not the offset) - /// * `rpl`: the requested privilege level - pub const fn new(index: u16, rpl: PrivilegeLevel) -> SegmentSelector { - SegmentSelector(index << 3 | (rpl as u16)) - } - - /// Returns the GDT index. - pub fn index(&self) -> u16 { - self.0 >> 3 - } - - /// Returns the requested privilege level. - pub fn rpl(&self) -> PrivilegeLevel { - PrivilegeLevel::from_u16(self.0.get_bits(0..2)) - } -} - -impl fmt::Debug for SegmentSelector { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let mut s = f.debug_struct("SegmentSelector"); - s.field("index", &self.index()); - s.field("rpl", &self.rpl()); - s.finish() - } -} - -/// A 64-bit mode global descriptor table (GDT). -/// -/// In 64-bit mode, segmentation is not supported. The GDT is used nonetheless, for example for -/// switching between user and kernel mode or for loading a TSS. -/// -/// The GDT has a fixed size of 8 entries, trying to add more entries will panic. -/// -/// You do **not** need to add a null segment descriptor yourself - this is already done -/// internally. -/// -/// Data segment registers in ring 0 can be loaded with the null segment selector. When running in -/// ring 3, the `ss` register must point to a valid data segment which can be obtained through the -/// [`Descriptor::user_data_segment()`](Descriptor::user_data_segment) function. Code segments must -/// be valid and non-null at all times and can be obtained through the -/// [`Descriptor::kernel_code_segment()`](Descriptor::kernel_code_segment) and -/// [`Descriptor::user_code_segment()`](Descriptor::user_code_segment) in rings 0 and 3 -/// respectively. -/// -/// For more info, see: -/// [x86 Instruction Reference for `mov`](https://www.felixcloutier.com/x86/mov#64-bit-mode-exceptions), -/// [Intel Manual](https://software.intel.com/sites/default/files/managed/39/c5/325462-sdm-vol-1-2abcd-3abcd.pdf), -/// [AMD Manual](https://www.amd.com/system/files/TechDocs/24593.pdf) -/// -/// # Example -/// ``` -/// use x86_64::structures::gdt::{GlobalDescriptorTable, Descriptor}; -/// -/// let mut gdt = GlobalDescriptorTable::new(); -/// gdt.add_entry(Descriptor::kernel_code_segment()); -/// gdt.add_entry(Descriptor::user_code_segment()); -/// gdt.add_entry(Descriptor::user_data_segment()); -/// -/// // Add entry for TSS, call gdt.load() then update segment registers -/// ``` - -#[derive(Debug, Clone)] -pub struct GlobalDescriptorTable { - table: [u64; 8], - next_free: usize, -} - -impl GlobalDescriptorTable { - /// Creates an empty GDT. - pub fn new() -> GlobalDescriptorTable { - GlobalDescriptorTable { - table: [0; 8], - next_free: 1, - } - } - - /// Adds the given segment descriptor to the GDT, returning the segment selector. - /// - /// Panics if the GDT has no free entries left. - pub fn add_entry(&mut self, entry: Descriptor) -> SegmentSelector { - let index = match entry { - Descriptor::UserSegment(value) => self.push(value), - Descriptor::SystemSegment(value_low, value_high) => { - let index = self.push(value_low); - self.push(value_high); - index - } - }; - SegmentSelector::new(index as u16, PrivilegeLevel::Ring0) - } - - /// Loads the GDT in the CPU using the `lgdt` instruction. This does **not** alter any of the - /// segment registers; you **must** (re)load them yourself using [the appropriate - /// functions](crate::instructions::segmentation): - /// [load_ss](crate::instructions::segmentation::load_ss), - /// [set_cs](crate::instructions::segmentation::set_cs). - #[cfg(target_arch = "x86_64")] - pub fn load(&'static self) { - use crate::instructions::tables::{lgdt, DescriptorTablePointer}; - use core::mem::size_of; - - let ptr = DescriptorTablePointer { - base: self.table.as_ptr() as u64, - limit: (self.table.len() * size_of::() - 1) as u16, - }; - - unsafe { lgdt(&ptr) }; - } - - fn push(&mut self, value: u64) -> usize { - if self.next_free < self.table.len() { - let index = self.next_free; - self.table[index] = value; - self.next_free += 1; - index - } else { - panic!("GDT full"); - } - } -} - -/// A 64-bit mode segment descriptor. -/// -/// Segmentation is no longer supported in 64-bit mode, so most of the descriptor -/// contents are ignored. -#[derive(Debug, Clone)] -pub enum Descriptor { - /// Descriptor for a code or data segment. - /// - /// Since segmentation is no longer supported in 64-bit mode, almost all of - /// code and data descriptors is ignored. Only some flags are still used. - UserSegment(u64), - /// A system segment descriptor such as a LDT or TSS descriptor. - SystemSegment(u64, u64), -} - -bitflags! { - /// Flags for a GDT descriptor. Not all flags are valid for all descriptor types. - pub struct DescriptorFlags: u64 { - /// For data segments, this flag sets the segment as writable. Ignored for code segments. - const WRITABLE = 1 << 41; - /// Marks a code segment as “conforming”. This influences the privilege checks that - /// occur on control transfers. - const CONFORMING = 1 << 42; - /// This flag must be set for code segments. - const EXECUTABLE = 1 << 43; - /// This flag must be set for user segments (in contrast to system segments). - const USER_SEGMENT = 1 << 44; - /// Must be set for any segment, causes a segment not present exception if not set. - const PRESENT = 1 << 47; - /// Must be set for long mode code segments. - const LONG_MODE = 1 << 53; - - /// The DPL for this descriptor is Ring 3 - const DPL_RING_3 = 3 << 45; - } -} - -impl Descriptor { - /// Creates a segment descriptor for a long mode kernel code segment. - pub fn kernel_code_segment() -> Descriptor { - use self::DescriptorFlags as Flags; - - let flags = Flags::USER_SEGMENT | Flags::PRESENT | Flags::EXECUTABLE | Flags::LONG_MODE; - Descriptor::UserSegment(flags.bits()) - } - - /// Creates a segment descriptor for a long mode ring 3 data segment. - pub fn user_data_segment() -> Descriptor { - use self::DescriptorFlags as Flags; - - let flags = Flags::USER_SEGMENT | Flags::PRESENT | Flags::WRITABLE | Flags::DPL_RING_3; - Descriptor::UserSegment(flags.bits()) - } - - /// Creates a segment descriptor for a long mode ring 3 code segment. - pub fn user_code_segment() -> Descriptor { - use self::DescriptorFlags as Flags; - - let flags = Flags::USER_SEGMENT - | Flags::PRESENT - | Flags::EXECUTABLE - | Flags::LONG_MODE - | Flags::DPL_RING_3; - Descriptor::UserSegment(flags.bits()) - } - - /// Creates a TSS system descriptor for the given TSS. - pub fn tss_segment(tss: &'static TaskStateSegment) -> Descriptor { - use self::DescriptorFlags as Flags; - use core::mem::size_of; - - let ptr = tss as *const _ as u64; - - let mut low = Flags::PRESENT.bits(); - // base - low.set_bits(16..40, ptr.get_bits(0..24)); - low.set_bits(56..64, ptr.get_bits(24..32)); - // limit (the `-1` in needed since the bound is inclusive) - low.set_bits(0..16, (size_of::() - 1) as u64); - // type (0b1001 = available 64-bit tss) - low.set_bits(40..44, 0b1001); - - let mut high = 0; - high.set_bits(0..32, ptr.get_bits(32..64)); - - Descriptor::SystemSegment(low, high) - } -} diff --git a/x86_64/src/structures/idt.rs b/x86_64/src/structures/idt.rs deleted file mode 100644 index 114742b..0000000 --- a/x86_64/src/structures/idt.rs +++ /dev/null @@ -1,764 +0,0 @@ -// Copyright 2017 Philipp Oppermann. See the README.md -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Provides types for the Interrupt Descriptor Table and its entries. - -use crate::{PrivilegeLevel, VirtAddr}; -use bit_field::BitField; -use bitflags::bitflags; -use core::fmt; -use core::marker::PhantomData; -use core::ops::{Deref, Index, IndexMut}; - -/// An Interrupt Descriptor Table with 256 entries. -/// -/// The first 32 entries are used for CPU exceptions. These entries can be either accessed through -/// fields on this struct or through an index operation, e.g. `idt[0]` returns the -/// first entry, the entry for the `divide_by_zero` exception. Note that the index access is -/// not possible for entries for which an error code is pushed. -/// -/// The remaining entries are used for interrupts. They can be accesed through index -/// operations on the idt, e.g. `idt[32]` returns the first interrupt entry, which is the 32th IDT -/// entry). -/// -/// -/// The field descriptions are taken from the -/// [AMD64 manual volume 2](https://support.amd.com/TechDocs/24593.pdf) -/// (with slight modifications). -#[allow(missing_debug_implementations)] -#[derive(Clone)] -#[repr(C)] -#[repr(align(16))] -pub struct InterruptDescriptorTable { - /// A divide by zero exception (`#DE`) occurs when the denominator of a DIV instruction or - /// an IDIV instruction is 0. A `#DE` also occurs if the result is too large to be - /// represented in the destination. - /// - /// The saved instruction pointer points to the instruction that caused the `#DE`. - /// - /// The vector number of the `#DE` exception is 0. - pub divide_by_zero: Entry, - - /// When the debug-exception mechanism is enabled, a `#DB` exception can occur under any - /// of the following circumstances: - /// - ///
- /// - /// - Instruction execution. - /// - Instruction single stepping. - /// - Data read. - /// - Data write. - /// - I/O read. - /// - I/O write. - /// - Task switch. - /// - Debug-register access, or general detect fault (debug register access when DR7.GD=1). - /// - Executing the INT1 instruction (opcode 0F1h). - /// - ///
- /// - /// `#DB` conditions are enabled and disabled using the debug-control register, `DR7` - /// and `RFLAGS.TF`. - /// - /// In the following cases, the saved instruction pointer points to the instruction that - /// caused the `#DB`: - /// - /// - Instruction execution. - /// - Invalid debug-register access, or general detect. - /// - /// In all other cases, the instruction that caused the `#DB` is completed, and the saved - /// instruction pointer points to the instruction after the one that caused the `#DB`. - /// - /// The vector number of the `#DB` exception is 1. - pub debug: Entry, - - /// An non maskable interrupt exception (NMI) occurs as a result of system logic - /// signaling a non-maskable interrupt to the processor. - /// - /// The processor recognizes an NMI at an instruction boundary. - /// The saved instruction pointer points to the instruction immediately following the - /// boundary where the NMI was recognized. - /// - /// The vector number of the NMI exception is 2. - pub non_maskable_interrupt: Entry, - - /// A breakpoint (`#BP`) exception occurs when an `INT3` instruction is executed. The - /// `INT3` is normally used by debug software to set instruction breakpoints by replacing - /// - /// The saved instruction pointer points to the byte after the `INT3` instruction. - /// - /// The vector number of the `#BP` exception is 3. - pub breakpoint: Entry, - - /// An overflow exception (`#OF`) occurs as a result of executing an `INTO` instruction - /// while the overflow bit in `RFLAGS` is set to 1. - /// - /// The saved instruction pointer points to the instruction following the `INTO` - /// instruction that caused the `#OF`. - /// - /// The vector number of the `#OF` exception is 4. - pub overflow: Entry, - - /// A bound-range exception (`#BR`) exception can occur as a result of executing - /// the `BOUND` instruction. The `BOUND` instruction compares an array index (first - /// operand) with the lower bounds and upper bounds of an array (second operand). - /// If the array index is not within the array boundary, the `#BR` occurs. - /// - /// The saved instruction pointer points to the `BOUND` instruction that caused the `#BR`. - /// - /// The vector number of the `#BR` exception is 5. - pub bound_range_exceeded: Entry, - - /// An invalid opcode exception (`#UD`) occurs when an attempt is made to execute an - /// invalid or undefined opcode. The validity of an opcode often depends on the - /// processor operating mode. - /// - ///
A `#UD` occurs under the following conditions: - /// - /// - Execution of any reserved or undefined opcode in any mode. - /// - Execution of the `UD2` instruction. - /// - Use of the `LOCK` prefix on an instruction that cannot be locked. - /// - Use of the `LOCK` prefix on a lockable instruction with a non-memory target location. - /// - Execution of an instruction with an invalid-operand type. - /// - Execution of the `SYSENTER` or `SYSEXIT` instructions in long mode. - /// - Execution of any of the following instructions in 64-bit mode: `AAA`, `AAD`, - /// `AAM`, `AAS`, `BOUND`, `CALL` (opcode 9A), `DAA`, `DAS`, `DEC`, `INC`, `INTO`, - /// `JMP` (opcode EA), `LDS`, `LES`, `POP` (`DS`, `ES`, `SS`), `POPA`, `PUSH` (`CS`, - /// `DS`, `ES`, `SS`), `PUSHA`, `SALC`. - /// - Execution of the `ARPL`, `LAR`, `LLDT`, `LSL`, `LTR`, `SLDT`, `STR`, `VERR`, or - /// `VERW` instructions when protected mode is not enabled, or when virtual-8086 mode - /// is enabled. - /// - Execution of any legacy SSE instruction when `CR4.OSFXSR` is cleared to 0. - /// - Execution of any SSE instruction (uses `YMM`/`XMM` registers), or 64-bit media - /// instruction (uses `MMXTM` registers) when `CR0.EM` = 1. - /// - Execution of any SSE floating-point instruction (uses `YMM`/`XMM` registers) that - /// causes a numeric exception when `CR4.OSXMMEXCPT` = 0. - /// - Use of the `DR4` or `DR5` debug registers when `CR4.DE` = 1. - /// - Execution of `RSM` when not in `SMM` mode. - /// - ///
- /// - /// The saved instruction pointer points to the instruction that caused the `#UD`. - /// - /// The vector number of the `#UD` exception is 6. - pub invalid_opcode: Entry, - - /// A device not available exception (`#NM`) occurs under any of the following conditions: - /// - ///
- /// - /// - An `FWAIT`/`WAIT` instruction is executed when `CR0.MP=1` and `CR0.TS=1`. - /// - Any x87 instruction other than `FWAIT` is executed when `CR0.EM=1`. - /// - Any x87 instruction is executed when `CR0.TS=1`. The `CR0.MP` bit controls whether the - /// `FWAIT`/`WAIT` instruction causes an `#NM` exception when `TS=1`. - /// - Any 128-bit or 64-bit media instruction when `CR0.TS=1`. - /// - ///
- /// - /// The saved instruction pointer points to the instruction that caused the `#NM`. - /// - /// The vector number of the `#NM` exception is 7. - pub device_not_available: Entry, - - /// A double fault (`#DF`) exception can occur when a second exception occurs during - /// the handling of a prior (first) exception or interrupt handler. - /// - ///
- /// - /// Usually, the first and second exceptions can be handled sequentially without - /// resulting in a `#DF`. In this case, the first exception is considered _benign_, as - /// it does not harm the ability of the processor to handle the second exception. In some - /// cases, however, the first exception adversely affects the ability of the processor to - /// handle the second exception. These exceptions contribute to the occurrence of a `#DF`, - /// and are called _contributory exceptions_. The following exceptions are contributory: - /// - /// - Invalid-TSS Exception - /// - Segment-Not-Present Exception - /// - Stack Exception - /// - General-Protection Exception - /// - /// A double-fault exception occurs in the following cases: - /// - /// - If a contributory exception is followed by another contributory exception. - /// - If a divide-by-zero exception is followed by a contributory exception. - /// - If a page fault is followed by another page fault or a contributory exception. - /// - /// If a third interrupting event occurs while transferring control to the `#DF` handler, - /// the processor shuts down. - /// - ///
- /// - /// The returned error code is always zero. The saved instruction pointer is undefined, - /// and the program cannot be restarted. - /// - /// The vector number of the `#DF` exception is 8. - pub double_fault: Entry, - - /// This interrupt vector is reserved. It is for a discontinued exception originally used - /// by processors that supported external x87-instruction coprocessors. On those processors, - /// the exception condition is caused by an invalid-segment or invalid-page access on an - /// x87-instruction coprocessor-instruction operand. On current processors, this condition - /// causes a general-protection exception to occur. - coprocessor_segment_overrun: Entry, - - /// An invalid TSS exception (`#TS`) occurs only as a result of a control transfer through - /// a gate descriptor that results in an invalid stack-segment reference using an `SS` - /// selector in the TSS. - /// - /// The returned error code is the `SS` segment selector. The saved instruction pointer - /// points to the control-transfer instruction that caused the `#TS`. - /// - /// The vector number of the `#TS` exception is 10. - pub invalid_tss: Entry, - - /// An segment-not-present exception (`#NP`) occurs when an attempt is made to load a - /// segment or gate with a clear present bit. - /// - /// The returned error code is the segment-selector index of the segment descriptor - /// causing the `#NP` exception. The saved instruction pointer points to the instruction - /// that loaded the segment selector resulting in the `#NP`. - /// - /// The vector number of the `#NP` exception is 11. - pub segment_not_present: Entry, - - /// An stack segment exception (`#SS`) can occur in the following situations: - /// - /// - Implied stack references in which the stack address is not in canonical - /// form. Implied stack references include all push and pop instructions, and any - /// instruction using `RSP` or `RBP` as a base register. - /// - Attempting to load a stack-segment selector that references a segment descriptor - /// containing a clear present bit. - /// - Any stack access that fails the stack-limit check. - /// - /// The returned error code depends on the cause of the `#SS`. If the cause is a cleared - /// present bit, the error code is the corresponding segment selector. Otherwise, the - /// error code is zero. The saved instruction pointer points to the instruction that - /// caused the `#SS`. - /// - /// The vector number of the `#NP` exception is 12. - pub stack_segment_fault: Entry, - - /// A general protection fault (`#GP`) can occur in various situations. Common causes include: - /// - /// - Executing a privileged instruction while `CPL > 0`. - /// - Writing a 1 into any register field that is reserved, must be zero (MBZ). - /// - Attempting to execute an SSE instruction specifying an unaligned memory operand. - /// - Loading a non-canonical base address into the `GDTR` or `IDTR`. - /// - Using WRMSR to write a read-only MSR. - /// - Any long-mode consistency-check violation. - /// - /// The returned error code is a segment selector, if the cause of the `#GP` is - /// segment-related, and zero otherwise. The saved instruction pointer points to - /// the instruction that caused the `#GP`. - /// - /// The vector number of the `#GP` exception is 13. - pub general_protection_fault: Entry, - - /// A page fault (`#PF`) can occur during a memory access in any of the following situations: - /// - /// - A page-translation-table entry or physical page involved in translating the memory - /// access is not present in physical memory. This is indicated by a cleared present - /// bit in the translation-table entry. - /// - An attempt is made by the processor to load the instruction TLB with a translation - /// for a non-executable page. - /// - The memory access fails the paging-protection checks (user/supervisor, read/write, - /// or both). - /// - A reserved bit in one of the page-translation-table entries is set to 1. A `#PF` - /// occurs for this reason only when `CR4.PSE=1` or `CR4.PAE=1`. - /// - /// The virtual (linear) address that caused the `#PF` is stored in the `CR2` register. - /// The saved instruction pointer points to the instruction that caused the `#PF`. - /// - /// The page-fault error code is described by the - /// [`PageFaultErrorCode`](struct.PageFaultErrorCode.html) struct. - /// - /// The vector number of the `#PF` exception is 14. - pub page_fault: Entry, - - /// vector nr. 15 - reserved_1: Entry, - - /// The x87 Floating-Point Exception-Pending exception (`#MF`) is used to handle unmasked x87 - /// floating-point exceptions. In 64-bit mode, the x87 floating point unit is not used - /// anymore, so this exception is only relevant when executing programs in the 32-bit - /// compatibility mode. - /// - /// The vector number of the `#MF` exception is 16. - pub x87_floating_point: Entry, - - /// An alignment check exception (`#AC`) occurs when an unaligned-memory data reference - /// is performed while alignment checking is enabled. An `#AC` can occur only when CPL=3. - /// - /// The returned error code is always zero. The saved instruction pointer points to the - /// instruction that caused the `#AC`. - /// - /// The vector number of the `#AC` exception is 17. - pub alignment_check: Entry, - - /// The machine check exception (`#MC`) is model specific. Processor implementations - /// are not required to support the `#MC` exception, and those implementations that do - /// support `#MC` can vary in how the `#MC` exception mechanism works. - /// - /// There is no reliable way to restart the program. - /// - /// The vector number of the `#MC` exception is 18. - pub machine_check: Entry, - - /// The SIMD Floating-Point Exception (`#XF`) is used to handle unmasked SSE - /// floating-point exceptions. The SSE floating-point exceptions reported by - /// the `#XF` exception are (including mnemonics): - /// - /// - IE: Invalid-operation exception (also called #I). - /// - DE: Denormalized-operand exception (also called #D). - /// - ZE: Zero-divide exception (also called #Z). - /// - OE: Overflow exception (also called #O). - /// - UE: Underflow exception (also called #U). - /// - PE: Precision exception (also called #P or inexact-result exception). - /// - /// The saved instruction pointer points to the instruction that caused the `#XF`. - /// - /// The vector number of the `#XF` exception is 19. - pub simd_floating_point: Entry, - - /// vector nr. 20 - pub virtualization: Entry, - - /// vector nr. 21-29 - reserved_2: [Entry; 9], - - /// The Security Exception (`#SX`) signals security-sensitive events that occur while - /// executing the VMM, in the form of an exception so that the VMM may take appropriate - /// action. (A VMM would typically intercept comparable sensitive events in the guest.) - /// In the current implementation, the only use of the `#SX` is to redirect external INITs - /// into an exception so that the VMM may — among other possibilities. - /// - /// The only error code currently defined is 1, and indicates redirection of INIT has occurred. - /// - /// The vector number of the ``#SX`` exception is 30. - pub security_exception: Entry, - - /// vector nr. 31 - reserved_3: Entry, - - /// User-defined interrupts can be initiated either by system logic or software. They occur - /// when: - /// - /// - System logic signals an external interrupt request to the processor. The signaling - /// mechanism and the method of communicating the interrupt vector to the processor are - /// implementation dependent. - /// - Software executes an `INTn` instruction. The `INTn` instruction operand provides - /// the interrupt vector number. - /// - /// Both methods can be used to initiate an interrupt into vectors 0 through 255. However, - /// because vectors 0 through 31 are defined or reserved by the AMD64 architecture, - /// software should not use vectors in this range for purposes other than their defined use. - /// - /// The saved instruction pointer depends on the interrupt source: - /// - /// - External interrupts are recognized on instruction boundaries. The saved instruction - /// pointer points to the instruction immediately following the boundary where the - /// external interrupt was recognized. - /// - If the interrupt occurs as a result of executing the INTn instruction, the saved - /// instruction pointer points to the instruction after the INTn. - interrupts: [Entry; 256 - 32], -} -impl InterruptDescriptorTable { - /// Creates a new IDT filled with non-present entries. - pub const fn new() -> InterruptDescriptorTable { - InterruptDescriptorTable { - divide_by_zero: Entry::missing(), - debug: Entry::missing(), - non_maskable_interrupt: Entry::missing(), - breakpoint: Entry::missing(), - overflow: Entry::missing(), - bound_range_exceeded: Entry::missing(), - invalid_opcode: Entry::missing(), - device_not_available: Entry::missing(), - double_fault: Entry::missing(), - coprocessor_segment_overrun: Entry::missing(), - invalid_tss: Entry::missing(), - segment_not_present: Entry::missing(), - stack_segment_fault: Entry::missing(), - general_protection_fault: Entry::missing(), - page_fault: Entry::missing(), - reserved_1: Entry::missing(), - x87_floating_point: Entry::missing(), - alignment_check: Entry::missing(), - machine_check: Entry::missing(), - simd_floating_point: Entry::missing(), - virtualization: Entry::missing(), - reserved_2: [Entry::missing(); 9], - security_exception: Entry::missing(), - reserved_3: Entry::missing(), - interrupts: [Entry::missing(); 256 - 32], - } - } - - /// Resets all entries of this IDT in place. - pub fn reset(&mut self) { - self.divide_by_zero = Entry::missing(); - self.debug = Entry::missing(); - self.non_maskable_interrupt = Entry::missing(); - self.breakpoint = Entry::missing(); - self.overflow = Entry::missing(); - self.bound_range_exceeded = Entry::missing(); - self.invalid_opcode = Entry::missing(); - self.device_not_available = Entry::missing(); - self.double_fault = Entry::missing(); - self.coprocessor_segment_overrun = Entry::missing(); - self.invalid_tss = Entry::missing(); - self.segment_not_present = Entry::missing(); - self.stack_segment_fault = Entry::missing(); - self.general_protection_fault = Entry::missing(); - self.page_fault = Entry::missing(); - self.reserved_1 = Entry::missing(); - self.x87_floating_point = Entry::missing(); - self.alignment_check = Entry::missing(); - self.machine_check = Entry::missing(); - self.simd_floating_point = Entry::missing(); - self.virtualization = Entry::missing(); - self.reserved_2 = [Entry::missing(); 9]; - self.security_exception = Entry::missing(); - self.reserved_3 = Entry::missing(); - self.interrupts = [Entry::missing(); 256 - 32]; - } - - /// Loads the IDT in the CPU using the `lidt` command. - #[cfg(target_arch = "x86_64")] - pub fn load(&'static self) { - use crate::instructions::tables::{lidt, DescriptorTablePointer}; - use core::mem::size_of; - - let ptr = DescriptorTablePointer { - base: self as *const _ as u64, - limit: (size_of::() - 1) as u16, - }; - - unsafe { lidt(&ptr) }; - } -} - -impl Index for InterruptDescriptorTable { - type Output = Entry; - - /// Returns the IDT entry with the specified index. - /// - /// Panics if index is outside the IDT (i.e. greater than 255) or if the entry is an - /// exception that pushes an error code (use the struct fields for accessing these entries). - fn index(&self, index: usize) -> &Self::Output { - match index { - 0 => &self.divide_by_zero, - 1 => &self.debug, - 2 => &self.non_maskable_interrupt, - 3 => &self.breakpoint, - 4 => &self.overflow, - 5 => &self.bound_range_exceeded, - 6 => &self.invalid_opcode, - 7 => &self.device_not_available, - 9 => &self.coprocessor_segment_overrun, - 16 => &self.x87_floating_point, - 18 => &self.machine_check, - 19 => &self.simd_floating_point, - 20 => &self.virtualization, - i @ 32..=255 => &self.interrupts[i - 32], - i @ 15 | i @ 31 | i @ 21..=29 => panic!("entry {} is reserved", i), - i @ 8 | i @ 10..=14 | i @ 17 | i @ 30 => { - panic!("entry {} is an exception with error code", i) - } - i => panic!("no entry with index {}", i), - } - } -} - -impl IndexMut for InterruptDescriptorTable { - /// Returns a mutable reference to the IDT entry with the specified index. - /// - /// Panics if index is outside the IDT (i.e. greater than 255) or if the entry is an - /// exception that pushes an error code (use the struct fields for accessing these entries). - fn index_mut(&mut self, index: usize) -> &mut Self::Output { - match index { - 0 => &mut self.divide_by_zero, - 1 => &mut self.debug, - 2 => &mut self.non_maskable_interrupt, - 3 => &mut self.breakpoint, - 4 => &mut self.overflow, - 5 => &mut self.bound_range_exceeded, - 6 => &mut self.invalid_opcode, - 7 => &mut self.device_not_available, - 9 => &mut self.coprocessor_segment_overrun, - 16 => &mut self.x87_floating_point, - 18 => &mut self.machine_check, - 19 => &mut self.simd_floating_point, - 20 => &mut self.virtualization, - i @ 32..=255 => &mut self.interrupts[i - 32], - i @ 15 | i @ 31 | i @ 21..=29 => panic!("entry {} is reserved", i), - i @ 8 | i @ 10..=14 | i @ 17 | i @ 30 => { - panic!("entry {} is an exception with error code", i) - } - i => panic!("no entry with index {}", i), - } - } -} - -/// An Interrupt Descriptor Table entry. -/// -/// The generic parameter can either be `HandlerFunc` or `HandlerFuncWithErrCode`, depending -/// on the interrupt vector. -#[derive(Debug, Clone, Copy, PartialEq)] -#[repr(C)] -pub struct Entry { - pointer_low: u16, - gdt_selector: u16, - options: EntryOptions, - pointer_middle: u16, - pointer_high: u32, - reserved: u32, - phantom: PhantomData, -} - -/// A handler function for an interrupt or an exception without error code. -pub type HandlerFunc = extern "x86-interrupt" fn(&mut InterruptStackFrame); -/// A handler function for an exception that pushes an error code. -pub type HandlerFuncWithErrCode = - extern "x86-interrupt" fn(&mut InterruptStackFrame, error_code: u64); -/// A page fault handler function that pushes a page fault error code. -pub type PageFaultHandlerFunc = - extern "x86-interrupt" fn(&mut InterruptStackFrame, error_code: PageFaultErrorCode); - -impl Entry { - /// Creates a non-present IDT entry (but sets the must-be-one bits). - pub const fn missing() -> Self { - Entry { - gdt_selector: 0, - pointer_low: 0, - pointer_middle: 0, - pointer_high: 0, - options: EntryOptions::minimal(), - reserved: 0, - phantom: PhantomData, - } - } - - /// Set the handler address for the IDT entry and sets the present bit. - /// - /// For the code selector field, this function uses the code segment selector currently - /// active in the CPU. - /// - /// The function returns a mutable reference to the entry's options that allows - /// further customization. - #[cfg(target_arch = "x86_64")] - fn set_handler_addr(&mut self, addr: u64) -> &mut EntryOptions { - use crate::instructions::segmentation; - - self.pointer_low = addr as u16; - self.pointer_middle = (addr >> 16) as u16; - self.pointer_high = (addr >> 32) as u32; - - self.gdt_selector = segmentation::cs().0; - - self.options.set_present(true); - &mut self.options - } -} - -macro_rules! impl_set_handler_fn { - ($h:ty) => { - #[cfg(target_arch = "x86_64")] - impl Entry<$h> { - /// Set the handler function for the IDT entry and sets the present bit. - /// - /// For the code selector field, this function uses the code segment selector currently - /// active in the CPU. - /// - /// The function returns a mutable reference to the entry's options that allows - /// further customization. - pub fn set_handler_fn(&mut self, handler: $h) -> &mut EntryOptions { - self.set_handler_addr(handler as u64) - } - } - }; -} - -impl_set_handler_fn!(HandlerFunc); -impl_set_handler_fn!(HandlerFuncWithErrCode); -impl_set_handler_fn!(PageFaultHandlerFunc); - -/// Represents the options field of an IDT entry. -#[repr(transparent)] -#[derive(Debug, Clone, Copy, PartialEq)] -pub struct EntryOptions(u16); - -impl EntryOptions { - /// Creates a minimal options field with all the must-be-one bits set. - const fn minimal() -> Self { - EntryOptions(0b1110_0000_0000) - } - - /// Set or reset the preset bit. - pub fn set_present(&mut self, present: bool) -> &mut Self { - self.0.set_bit(15, present); - self - } - - /// Let the CPU disable hardware interrupts when the handler is invoked. By default, - /// interrupts are disabled on handler invocation. - pub fn disable_interrupts(&mut self, disable: bool) -> &mut Self { - self.0.set_bit(8, !disable); - self - } - - /// Set the required privilege level (DPL) for invoking the handler. The DPL can be 0, 1, 2, - /// or 3, the default is 0. If CPL < DPL, a general protection fault occurs. - /// - /// This function panics for a DPL > 3. - pub fn set_privilege_level(&mut self, dpl: PrivilegeLevel) -> &mut Self { - self.0.set_bits(13..15, dpl as u16); - self - } - - /// Assigns a Interrupt Stack Table (IST) stack to this handler. The CPU will then always - /// switch to the specified stack before the handler is invoked. This allows kernels to - /// recover from corrupt stack pointers (e.g., on kernel stack overflow). - /// - /// An IST stack is specified by an IST index between 0 and 6 (inclusive). Using the same - /// stack for multiple interrupts can be dangerous when nested interrupts are possible. - /// - /// This function panics if the index is not in the range 0..7. - /// - /// ## Safety - /// This function is unsafe because the caller must ensure that the passed stack index is - /// valid and not used by other interrupts. Otherwise, memory safety violations are possible. - pub unsafe fn set_stack_index(&mut self, index: u16) -> &mut Self { - // The hardware IST index starts at 1, but our software IST index - // starts at 0. Therefore we need to add 1 here. - self.0.set_bits(0..3, index + 1); - self - } -} - -/// Wrapper type for the exception stack frame pushed by the CPU. -/// -/// Identical to [`InterruptStackFrame`]. -#[deprecated(note = "This type was renamed to InterruptStackFrame.")] -pub type ExceptionStackFrame = InterruptStackFrame; - -/// Wrapper type for the interrupt stack frame pushed by the CPU. -/// -/// This type derefs to an [`InterruptStackFrameValue`], which allows reading the actual values. -/// -/// This wrapper type ensures that no accidental modification of the interrupt stack frame -/// occurs, which can cause undefined behavior (see the [`as_mut`](InterruptStackFrame::as_mut) -/// method for more information). -pub struct InterruptStackFrame { - value: InterruptStackFrameValue, -} - -impl InterruptStackFrame { - /// Gives mutable access to the contents of the interrupt stack frame. - /// - /// This function is unsafe since modifying the content of the interrupt stack frame - /// can easily lead to undefined behavior. For example, by writing an invalid value to - /// the instruction pointer field, the CPU can jump to arbitrary code at the end of the - /// interrupt. - pub unsafe fn as_mut(&mut self) -> &mut InterruptStackFrameValue { - &mut self.value - } -} - -impl Deref for InterruptStackFrame { - type Target = InterruptStackFrameValue; - - fn deref(&self) -> &Self::Target { - &self.value - } -} - -impl fmt::Debug for InterruptStackFrame { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.value.fmt(f) - } -} - -/// Represents the interrupt stack frame pushed by the CPU on interrupt or exception entry. -#[derive(Clone)] -#[repr(C)] -pub struct InterruptStackFrameValue { - /// This value points to the instruction that should be executed when the interrupt - /// handler returns. For most interrupts, this value points to the instruction immediately - /// following the last executed instruction. However, for some exceptions (e.g., page faults), - /// this value points to the faulting instruction, so that the instruction is restarted on - /// return. See the documentation of the `InterruptDescriptorTable` fields for more details. - pub instruction_pointer: VirtAddr, - /// The code segment selector, padded with zeros. - pub code_segment: u64, - /// The flags register before the interrupt handler was invoked. - pub cpu_flags: u64, - /// The stack pointer at the time of the interrupt. - pub stack_pointer: VirtAddr, - /// The stack segment descriptor at the time of the interrupt (often zero in 64-bit mode). - pub stack_segment: u64, -} - -impl fmt::Debug for InterruptStackFrameValue { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - struct Hex(u64); - impl fmt::Debug for Hex { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{:#x}", self.0) - } - } - - let mut s = f.debug_struct("InterruptStackFrame"); - s.field("instruction_pointer", &self.instruction_pointer); - s.field("code_segment", &self.code_segment); - s.field("cpu_flags", &Hex(self.cpu_flags)); - s.field("stack_pointer", &self.stack_pointer); - s.field("stack_segment", &self.stack_segment); - s.finish() - } -} - -bitflags! { - /// Describes an page fault error code. - #[repr(transparent)] - pub struct PageFaultErrorCode: u64 { - /// If this flag is set, the page fault was caused by a page-protection violation, - /// else the page fault was caused by a not-present page. - const PROTECTION_VIOLATION = 1 << 0; - - /// If this flag is set, the memory access that caused the page fault was a write. - /// Else the access that caused the page fault is a memory read. This bit does not - /// necessarily indicate the cause of the page fault was a read or write violation. - const CAUSED_BY_WRITE = 1 << 1; - - /// If this flag is set, an access in user mode (CPL=3) caused the page fault. Else - /// an access in supervisor mode (CPL=0, 1, or 2) caused the page fault. This bit - /// does not necessarily indicate the cause of the page fault was a privilege violation. - const USER_MODE = 1 << 2; - - /// If this flag is set, the page fault is a result of the processor reading a 1 from - /// a reserved field within a page-translation-table entry. - const MALFORMED_TABLE = 1 << 3; - - /// If this flag is set, it indicates that the access that caused the page fault was an - /// instruction fetch. - const INSTRUCTION_FETCH = 1 << 4; - } -} - -#[cfg(test)] -mod test { - use super::*; - - #[test] - fn size_test() { - use core::mem::size_of; - assert_eq!(size_of::>(), 16); - assert_eq!(size_of::(), 256 * 16); - } -} diff --git a/x86_64/src/structures/mod.rs b/x86_64/src/structures/mod.rs deleted file mode 100644 index 942399d..0000000 --- a/x86_64/src/structures/mod.rs +++ /dev/null @@ -1,18 +0,0 @@ -//! Representations of various x86 specific structures and descriptor tables. - -pub mod gdt; -pub mod idt; -pub mod paging; -pub mod port; -pub mod tss; - -/// A struct describing a pointer to a descriptor table (GDT / IDT). -/// This is in a format suitable for giving to 'lgdt' or 'lidt'. -#[derive(Debug, Clone, Copy)] -#[repr(C, packed)] -pub struct DescriptorTablePointer { - /// Size of the DT. - pub limit: u16, - /// Pointer to the memory region containing the DT. - pub base: u64, -} diff --git a/x86_64/src/structures/paging/frame.rs b/x86_64/src/structures/paging/frame.rs deleted file mode 100644 index 7325640..0000000 --- a/x86_64/src/structures/paging/frame.rs +++ /dev/null @@ -1,194 +0,0 @@ -//! Abstractions for default-sized and huge physical memory frames. - -use crate::structures::paging::page::{PageSize, Size4KiB}; -use crate::PhysAddr; -use core::fmt; -use core::marker::PhantomData; -use core::ops::{Add, AddAssign, Sub, SubAssign}; - -/// A physical memory frame. -#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] -#[repr(C)] -pub struct PhysFrame { - start_address: PhysAddr, - size: PhantomData, -} - -impl PhysFrame { - /// Returns the frame that starts at the given virtual address. - /// - /// Returns an error if the address is not correctly aligned (i.e. is not a valid frame start). - pub fn from_start_address(address: PhysAddr) -> Result { - if !address.is_aligned(S::SIZE) { - return Err(()); - } - Ok(PhysFrame::containing_address(address)) - } - - /// Returns the frame that contains the given physical address. - pub fn containing_address(address: PhysAddr) -> Self { - PhysFrame { - start_address: address.align_down(S::SIZE), - size: PhantomData, - } - } - - /// Returns the start address of the frame. - pub fn start_address(&self) -> PhysAddr { - self.start_address - } - - /// Returns the size the frame (4KB, 2MB or 1GB). - pub fn size() -> usize { - S::SIZE - } - - /// Returns a range of frames, exclusive `end`. - pub fn range(start: PhysFrame, end: PhysFrame) -> PhysFrameRange { - PhysFrameRange { start, end } - } - - /// Returns a range of frames, inclusive `end`. - pub fn range_inclusive(start: PhysFrame, end: PhysFrame) -> PhysFrameRangeInclusive { - PhysFrameRangeInclusive { start, end } - } -} - -impl fmt::Debug for PhysFrame { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.write_fmt(format_args!( - "PhysFrame[{}]({:#x})", - S::SIZE_AS_DEBUG_STR, - self.start_address().as_usize() - )) - } -} - -impl Add for PhysFrame { - type Output = Self; - fn add(self, rhs: usize) -> Self::Output { - PhysFrame::containing_address(self.start_address() + rhs * S::SIZE) - } -} - -impl AddAssign for PhysFrame { - fn add_assign(&mut self, rhs: usize) { - *self = self.clone() + rhs; - } -} - -impl Sub for PhysFrame { - type Output = Self; - fn sub(self, rhs: usize) -> Self::Output { - PhysFrame::containing_address(self.start_address() - rhs * S::SIZE) - } -} - -impl SubAssign for PhysFrame { - fn sub_assign(&mut self, rhs: usize) { - *self = self.clone() - rhs; - } -} - -impl Sub> for PhysFrame { - type Output = usize; - fn sub(self, rhs: PhysFrame) -> Self::Output { - (self.start_address - rhs.start_address) / S::SIZE - } -} - -/// An range of physical memory frames, exclusive the upper bound. -#[derive(Clone, Copy, PartialEq, Eq)] -#[repr(C)] -pub struct PhysFrameRange { - /// The start of the range, inclusive. - pub start: PhysFrame, - /// The end of the range, exclusive. - pub end: PhysFrame, -} - -impl PhysFrameRange { - /// Returns whether the range contains no frames. - pub fn is_empty(&self) -> bool { - !(self.start < self.end) - } - - pub fn len(&self) -> usize { - self.end - self.start - } - - pub fn contains(&self, frame: PhysFrame) -> bool { - self.start.start_address() <= frame.start_address() && frame.start_address() < self.end.start_address() - } - - pub fn contains_address(&self, addr: PhysAddr) -> bool { - self.contains(PhysFrame::::containing_address(addr)) - } - - pub fn contains_range(&self, range: Self) -> bool { - self.start.start_address() <= range.start.start_address() && range.end.start_address() <= self.end.start_address() - } -} - -impl Iterator for PhysFrameRange { - type Item = PhysFrame; - - fn next(&mut self) -> Option { - if self.start < self.end { - let frame = self.start.clone(); - self.start += 1; - Some(frame) - } else { - None - } - } -} - -impl fmt::Debug for PhysFrameRange { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_struct("PhysFrameRange") - .field("start", &self.start) - .field("end", &self.end) - .finish() - } -} - -/// An range of physical memory frames, inclusive the upper bound. -#[derive(Clone, Copy, PartialEq, Eq)] -#[repr(C)] -pub struct PhysFrameRangeInclusive { - /// The start of the range, inclusive. - pub start: PhysFrame, - /// The start of the range, exclusive. - pub end: PhysFrame, -} - -impl PhysFrameRangeInclusive { - /// Returns whether the range contains no frames. - pub fn is_empty(&self) -> bool { - !(self.start <= self.end) - } -} - -impl Iterator for PhysFrameRangeInclusive { - type Item = PhysFrame; - - fn next(&mut self) -> Option { - if self.start <= self.end { - let frame = self.start.clone(); - self.start += 1; - Some(frame) - } else { - None - } - } -} - -impl fmt::Debug for PhysFrameRangeInclusive { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_struct("PhysFrameRangeInclusive") - .field("start", &self.start) - .field("end", &self.end) - .finish() - } -} diff --git a/x86_64/src/structures/paging/frame_alloc.rs b/x86_64/src/structures/paging/frame_alloc.rs deleted file mode 100644 index 6e80f15..0000000 --- a/x86_64/src/structures/paging/frame_alloc.rs +++ /dev/null @@ -1,18 +0,0 @@ -//! Traits for abstracting away frame allocation and deallocation. - -use crate::structures::paging::{PageSize, PhysFrame}; - -/// A trait for types that can allocate a frame of memory. -/// -/// This trait is unsafe to implement because the implementer must guarantee that -/// the `allocate_frame` method returns only unique unused frames. -pub unsafe trait FrameAllocator { - /// Allocate a frame of the appropriate size and return it if possible. - fn allocate_frame(&mut self) -> Option>; -} - -/// A trait for types that can deallocate a frame of memory. -pub trait FrameDeallocator { - /// Deallocate the given frame of memory. - fn deallocate_frame(&mut self, frame: PhysFrame); -} diff --git a/x86_64/src/structures/paging/mapper/mapped_page_table.rs b/x86_64/src/structures/paging/mapper/mapped_page_table.rs deleted file mode 100644 index 152219f..0000000 --- a/x86_64/src/structures/paging/mapper/mapped_page_table.rs +++ /dev/null @@ -1,560 +0,0 @@ -use crate::structures::paging::{ - frame::PhysFrame, - frame_alloc::FrameAllocator, - mapper::*, - page::{Page, Size1GiB, Size2MiB, Size4KiB}, - page_table::{FrameError, PageTable, PageTableEntry, PageTableFlags}, -}; - -/// A Mapper implementation that relies on a PhysAddr to VirtAddr conversion function. -/// -/// This type requires that the all physical page table frames are mapped to some virtual -/// address. Normally, this is done by mapping the complete physical address space into -/// the virtual address space at some offset. Other mappings between physical and virtual -/// memory are possible too, as long as they can be calculated as an `PhysAddr` to -/// `VirtAddr` closure. -#[derive(Debug)] -pub struct MappedPageTable<'a, P: PhysToVirt> { - page_table_walker: PageTableWalker

, - level_4_table: &'a mut PageTable, -} - -impl<'a, P: PhysToVirt> MappedPageTable<'a, P> { - /// Creates a new `MappedPageTable` that uses the passed closure for converting virtual - /// to physical addresses. - /// - /// This function is unsafe because the caller must guarantee that the passed `phys_to_virt` - /// closure is correct. Also, the passed `level_4_table` must point to the level 4 page table - /// of a valid page table hierarchy. Otherwise this function might break memory safety, e.g. - /// by writing to an illegal memory location. - pub unsafe fn new(level_4_table: &'a mut PageTable, phys_to_virt: P) -> Self { - Self { - level_4_table, - page_table_walker: PageTableWalker::new(phys_to_virt), - } - } - - /// Helper function for implementing Mapper. Safe to limit the scope of unsafe, see - /// https://github.com/rust-lang/rfcs/pull/2585. - fn map_to_1gib( - &mut self, - page: Page, - frame: PhysFrame, - flags: PageTableFlags, - allocator: &mut A, - ) -> Result, MapToError> - where - A: FrameAllocator, - { - let p4 = &mut self.level_4_table; - let p3 = self - .page_table_walker - .create_next_table(&mut p4[page.p4_index()], allocator)?; - - if !p3[page.p3_index()].is_unused() { - return Err(MapToError::PageAlreadyMapped); - } - p3[page.p3_index()].set_addr(frame.start_address(), flags | PageTableFlags::HUGE_PAGE); - - Ok(MapperFlush::new(page)) - } - - /// Helper function for implementing Mapper. Safe to limit the scope of unsafe, see - /// https://github.com/rust-lang/rfcs/pull/2585. - fn map_to_2mib( - &mut self, - page: Page, - frame: PhysFrame, - flags: PageTableFlags, - allocator: &mut A, - ) -> Result, MapToError> - where - A: FrameAllocator, - { - let p4 = &mut self.level_4_table; - let p3 = self - .page_table_walker - .create_next_table(&mut p4[page.p4_index()], allocator)?; - let p2 = self - .page_table_walker - .create_next_table(&mut p3[page.p3_index()], allocator)?; - - if !p2[page.p2_index()].is_unused() { - return Err(MapToError::PageAlreadyMapped); - } - p2[page.p2_index()].set_addr(frame.start_address(), flags | PageTableFlags::HUGE_PAGE); - - Ok(MapperFlush::new(page)) - } - - /// Helper function for implementing Mapper. Safe to limit the scope of unsafe, see - /// https://github.com/rust-lang/rfcs/pull/2585. - fn map_to_4kib( - &mut self, - page: Page, - frame: PhysFrame, - flags: PageTableFlags, - allocator: &mut A, - ) -> Result, MapToError> - where - A: FrameAllocator, - { - let p4 = &mut self.level_4_table; - let p3 = self - .page_table_walker - .create_next_table(&mut p4[page.p4_index()], allocator)?; - let p2 = self - .page_table_walker - .create_next_table(&mut p3[page.p3_index()], allocator)?; - let p1 = self - .page_table_walker - .create_next_table(&mut p2[page.p2_index()], allocator)?; - - if !p1[page.p1_index()].is_unused() { - return Err(MapToError::PageAlreadyMapped); - } - p1[page.p1_index()].set_frame(frame, flags); - - Ok(MapperFlush::new(page)) - } -} - -impl<'a, P: PhysToVirt> Mapper for MappedPageTable<'a, P> { - unsafe fn map_to( - &mut self, - page: Page, - frame: PhysFrame, - flags: PageTableFlags, - allocator: &mut A, - ) -> Result, MapToError> - where - A: FrameAllocator, - { - self.map_to_1gib(page, frame, flags, allocator) - } - - fn unmap( - &mut self, - page: Page, - ) -> Result<(PhysFrame, MapperFlush), UnmapError> { - let p4 = &mut self.level_4_table; - let p3 = self - .page_table_walker - .next_table_mut(&mut p4[page.p4_index()])?; - - let p3_entry = &mut p3[page.p3_index()]; - let flags = p3_entry.flags(); - - if !flags.contains(PageTableFlags::PRESENT) { - return Err(UnmapError::PageNotMapped); - } - if !flags.contains(PageTableFlags::HUGE_PAGE) { - return Err(UnmapError::ParentEntryHugePage); - } - - let frame = PhysFrame::from_start_address(p3_entry.addr()) - .map_err(|()| UnmapError::InvalidFrameAddress(p3_entry.addr()))?; - - p3_entry.set_unused(); - Ok((frame, MapperFlush::new(page))) - } - - fn update_flags( - &mut self, - page: Page, - flags: PageTableFlags, - ) -> Result, FlagUpdateError> { - let p4 = &mut self.level_4_table; - let p3 = self - .page_table_walker - .next_table_mut(&mut p4[page.p4_index()])?; - - if p3[page.p3_index()].is_unused() { - return Err(FlagUpdateError::PageNotMapped); - } - p3[page.p3_index()].set_flags(flags | PageTableFlags::HUGE_PAGE); - - Ok(MapperFlush::new(page)) - } - - fn translate_page(&self, page: Page) -> Result, TranslateError> { - let p4 = &self.level_4_table; - let p3 = self.page_table_walker.next_table(&p4[page.p4_index()])?; - - let p3_entry = &p3[page.p3_index()]; - - if p3_entry.is_unused() { - return Err(TranslateError::PageNotMapped); - } - - PhysFrame::from_start_address(p3_entry.addr()) - .map_err(|()| TranslateError::InvalidFrameAddress(p3_entry.addr())) - } -} - -impl<'a, P: PhysToVirt> Mapper for MappedPageTable<'a, P> { - unsafe fn map_to( - &mut self, - page: Page, - frame: PhysFrame, - flags: PageTableFlags, - allocator: &mut A, - ) -> Result, MapToError> - where - A: FrameAllocator, - { - self.map_to_2mib(page, frame, flags, allocator) - } - - fn unmap( - &mut self, - page: Page, - ) -> Result<(PhysFrame, MapperFlush), UnmapError> { - let p4 = &mut self.level_4_table; - let p3 = self - .page_table_walker - .next_table_mut(&mut p4[page.p4_index()])?; - let p2 = self - .page_table_walker - .next_table_mut(&mut p3[page.p3_index()])?; - - let p2_entry = &mut p2[page.p2_index()]; - let flags = p2_entry.flags(); - - if !flags.contains(PageTableFlags::PRESENT) { - return Err(UnmapError::PageNotMapped); - } - if !flags.contains(PageTableFlags::HUGE_PAGE) { - return Err(UnmapError::ParentEntryHugePage); - } - - let frame = PhysFrame::from_start_address(p2_entry.addr()) - .map_err(|()| UnmapError::InvalidFrameAddress(p2_entry.addr()))?; - - p2_entry.set_unused(); - Ok((frame, MapperFlush::new(page))) - } - - fn update_flags( - &mut self, - page: Page, - flags: PageTableFlags, - ) -> Result, FlagUpdateError> { - let p4 = &mut self.level_4_table; - let p3 = self - .page_table_walker - .next_table_mut(&mut p4[page.p4_index()])?; - let p2 = self - .page_table_walker - .next_table_mut(&mut p3[page.p3_index()])?; - - if p2[page.p2_index()].is_unused() { - return Err(FlagUpdateError::PageNotMapped); - } - - p2[page.p2_index()].set_flags(flags | PageTableFlags::HUGE_PAGE); - - Ok(MapperFlush::new(page)) - } - - fn translate_page(&self, page: Page) -> Result, TranslateError> { - let p4 = &self.level_4_table; - let p3 = self.page_table_walker.next_table(&p4[page.p4_index()])?; - let p2 = self.page_table_walker.next_table(&p3[page.p3_index()])?; - - let p2_entry = &p2[page.p2_index()]; - - if p2_entry.is_unused() { - return Err(TranslateError::PageNotMapped); - } - - PhysFrame::from_start_address(p2_entry.addr()) - .map_err(|()| TranslateError::InvalidFrameAddress(p2_entry.addr())) - } -} - -impl<'a, P: PhysToVirt> Mapper for MappedPageTable<'a, P> { - unsafe fn map_to( - &mut self, - page: Page, - frame: PhysFrame, - flags: PageTableFlags, - allocator: &mut A, - ) -> Result, MapToError> - where - A: FrameAllocator, - { - self.map_to_4kib(page, frame, flags, allocator) - } - - fn unmap( - &mut self, - page: Page, - ) -> Result<(PhysFrame, MapperFlush), UnmapError> { - let p4 = &mut self.level_4_table; - let p3 = self - .page_table_walker - .next_table_mut(&mut p4[page.p4_index()])?; - let p2 = self - .page_table_walker - .next_table_mut(&mut p3[page.p3_index()])?; - let p1 = self - .page_table_walker - .next_table_mut(&mut p2[page.p2_index()])?; - - let p1_entry = &mut p1[page.p1_index()]; - - let frame = p1_entry.frame().map_err(|err| match err { - FrameError::FrameNotPresent => UnmapError::PageNotMapped, - FrameError::HugeFrame => UnmapError::ParentEntryHugePage, - })?; - - p1_entry.set_unused(); - Ok((frame, MapperFlush::new(page))) - } - - fn update_flags( - &mut self, - page: Page, - flags: PageTableFlags, - ) -> Result, FlagUpdateError> { - let p4 = &mut self.level_4_table; - let p3 = self - .page_table_walker - .next_table_mut(&mut p4[page.p4_index()])?; - let p2 = self - .page_table_walker - .next_table_mut(&mut p3[page.p3_index()])?; - let p1 = self - .page_table_walker - .next_table_mut(&mut p2[page.p2_index()])?; - - if p1[page.p1_index()].is_unused() { - return Err(FlagUpdateError::PageNotMapped); - } - - p1[page.p1_index()].set_flags(flags); - - Ok(MapperFlush::new(page)) - } - - fn translate_page(&self, page: Page) -> Result, TranslateError> { - let p4 = &self.level_4_table; - let p3 = self.page_table_walker.next_table(&p4[page.p4_index()])?; - let p2 = self.page_table_walker.next_table(&p3[page.p3_index()])?; - let p1 = self.page_table_walker.next_table(&p2[page.p2_index()])?; - - let p1_entry = &p1[page.p1_index()]; - - if p1_entry.is_unused() { - return Err(TranslateError::PageNotMapped); - } - - PhysFrame::from_start_address(p1_entry.addr()) - .map_err(|()| TranslateError::InvalidFrameAddress(p1_entry.addr())) - } -} - -impl<'a, P: PhysToVirt> MapperAllSizes for MappedPageTable<'a, P> { - fn translate(&self, addr: VirtAddr) -> TranslateResult { - let p4 = &self.level_4_table; - let p3 = match self.page_table_walker.next_table(&p4[addr.p4_index()]) { - Ok(page_table) => page_table, - Err(PageTableWalkError::NotMapped) => return TranslateResult::PageNotMapped, - Err(PageTableWalkError::MappedToHugePage) => { - panic!("level 4 entry has huge page bit set") - } - }; - let p2 = match self.page_table_walker.next_table(&p3[addr.p3_index()]) { - Ok(page_table) => page_table, - Err(PageTableWalkError::NotMapped) => return TranslateResult::PageNotMapped, - Err(PageTableWalkError::MappedToHugePage) => { - let frame = PhysFrame::containing_address(p3[addr.p3_index()].addr()); - let offset = addr.as_usize() & 0o_777_777_7777; - return TranslateResult::Frame1GiB { frame, offset }; - } - }; - let p1 = match self.page_table_walker.next_table(&p2[addr.p2_index()]) { - Ok(page_table) => page_table, - Err(PageTableWalkError::NotMapped) => return TranslateResult::PageNotMapped, - Err(PageTableWalkError::MappedToHugePage) => { - let frame = PhysFrame::containing_address(p2[addr.p2_index()].addr()); - let offset = addr.as_usize() & 0o_777_7777; - return TranslateResult::Frame2MiB { frame, offset }; - } - }; - - let p1_entry = &p1[addr.p1_index()]; - - if p1_entry.is_unused() { - return TranslateResult::PageNotMapped; - } - - let frame = match PhysFrame::from_start_address(p1_entry.addr()) { - Ok(frame) => frame, - Err(()) => return TranslateResult::InvalidFrameAddress(p1_entry.addr()), - }; - let offset = u64::from(addr.page_offset()) as usize; - TranslateResult::Frame4KiB { frame, offset } - } -} - -#[derive(Debug)] -struct PageTableWalker { - phys_to_virt: P, -} - -impl PageTableWalker

{ - pub unsafe fn new(phys_to_virt: P) -> Self { - Self { phys_to_virt } - } - - /// Internal helper function to get a reference to the page table of the next level. - /// - /// Returns `PageTableWalkError::NotMapped` if the entry is unused. Returns - /// `PageTableWalkError::MappedToHugePage` if the `HUGE_PAGE` flag is set - /// in the passed entry. - fn next_table<'b>( - &self, - entry: &'b PageTableEntry, - ) -> Result<&'b PageTable, PageTableWalkError> { - let page_table_ptr = self.phys_to_virt.phys_to_virt(entry.frame()?); - let page_table: &PageTable = unsafe { &*page_table_ptr }; - - Ok(page_table) - } - - /// Internal helper function to get a mutable reference to the page table of the next level. - /// - /// Returns `PageTableWalkError::NotMapped` if the entry is unused. Returns - /// `PageTableWalkError::MappedToHugePage` if the `HUGE_PAGE` flag is set - /// in the passed entry. - fn next_table_mut<'b>( - &self, - entry: &'b mut PageTableEntry, - ) -> Result<&'b mut PageTable, PageTableWalkError> { - let page_table_ptr = self.phys_to_virt.phys_to_virt(entry.frame()?); - let page_table: &mut PageTable = unsafe { &mut *page_table_ptr }; - - Ok(page_table) - } - - /// Internal helper function to create the page table of the next level if needed. - /// - /// If the passed entry is unused, a new frame is allocated from the given allocator, zeroed, - /// and the entry is updated to that address. If the passed entry is already mapped, the next - /// table is returned directly. - /// - /// Returns `MapToError::FrameAllocationFailed` if the entry is unused and the allocator - /// returned `None`. Returns `MapToError::ParentEntryHugePage` if the `HUGE_PAGE` flag is set - /// in the passed entry. - fn create_next_table<'b, A>( - &self, - entry: &'b mut PageTableEntry, - allocator: &mut A, - ) -> Result<&'b mut PageTable, PageTableCreateError> - where - A: FrameAllocator, - { - let created; - - if entry.is_unused() { - if let Some(frame) = allocator.allocate_frame() { - entry.set_frame(frame, PageTableFlags::PRESENT | PageTableFlags::WRITABLE); - created = true; - } else { - return Err(PageTableCreateError::FrameAllocationFailed); - } - } else { - created = false; - } - - let page_table = match self.next_table_mut(entry) { - Err(PageTableWalkError::MappedToHugePage) => { - Err(PageTableCreateError::MappedToHugePage)? - } - Err(PageTableWalkError::NotMapped) => panic!("entry should be mapped at this point"), - Ok(page_table) => page_table, - }; - - if created { - page_table.zero(); - } - Ok(page_table) - } -} - -#[derive(Debug)] -enum PageTableWalkError { - NotMapped, - MappedToHugePage, -} - -#[derive(Debug)] -enum PageTableCreateError { - MappedToHugePage, - FrameAllocationFailed, -} - -impl From for MapToError { - fn from(err: PageTableCreateError) -> Self { - match err { - PageTableCreateError::MappedToHugePage => MapToError::ParentEntryHugePage, - PageTableCreateError::FrameAllocationFailed => MapToError::FrameAllocationFailed, - } - } -} - -impl From for PageTableWalkError { - fn from(err: FrameError) -> Self { - match err { - FrameError::HugeFrame => PageTableWalkError::MappedToHugePage, - FrameError::FrameNotPresent => PageTableWalkError::NotMapped, - } - } -} - -impl From for UnmapError { - fn from(err: PageTableWalkError) -> Self { - match err { - PageTableWalkError::MappedToHugePage => UnmapError::ParentEntryHugePage, - PageTableWalkError::NotMapped => UnmapError::PageNotMapped, - } - } -} - -impl From for FlagUpdateError { - fn from(err: PageTableWalkError) -> Self { - match err { - PageTableWalkError::MappedToHugePage => FlagUpdateError::ParentEntryHugePage, - PageTableWalkError::NotMapped => FlagUpdateError::PageNotMapped, - } - } -} - -impl From for TranslateError { - fn from(err: PageTableWalkError) -> Self { - match err { - PageTableWalkError::MappedToHugePage => TranslateError::ParentEntryHugePage, - PageTableWalkError::NotMapped => TranslateError::PageNotMapped, - } - } -} - -/// Trait for converting a physical address to a virtual one. -/// -/// This only works if the physical address space is somehow mapped to the virtual -/// address space, e.g. at an offset. -pub trait PhysToVirt { - /// Translate the given physical frame to a virtual page table pointer. - fn phys_to_virt(&self, phys_frame: PhysFrame) -> *mut PageTable; -} - -impl PhysToVirt for T -where - T: Fn(PhysFrame) -> *mut PageTable, -{ - fn phys_to_virt(&self, phys_frame: PhysFrame) -> *mut PageTable { - self(phys_frame) - } -} diff --git a/x86_64/src/structures/paging/mapper/mod.rs b/x86_64/src/structures/paging/mapper/mod.rs deleted file mode 100644 index 57a6103..0000000 --- a/x86_64/src/structures/paging/mapper/mod.rs +++ /dev/null @@ -1,207 +0,0 @@ -//! Abstractions for reading and modifying the mapping of pages. - -pub use self::mapped_page_table::{MappedPageTable, PhysToVirt}; -#[cfg(target_arch = "x86_64")] -pub use self::offset_page_table::OffsetPageTable; -#[cfg(target_arch = "x86_64")] -pub use self::recursive_page_table::RecursivePageTable; - -use crate::structures::paging::{ - frame_alloc::FrameAllocator, page_table::PageTableFlags, Page, PageSize, PhysFrame, Size1GiB, - Size2MiB, Size4KiB, -}; -use crate::{PhysAddr, VirtAddr}; - -mod mapped_page_table; -mod offset_page_table; -mod recursive_page_table; - -/// This trait defines page table operations that work for all page sizes of the x86_64 -/// architecture. -pub trait MapperAllSizes: Mapper + Mapper + Mapper { - /// Return the frame that the given virtual address is mapped to and the offset within that - /// frame. - /// - /// If the given address has a valid mapping, the mapped frame and the offset within that - /// frame is returned. Otherwise an error value is returned. - /// - /// This function works with huge pages of all sizes. - fn translate(&self, addr: VirtAddr) -> TranslateResult; - - /// Translates the given virtual address to the physical address that it maps to. - /// - /// Returns `None` if there is no valid mapping for the given address. - /// - /// This is a convenience method. For more information about a mapping see the - /// [`translate`](MapperAllSizes::translate) method. - fn translate_addr(&self, addr: VirtAddr) -> Option { - match self.translate(addr) { - TranslateResult::PageNotMapped | TranslateResult::InvalidFrameAddress(_) => None, - TranslateResult::Frame4KiB { frame, offset } => Some(frame.start_address() + offset), - TranslateResult::Frame2MiB { frame, offset } => Some(frame.start_address() + offset), - TranslateResult::Frame1GiB { frame, offset } => Some(frame.start_address() + offset), - } - } -} - -/// The return value of the [`MapperAllSizes::translate`] function. -/// -/// If the given address has a valid mapping, a `Frame4KiB`, `Frame2MiB`, or `Frame1GiB` variant -/// is returned, depending on the size of the mapped page. The remaining variants indicate errors. -#[derive(Debug)] -pub enum TranslateResult { - /// The page is mapped to a physical frame of size 4KiB. - Frame4KiB { - /// The mapped frame. - frame: PhysFrame, - /// The offset whithin the mapped frame. - offset: usize, - }, - /// The page is mapped to a physical frame of size 2MiB. - Frame2MiB { - /// The mapped frame. - frame: PhysFrame, - /// The offset whithin the mapped frame. - offset: usize, - }, - /// The page is mapped to a physical frame of size 2MiB. - Frame1GiB { - /// The mapped frame. - frame: PhysFrame, - /// The offset whithin the mapped frame. - offset: usize, - }, - /// The given page is not mapped to a physical frame. - PageNotMapped, - /// The page table entry for the given page points to an invalid physical address. - InvalidFrameAddress(PhysAddr), -} - -/// A trait for common page table operations on pages of size `S`. -pub trait Mapper { - /// Creates a new mapping in the page table. - /// - /// This function might need additional physical frames to create new page tables. These - /// frames are allocated from the `allocator` argument. At most three frames are required. - /// - /// This function is unsafe because the caller must guarantee that passed `frame` is - /// unused, i.e. not used for any other mappings. - unsafe fn map_to( - &mut self, - page: Page, - frame: PhysFrame, - flags: PageTableFlags, - frame_allocator: &mut A, - ) -> Result, MapToError> - where - A: FrameAllocator; - - /// Removes a mapping from the page table and returns the frame that used to be mapped. - /// - /// Note that no page tables or pages are deallocated. - fn unmap(&mut self, page: Page) -> Result<(PhysFrame, MapperFlush), UnmapError>; - - /// Updates the flags of an existing mapping. - fn update_flags( - &mut self, - page: Page, - flags: PageTableFlags, - ) -> Result, FlagUpdateError>; - - /// Return the frame that the specified page is mapped to. - /// - /// This function assumes that the page is mapped to a frame of size `S` and returns an - /// error otherwise. - fn translate_page(&self, page: Page) -> Result, TranslateError>; - - /// Maps the given frame to the virtual page with the same address. - /// - /// This function is unsafe because the caller must guarantee that the passed `frame` is - /// unused, i.e. not used for any other mappings. - unsafe fn identity_map( - &mut self, - frame: PhysFrame, - flags: PageTableFlags, - frame_allocator: &mut A, - ) -> Result, MapToError> - where - A: FrameAllocator, - S: PageSize, - Self: Mapper, - { - let page = Page::containing_address(VirtAddr::new(frame.start_address().as_usize())); - self.map_to(page, frame, flags, frame_allocator) - } -} - -/// This type represents a page whose mapping has changed in the page table. -/// -/// The old mapping might be still cached in the translation lookaside buffer (TLB), so it needs -/// to be flushed from the TLB before it's accessed. This type is returned from function that -/// change the mapping of a page to ensure that the TLB flush is not forgotten. -#[derive(Debug)] -#[must_use = "Page Table changes must be flushed or ignored."] -pub struct MapperFlush(Page); - -impl MapperFlush { - /// Create a new flush promise - fn new(page: Page) -> Self { - MapperFlush(page) - } - - /// Flush the page from the TLB to ensure that the newest mapping is used. - #[cfg(target_arch = "x86_64")] - pub fn flush(self) { - crate::instructions::tlb::flush(self.0.start_address()); - } - - /// Don't flush the TLB and silence the “must be used” warning. - pub fn ignore(self) {} -} - -/// This error is returned from `map_to` and similar methods. -#[derive(Debug)] -pub enum MapToError { - /// An additional frame was needed for the mapping process, but the frame allocator - /// returned `None`. - FrameAllocationFailed, - /// An upper level page table entry has the `HUGE_PAGE` flag set, which means that the - /// given page is part of an already mapped huge page. - ParentEntryHugePage, - /// The given page is already mapped to a physical frame. - PageAlreadyMapped, -} - -/// An error indicating that an `unmap` call failed. -#[derive(Debug)] -pub enum UnmapError { - /// An upper level page table entry has the `HUGE_PAGE` flag set, which means that the - /// given page is part of a huge page and can't be freed individually. - ParentEntryHugePage, - /// The given page is not mapped to a physical frame. - PageNotMapped, - /// The page table entry for the given page points to an invalid physical address. - InvalidFrameAddress(PhysAddr), -} - -/// An error indicating that an `update_flags` call failed. -#[derive(Debug)] -pub enum FlagUpdateError { - /// The given page is not mapped to a physical frame. - PageNotMapped, - /// An upper level page table entry has the `HUGE_PAGE` flag set, which means that the - /// given page is part of a huge page and can't be freed individually. - ParentEntryHugePage, -} - -/// An error indicating that an `translate` call failed. -#[derive(Debug)] -pub enum TranslateError { - /// The given page is not mapped to a physical frame. - PageNotMapped, - /// An upper level page table entry has the `HUGE_PAGE` flag set, which means that the - /// given page is part of a huge page and can't be freed individually. - ParentEntryHugePage, - /// The page table entry for the given page points to an invalid physical address. - InvalidFrameAddress(PhysAddr), -} diff --git a/x86_64/src/structures/paging/mapper/offset_page_table.rs b/x86_64/src/structures/paging/mapper/offset_page_table.rs deleted file mode 100644 index 80ecc3b..0000000 --- a/x86_64/src/structures/paging/mapper/offset_page_table.rs +++ /dev/null @@ -1,151 +0,0 @@ -#![cfg(target_arch = "x86_64")] - -use crate::structures::paging::{frame::PhysFrame, mapper::*, page_table::PageTable}; - -/// A Mapper implementation that requires that the complete physically memory is mapped at some -/// offset in the virtual address space. -#[derive(Debug)] -pub struct OffsetPageTable<'a> { - inner: MappedPageTable<'a, PhysOffset>, -} - -impl<'a> OffsetPageTable<'a> { - /// Creates a new `OffsetPageTable` that uses the given offset for converting virtual - /// to physical addresses. - /// - /// This function is unsafe because the caller must guarantee that the passed `phys_offset` - /// is correct. Also, the passed `level_4_table` must point to the level 4 page table - /// of a valid page table hierarchy. Otherwise this function might break memory safety, e.g. - /// by writing to an illegal memory location. - pub unsafe fn new(level_4_table: &'a mut PageTable, phys_offset: usize) -> Self { - let phys_offset = PhysOffset { - offset: phys_offset, - }; - Self { - inner: MappedPageTable::new(level_4_table, phys_offset), - } - } -} - -#[derive(Debug)] -struct PhysOffset { - offset: usize, -} - -impl PhysToVirt for PhysOffset { - fn phys_to_virt(&self, frame: PhysFrame) -> *mut PageTable { - let phys = frame.start_address().as_usize(); - let virt = VirtAddr::new(phys + self.offset); - virt.as_mut_ptr() - } -} - -// delegate all trait implementations to inner - -impl<'a> Mapper for OffsetPageTable<'a> { - unsafe fn map_to( - &mut self, - page: Page, - frame: PhysFrame, - flags: PageTableFlags, - allocator: &mut A, - ) -> Result, MapToError> - where - A: FrameAllocator, - { - self.inner.map_to(page, frame, flags, allocator) - } - - fn unmap( - &mut self, - page: Page, - ) -> Result<(PhysFrame, MapperFlush), UnmapError> { - self.inner.unmap(page) - } - - fn update_flags( - &mut self, - page: Page, - flags: PageTableFlags, - ) -> Result, FlagUpdateError> { - self.inner.update_flags(page, flags) - } - - fn translate_page(&self, page: Page) -> Result, TranslateError> { - self.inner.translate_page(page) - } -} - -impl<'a> Mapper for OffsetPageTable<'a> { - unsafe fn map_to( - &mut self, - page: Page, - frame: PhysFrame, - flags: PageTableFlags, - allocator: &mut A, - ) -> Result, MapToError> - where - A: FrameAllocator, - { - self.inner.map_to(page, frame, flags, allocator) - } - - fn unmap( - &mut self, - page: Page, - ) -> Result<(PhysFrame, MapperFlush), UnmapError> { - self.inner.unmap(page) - } - - fn update_flags( - &mut self, - page: Page, - flags: PageTableFlags, - ) -> Result, FlagUpdateError> { - self.inner.update_flags(page, flags) - } - - fn translate_page(&self, page: Page) -> Result, TranslateError> { - self.inner.translate_page(page) - } -} - -impl<'a> Mapper for OffsetPageTable<'a> { - unsafe fn map_to( - &mut self, - page: Page, - frame: PhysFrame, - flags: PageTableFlags, - allocator: &mut A, - ) -> Result, MapToError> - where - A: FrameAllocator, - { - self.inner.map_to(page, frame, flags, allocator) - } - - fn unmap( - &mut self, - page: Page, - ) -> Result<(PhysFrame, MapperFlush), UnmapError> { - self.inner.unmap(page) - } - - fn update_flags( - &mut self, - page: Page, - flags: PageTableFlags, - ) -> Result, FlagUpdateError> { - self.inner.update_flags(page, flags) - } - - fn translate_page(&self, page: Page) -> Result, TranslateError> { - self.inner.translate_page(page) - } -} - -impl<'a> MapperAllSizes for OffsetPageTable<'a> { - fn translate(&self, addr: VirtAddr) -> TranslateResult { - self.inner.translate(addr) - } -} diff --git a/x86_64/src/structures/paging/mapper/recursive_page_table.rs b/x86_64/src/structures/paging/mapper/recursive_page_table.rs deleted file mode 100644 index 5865dc9..0000000 --- a/x86_64/src/structures/paging/mapper/recursive_page_table.rs +++ /dev/null @@ -1,621 +0,0 @@ -#![cfg(target_arch = "x86_64")] - -//! Access the page tables through a recursively mapped level 4 table. - -use super::*; -use crate::registers::control::Cr3; -use crate::structures::paging::{ - frame_alloc::FrameAllocator, - page::NotGiantPageSize, - page_table::{FrameError, PageTable, PageTableEntry, PageTableFlags}, - Page, PageSize, PhysFrame, Size1GiB, Size2MiB, Size4KiB, -}; -use crate::VirtAddr; -use ux::u9; - -/// A recursive page table is a last level page table with an entry mapped to the table itself. -/// -/// This recursive mapping allows accessing all page tables in the hierarchy: -/// -/// - To access the level 4 page table, we “loop“ (i.e. follow the recursively mapped entry) four -/// times. -/// - To access a level 3 page table, we “loop” three times and then use the level 4 index. -/// - To access a level 2 page table, we “loop” two times, then use the level 4 index, then the -/// level 3 index. -/// - To access a level 1 page table, we “loop” once, then use the level 4 index, then the -/// level 3 index, then the level 2 index. -/// -/// This struct implements the `Mapper` trait. -#[derive(Debug)] -pub struct RecursivePageTable<'a> { - p4: &'a mut PageTable, - recursive_index: u9, -} - -impl<'a> RecursivePageTable<'a> { - /// Creates a new RecursivePageTable from the passed level 4 PageTable. - /// - /// The page table must be recursively mapped, that means: - /// - /// - The page table must have one recursive entry, i.e. an entry that points to the table - /// itself. - /// - The reference must use that “loop”, i.e. be of the form `0o_xxx_xxx_xxx_xxx_0000` - /// where `xxx` is the recursive entry. - /// - The page table must be active, i.e. the CR3 register must contain its physical address. - /// - /// Otherwise `Err(())` is returned. - pub fn new(table: &'a mut PageTable) -> Result { - let page = Page::containing_address(VirtAddr::new(table as *const _ as usize)); - let recursive_index = page.p4_index(); - - if page.p3_index() != recursive_index - || page.p2_index() != recursive_index - || page.p1_index() != recursive_index - { - return Err(()); - } - if Ok(Cr3::read().0) != table[recursive_index].frame() { - return Err(()); - } - - Ok(RecursivePageTable { - p4: table, - recursive_index, - }) - } - - /// Creates a new RecursivePageTable without performing any checks. - /// - /// The `recursive_index` parameter must be the index of the recursively mapped entry. - pub unsafe fn new_unchecked(table: &'a mut PageTable, recursive_index: u9) -> Self { - RecursivePageTable { - p4: table, - recursive_index, - } - } - - /// Internal helper function to create the page table of the next level if needed. - /// - /// If the passed entry is unused, a new frame is allocated from the given allocator, zeroed, - /// and the entry is updated to that address. If the passed entry is already mapped, the next - /// table is returned directly. - /// - /// The `next_page_table` page must be the page of the next page table in the hierarchy. - /// - /// Returns `MapToError::FrameAllocationFailed` if the entry is unused and the allocator - /// returned `None`. Returns `MapToError::ParentEntryHugePage` if the `HUGE_PAGE` flag is set - /// in the passed entry. - unsafe fn create_next_table<'b, A>( - entry: &'b mut PageTableEntry, - next_table_page: Page, - allocator: &mut A, - ) -> Result<&'b mut PageTable, MapToError> - where - A: FrameAllocator, - { - /// This inner function is used to limit the scope of `unsafe`. - /// - /// This is a safe function, so we need to use `unsafe` blocks when we do something unsafe. - fn inner<'b, A>( - entry: &'b mut PageTableEntry, - next_table_page: Page, - allocator: &mut A, - ) -> Result<&'b mut PageTable, MapToError> - where - A: FrameAllocator, - { - use crate::structures::paging::PageTableFlags as Flags; - - let created; - - if entry.is_unused() { - if let Some(frame) = allocator.allocate_frame() { - entry.set_frame(frame, Flags::PRESENT | Flags::WRITABLE); - created = true; - } else { - return Err(MapToError::FrameAllocationFailed); - } - } else { - created = false; - } - if entry.flags().contains(Flags::HUGE_PAGE) { - return Err(MapToError::ParentEntryHugePage); - } - - let page_table_ptr = next_table_page.start_address().as_mut_ptr(); - let page_table: &mut PageTable = unsafe { &mut *(page_table_ptr) }; - if created { - page_table.zero(); - } - Ok(page_table) - } - - inner(entry, next_table_page, allocator) - } - - /// Helper function for implementing Mapper. Safe to limit the scope of unsafe, see - /// https://github.com/rust-lang/rfcs/pull/2585. - fn map_to_1gib( - &mut self, - page: Page, - frame: PhysFrame, - flags: PageTableFlags, - allocator: &mut A, - ) -> Result, MapToError> - where - A: FrameAllocator, - { - use crate::structures::paging::PageTableFlags as Flags; - let p4 = &mut self.p4; - - let p3_page = p3_page(page, self.recursive_index); - let p3 = unsafe { Self::create_next_table(&mut p4[page.p4_index()], p3_page, allocator)? }; - - if !p3[page.p3_index()].is_unused() { - return Err(MapToError::PageAlreadyMapped); - } - p3[page.p3_index()].set_addr(frame.start_address(), flags | Flags::HUGE_PAGE); - - Ok(MapperFlush::new(page)) - } - - /// Helper function for implementing Mapper. Safe to limit the scope of unsafe, see - /// https://github.com/rust-lang/rfcs/pull/2585. - fn map_to_2mib( - &mut self, - page: Page, - frame: PhysFrame, - flags: PageTableFlags, - allocator: &mut A, - ) -> Result, MapToError> - where - A: FrameAllocator, - { - use crate::structures::paging::PageTableFlags as Flags; - let p4 = &mut self.p4; - - let p3_page = p3_page(page, self.recursive_index); - let p3 = unsafe { Self::create_next_table(&mut p4[page.p4_index()], p3_page, allocator)? }; - - let p2_page = p2_page(page, self.recursive_index); - let p2 = unsafe { Self::create_next_table(&mut p3[page.p3_index()], p2_page, allocator)? }; - - if !p2[page.p2_index()].is_unused() { - return Err(MapToError::PageAlreadyMapped); - } - p2[page.p2_index()].set_addr(frame.start_address(), flags | Flags::HUGE_PAGE); - - Ok(MapperFlush::new(page)) - } - - /// Helper function for implementing Mapper. Safe to limit the scope of unsafe, see - /// https://github.com/rust-lang/rfcs/pull/2585. - fn map_to_4kib( - &mut self, - page: Page, - frame: PhysFrame, - flags: PageTableFlags, - allocator: &mut A, - ) -> Result, MapToError> - where - A: FrameAllocator, - { - let p4 = &mut self.p4; - - let p3_page = p3_page(page, self.recursive_index); - let p3 = unsafe { Self::create_next_table(&mut p4[page.p4_index()], p3_page, allocator)? }; - - let p2_page = p2_page(page, self.recursive_index); - let p2 = unsafe { Self::create_next_table(&mut p3[page.p3_index()], p2_page, allocator)? }; - - let p1_page = p1_page(page, self.recursive_index); - let p1 = unsafe { Self::create_next_table(&mut p2[page.p2_index()], p1_page, allocator)? }; - - if !p1[page.p1_index()].is_unused() { - return Err(MapToError::PageAlreadyMapped); - } - p1[page.p1_index()].set_frame(frame, flags); - - Ok(MapperFlush::new(page)) - } -} - -impl<'a> Mapper for RecursivePageTable<'a> { - unsafe fn map_to( - &mut self, - page: Page, - frame: PhysFrame, - flags: PageTableFlags, - allocator: &mut A, - ) -> Result, MapToError> - where - A: FrameAllocator, - { - self.map_to_1gib(page, frame, flags, allocator) - } - - fn unmap( - &mut self, - page: Page, - ) -> Result<(PhysFrame, MapperFlush), UnmapError> { - let p4 = &mut self.p4; - let p4_entry = &p4[page.p4_index()]; - - p4_entry.frame().map_err(|err| match err { - FrameError::FrameNotPresent => UnmapError::PageNotMapped, - FrameError::HugeFrame => UnmapError::ParentEntryHugePage, - })?; - - let p3 = unsafe { &mut *(p3_ptr(page, self.recursive_index)) }; - let p3_entry = &mut p3[page.p3_index()]; - let flags = p3_entry.flags(); - - if !flags.contains(PageTableFlags::PRESENT) { - return Err(UnmapError::PageNotMapped); - } - if !flags.contains(PageTableFlags::HUGE_PAGE) { - return Err(UnmapError::ParentEntryHugePage); - } - - let frame = PhysFrame::from_start_address(p3_entry.addr()) - .map_err(|()| UnmapError::InvalidFrameAddress(p3_entry.addr()))?; - - p3_entry.set_unused(); - Ok((frame, MapperFlush::new(page))) - } - - fn update_flags( - &mut self, - page: Page, - flags: PageTableFlags, - ) -> Result, FlagUpdateError> { - use crate::structures::paging::PageTableFlags as Flags; - let p4 = &mut self.p4; - - if p4[page.p4_index()].is_unused() { - return Err(FlagUpdateError::PageNotMapped); - } - - let p3 = unsafe { &mut *(p3_ptr(page, self.recursive_index)) }; - - if p3[page.p3_index()].is_unused() { - return Err(FlagUpdateError::PageNotMapped); - } - p3[page.p3_index()].set_flags(flags | Flags::HUGE_PAGE); - - Ok(MapperFlush::new(page)) - } - - fn translate_page(&self, page: Page) -> Result, TranslateError> { - let p4 = &self.p4; - - if p4[page.p4_index()].is_unused() { - return Err(TranslateError::PageNotMapped); - } - - let p3 = unsafe { &*(p3_ptr(page, self.recursive_index)) }; - let p3_entry = &p3[page.p3_index()]; - - if p3_entry.is_unused() { - return Err(TranslateError::PageNotMapped); - } - - PhysFrame::from_start_address(p3_entry.addr()) - .map_err(|()| TranslateError::InvalidFrameAddress(p3_entry.addr())) - } -} - -impl<'a> Mapper for RecursivePageTable<'a> { - unsafe fn map_to( - &mut self, - page: Page, - frame: PhysFrame, - flags: PageTableFlags, - allocator: &mut A, - ) -> Result, MapToError> - where - A: FrameAllocator, - { - self.map_to_2mib(page, frame, flags, allocator) - } - - fn unmap( - &mut self, - page: Page, - ) -> Result<(PhysFrame, MapperFlush), UnmapError> { - let p4 = &mut self.p4; - let p4_entry = &p4[page.p4_index()]; - p4_entry.frame().map_err(|err| match err { - FrameError::FrameNotPresent => UnmapError::PageNotMapped, - FrameError::HugeFrame => UnmapError::ParentEntryHugePage, - })?; - - let p3 = unsafe { &mut *(p3_ptr(page, self.recursive_index)) }; - let p3_entry = &p3[page.p3_index()]; - p3_entry.frame().map_err(|err| match err { - FrameError::FrameNotPresent => UnmapError::PageNotMapped, - FrameError::HugeFrame => UnmapError::ParentEntryHugePage, - })?; - - let p2 = unsafe { &mut *(p2_ptr(page, self.recursive_index)) }; - let p2_entry = &mut p2[page.p2_index()]; - let flags = p2_entry.flags(); - - if !flags.contains(PageTableFlags::PRESENT) { - return Err(UnmapError::PageNotMapped); - } - if !flags.contains(PageTableFlags::HUGE_PAGE) { - return Err(UnmapError::ParentEntryHugePage); - } - - let frame = PhysFrame::from_start_address(p2_entry.addr()) - .map_err(|()| UnmapError::InvalidFrameAddress(p2_entry.addr()))?; - - p2_entry.set_unused(); - Ok((frame, MapperFlush::new(page))) - } - - fn update_flags( - &mut self, - page: Page, - flags: PageTableFlags, - ) -> Result, FlagUpdateError> { - use crate::structures::paging::PageTableFlags as Flags; - let p4 = &mut self.p4; - - if p4[page.p4_index()].is_unused() { - return Err(FlagUpdateError::PageNotMapped); - } - - let p3 = unsafe { &mut *(p3_ptr(page, self.recursive_index)) }; - - if p3[page.p3_index()].is_unused() { - return Err(FlagUpdateError::PageNotMapped); - } - - let p2 = unsafe { &mut *(p2_ptr(page, self.recursive_index)) }; - - if p2[page.p2_index()].is_unused() { - return Err(FlagUpdateError::PageNotMapped); - } - - p2[page.p2_index()].set_flags(flags | Flags::HUGE_PAGE); - - Ok(MapperFlush::new(page)) - } - - fn translate_page(&self, page: Page) -> Result, TranslateError> { - let p4 = &self.p4; - - if p4[page.p4_index()].is_unused() { - return Err(TranslateError::PageNotMapped); - } - - let p3 = unsafe { &*(p3_ptr(page, self.recursive_index)) }; - let p3_entry = &p3[page.p3_index()]; - - if p3_entry.is_unused() { - return Err(TranslateError::PageNotMapped); - } - - let p2 = unsafe { &*(p2_ptr(page, self.recursive_index)) }; - let p2_entry = &p2[page.p2_index()]; - - if p2_entry.is_unused() { - return Err(TranslateError::PageNotMapped); - } - - PhysFrame::from_start_address(p2_entry.addr()) - .map_err(|()| TranslateError::InvalidFrameAddress(p2_entry.addr())) - } -} - -impl<'a> Mapper for RecursivePageTable<'a> { - unsafe fn map_to( - &mut self, - page: Page, - frame: PhysFrame, - flags: PageTableFlags, - allocator: &mut A, - ) -> Result, MapToError> - where - A: FrameAllocator, - { - self.map_to_4kib(page, frame, flags, allocator) - } - - fn unmap( - &mut self, - page: Page, - ) -> Result<(PhysFrame, MapperFlush), UnmapError> { - let p4 = &mut self.p4; - let p4_entry = &p4[page.p4_index()]; - p4_entry.frame().map_err(|err| match err { - FrameError::FrameNotPresent => UnmapError::PageNotMapped, - FrameError::HugeFrame => UnmapError::ParentEntryHugePage, - })?; - - let p3 = unsafe { &mut *(p3_ptr(page, self.recursive_index)) }; - let p3_entry = &p3[page.p3_index()]; - p3_entry.frame().map_err(|err| match err { - FrameError::FrameNotPresent => UnmapError::PageNotMapped, - FrameError::HugeFrame => UnmapError::ParentEntryHugePage, - })?; - - let p2 = unsafe { &mut *(p2_ptr(page, self.recursive_index)) }; - let p2_entry = &p2[page.p2_index()]; - p2_entry.frame().map_err(|err| match err { - FrameError::FrameNotPresent => UnmapError::PageNotMapped, - FrameError::HugeFrame => UnmapError::ParentEntryHugePage, - })?; - - let p1 = unsafe { &mut *(p1_ptr(page, self.recursive_index)) }; - let p1_entry = &mut p1[page.p1_index()]; - - let frame = p1_entry.frame().map_err(|err| match err { - FrameError::FrameNotPresent => UnmapError::PageNotMapped, - FrameError::HugeFrame => UnmapError::ParentEntryHugePage, - })?; - - p1_entry.set_unused(); - Ok((frame, MapperFlush::new(page))) - } - - fn update_flags( - &mut self, - page: Page, - flags: PageTableFlags, - ) -> Result, FlagUpdateError> { - let p4 = &mut self.p4; - - if p4[page.p4_index()].is_unused() { - return Err(FlagUpdateError::PageNotMapped); - } - - let p3 = unsafe { &mut *(p3_ptr(page, self.recursive_index)) }; - - if p3[page.p3_index()].is_unused() { - return Err(FlagUpdateError::PageNotMapped); - } - - let p2 = unsafe { &mut *(p2_ptr(page, self.recursive_index)) }; - - if p2[page.p2_index()].is_unused() { - return Err(FlagUpdateError::PageNotMapped); - } - - let p1 = unsafe { &mut *(p1_ptr(page, self.recursive_index)) }; - - if p1[page.p1_index()].is_unused() { - return Err(FlagUpdateError::PageNotMapped); - } - - p1[page.p1_index()].set_flags(flags); - - Ok(MapperFlush::new(page)) - } - - fn translate_page(&self, page: Page) -> Result, TranslateError> { - let p4 = &self.p4; - - if p4[page.p4_index()].is_unused() { - return Err(TranslateError::PageNotMapped); - } - - let p3 = unsafe { &*(p3_ptr(page, self.recursive_index)) }; - let p3_entry = &p3[page.p3_index()]; - - if p3_entry.is_unused() { - return Err(TranslateError::PageNotMapped); - } - - let p2 = unsafe { &*(p2_ptr(page, self.recursive_index)) }; - let p2_entry = &p2[page.p2_index()]; - - if p2_entry.is_unused() { - return Err(TranslateError::PageNotMapped); - } - - let p1 = unsafe { &*(p1_ptr(page, self.recursive_index)) }; - let p1_entry = &p1[page.p1_index()]; - - if p1_entry.is_unused() { - return Err(TranslateError::PageNotMapped); - } - - PhysFrame::from_start_address(p1_entry.addr()) - .map_err(|()| TranslateError::InvalidFrameAddress(p1_entry.addr())) - } -} - -impl<'a> MapperAllSizes for RecursivePageTable<'a> { - fn translate(&self, addr: VirtAddr) -> TranslateResult { - let page = Page::containing_address(addr); - - let p4 = &self.p4; - let p4_entry = &p4[addr.p4_index()]; - if p4_entry.is_unused() { - return TranslateResult::PageNotMapped; - } - if p4_entry.flags().contains(PageTableFlags::HUGE_PAGE) { - panic!("level 4 entry has huge page bit set") - } - - let p3 = unsafe { &*(p3_ptr(page, self.recursive_index)) }; - let p3_entry = &p3[addr.p3_index()]; - if p3_entry.is_unused() { - return TranslateResult::PageNotMapped; - } - if p3_entry.flags().contains(PageTableFlags::HUGE_PAGE) { - let frame = PhysFrame::containing_address(p3[addr.p3_index()].addr()); - let offset = addr.as_usize() & 0o_777_777_7777; - return TranslateResult::Frame1GiB { frame, offset }; - } - - let p2 = unsafe { &*(p2_ptr(page, self.recursive_index)) }; - let p2_entry = &p2[addr.p2_index()]; - if p2_entry.is_unused() { - return TranslateResult::PageNotMapped; - } - if p2_entry.flags().contains(PageTableFlags::HUGE_PAGE) { - let frame = PhysFrame::containing_address(p2[addr.p2_index()].addr()); - let offset = addr.as_usize() & 0o_777_7777; - return TranslateResult::Frame2MiB { frame, offset }; - } - - let p1 = unsafe { &*(p1_ptr(page, self.recursive_index)) }; - let p1_entry = &p1[addr.p1_index()]; - if p1_entry.is_unused() { - return TranslateResult::PageNotMapped; - } - if p1_entry.flags().contains(PageTableFlags::HUGE_PAGE) { - panic!("level 1 entry has huge page bit set") - } - - let frame = match PhysFrame::from_start_address(p1_entry.addr()) { - Ok(frame) => frame, - Err(()) => return TranslateResult::InvalidFrameAddress(p1_entry.addr()), - }; - let offset = u64::from(addr.page_offset()) as usize; - TranslateResult::Frame4KiB { frame, offset } - } -} - -fn p3_ptr(page: Page, recursive_index: u9) -> *mut PageTable { - p3_page(page, recursive_index).start_address().as_mut_ptr() -} - -fn p3_page(page: Page, recursive_index: u9) -> Page { - Page::from_page_table_indices( - recursive_index, - recursive_index, - recursive_index, - page.p4_index(), - ) -} - -fn p2_ptr(page: Page, recursive_index: u9) -> *mut PageTable { - p2_page(page, recursive_index).start_address().as_mut_ptr() -} - -fn p2_page(page: Page, recursive_index: u9) -> Page { - Page::from_page_table_indices( - recursive_index, - recursive_index, - page.p4_index(), - page.p3_index(), - ) -} - -fn p1_ptr(page: Page, recursive_index: u9) -> *mut PageTable { - p1_page(page, recursive_index).start_address().as_mut_ptr() -} - -fn p1_page(page: Page, recursive_index: u9) -> Page { - Page::from_page_table_indices( - recursive_index, - page.p4_index(), - page.p3_index(), - page.p2_index(), - ) -} diff --git a/x86_64/src/structures/paging/mod.rs b/x86_64/src/structures/paging/mod.rs deleted file mode 100644 index 5b53829..0000000 --- a/x86_64/src/structures/paging/mod.rs +++ /dev/null @@ -1,18 +0,0 @@ -//! Abstractions for page tables and other paging related structures. -//! -//! Page tables translate virtual memory “pages” to physical memory “frames”. - -pub use self::frame::PhysFrame; -pub use self::frame_alloc::{FrameAllocator, FrameDeallocator}; -#[cfg(target_arch = "x86_64")] -#[doc(no_inline)] -pub use self::mapper::{MappedPageTable, OffsetPageTable, RecursivePageTable}; -pub use self::mapper::{Mapper, MapperAllSizes}; -pub use self::page::{Page, PageSize, Size1GiB, Size2MiB, Size4KiB}; -pub use self::page_table::{PageTable, PageTableFlags}; - -pub mod frame; -mod frame_alloc; -pub mod mapper; -pub mod page; -pub mod page_table; diff --git a/x86_64/src/structures/paging/page.rs b/x86_64/src/structures/paging/page.rs deleted file mode 100644 index dc09447..0000000 --- a/x86_64/src/structures/paging/page.rs +++ /dev/null @@ -1,330 +0,0 @@ -//! Abstractions for default-sized and huge virtual memory pages. - -use crate::VirtAddr; -use core::fmt; -use core::marker::PhantomData; -use core::ops::{Add, AddAssign, Sub, SubAssign}; -use ux::*; - -/// Trait for abstracting over the three possible page sizes on x86_64, 4KiB, 2MiB, 1GiB. -pub trait PageSize: Copy + Eq + PartialOrd + Ord { - /// The page size in bytes. - const SIZE: usize; - - /// A string representation of the page size for debug output. - const SIZE_AS_DEBUG_STR: &'static str; -} - -/// This trait is implemented for 4KiB and 2MiB pages, but not for 1GiB pages. -pub trait NotGiantPageSize: PageSize {} - -/// A standard 4KiB page. -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] -pub enum Size4KiB {} - -/// A “huge” 2MiB page. -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] -pub enum Size2MiB {} - -/// A “giant” 1GiB page. -/// -/// (Only available on newer x86_64 CPUs.) -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] -pub enum Size1GiB {} - -impl PageSize for Size4KiB { - const SIZE: usize = 4096; - const SIZE_AS_DEBUG_STR: &'static str = "4KiB"; -} - -impl NotGiantPageSize for Size4KiB {} - -impl PageSize for Size2MiB { - const SIZE: usize = Size4KiB::SIZE * 512; - const SIZE_AS_DEBUG_STR: &'static str = "2MiB"; -} - -impl NotGiantPageSize for Size2MiB {} - -impl PageSize for Size1GiB { - const SIZE: usize = Size2MiB::SIZE * 512; - const SIZE_AS_DEBUG_STR: &'static str = "1GiB"; -} - -/// A virtual memory page. -#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] -#[repr(C)] -pub struct Page { - start_address: VirtAddr, - size: PhantomData, -} - -impl Page { - /// The page size in bytes. - pub const SIZE: usize = S::SIZE; - - /// Returns the page that starts at the given virtual address. - /// - /// Returns an error if the address is not correctly aligned (i.e. is not a valid page start). - pub fn from_start_address(address: VirtAddr) -> Result { - if !address.is_aligned(S::SIZE) { - return Err(()); - } - Ok(Page::containing_address(address)) - } - - /// Returns the page that contains the given virtual address. - pub fn containing_address(address: VirtAddr) -> Self { - Page { - start_address: address.align_down(S::SIZE), - size: PhantomData, - } - } - - /// Returns the start address of the page. - pub fn start_address(&self) -> VirtAddr { - self.start_address - } - - /// Returns the size the page (4KB, 2MB or 1GB). - pub const fn size() -> usize { - S::SIZE - } - - /// Returns the level 4 page table index of this page. - pub fn p4_index(&self) -> u9 { - self.start_address().p4_index() - } - - /// Returns the level 3 page table index of this page. - pub fn p3_index(&self) -> u9 { - self.start_address().p3_index() - } - - /// Returns a range of pages, exclusive `end`. - pub fn range(start: Self, end: Self) -> PageRange { - PageRange { start, end } - } - - /// Returns a range of pages, inclusive `end`. - pub fn range_inclusive(start: Self, end: Self) -> PageRangeInclusive { - PageRangeInclusive { start, end } - } -} - -impl Page { - /// Returns the level 2 page table index of this page. - pub fn p2_index(&self) -> u9 { - self.start_address().p2_index() - } -} - -impl Page { - /// Returns the 1GiB memory page with the specified page table indices. - pub fn from_page_table_indices_1gib(p4_index: u9, p3_index: u9) -> Self { - use bit_field::BitField; - - let mut addr = 0; - addr.set_bits(39..48, u64::from(p4_index) as usize); - addr.set_bits(30..39, u64::from(p3_index) as usize); - Page::containing_address(VirtAddr::new(addr)) - } -} - -impl Page { - /// Returns the 2MiB memory page with the specified page table indices. - pub fn from_page_table_indices_2mib(p4_index: u9, p3_index: u9, p2_index: u9) -> Self { - use bit_field::BitField; - - let mut addr = 0; - addr.set_bits(39..48, u64::from(p4_index) as usize); - addr.set_bits(30..39, u64::from(p3_index) as usize); - addr.set_bits(21..30, u64::from(p2_index) as usize); - Page::containing_address(VirtAddr::new(addr)) - } -} - -impl Page { - /// Returns the 4KiB memory page with the specified page table indices. - pub fn from_page_table_indices(p4_index: u9, p3_index: u9, p2_index: u9, p1_index: u9) -> Self { - use bit_field::BitField; - - let mut addr = 0; - addr.set_bits(39..48, u64::from(p4_index) as usize); - addr.set_bits(30..39, u64::from(p3_index) as usize); - addr.set_bits(21..30, u64::from(p2_index) as usize); - addr.set_bits(12..21, u64::from(p1_index) as usize); - Page::containing_address(VirtAddr::new(addr)) - } - - /// Returns the level 1 page table index of this page. - pub fn p1_index(&self) -> u9 { - self.start_address().p1_index() - } -} - -impl fmt::Debug for Page { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.write_fmt(format_args!( - "Page[{}]({:#x})", - S::SIZE_AS_DEBUG_STR, - self.start_address().as_usize() - )) - } -} - -impl Add for Page { - type Output = Self; - fn add(self, rhs: usize) -> Self::Output { - Page::containing_address(self.start_address() + rhs * S::SIZE) - } -} - -impl AddAssign for Page { - fn add_assign(&mut self, rhs: usize) { - *self = self.clone() + rhs; - } -} - -impl Sub for Page { - type Output = Self; - fn sub(self, rhs: usize) -> Self::Output { - Page::containing_address(self.start_address() - rhs * S::SIZE) - } -} - -impl SubAssign for Page { - fn sub_assign(&mut self, rhs: usize) { - *self = self.clone() - rhs; - } -} - -impl Sub for Page { - type Output = usize; - fn sub(self, rhs: Self) -> Self::Output { - (self.start_address - rhs.start_address) / S::SIZE - } -} - -/// A range of pages with exclusive upper bound. -#[derive(Clone, Copy, PartialEq, Eq)] -#[repr(C)] -pub struct PageRange { - /// The start of the range, inclusive. - pub start: Page, - /// The end of the range, exclusive. - pub end: Page, -} - -impl PageRange { - /// Returns wether this range contains no pages. - pub fn is_empty(&self) -> bool { - !(self.start < self.end) - } -} - -impl Iterator for PageRange { - type Item = Page; - - fn next(&mut self) -> Option { - if self.start < self.end { - let page = self.start.clone(); - self.start += 1; - Some(page) - } else { - None - } - } -} - -impl PageRange { - /// Converts the range of 2MiB pages to a range of 4KiB pages. - pub fn as_4kib_page_range(self) -> PageRange { - PageRange { - start: Page::containing_address(self.start.start_address()), - end: Page::containing_address(self.end.start_address()), - } - } -} - -impl fmt::Debug for PageRange { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_struct("PageRange") - .field("start", &self.start) - .field("end", &self.end) - .finish() - } -} - -/// A range of pages with inclusive upper bound. -#[derive(Clone, Copy, PartialEq, Eq)] -#[repr(C)] -pub struct PageRangeInclusive { - /// The start of the range, inclusive. - pub start: Page, - /// The end of the range, inclusive. - pub end: Page, -} - -impl PageRangeInclusive { - /// Returns wether this range contains no pages. - pub fn is_empty(&self) -> bool { - !(self.start <= self.end) - } -} - -impl Iterator for PageRangeInclusive { - type Item = Page; - - fn next(&mut self) -> Option { - if self.start <= self.end { - let page = self.start.clone(); - self.start += 1; - Some(page) - } else { - None - } - } -} - -impl fmt::Debug for PageRangeInclusive { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_struct("PageRangeInclusive") - .field("start", &self.start) - .field("end", &self.end) - .finish() - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - pub fn test_page_ranges() { - let page_size = Size4KiB::SIZE; - let number = 1000; - - let start_addr = VirtAddr::new(0xdeadbeaf); - let start: Page = Page::containing_address(start_addr); - let end = start.clone() + number; - - let mut range = Page::range(start.clone(), end.clone()); - for i in 0..number { - assert_eq!( - range.next(), - Some(Page::containing_address(start_addr + page_size * i)) - ); - } - assert_eq!(range.next(), None); - - let mut range_inclusive = Page::range_inclusive(start, end); - for i in 0..=number { - assert_eq!( - range_inclusive.next(), - Some(Page::containing_address(start_addr + page_size * i)) - ); - } - assert_eq!(range_inclusive.next(), None); - } -} diff --git a/x86_64/src/structures/paging/page_table.rs b/x86_64/src/structures/paging/page_table.rs deleted file mode 100644 index 5044eb9..0000000 --- a/x86_64/src/structures/paging/page_table.rs +++ /dev/null @@ -1,236 +0,0 @@ -//! Abstractions for page tables and page table entries. - -use core::fmt; -use core::ops::{Index, IndexMut}; - -use super::{PageSize, PhysFrame, Size4KiB}; -use crate::addr::PhysAddr; - -use bitflags::bitflags; -use ux::*; - -/// The error returned by the `PageTableEntry::frame` method. -#[derive(Debug, Clone, Copy, PartialEq)] -pub enum FrameError { - /// The entry does not have the `PRESENT` flag set, so it isn't currently mapped to a frame. - FrameNotPresent, - /// The entry does have the `HUGE_PAGE` flag set. The `frame` method has a standard 4KiB frame - /// as return type, so a huge frame can't be returned. - HugeFrame, -} - -/// A 64-bit page table entry. -#[derive(Clone)] -#[repr(transparent)] -pub struct PageTableEntry { - entry: u64, -} - -impl PageTableEntry { - /// Creates an unused page table entry. - pub fn new() -> Self { - PageTableEntry { entry: 0 } - } - - /// Returns whether this entry is zero. - pub fn is_unused(&self) -> bool { - self.entry == 0 - } - - /// Sets this entry to zero. - pub fn set_unused(&mut self) { - self.entry = 0; - } - - /// Returns the flags of this entry. - pub fn flags(&self) -> PageTableFlags { - PageTableFlags::from_bits_truncate(self.entry) - } - - /// Returns the physical address mapped by this entry, might be zero. - pub fn addr(&self) -> PhysAddr { - PhysAddr::new(self.entry as usize & 0x000fffff_fffff000) - } - - /// Returns the physical frame mapped by this entry. - /// - /// Returns the following errors: - /// - /// - `FrameError::FrameNotPresent` if the entry doesn't have the `PRESENT` flag set. - /// - `FrameError::HugeFrame` if the entry has the `HUGE_PAGE` flag set (for huge pages the - /// `addr` function must be used) - pub fn frame(&self) -> Result { - if !self.flags().contains(PageTableFlags::PRESENT) { - Err(FrameError::FrameNotPresent) - } else if self.flags().contains(PageTableFlags::HUGE_PAGE) { - Err(FrameError::HugeFrame) - } else { - Ok(PhysFrame::containing_address(self.addr())) - } - } - - /// Map the entry to the specified physical address with the specified flags. - pub fn set_addr(&mut self, addr: PhysAddr, flags: PageTableFlags) { - assert!(addr.is_aligned(Size4KiB::SIZE)); - self.entry = addr.as_usize() as u64 | flags.bits(); - } - - /// Map the entry to the specified physical frame with the specified flags. - pub fn set_frame(&mut self, frame: PhysFrame, flags: PageTableFlags) { - assert!(!flags.contains(PageTableFlags::HUGE_PAGE)); - self.set_addr(frame.start_address(), flags) - } - - /// Sets the flags of this entry. - pub fn set_flags(&mut self, flags: PageTableFlags) { - self.entry = self.addr().as_usize() as u64 | flags.bits(); - } -} - -impl fmt::Debug for PageTableEntry { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let mut f = f.debug_struct("PageTableEntry"); - f.field("addr", &self.addr()); - f.field("flags", &self.flags()); - f.finish() - } -} - -bitflags! { - /// Possible flags for a page table entry. - pub struct PageTableFlags: u64 { - /// Specifies whether the mapped frame or page table is loaded in memory. - const PRESENT = 1 << 0; - /// Controls whether writes to the mapped frames are allowed. - /// - /// If this bit is unset in a level 1 page table entry, the mapped frame is read-only. - /// If this bit is unset in a higher level page table entry the complete range of mapped - /// pages is read-only. - const WRITABLE = 1 << 1; - /// Controls whether accesses from userspace (i.e. ring 3) are permitted. - const USER_ACCESSIBLE = 1 << 2; - /// If this bit is set, a “write-through” policy is used for the cache, else a “write-back” - /// policy is used. - const WRITE_THROUGH = 1 << 3; - /// Disables caching for the pointed entry is cacheable. - const NO_CACHE = 1 << 4; - /// Set by the CPU when the mapped frame or page table is accessed. - const ACCESSED = 1 << 5; - /// Set by the CPU on a write to the mapped frame. - const DIRTY = 1 << 6; - /// Specifies that the entry maps a huge frame instead of a page table. Only allowed in - /// P2 or P3 tables. - const HUGE_PAGE = 1 << 7; - /// Indicates that the mapping is present in all address spaces, so it isn't flushed from - /// the TLB on an address space switch. - const GLOBAL = 1 << 8; - /// Available to the OS, can be used to store additional data, e.g. custom flags. - const BIT_9 = 1 << 9; - /// Available to the OS, can be used to store additional data, e.g. custom flags. - const BIT_10 = 1 << 10; - /// Available to the OS, can be used to store additional data, e.g. custom flags. - const BIT_11 = 1 << 11; - /// Available to the OS, can be used to store additional data, e.g. custom flags. - const BIT_52 = 1 << 52; - /// Available to the OS, can be used to store additional data, e.g. custom flags. - const BIT_53 = 1 << 53; - /// Available to the OS, can be used to store additional data, e.g. custom flags. - const BIT_54 = 1 << 54; - /// Available to the OS, can be used to store additional data, e.g. custom flags. - const BIT_55 = 1 << 55; - /// Available to the OS, can be used to store additional data, e.g. custom flags. - const BIT_56 = 1 << 56; - /// Available to the OS, can be used to store additional data, e.g. custom flags. - const BIT_57 = 1 << 57; - /// Available to the OS, can be used to store additional data, e.g. custom flags. - const BIT_58 = 1 << 58; - /// Available to the OS, can be used to store additional data, e.g. custom flags. - const BIT_59 = 1 << 59; - /// Available to the OS, can be used to store additional data, e.g. custom flags. - const BIT_60 = 1 << 60; - /// Available to the OS, can be used to store additional data, e.g. custom flags. - const BIT_61 = 1 << 61; - /// Available to the OS, can be used to store additional data, e.g. custom flags. - const BIT_62 = 1 << 62; - /// Forbid code execution from the mapped frames. - /// - /// Can be only used when the no-execute page protection feature is enabled in the EFER - /// register. - const NO_EXECUTE = 1 << 63; - } -} - -/// The number of entries in a page table. -const ENTRY_COUNT: usize = 512; - -/// Represents a page table. -/// -/// Always page-sized. -/// -/// This struct implements the `Index` and `IndexMut` traits, so the entries can be accessed -/// through index operations. For example, `page_table[15]` returns the 15th page table entry. -#[repr(align(4096))] -#[repr(C)] -pub struct PageTable { - entries: [PageTableEntry; ENTRY_COUNT], -} - -impl PageTable { - /// Creates an empty page table. - pub fn new() -> Self { - PageTable { - entries: unsafe { core::mem::zeroed() }, - } - } - - /// Clears all entries. - pub fn zero(&mut self) { - for entry in self.entries.iter_mut() { - entry.set_unused(); - } - } - - /// Returns an iterator over the entries of the page table. - pub fn iter(&self) -> impl Iterator { - self.entries.iter() - } - - /// Returns an iterator that allows modifying the entries of the page table. - pub fn iter_mut(&mut self) -> impl Iterator { - self.entries.iter_mut() - } -} - -impl Index for PageTable { - type Output = PageTableEntry; - - fn index(&self, index: usize) -> &Self::Output { - &self.entries[index] - } -} - -impl IndexMut for PageTable { - fn index_mut(&mut self, index: usize) -> &mut Self::Output { - &mut self.entries[index] - } -} - -impl Index for PageTable { - type Output = PageTableEntry; - - fn index(&self, index: u9) -> &Self::Output { - &self.entries[cast::usize(u16::from(index))] - } -} - -impl IndexMut for PageTable { - fn index_mut(&mut self, index: u9) -> &mut Self::Output { - &mut self.entries[cast::usize(u16::from(index))] - } -} - -impl fmt::Debug for PageTable { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.entries[..].fmt(f) - } -} diff --git a/x86_64/src/structures/port.rs b/x86_64/src/structures/port.rs deleted file mode 100644 index 925b082..0000000 --- a/x86_64/src/structures/port.rs +++ /dev/null @@ -1,31 +0,0 @@ -//! Traits for accessing I/O ports. - -/// A helper trait that implements the read port operation. -/// -/// On x86, I/O ports operate on either `u8` (via `inb`/`outb`), `u16` (via `inw`/`outw`), -/// or `u32` (via `inl`/`outl`). Therefore this trait is implemented for exactly these types. -pub trait PortRead { - /// Reads a `Self` value from the given port. - /// - /// This function is unsafe because the I/O port could have side effects that violate memory - /// safety. - unsafe fn read_from_port(port: u16) -> Self; -} - -/// A helper trait that implements the write port operation. -/// -/// On x86, I/O ports operate on either `u8` (via `inb`/`outb`), `u16` (via `inw`/`outw`), -/// or `u32` (via `inl`/`outl`). Therefore this trait is implemented for exactly these types. -pub trait PortWrite { - /// Writes a `Self` value to the given port. - /// - /// This function is unsafe because the I/O port could have side effects that violate memory - /// safety. - unsafe fn write_to_port(port: u16, value: Self); -} - -/// A helper trait that implements the read/write port operations. -/// -/// On x86, I/O ports operate on either `u8` (via `inb`/`outb`), `u16` (via `inw`/`outw`), -/// or `u32` (via `inl`/`outl`). Therefore this trait is implemented for exactly these types. -pub trait PortReadWrite: PortRead + PortWrite {} diff --git a/x86_64/src/structures/tss.rs b/x86_64/src/structures/tss.rs deleted file mode 100644 index 28448d2..0000000 --- a/x86_64/src/structures/tss.rs +++ /dev/null @@ -1,38 +0,0 @@ -//! Provides a type for the task state segment structure. - -use crate::VirtAddr; - -/// In 64-bit mode the TSS holds information that is not -/// directly related to the task-switch mechanism, -/// but is used for finding kernel level stack -/// if interrupts arrive while in kernel mode. -#[derive(Debug, Clone, Copy)] -#[repr(C, packed)] -pub struct TaskStateSegment { - reserved_1: u32, - /// The full 64-bit canonical forms of the stack pointers (RSP) for privilege levels 0-2. - pub privilege_stack_table: [VirtAddr; 3], - reserved_2: u64, - /// The full 64-bit canonical forms of the interrupt stack table (IST) pointers. - pub interrupt_stack_table: [VirtAddr; 7], - reserved_3: u64, - reserved_4: u16, - /// The 16-bit offset to the I/O permission bit map from the 64-bit TSS base. - pub iomap_base: u16, -} - -impl TaskStateSegment { - /// Creates a new TSS with zeroed privilege and interrupt stack table and a zero - /// `iomap_base`. - pub const fn new() -> TaskStateSegment { - TaskStateSegment { - privilege_stack_table: [VirtAddr::zero(); 3], - interrupt_stack_table: [VirtAddr::zero(); 7], - iomap_base: 0, - reserved_1: 0, - reserved_2: 0, - reserved_3: 0, - reserved_4: 0, - } - } -} From 01f77c259fc251cc12a63b42e530fdcc991d1079 Mon Sep 17 00:00:00 2001 From: trashcognito Date: Thu, 1 Jul 2021 23:07:11 +0300 Subject: [PATCH 15/18] broke everything further --- Cargo.lock | 136 +++++++++++++++++++----------------------- Cargo.toml | 8 +-- acpi | 1 - bx_enh_dbg.ini | 26 ++++++++ scripts/bochs.sh | 2 +- scripts/gdb.sh | 2 +- scripts/symextract.sh | 2 + src/cpu/idt.rs | 40 ++++++------- src/drivers/acpi.rs | 122 +++++++++++++++++++++++-------------- src/kernel.rs | 11 ++-- src/mm/addr_space.rs | 10 ++-- src/mm/map.rs | 32 +++++----- src/mm/mod.rs | 8 +-- src/mm/pmm.rs | 26 ++++---- 14 files changed, 237 insertions(+), 189 deletions(-) delete mode 160000 acpi create mode 100644 bx_enh_dbg.ini create mode 100755 scripts/symextract.sh diff --git a/Cargo.lock b/Cargo.lock index ba08f33..276ec48 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,167 +1,155 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +version = 3 + [[package]] name = "acpi" -version = "0.4.0" +version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30deabfb5818ba33c3963a7d182c974afb42d94b21ee229b5d005f3ac742b0c7" dependencies = [ - "bit_field 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "typenum 1.11.2 (registry+https://github.com/rust-lang/crates.io-index)", + "bit_field 0.10.1", + "log", + "rsdp", ] [[package]] name = "aml" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7669e841017880c2710777c46ec654272163379bbe55de6e17a2a2388d44d92" dependencies = [ - "bit_field 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "bit_field 0.9.0", + "log", ] [[package]] name = "arrayvec" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cff77d8686867eceff3105329d4698d96c2391c176d5d03adc90c7389162b5b8" + +[[package]] +name = "autocfg" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" [[package]] name = "bit_field" version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed8765909f9009617974ab6b7d332625b320b33c326b1e9321382ef1999b5d56" [[package]] -name = "bitflags" -version = "1.2.1" +name = "bit_field" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcb6dd1c2376d2e096796e234a70e17e94cc2d5d54ff8ce42b28cef1d0d359a4" [[package]] -name = "bootloader" -version = "0.8.3" +name = "bitflags" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" [[package]] -name = "cast" -version = "0.2.3" +name = "bootloader" +version = "0.9.18" source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", -] +checksum = "7a3c1ceed1cd9e61c7998100cc18c13d413aa40d018992b871ab8e7435ce6372" [[package]] name = "cfg-if" version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" [[package]] name = "intrusive-collections" -version = "0.8.3" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c1d0072a5e5c56adba35b9001f029ccc46f0e9ad0c7bcecd9b2f33b37123bca" dependencies = [ - "memoffset 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", + "memoffset", ] [[package]] name = "lazy_static" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" dependencies = [ - "spin 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", + "spin", ] [[package]] name = "log" version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" dependencies = [ - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if", ] [[package]] name = "memoffset" -version = "0.5.3" +version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "043175f069eda7b85febe4a74abbaeff828d9f8b448515d3151a14a3542811aa" dependencies = [ - "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg", ] [[package]] -name = "rustc_version" -version = "0.2.3" +name = "rsdp" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66d3add2fc55ef37511bcf81a08ee7a09eff07b23aae38b06a29024a38c604b1" dependencies = [ - "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", + "log", ] -[[package]] -name = "semver" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "semver-parser" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "solstice" version = "0.1.0" dependencies = [ - "acpi 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "aml 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "arrayvec 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "bootloader 0.8.3 (registry+https://github.com/rust-lang/crates.io-index)", - "intrusive-collections 0.8.3 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "volatile 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", - "x86_64 0.8.3 (registry+https://github.com/rust-lang/crates.io-index)", + "acpi", + "aml", + "arrayvec", + "bootloader", + "intrusive-collections", + "lazy_static", + "log", + "volatile 0.2.6", + "x86_64", ] [[package]] name = "spin" version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" [[package]] -name = "typenum" -version = "1.11.2" +name = "volatile" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6af0edf5b4faacc31fc51159244d78d65ec580f021afcef7bd53c04aeabc7f29" [[package]] name = "volatile" -version = "0.2.6" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4c2dbd44eb8b53973357e6e207e370f0c1059990df850aca1eca8947cf464f0" [[package]] name = "x86_64" -version = "0.8.3" +version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7c54a17492391c594753ce2a180142bec7ad2876543565c2a08aa11cddef251" dependencies = [ - "bit_field 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "cast 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "bit_field 0.9.0", + "bitflags", + "volatile 0.4.4", ] - -[metadata] -"checksum acpi 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2c18d706bdc322dd4f8f7930a5879ad8df3d78d4452a678d5419c72f9f69acea" -"checksum aml 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b7669e841017880c2710777c46ec654272163379bbe55de6e17a2a2388d44d92" -"checksum arrayvec 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cff77d8686867eceff3105329d4698d96c2391c176d5d03adc90c7389162b5b8" -"checksum bit_field 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ed8765909f9009617974ab6b7d332625b320b33c326b1e9321382ef1999b5d56" -"checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" -"checksum bootloader 0.8.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d596849a47f28abdea62d7a6a25c4f6e69c3d9b09b0a2877db6e9cda004ca993" -"checksum cast 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "4b9434b9a5aa1450faa3f9cb14ea0e8c53bb5d2b3c1bfd1ab4fc03e9f33fbfb0" -"checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" -"checksum intrusive-collections 0.8.3 (registry+https://github.com/rust-lang/crates.io-index)" = "163ff4f05115a819d7d8dab45661a2a38d7dde7ee93690a0b84cc819b78ba8c4" -"checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" -"checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" -"checksum memoffset 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "75189eb85871ea5c2e2c15abbdd541185f63b408415e5051f5cac122d8c774b9" -"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" -"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" -"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" -"checksum spin 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" -"checksum typenum 1.11.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6d2783fe2d6b8c1101136184eb41be8b1ad379e4657050b8aaff0c79ee7575f9" -"checksum volatile 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "6af0edf5b4faacc31fc51159244d78d65ec580f021afcef7bd53c04aeabc7f29" -"checksum x86_64 0.8.3 (registry+https://github.com/rust-lang/crates.io-index)" = "5d9e3e26fcb51976eafa310e8f2b7a5a83ae8c185443efe50cbc6534a4fffa0d" diff --git a/Cargo.toml b/Cargo.toml index d5e788e..02bdc8f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -31,14 +31,14 @@ lto = true panic = "abort" [dependencies] -x86_64 = "0.8.3" -bootloader = { version = "0.8.3", features = ["map_physical_memory"] } +x86_64 = {version = "0.14.3", features = ["nightly"]} +bootloader = { version = "0.9.0", features = ["map_physical_memory"] } log = "0.4.8" volatile = "0.2.6" lazy_static = { version = "1.4.0", features = ["spin_no_std"] } -intrusive-collections = { version = "0.8.3", features = ["nightly"] } +intrusive-collections = { version = "0.9.1", features = ["nightly"] } arrayvec = { version = "0.5.1", default-features = false } -acpi = "0.4.0" +acpi = "3.0.0" aml = "0.4.0" #acpi = { path = "../acpi/acpi/" } #aml = { path = "../acpi/aml/" } diff --git a/acpi b/acpi deleted file mode 160000 index 5bf81d6..0000000 --- a/acpi +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 5bf81d63074ff0667cb4d64c53fc554bb186848b diff --git a/bx_enh_dbg.ini b/bx_enh_dbg.ini new file mode 100644 index 0000000..2bc6660 --- /dev/null +++ b/bx_enh_dbg.ini @@ -0,0 +1,26 @@ +# bx_enh_dbg_ini +SeeReg[0] = TRUE +SeeReg[1] = TRUE +SeeReg[2] = TRUE +SeeReg[3] = TRUE +SeeReg[4] = FALSE +SeeReg[5] = FALSE +SeeReg[6] = FALSE +SeeReg[7] = FALSE +SingleCPU = FALSE +ShowIOWindows = TRUE +ShowButtons = TRUE +SeeRegColors = TRUE +ignoreNxtT = TRUE +ignSSDisasm = TRUE +UprCase = 0 +DumpInAsciiMode = 3 +isLittleEndian = TRUE +DefaultAsmLines = 512 +DumpWSIndex = 0 +DockOrder = 0x123 +ListWidthPix[0] = 484 +ListWidthPix[1] = 671 +ListWidthPix[2] = 765 +MainWindow = 0, 0, 1295, 370 +FontName = Normal diff --git a/scripts/bochs.sh b/scripts/bochs.sh index c16bc81..d558a38 100755 --- a/scripts/bochs.sh +++ b/scripts/bochs.sh @@ -1,6 +1,6 @@ #!/bin/sh set -e -bootimage build +cargo xbuild dd if=/dev/zero of=/tmp/solstice.img count=1008 bs=512 dd if=target/x86_64-solstice/debug/bootimage-solstice.bin of=/tmp/solstice.img conv=notrunc bochs -f scripts/.bochsrc -q diff --git a/scripts/gdb.sh b/scripts/gdb.sh index 86e096d..9786b15 100755 --- a/scripts/gdb.sh +++ b/scripts/gdb.sh @@ -1,6 +1,6 @@ #!/bin/sh set -me -bootimage build +cargo xbuild qemu-system-x86_64 -drive format=raw,file=../target/x86_64-solstice/debug/bootimage-solstice.bin -machine q35 -no-reboot -S -s & sleep 0.5 gdb ../target/x86_64-solstice/debug/solstice -ex "target remote :1234" \ No newline at end of file diff --git a/scripts/symextract.sh b/scripts/symextract.sh new file mode 100755 index 0000000..80e365e --- /dev/null +++ b/scripts/symextract.sh @@ -0,0 +1,2 @@ +#!/bin/sh +nm $1 | grep " T " | awk '{ print $1" "$3 }' > $1.sym \ No newline at end of file diff --git a/src/cpu/idt.rs b/src/cpu/idt.rs index ead4cb9..0745afb 100644 --- a/src/cpu/idt.rs +++ b/src/cpu/idt.rs @@ -40,82 +40,82 @@ test_case!(int3_handler, { x86_64::instructions::interrupts::int3(); }); -extern "x86-interrupt" fn divide_error_handler(frame: &mut idt::InterruptStackFrame) { +extern "x86-interrupt" fn divide_error_handler(frame: idt::InterruptStackFrame) { panic!("EXCEPTION: Zero Division\n{:#?}", frame); } -extern "x86-interrupt" fn debug_handler(frame: &mut idt::InterruptStackFrame) { +extern "x86-interrupt" fn debug_handler(frame: idt::InterruptStackFrame) { panic!("EXCEPTION: Debug\n{:#?}", frame); } -extern "x86-interrupt" fn non_maskable_interrupt_handler(frame: &mut idt::InterruptStackFrame) { +extern "x86-interrupt" fn non_maskable_interrupt_handler(frame: idt::InterruptStackFrame) { panic!("EXCEPTION: Non-Maskable Interrupt\n{:#?}", frame); } -extern "x86-interrupt" fn breakpoint_handler(frame: &mut idt::InterruptStackFrame) { +extern "x86-interrupt" fn breakpoint_handler(frame: idt::InterruptStackFrame) { trace!("EXCEPTION: Breakpoint\n{:#?}", frame); } -extern "x86-interrupt" fn overflow_handler(frame: &mut idt::InterruptStackFrame) { +extern "x86-interrupt" fn overflow_handler(frame: idt::InterruptStackFrame) { panic!("EXCEPTION: Overflow\n{:#?}", frame); } -extern "x86-interrupt" fn bound_range_exceeded_handler(frame: &mut idt::InterruptStackFrame) { +extern "x86-interrupt" fn bound_range_exceeded_handler(frame: idt::InterruptStackFrame) { panic!("EXCEPTION: Bound Range Exceeded\n{:#?}", frame); } -extern "x86-interrupt" fn invalid_opcode_handler(frame: &mut idt::InterruptStackFrame) { +extern "x86-interrupt" fn invalid_opcode_handler(frame: idt::InterruptStackFrame) { panic!("EXCEPTION: Invalid Opcode\n{:#?}", frame); } -extern "x86-interrupt" fn device_not_available_handler(frame: &mut idt::InterruptStackFrame) { +extern "x86-interrupt" fn device_not_available_handler(frame: idt::InterruptStackFrame) { panic!("EXCEPTION: Device Not Available\n{:#?}", frame); } -extern "x86-interrupt" fn double_fault_handler(frame: &mut idt::InterruptStackFrame, error_code: u64) -> ! { +extern "x86-interrupt" fn double_fault_handler(frame: idt::InterruptStackFrame, error_code: u64) -> ! { panic!("EXCEPTION: Double Fault with error code {}\n{:#?}", error_code, frame); } -extern "x86-interrupt" fn invalid_tss_handler(frame: &mut idt::InterruptStackFrame, error_code: u64) { +extern "x86-interrupt" fn invalid_tss_handler(frame: idt::InterruptStackFrame, error_code: u64) { panic!("EXCEPTION: Invalid TSS with error code {}\n{:#?}", error_code, frame); } -extern "x86-interrupt" fn segment_not_present_handler(frame: &mut idt::InterruptStackFrame, error_code: u64) { +extern "x86-interrupt" fn segment_not_present_handler(frame: idt::InterruptStackFrame, error_code: u64) { panic!("EXCEPTION: Segment Not Present with error code {}\n{:#?}", error_code, frame); } -extern "x86-interrupt" fn stack_segment_fault_handler(frame: &mut idt::InterruptStackFrame, error_code: u64) { +extern "x86-interrupt" fn stack_segment_fault_handler(frame: idt::InterruptStackFrame, error_code: u64) { panic!("EXCEPTION: Stack Segment Fault with error code {}\n{:#?}", error_code, frame); } -extern "x86-interrupt" fn general_protection_fault_handler(frame: &mut idt::InterruptStackFrame, error_code: u64) { +extern "x86-interrupt" fn general_protection_fault_handler(frame: idt::InterruptStackFrame, error_code: u64) { panic!("EXCEPTION: General Protection Fault with error code {}\n{:#?}", error_code, frame); } -extern "x86-interrupt" fn page_fault_handler(frame: &mut idt::InterruptStackFrame, error_code: idt::PageFaultErrorCode) { +extern "x86-interrupt" fn page_fault_handler(frame: idt::InterruptStackFrame, error_code: idt::PageFaultErrorCode) { panic!("EXCEPTION: Page Fault with error code {:#?}\nAddress {:?}\n{:#?}", error_code, Cr2::read(), frame); } -extern "x86-interrupt" fn x87_floating_point_handler(frame: &mut idt::InterruptStackFrame) { +extern "x86-interrupt" fn x87_floating_point_handler(frame: idt::InterruptStackFrame) { panic!("EXCEPTION: x87 Floating Point\n{:#?}", frame); } -extern "x86-interrupt" fn alignment_check_handler(frame: &mut idt::InterruptStackFrame, error_code: u64) { +extern "x86-interrupt" fn alignment_check_handler(frame: idt::InterruptStackFrame, error_code: u64) { panic!("EXCEPTION: Alignment Check with error code {}\n{:#?}", error_code, frame); } -extern "x86-interrupt" fn machine_check_handler(frame: &mut idt::InterruptStackFrame) -> ! { +extern "x86-interrupt" fn machine_check_handler(frame: idt::InterruptStackFrame) -> ! { panic!("EXCEPTION: Machine Check\n{:#?}", frame); } -extern "x86-interrupt" fn simd_floating_point_handler(frame: &mut idt::InterruptStackFrame) { +extern "x86-interrupt" fn simd_floating_point_handler(frame: idt::InterruptStackFrame) { panic!("EXCEPTION: SIMD Floating Point\n{:#?}", frame); } -extern "x86-interrupt" fn virtualization_handler(frame: &mut idt::InterruptStackFrame) { +extern "x86-interrupt" fn virtualization_handler(frame: idt::InterruptStackFrame) { panic!("EXCEPTION: Virtualization\n{:#?}", frame); } -extern "x86-interrupt" fn security_exception_handler(frame: &mut idt::InterruptStackFrame, error_code: u64, ) { +extern "x86-interrupt" fn security_exception_handler(frame: idt::InterruptStackFrame, error_code: u64, ) { panic!("EXCEPTION: Security Exception with error code {}\n{:#?}", error_code, frame); } diff --git a/src/drivers/acpi.rs b/src/drivers/acpi.rs index 0f3aaf2..ab14f45 100644 --- a/src/drivers/acpi.rs +++ b/src/drivers/acpi.rs @@ -3,10 +3,14 @@ use aml::{AmlContext, AmlError, AmlValue}; use core::ptr::NonNull; use x86_64::{PhysAddr, VirtAddr, instructions::port::{PortRead,PortWrite}}; use lazy_static::__Deref; +use acpi::{AcpiTables, AcpiError, InterruptModel}; +use acpi::sdt::Signature; +use acpi::platform::address::GenericAddress; +use acpi::platform::ProcessorInfo; static mut SLP_TYPA:u64 = 0; -pub fn init() -> ::acpi::Acpi { - let our_acpi = unsafe {acpi::search_for_rsdp_bios(&mut Acpi).expect("ACPI table parsing failed")}; +pub fn init() -> AcpiObject { + let our_acpi = unsafe {acpi::AcpiTables::search_for_rsdp_bios(Acpi)}.expect("ACPI table parsing failed"); debug!("acpi: found tables"); let mut ctx = AmlContext::new(); @@ -47,28 +51,28 @@ pub fn init() -> ::acpi::Acpi { unreachable!(); } } - return our_acpi; + return AcpiObject::new(our_acpi); } -pub fn enable(acpi: &mut ::acpi::Acpi) { - - let fadt = acpi.fadt - .unwrap() - .as_ptr() - .clone(); - let fadt = unsafe {fadt.read()}; - let mut readval:u16 = unsafe { PortRead::read_from_port(fadt.pm1a_control_block as u16) }; +pub fn enable(acpi: &mut AcpiObject) { + let pm1a_control_block = unsafe {*(acpi.fadt.pm1a_control_block() + .expect("Could not get pm1a_control_block of ACPI!") + .address as *const u16)}; + let mut readval:u16 = unsafe { PortRead::read_from_port(pm1a_control_block) }; if readval & 1 == 0 { - if fadt.smi_cmd_port != 0 && fadt.acpi_enable != 0 { - unsafe { PortWrite::write_to_port(fadt.smi_cmd_port as u16, fadt.acpi_enable); } - readval = unsafe { PortRead::read_from_port(fadt.pm1a_control_block as u16) }; + if acpi.fadt.smi_cmd_port != 0 && acpi.fadt.acpi_enable != 0 { + unsafe { PortWrite::write_to_port(acpi.fadt.smi_cmd_port as u16, acpi.fadt.acpi_enable); } + readval = unsafe { PortRead::read_from_port(pm1a_control_block) }; while readval & 1 == 0 { - readval = unsafe { PortRead::read_from_port(fadt.pm1a_control_block as u16) }; + readval = unsafe { PortRead::read_from_port(pm1a_control_block) }; } - - if fadt.pm1b_control_block != 0 { - readval = unsafe { PortRead::read_from_port(fadt.pm1b_control_block as u16) }; - while readval & 1 == 0 { - readval = unsafe { PortRead::read_from_port(fadt.pm1b_control_block as u16) }; + match acpi.fadt.pm1b_control_block().expect("Could not get pm1b_control_block") { + None => {} + Some(pm1b_control_block_addr) => { + let pm1b_control_block = unsafe {*(pm1b_control_block_addr.address as *const u16)}; + readval = unsafe { PortRead::read_from_port(pm1b_control_block as u16) }; + while readval & 1 == 0 { + readval = unsafe { PortRead::read_from_port(pm1b_control_block as u16) }; + } } } return; @@ -80,43 +84,73 @@ pub fn enable(acpi: &mut ::acpi::Acpi) { } } -pub fn shutdown(acpi: &mut ::acpi::Acpi) { - let fadt = acpi.fadt - .unwrap() - .as_ptr() - .clone(); - let fadt = unsafe {fadt.read()}; +pub fn shutdown(acpi: &mut AcpiObject) { + let pm1a_control_block = unsafe {*(acpi.fadt.pm1a_control_block() + .expect("Could not get pm1a_control_block of ACPI!") + .address as *const u16)}; loop { - unsafe { PortWrite::write_to_port(fadt.pm1a_control_block as u16, (SLP_TYPA | (1 << 13)) as u16); } - if fadt.pm1b_control_block != 0 { - unsafe { PortWrite::write_to_port(fadt.pm1b_control_block as u16, (SLP_TYPA | (1 << 13)) as u16); } + unsafe { PortWrite::write_to_port(pm1a_control_block as u16, (SLP_TYPA | (1 << 13)) as u16); } + match acpi.fadt.pm1b_control_block().expect("Could not get pm1b_control_block") { + None => {} + Some(pm1b_control_block_addr) => { + let pm1b_control_block = unsafe {*(pm1b_control_block_addr.address as *const u16)}; + unsafe { PortWrite::write_to_port(pm1b_control_block as u16, (SLP_TYPA | (1 << 13)) as u16); } + } } //wait till dead } } fn parse_table(ctx: &mut AmlContext, table: &AmlTable) -> Result<(), AmlError> { - let virt = VirtAddr::from(PhysAddr::new(table.address)); - + let virt = VirtAddr::new(table.address as u64); ctx.parse_table(unsafe { core::slice::from_raw_parts(virt.as_ptr(), table.length as usize) }) } -struct Acpi; - +pub struct Acpi; +impl Clone for Acpi { + fn clone(&self) -> Self { + Acpi + } +} impl AcpiHandler for Acpi { - fn map_physical_region( - &mut self, + unsafe fn map_physical_region( + &self, physical_address: usize, size: usize, - ) -> PhysicalMapping { - let start_virt = VirtAddr::from(PhysAddr::new(physical_address)); + ) -> PhysicalMapping { + let start_virt = VirtAddr::new(physical_address as u64); + PhysicalMapping::new(physical_address, NonNull::new(start_virt.as_mut_ptr()).expect("acpi mapped null ptr"), size, size, Acpi) - PhysicalMapping { - physical_start: physical_address, - virtual_start: NonNull::new(start_virt.as_mut_ptr()).expect("acpi mapped null ptr"), - region_length: size, - mapped_length: size, - } } - fn unmap_physical_region(&mut self, _region: PhysicalMapping) {} + fn unmap_physical_region(_region: &PhysicalMapping) {} +} +pub struct AcpiObject { + pub tables: AcpiTables, + pub fadt: PhysicalMapping, + pub madt: PhysicalMapping, + pub interrupt_model: InterruptModel, + pub processor_info: Option +} +impl AcpiObject { + pub fn new(acpi_tables: AcpiTables) -> Self { + let madt = unsafe { acpi_tables.get_sdt::(Signature::MADT) } + .expect("Could not get MADT") + .expect("Could not get physical mapping"); + let fadt = unsafe { acpi_tables.get_sdt::(Signature::FADT) } + .expect("Could not get FADT") + .expect("Could not get physical mapping"); + let madt_result = madt.parse_interrupt_model() + .expect("Could not get interrupt model"); + AcpiObject { + tables: acpi_tables, + fadt, + madt, + interrupt_model: madt_result.0, + processor_info: madt_result.1 + } + } } +pub fn apic_supported() -> bool { + let cpuid = unsafe {core::arch::x86_64::__cpuid(0x1)}; + (cpuid.edx & (1 << 9)) != 0 +} \ No newline at end of file diff --git a/src/kernel.rs b/src/kernel.rs index eeff5c0..a6b7e0b 100644 --- a/src/kernel.rs +++ b/src/kernel.rs @@ -4,9 +4,7 @@ use crate::{ mm::{map::MemoryMap, pmm::PhysAllocator}, }; use acpi::InterruptModel; -use apic::{LocalApic, XApic}; use bootloader::bootinfo::BootInfo; - pub fn kernel_main(info: &BootInfo) { drivers::serial::init(); drivers::vga::text_mode::init().unwrap(); @@ -30,16 +28,15 @@ pub fn kernel_main(info: &BootInfo) { PhysAllocator::init(map); let acpi = drivers::acpi::init(); - match acpi.interrupt_model { - None => panic!("unknown interrupt model"), - Some(InterruptModel::Pic { .. }) => panic!("unsupported acpi interrupt model"), - Some(InterruptModel::Apic { .. }) => { - if !XApic::is_supported() { + InterruptModel::Unknown { .. } => panic!("unsupported acpi interrupt model"), + InterruptModel::Apic { .. } => { + if !drivers::acpi::apic_supported() { error!("apic: xapic is not supported"); } else { info!("apic: detected xapic support"); } } + _ => {panic!("unknown acpi interrupt model")} }; } diff --git a/src/mm/addr_space.rs b/src/mm/addr_space.rs index c40c13b..a8aba8c 100644 --- a/src/mm/addr_space.rs +++ b/src/mm/addr_space.rs @@ -2,7 +2,6 @@ use crate::{ds::RwSpinLock, mm::pmm::PhysAllocator}; use x86_64::{ registers::control::Cr3, structures::paging::{ - UnusedPhysFrame, mapper::{MapToError, MapperAllSizes, MapperFlush}, page::Size4KiB, FrameAllocator, @@ -14,6 +13,7 @@ use x86_64::{ PhysAddr, VirtAddr, }; +use x86_64::structures::paging::{Translate, PhysFrame}; pub struct AddrSpace { table: RwSpinLock>, @@ -45,10 +45,10 @@ impl AddrSpace { virt: VirtAddr, phys: PhysAddr, flags: PageTableFlags, - ) -> Result, MapToError> { + ) -> Result, MapToError> { struct PhysAllocatorProxy; unsafe impl FrameAllocator for PhysAllocatorProxy { - fn allocate_frame(&mut self) -> Option> { + fn allocate_frame(&mut self) -> Option> { Some(PhysAllocator::alloc(0).start) } } @@ -64,11 +64,11 @@ impl AddrSpace { phys: PhysAddr, flags: PageTableFlags, alloc: &mut A, - ) -> Result, MapToError> { + ) -> Result, MapToError> { unsafe { self.table.write().map_to( Page::containing_address(virt), - UnusedPhysFrame::containing_address(phys), + PhysFrame::containing_address(phys), flags, alloc, ) diff --git a/src/mm/map.rs b/src/mm/map.rs index 9df0e5f..d23afa6 100644 --- a/src/mm/map.rs +++ b/src/mm/map.rs @@ -7,7 +7,7 @@ use core::{ ptr::{self, NonNull}, }; use x86_64::{ - structures::paging::{FrameAllocator, PageSize, PageTableFlags, UnusedPhysFrame, PhysFrame, Size4KiB}, + structures::paging::{FrameAllocator, PageSize, PageTableFlags, PhysFrame, Size4KiB}, PhysAddr, VirtAddr, }; @@ -27,7 +27,7 @@ impl Region { size: offset, }, Region { - addr: PhysAddr::new(self.addr.as_usize() + offset), + addr: PhysAddr::new(self.addr.as_u64() + offset as u64), size: self.size - offset, }, ) @@ -57,7 +57,7 @@ impl MemoryMap { { bump.push(Region { addr: PhysAddr::new(reg.range.start_addr()), - size: reg.range.end_addr() - reg.range.start_addr(), + size: (reg.range.end_addr() - reg.range.start_addr()) as usize, }); } } @@ -101,24 +101,24 @@ impl MemoryMap { } fn push(&mut self, rg: Region) { - self.num_pages += rg.size / Size4KiB::SIZE; + self.num_pages += rg.size / Size4KiB::SIZE as usize; self.regions.push(rg); } } unsafe impl FrameAllocator for MemoryMap { - fn allocate_frame(&mut self) -> Option { + fn allocate_frame(&mut self) -> Option { let (idx, found_region) = self .regions .iter_mut() .enumerate() - .find(|(_, rg)| rg.size >= Size4KiB::SIZE) + .find(|(_, rg)| rg.size >= Size4KiB::SIZE as usize) .expect("bump allocator - out of memory"); let out = PhysFrame::containing_address(found_region.addr); - found_region.addr += Size4KiB::SIZE; - found_region.size -= Size4KiB::SIZE; + found_region.addr += Size4KiB::SIZE as usize; + found_region.size -= Size4KiB::SIZE as usize; self.num_pages -= 1; if found_region.size == 0 { @@ -129,15 +129,15 @@ unsafe impl FrameAllocator for MemoryMap { // Clear the page #[cfg(not(test))] unsafe { - let page: *mut u8 = VirtAddr::from(out.start_address()).as_mut_ptr(); + let page: *mut u8 = out.start_address().as_u64() as *mut u8; core::intrinsics::write_bytes( page, if cfg!(debug_assertions) { 0xB8 } else { 0x00 }, - Size4KiB::SIZE, + Size4KiB::SIZE as usize, ) }; - unsafe { Some(UnusedPhysFrame::new(out)) } + unsafe { Some(PhysFrame::from(out)) } } } @@ -173,21 +173,21 @@ pub struct RegionBumpAllocator { impl RegionBumpAllocator { pub fn alloc(&mut self, layout: Layout) -> Option> { - let new_off = x86_64::align_up(self.offset + layout.size(), layout.align()); + let new_off = x86_64::align_up((self.offset + layout.size()) as u64, layout.align() as u64); - if new_off > self.size { + if new_off > self.size as u64 { None } else { let out = NonNull::new( VirtAddr::new( - self.start.as_usize() - + x86_64::align_up(self.offset, layout.align()) + self.start.as_u64() + + x86_64::align_up(self.offset as u64, layout.align() as u64) + super::PHYS_OFFSET, ) .as_mut_ptr(), ) .unwrap(); - self.offset = new_off; + self.offset = new_off as usize; Some(out) } } diff --git a/src/mm/mod.rs b/src/mm/mod.rs index 6a1ff1c..59d5002 100644 --- a/src/mm/mod.rs +++ b/src/mm/mod.rs @@ -17,8 +17,8 @@ pub struct PageInfo { } pub fn phys_to_page_info(frame: PhysFrame) -> *const PageInfo { - let idx = frame.start_address().as_usize() / PAGE_SIZE; - let out_addr = PAGE_INFO_OFFSET + idx * core::mem::size_of::>(); + let idx = frame.start_address().as_u64() / PAGE_SIZE; + let out_addr = PAGE_INFO_OFFSET + idx * (core::mem::size_of::>()) as u64; // Check that it's not too large debug_assert!(out_addr < PAGE_INFO_OFFSET + 0x0000100000000000); @@ -27,8 +27,8 @@ pub fn phys_to_page_info(frame: PhysFrame) -> *const PageInfo { } pub fn kernel_virt_to_phys(virt: VirtAddr) -> PhysAddr { - debug_assert!(virt.start_address() >= PHYS_OFFSET); - PhysAddr::new(virt.start_address() - PHYS_OFFSET); + debug_assert!(virt.as_u64() >= PHYS_OFFSET); + PhysAddr::new(virt.as_u64() - PHYS_OFFSET) } pub fn phys_to_kernel_virt(phys: PhysAddr) -> VirtAddr { diff --git a/src/mm/pmm.rs b/src/mm/pmm.rs index 4a59344..3bfc46c 100644 --- a/src/mm/pmm.rs +++ b/src/mm/pmm.rs @@ -32,7 +32,7 @@ impl Zone { let mut blocks_in_order = num_pages; for (order, list) in order_list.iter_mut().enumerate() { - for block in list.iter_mut().take(blocks_in_order) { + for block in list.iter_mut().take(blocks_in_order as usize) { *block = Block::from_order(order as u8); } @@ -40,7 +40,7 @@ impl Zone { } let largest_order = - (num_pages.next_power_of_two().trailing_zeros() as usize).min(MAX_ORDER + 1); + (num_pages.next_power_of_two().trailing_zeros() as usize).min((MAX_ORDER + 1) as usize); for list in order_list[largest_order..].iter_mut() { list[0] = Block::from_order(largest_order as u8); } @@ -62,7 +62,7 @@ impl Zone { let max_order_blocks = x86_64::align_up(num_pages, MAX_ORDER_PAGES) / MAX_ORDER_PAGES; // TODO: This whole section is a bit of a hack - let mut tmp: [Option<&'static mut [Block]>; MAX_ORDER + 1] = [ + let mut tmp: [Option<&'static mut [Block]>; (MAX_ORDER + 1) as usize] = [ None, None, None, None, None, None, None, None, None, None, None, None, ]; @@ -79,7 +79,7 @@ impl Zone { // Iterate back up, setting parents to have the correct largest order value fn update_tree(&mut self, start_order: u8, mut idx: u64) { for current_order in start_order + 1..=MAX_ORDER as u8 { - let left_idx = idx & !1; + let left_idx = (idx & !1) as usize; let left = self.order_list[current_order as usize - 1][left_idx]; let right = self.order_list[current_order as usize - 1][left_idx + 1]; self.order_list[current_order as usize][idx as usize / 2] = Block::parent_state(left, right); @@ -109,10 +109,10 @@ impl Zone { } self.order_list[order as usize][idx as usize] = Block::Used; - self.update_tree(order, idx); + self.update_tree(order, idx as u64); - let start_frame = self.pages.start + 2u64.pow(order as u32) * idx; - let end_frame = self.pages.start + 2u64.pow(order as u32) * (idx + 1); + let start_frame = self.pages.start + 2u64.pow(order as u32) * idx as u64; + let end_frame = self.pages.start + 2u64.pow(order as u32) * (idx + 1) as u64; // Zero out region unsafe { @@ -128,11 +128,13 @@ impl Zone { } fn free(&mut self, range: PhysFrameRange) { - let order = range.len().trailing_zeros(); - debug_assert!(order <= MAX_ORDER); - debug_assert!(self.pages.contains_range(range)); + let len = range.end.start_address() - range.start.start_address(); + let order = len.trailing_zeros(); + debug_assert!(order <= MAX_ORDER as u32); + debug_assert!(self.pages.start.start_address() <= range.start.start_address()); + debug_assert!(self.pages.end.start_address() >= range.end.start_address()); - let idx = (range.start - self.pages.start) / range.len(); + let idx = (range.start - self.pages.start) / len; debug_assert_eq!(self.order_list[order as usize][idx as usize], Block::Used); self.order_list[order as usize][idx as usize] = Block::from_order(order as u8); @@ -281,7 +283,7 @@ impl PhysAllocator { pub fn free(range: PhysFrameRange) { for zone in PMM.zones.read().as_ref().unwrap() { let mut zone = zone.lock(); - if zone.pages.contains_range(range) { + if zone.pages.start.start_address() <= range.start.start_address() && zone.pages.end.start_address() >= range.end.start_address() { zone.free(range); return; } From 9d5b30ecd35c8fe357676e957ddde93e999b8f60 Mon Sep 17 00:00:00 2001 From: trashcognito Date: Fri, 2 Jul 2021 01:05:00 +0300 Subject: [PATCH 16/18] somehow fixed println, now debug is broken probably shouldnt be using macros anyway --- src/kernel.rs | 1 - src/macros.rs | 28 +++++++++++++++++----------- src/main.rs | 1 - src/testing.rs | 1 - 4 files changed, 17 insertions(+), 14 deletions(-) diff --git a/src/kernel.rs b/src/kernel.rs index a6b7e0b..66570f7 100644 --- a/src/kernel.rs +++ b/src/kernel.rs @@ -8,7 +8,6 @@ use bootloader::bootinfo::BootInfo; pub fn kernel_main(info: &BootInfo) { drivers::serial::init(); drivers::vga::text_mode::init().unwrap(); - #[rustfmt::skip] { println!(" _____ _ _ _ Developed by:"); diff --git a/src/macros.rs b/src/macros.rs index 7ce9763..9efff9a 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -11,6 +11,7 @@ pub struct ScreenLocker(SpinLock); pub struct ScreenWriter(Writer); impl fmt::Write for ScreenWriter { + fn write_str(&mut self, s: &str) -> fmt::Result { #[cfg(any(debug_assertions, test))] { @@ -28,28 +29,30 @@ lazy_static! { pub static ref SCREEN: ScreenLocker = ScreenLocker(SpinLock::new(ScreenWriter(Writer::default()))); } - +// TODO: only debug is broke now +#[macro_export] macro_rules! print { ($($arg:tt)*) => ($crate::macros::_print(format_args!($($arg)*))); } - +#[macro_export] macro_rules! println { - () => (print!("\n")); - ($($arg:tt)*) => (print!("{}\n", format_args!($($arg)*))); + () => ($crate::print!("\n")); + ($fmt:expr) => ($crate::print!(concat!($fmt, "\n"))); + ($fmt:expr, $($arg:tt)*) => ($crate::print!(concat!($fmt, "\n"), $($arg)*)); } - // Lifted from standard library #[allow(unused_macros)] +#[macro_export] macro_rules! dbg { () => { - println!("[DEBUG {}:{}]", file!(), line!()); + $crate::println!("[DEBUG {}:{}]", file!(), line!()); }; ($val:expr) => { // Use of `match` here is intentional because it affects the lifetimes // of temporaries - https://stackoverflow.com/a/48732525/1063961 match $val { tmp => { - println!( + $crate::println!( "[\x1B[36mDEBUG\x1B[0m {}:{}] {} = {:#?}", file!(), line!(), @@ -65,12 +68,15 @@ macro_rules! dbg { ($(dbg!($val)),+,) }; } - #[doc(hidden)] pub fn _print(args: fmt::Arguments) { use core::fmt::Write; x86_64::instructions::interrupts::without_interrupts(|| { - SCREEN.0.lock().write_fmt(args).unwrap(); + SCREEN + .0 + .lock() + .write_fmt(args) + .unwrap(); }); } @@ -91,13 +97,13 @@ impl Log for ScreenLocker { let reset = "\x1B[0m"; - println!("[{}{}{}] {}", color, record.level(), reset, record.args()); + crate::println!("[{}{}{}] {}", color, record.level(), reset, record.args()); } } fn flush(&self) {} } - +#[macro_export] macro_rules! test_case { ($test_name:ident, $body:expr) => { #[test_case] diff --git a/src/main.rs b/src/main.rs index bae933d..25561c8 100644 --- a/src/main.rs +++ b/src/main.rs @@ -22,7 +22,6 @@ extern crate alloc; #[macro_use] mod macros; - mod cpu; mod drivers; mod ds; diff --git a/src/testing.rs b/src/testing.rs index 435f03b..2c8be10 100644 --- a/src/testing.rs +++ b/src/testing.rs @@ -1,7 +1,6 @@ #![allow(unused_imports)] #![allow(dead_code)] use core::panic::PanicInfo; - #[derive(Debug, Clone, Copy, PartialEq, Eq)] #[repr(u32)] enum ExitCode { From 287126997f8f4eb445244d9181b49e47b98dcdac Mon Sep 17 00:00:00 2001 From: trashcognito Date: Sun, 4 Jul 2021 13:22:18 +0300 Subject: [PATCH 17/18] fixed debugging by copy pasting dbg!() into debug!() todo: fully alias the two --- src/macros.rs | 34 ++++++++++++++++++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/src/macros.rs b/src/macros.rs index 9efff9a..2593f15 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -40,6 +40,36 @@ macro_rules! println { ($fmt:expr) => ($crate::print!(concat!($fmt, "\n"))); ($fmt:expr, $($arg:tt)*) => ($crate::print!(concat!($fmt, "\n"), $($arg)*)); } +#[allow(unused_macros)] +#[macro_export] +macro_rules! debug { + //copy paste dbg into debug + () => { + $crate::println!("[DEBUG {}:{}]", file!(), line!()); + }; + ($val:expr) => { + // Use of `match` here is intentional because it affects the lifetimes + // of temporaries - https://stackoverflow.com/a/48732525/1063961 + match $val { + tmp => { + $crate::println!( + "[\x1B[36mDEBUG\x1B[0m {}:{}] {} = {:#?}", + file!(), + line!(), + stringify!($val), + &tmp + ); + tmp + } + } + }; + ($val:expr,) => { $crate::dbg!($val) }; + ($($val:expr),+ $(,)?) => { + ($($crate::dbg!($val)),+,) + }; +} + + // Lifted from standard library #[allow(unused_macros)] #[macro_export] @@ -63,9 +93,9 @@ macro_rules! dbg { } } }; - ($val:expr,) => { dbg!($val) }; + ($val:expr,) => { $crate::dbg!($val) }; ($($val:expr),+ $(,)?) => { - ($(dbg!($val)),+,) + ($($crate::dbg!($val)),+,) }; } #[doc(hidden)] From 8ac096d4b9abd373ae8b4e6119d4c7609769a1b9 Mon Sep 17 00:00:00 2001 From: trashcognito Date: Sun, 4 Jul 2021 18:42:14 +0300 Subject: [PATCH 18/18] change the bugs to other bugs --- scripts/debug.sh | 4 ++++ src/cpu/gdt.rs | 3 +-- src/cpu/idt.rs | 2 +- src/drivers/acpi.rs | 7 +++---- src/ds/sync/rwspinlock.rs | 3 ++- src/ds/sync/spinlock.rs | 9 +++++---- src/kernel.rs | 6 ++---- src/macros.rs | 41 +++++++++------------------------------ src/mm/addr_space.rs | 2 +- src/mm/map.rs | 4 ++-- src/mm/mod.rs | 2 +- 11 files changed, 31 insertions(+), 52 deletions(-) create mode 100755 scripts/debug.sh diff --git a/scripts/debug.sh b/scripts/debug.sh new file mode 100755 index 0000000..877e482 --- /dev/null +++ b/scripts/debug.sh @@ -0,0 +1,4 @@ +#!/bin/sh +set -me +cargo xbuild +qemu-system-x86_64 -drive format=raw,file=../target/x86_64-solstice/debug/bootimage-solstice.bin -machine q35 -no-reboot -S -s -d int,guest_errors -no-shutdown \ No newline at end of file diff --git a/src/cpu/gdt.rs b/src/cpu/gdt.rs index c761ed4..29fe2ba 100644 --- a/src/cpu/gdt.rs +++ b/src/cpu/gdt.rs @@ -17,7 +17,6 @@ lazy_static! { tss.interrupt_stack_table[DOUBLE_FAULT_IST_INDEX as usize] = { const STACK_SIZE: usize = 4096; static mut STACK: [u8; STACK_SIZE] = [0; STACK_SIZE]; - let stack_start = VirtAddr::from_ptr(unsafe { &STACK }); stack_start + STACK_SIZE @@ -64,5 +63,5 @@ pub fn load() { } - debug!("gdt: loaded"); + //debug!("gdt: loaded"); } diff --git a/src/cpu/idt.rs b/src/cpu/idt.rs index 0745afb..ba4a7fd 100644 --- a/src/cpu/idt.rs +++ b/src/cpu/idt.rs @@ -33,7 +33,7 @@ lazy_static! { pub fn load() { IDT.load(); - debug!("idt: loaded"); + //debug!("idt: loaded"); } test_case!(int3_handler, { diff --git a/src/drivers/acpi.rs b/src/drivers/acpi.rs index ab14f45..6c82b7c 100644 --- a/src/drivers/acpi.rs +++ b/src/drivers/acpi.rs @@ -3,15 +3,14 @@ use aml::{AmlContext, AmlError, AmlValue}; use core::ptr::NonNull; use x86_64::{PhysAddr, VirtAddr, instructions::port::{PortRead,PortWrite}}; use lazy_static::__Deref; -use acpi::{AcpiTables, AcpiError, InterruptModel}; +use acpi::{AcpiTables, InterruptModel}; use acpi::sdt::Signature; -use acpi::platform::address::GenericAddress; use acpi::platform::ProcessorInfo; +use crate::mm::phys_to_kernel_virt; static mut SLP_TYPA:u64 = 0; pub fn init() -> AcpiObject { let our_acpi = unsafe {acpi::AcpiTables::search_for_rsdp_bios(Acpi)}.expect("ACPI table parsing failed"); - debug!("acpi: found tables"); let mut ctx = AmlContext::new(); match unsafe {core::ptr::read(&our_acpi.dsdt)} { @@ -117,7 +116,7 @@ impl AcpiHandler for Acpi { physical_address: usize, size: usize, ) -> PhysicalMapping { - let start_virt = VirtAddr::new(physical_address as u64); + let start_virt = phys_to_kernel_virt(PhysAddr::new(physical_address as u64)); PhysicalMapping::new(physical_address, NonNull::new(start_virt.as_mut_ptr()).expect("acpi mapped null ptr"), size, size, Acpi) } diff --git a/src/ds/sync/rwspinlock.rs b/src/ds/sync/rwspinlock.rs index 0b5c554..0c4efbc 100644 --- a/src/ds/sync/rwspinlock.rs +++ b/src/ds/sync/rwspinlock.rs @@ -8,7 +8,8 @@ use core::{ mem, ops::{Deref, DerefMut}, ptr::NonNull, - sync::atomic::{spin_loop_hint as cpu_relax, AtomicUsize, Ordering}, + hint::spin_loop as cpu_relax, + sync::atomic::{AtomicUsize, Ordering}, }; use crate::cpu::percpu::PerCpu; diff --git a/src/ds/sync/spinlock.rs b/src/ds/sync/spinlock.rs index 2aa58fd..49caafb 100644 --- a/src/ds/sync/spinlock.rs +++ b/src/ds/sync/spinlock.rs @@ -2,7 +2,8 @@ use crate::cpu::percpu::PerCpu; use core::{ cell::UnsafeCell, ops::{Deref, DerefMut}, - sync::atomic::{spin_loop_hint, AtomicBool, Ordering}, + hint::spin_loop, + sync::atomic::{AtomicBool, Ordering}, }; pub struct SpinLock { @@ -24,9 +25,9 @@ impl SpinLock { pub fn lock(&self) -> SpinLockGuard { // Acquire the lock unsafe { PerCpu::current().preempt_inc() }; - while self.locked.compare_and_swap(false, true, Ordering::Acquire) { + while self.locked.compare_exchange(false, true, Ordering::Acquire, Ordering::Acquire).is_err() { while self.locked.load(Ordering::Relaxed) { - spin_loop_hint(); + spin_loop(); } } @@ -39,7 +40,7 @@ impl SpinLock { pub fn try_lock(&self) -> Option> { unsafe { PerCpu::current().preempt_inc() }; - if !self.locked.compare_and_swap(false, true, Ordering::Acquire) { + if self.locked.compare_exchange(false, true, Ordering::Acquire, Ordering::Acquire).is_err() { Some(SpinLockGuard { locked: &self.locked, data: unsafe { &mut *self.data.get() }, diff --git a/src/kernel.rs b/src/kernel.rs index 66570f7..16b7ae8 100644 --- a/src/kernel.rs +++ b/src/kernel.rs @@ -15,17 +15,15 @@ pub fn kernel_main(info: &BootInfo) { println!("| (___ ___ | |___| |_ _ ___ ___ - Crally"); println!(" \\___ \\ / _ \\| / __| __| |/ __/ _ \\ - Mehodin"); println!(" ____) | (_) | \\__ \\ |_| | (_| __/ - Alex8675"); - println!("|_____/ \\___/|_|___/\\__|_|\\___\\___|"); + println!("|_____/ \\___/|_|___/\\__|_|\\___\\___| - trash"); println!(); }; - + cpu::gdt::load(); cpu::idt::load(); - let map = MemoryMap::new(&info.memory_map); PhysAllocator::init(map); - let acpi = drivers::acpi::init(); match acpi.interrupt_model { InterruptModel::Unknown { .. } => panic!("unsupported acpi interrupt model"), diff --git a/src/macros.rs b/src/macros.rs index 2593f15..faff944 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -4,6 +4,9 @@ use crate::{drivers::vga::text_mode::Writer, ds::SpinLock}; use core::fmt; use lazy_static::lazy_static; use log::{Level, Log, Metadata, Record}; +use core::fmt::Debug; +use alloc::format; +use alloc::string::ToString; // Need a separate struct so we can implement Log trait pub struct ScreenLocker(SpinLock); @@ -24,12 +27,11 @@ impl fmt::Write for ScreenWriter { Ok(()) } } - +// TODO: Macro formatting is broken, maybe due to broken memory alloc lazy_static! { pub static ref SCREEN: ScreenLocker = ScreenLocker(SpinLock::new(ScreenWriter(Writer::default()))); } -// TODO: only debug is broke now #[macro_export] macro_rules! print { ($($arg:tt)*) => ($crate::macros::_print(format_args!($($arg)*))); @@ -40,34 +42,6 @@ macro_rules! println { ($fmt:expr) => ($crate::print!(concat!($fmt, "\n"))); ($fmt:expr, $($arg:tt)*) => ($crate::print!(concat!($fmt, "\n"), $($arg)*)); } -#[allow(unused_macros)] -#[macro_export] -macro_rules! debug { - //copy paste dbg into debug - () => { - $crate::println!("[DEBUG {}:{}]", file!(), line!()); - }; - ($val:expr) => { - // Use of `match` here is intentional because it affects the lifetimes - // of temporaries - https://stackoverflow.com/a/48732525/1063961 - match $val { - tmp => { - $crate::println!( - "[\x1B[36mDEBUG\x1B[0m {}:{}] {} = {:#?}", - file!(), - line!(), - stringify!($val), - &tmp - ); - tmp - } - } - }; - ($val:expr,) => { $crate::dbg!($val) }; - ($($val:expr),+ $(,)?) => { - ($($crate::dbg!($val)),+,) - }; -} // Lifted from standard library @@ -126,8 +100,11 @@ impl Log for ScreenLocker { }; let reset = "\x1B[0m"; - - crate::println!("[{}{}{}] {}", color, record.level(), reset, record.args()); + let args = match record.args().as_str() { + None => {"Cannot format log entry"} + Some(s) => {s} + }; //.to_string(); + println!("[{}{}{}] {}", color, record.level(), reset, args); } } diff --git a/src/mm/addr_space.rs b/src/mm/addr_space.rs index a8aba8c..698d963 100644 --- a/src/mm/addr_space.rs +++ b/src/mm/addr_space.rs @@ -2,7 +2,7 @@ use crate::{ds::RwSpinLock, mm::pmm::PhysAllocator}; use x86_64::{ registers::control::Cr3, structures::paging::{ - mapper::{MapToError, MapperAllSizes, MapperFlush}, + mapper::{MapToError, MapperFlush}, page::Size4KiB, FrameAllocator, Mapper, diff --git a/src/mm/map.rs b/src/mm/map.rs index d23afa6..3db3858 100644 --- a/src/mm/map.rs +++ b/src/mm/map.rs @@ -1,5 +1,5 @@ // TODO: This should all be implemented in the bootloader, ideally -use crate::mm::{self, addr_space::AddrSpace}; +use crate::mm::{self, addr_space::AddrSpace, phys_to_kernel_virt}; use arrayvec::ArrayVec; use bootloader::bootinfo::{MemoryRegion, MemoryRegionType}; use core::{ @@ -129,7 +129,7 @@ unsafe impl FrameAllocator for MemoryMap { // Clear the page #[cfg(not(test))] unsafe { - let page: *mut u8 = out.start_address().as_u64() as *mut u8; + let page: *mut u8 = phys_to_kernel_virt(out.start_address()).as_u64() as *mut u8; core::intrinsics::write_bytes( page, if cfg!(debug_assertions) { 0xB8 } else { 0x00 }, diff --git a/src/mm/mod.rs b/src/mm/mod.rs index 59d5002..5ec6721 100644 --- a/src/mm/mod.rs +++ b/src/mm/mod.rs @@ -32,5 +32,5 @@ pub fn kernel_virt_to_phys(virt: VirtAddr) -> PhysAddr { } pub fn phys_to_kernel_virt(phys: PhysAddr) -> VirtAddr { - VirtAddr::new(phys.as_u64()) + VirtAddr::new(phys.as_u64() + PHYS_OFFSET) }