From 8563961f2840b9b0df9a8024cac9c29fea17f025 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sun, 11 Sep 2016 15:02:35 -0600 Subject: [PATCH] Flush TLB correctly when remapping Seperate mouse and keyboard structs in PS/2 driver --- Makefile | 5 +- arch/x86_64/src/device/ps2.rs | 168 +++++++++++++++++++------------ arch/x86_64/src/interrupt/irq.rs | 36 ++++--- arch/x86_64/src/interrupt/mod.rs | 12 +++ arch/x86_64/src/paging/mod.rs | 25 +++-- kernel/elf.rs | 31 ++---- kernel/syscall/process.rs | 2 + libstd | 2 +- 8 files changed, 169 insertions(+), 112 deletions(-) diff --git a/Makefile b/Makefile index e9f5233..b43674c 100644 --- a/Makefile +++ b/Makefile @@ -47,7 +47,10 @@ qemu: $(KBUILD)/harddrive.bin $(QEMU) $(QEMUFLAGS) -kernel $< else LD=ld - QEMUFLAGS+=-enable-kvm -cpu host -machine q35 -smp 4 + QEMUFLAGS+=-machine q35 -smp 4 +ifneq ($(kvm),no) + QEMUFLAGS+=-enable-kvm -cpu host +endif ifeq ($(vga),no) QEMUFLAGS+=-nographic -vga none endif diff --git a/arch/x86_64/src/device/ps2.rs b/arch/x86_64/src/device/ps2.rs index 49ae83b..8980086 100644 --- a/arch/x86_64/src/device/ps2.rs +++ b/arch/x86_64/src/device/ps2.rs @@ -3,10 +3,13 @@ use spin::Mutex; use io::{Io, Pio, ReadOnly, WriteOnly}; -pub static PS2: Mutex = Mutex::new(Ps2::new()); +pub static PS2_KEYBOARD: Mutex> = Mutex::new(None); +pub static PS2_MOUSE: Mutex> = Mutex::new(None); pub unsafe fn init() { - PS2.lock().init(); + let (keyboard, mouse) = Ps2::new().init(); + *PS2_KEYBOARD.lock() = keyboard; + *PS2_MOUSE.lock() = mouse; } bitflags! { @@ -95,12 +98,36 @@ bitflags! { } } -pub struct Ps2 { - data: Pio, - status: ReadOnly>, - command: WriteOnly>, +pub struct Ps2Keyboard { + data: ReadOnly>, key: [u8; 3], key_i: usize, +} + +impl Ps2Keyboard { + fn new() -> Self { + Ps2Keyboard { + data: ReadOnly::new(Pio::new(0x60)), + key: [0; 3], + key_i: 0 + } + } + + pub fn on_irq(&mut self) { + let scancode = self.data.read(); + self.key[self.key_i] = scancode; + self.key_i += 1; + if self.key_i >= self.key.len() || scancode < 0xE0 { + println!("KEY: {:X} {:X} {:X}", self.key[0], self.key[1], self.key[2]); + + self.key = [0; 3]; + self.key_i = 0; + } + } +} + +pub struct Ps2Mouse { + data: ReadOnly>, mouse: [u8; 4], mouse_i: usize, mouse_extra: bool, @@ -108,19 +135,76 @@ pub struct Ps2 { mouse_y: usize } +impl Ps2Mouse { + fn new(mouse_extra: bool) -> Self { + Ps2Mouse { + data: ReadOnly::new(Pio::new(0x60)), + mouse: [0; 4], + mouse_i: 0, + mouse_extra: mouse_extra, + mouse_x: 0, + mouse_y: 0 + } + } + + pub fn on_irq(&mut self) { + self.mouse[self.mouse_i] = self.data.read(); + self.mouse_i += 1; + + let flags = MousePacketFlags::from_bits_truncate(self.mouse[0]); + if ! flags.contains(ALWAYS_ON) { + println!("MOUSE MISALIGN {:X}", self.mouse[0]); + + self.mouse = [0; 4]; + self.mouse_i = 0; + } else if self.mouse_i >= self.mouse.len() || (!self.mouse_extra && self.mouse_i >= 3) { + if ! flags.contains(X_OVERFLOW) && ! flags.contains(Y_OVERFLOW) { + let mut dx = self.mouse[1] as isize; + if flags.contains(X_SIGN) { + dx -= 0x100; + } + + let mut dy = self.mouse[2] as isize; + if flags.contains(Y_SIGN) { + dy -= 0x100; + } + + let _extra = if self.mouse_extra { + self.mouse[3] + } else { + 0 + }; + + //print!("MOUSE {:?}, {}, {}, {}\n", flags, dx, dy, extra); + + if let Some(ref mut display) = *super::display::DISPLAY.lock() { + self.mouse_x = cmp::max(0, cmp::min(display.width as isize - 1, self.mouse_x as isize + dx)) as usize; + self.mouse_y = cmp::max(0, cmp::min(display.height as isize - 1, self.mouse_y as isize - dy)) as usize; + let offset = self.mouse_y * display.width + self.mouse_x; + display.onscreen[offset as usize] = 0xFF0000; + } + } else { + println!("MOUSE OVERFLOW {:X} {:X} {:X} {:X}", self.mouse[0], self.mouse[1], self.mouse[2], self.mouse[3]); + } + + self.mouse = [0; 4]; + self.mouse_i = 0; + } + } +} + +pub struct Ps2 { + data: Pio, + status: ReadOnly>, + command: WriteOnly> +} + impl Ps2 { - const fn new() -> Ps2 { + const fn new() -> Self { Ps2 { data: Pio::new(0x60), status: ReadOnly::new(Pio::new(0x64)), command: WriteOnly::new(Pio::new(0x64)), - key: [0; 3], - key_i: 0, - mouse: [0; 4], - mouse_i: 0, - mouse_extra: false, - mouse_x: 0, - mouse_y: 0 } } @@ -194,7 +278,7 @@ impl Ps2 { self.read() } - fn init(&mut self) { + fn init(&mut self) -> (Option, Option) { // Disable devices self.command(Command::DisableFirst); self.command(Command::DisableSecond); @@ -242,7 +326,7 @@ impl Ps2 { assert_eq!(self.mouse_command_data(MouseCommandData::SetSampleRate, 80), 0xFA); assert_eq!(self.mouse_command(MouseCommand::GetDeviceId), 0xFA); let mouse_id = self.read(); - self.mouse_extra = mouse_id == 3; + let mouse_extra = mouse_id == 3; // Enable extra buttons, TODO /* @@ -272,57 +356,9 @@ impl Ps2 { config.insert(SECOND_INTERRUPT); self.set_config(config); } - } - pub fn on_keyboard(&mut self) { - let scancode = self.data.read(); - self.key[self.key_i] = scancode; - self.key_i += 1; - if self.key_i >= self.key.len() || scancode < 0xE0 { - //println!("KEY: {:X} {:X} {:X}", self.key[0], self.key[1], self.key[2]); + self.flush_read(); - self.key = [0; 3]; - self.key_i = 0; - } - } - - pub fn on_mouse(&mut self) { - self.mouse[self.mouse_i] = self.data.read(); - self.mouse_i += 1; - if self.mouse_i >= self.mouse.len() || (!self.mouse_extra && self.mouse_i >= 3) { - let flags = MousePacketFlags::from_bits_truncate(self.mouse[0]); - - if flags.contains(ALWAYS_ON) && ! flags.contains(X_OVERFLOW) && ! flags.contains(Y_OVERFLOW) { - let mut dx = self.mouse[1] as isize; - if flags.contains(X_SIGN) { - dx -= 0x100; - } - - let mut dy = self.mouse[2] as isize; - if flags.contains(Y_SIGN) { - dy -= 0x100; - } - - let _extra = if self.mouse_extra { - self.mouse[3] - } else { - 0 - }; - - //print!("MOUSE {:?}, {}, {}, {}\n", flags, dx, dy, extra); - - if let Some(ref mut display) = *super::display::DISPLAY.lock() { - self.mouse_x = cmp::max(0, cmp::min(display.width as isize - 1, self.mouse_x as isize + dx)) as usize; - self.mouse_y = cmp::max(0, cmp::min(display.height as isize - 1, self.mouse_y as isize - dy)) as usize; - let offset = self.mouse_y * display.width + self.mouse_x; - display.onscreen[offset as usize] = 0xFF0000; - } - } else { - println!("BAD MOUSE {:?}", self.mouse); - } - - self.mouse = [0; 4]; - self.mouse_i = 0; - } + (Some(Ps2Keyboard::new()), Some(Ps2Mouse::new(mouse_extra))) } } diff --git a/arch/x86_64/src/interrupt/irq.rs b/arch/x86_64/src/interrupt/irq.rs index fbc82af..c0c0db4 100644 --- a/arch/x86_64/src/interrupt/irq.rs +++ b/arch/x86_64/src/interrupt/irq.rs @@ -1,6 +1,6 @@ use x86::io; -use device::ps2::PS2; +use device::ps2::{PS2_KEYBOARD, PS2_MOUSE}; use device::serial::{COM1, COM2}; #[inline(always)] @@ -19,76 +19,80 @@ interrupt!(pit, { }); interrupt!(keyboard, { - PS2.lock().on_keyboard(); master_ack(); + if let Some(ref mut keyboard) = *PS2_KEYBOARD.lock(){ + keyboard.on_irq(); + } }); interrupt!(cascade, { - print!("CASCADE\n"); master_ack(); + print!("CASCADE\n"); }); interrupt!(com2, { - COM2.lock().on_receive(); master_ack(); + COM2.lock().on_receive(); }); interrupt!(com1, { - COM1.lock().on_receive(); master_ack(); + COM1.lock().on_receive(); }); interrupt!(lpt2, { - print!("LPT2\n"); master_ack(); + print!("LPT2\n"); }); interrupt!(floppy, { - print!("FLOPPY\n"); master_ack(); + print!("FLOPPY\n"); }); interrupt!(lpt1, { - print!("LPT1\n"); master_ack(); + print!("LPT1\n"); }); interrupt!(rtc, { - print!("RTC\n"); slave_ack(); + print!("RTC\n"); }); interrupt!(pci1, { - print!("PCI1\n"); slave_ack(); + print!("PCI1\n"); }); interrupt!(pci2, { - print!("PCI2\n"); slave_ack(); + print!("PCI2\n"); }); interrupt!(pci3, { - print!("PCI3\n"); slave_ack(); + print!("PCI3\n"); }); interrupt!(mouse, { - PS2.lock().on_mouse(); slave_ack(); + if let Some(ref mut mouse) = *PS2_MOUSE.lock() { + mouse.on_irq(); + } }); interrupt!(fpu, { - print!("FPU\n"); slave_ack(); + print!("FPU\n"); }); interrupt!(ata1, { - print!("ATA1\n"); slave_ack(); + print!("ATA1\n"); }); interrupt!(ata2, { - print!("ATA2\n"); slave_ack(); + print!("ATA2\n"); }); diff --git a/arch/x86_64/src/interrupt/mod.rs b/arch/x86_64/src/interrupt/mod.rs index ad93b1a..e34f1d6 100644 --- a/arch/x86_64/src/interrupt/mod.rs +++ b/arch/x86_64/src/interrupt/mod.rs @@ -21,6 +21,8 @@ pub unsafe fn enable() { } /// Set interrupts and halt +/// This will atomically wait for the next interrupt +/// Performing enable followed by halt is not guaranteed to be atomic, use this instead! #[inline(always)] pub unsafe fn enable_and_halt() { asm!("sti @@ -28,6 +30,16 @@ pub unsafe fn enable_and_halt() { : : : : "intel", "volatile"); } +/// Set interrupts and nop +/// This will enable interrupts and allow the IF flag to be processed +/// Simply enabling interrupts does not gurantee that they will trigger, use this instead! +#[inline(always)] +pub unsafe fn enable_and_nop() { + asm!("sti + nop" + : : : : "intel", "volatile"); +} + /// Halt instruction #[inline(always)] pub unsafe fn halt() { diff --git a/arch/x86_64/src/paging/mod.rs b/arch/x86_64/src/paging/mod.rs index 420ca49..fd02184 100644 --- a/arch/x86_64/src/paging/mod.rs +++ b/arch/x86_64/src/paging/mod.rs @@ -128,14 +128,14 @@ pub unsafe fn init(stack_start: usize, stack_end: usize) -> ActivePageTable { { let frame = Frame::containing_address(PhysicalAddress::new(page.start_address().get())); active_table.identity_map(frame, PRESENT | NO_EXECUTE); - tlb::flush_all(); + active_table.flush(page); ::externs::memcpy(temporary_page.start_address().get() as *mut u8, page.start_address().get() as *const u8, 4096); active_table.unmap(page); } // Copy temporary page to child { active_table.map(page, PRESENT | NO_EXECUTE | WRITABLE); - tlb::flush_all(); + active_table.flush(page); ::externs::memcpy(page.start_address().get() as *mut u8, temporary_page.start_address().get() as *const u8, 4096); } } @@ -153,7 +153,7 @@ pub unsafe fn init(stack_start: usize, stack_end: usize) -> ActivePageTable { let end_page = Page::containing_address(VirtualAddress::new(end - 1)); for page in Page::range_inclusive(start_page, end_page) { active_table.map(page, PRESENT | NO_EXECUTE | WRITABLE); - tlb::flush_all(); + active_table.flush(page); ::externs::memset(page.start_address().get() as *mut u8, 0, 4096); } @@ -161,6 +161,8 @@ pub unsafe fn init(stack_start: usize, stack_end: usize) -> ActivePageTable { } } + active_table.flush_all(); + active_table } @@ -203,12 +205,19 @@ impl ActivePageTable { old_table } + pub fn flush(&mut self, page: Page) { + unsafe { tlb::flush(page.start_address().get()); } + } + + pub fn flush_all(&mut self) { + unsafe { tlb::flush_all(); } + } + pub fn with(&mut self, table: &mut InactivePageTable, temporary_page: &mut temporary_page::TemporaryPage, f: F) where F: FnOnce(&mut Mapper) { - use x86::{controlregs, tlb}; - let flush_tlb = || unsafe { tlb::flush_all() }; - + use x86::controlregs; + { let backup = Frame::containing_address(PhysicalAddress::new(unsafe { controlregs::cr3() } as usize)); @@ -217,14 +226,14 @@ impl ActivePageTable { // overwrite recursive mapping self.p4_mut()[511].set(table.p4_frame.clone(), PRESENT | WRITABLE | NO_EXECUTE); - flush_tlb(); + self.flush_all(); // execute f in the new context f(self); // restore recursive mapping to original p4 table p4_table[511].set(backup, PRESENT | WRITABLE | NO_EXECUTE); - flush_tlb(); + self.flush_all(); } temporary_page.unmap(self); diff --git a/kernel/elf.rs b/kernel/elf.rs index b379bba..10be116 100644 --- a/kernel/elf.rs +++ b/kernel/elf.rs @@ -13,7 +13,6 @@ use goblin::elf64::{header, program_header}; use arch::externs::{memcpy, memset}; use arch::paging::{entry, ActivePageTable, Page, VirtualAddress}; use arch::start::usermode; -use arch::x86::tlb; /// An ELF executable pub struct Elf<'a> { @@ -63,11 +62,9 @@ impl<'a> Elf<'a> { for page in Page::range_inclusive(start_page, end_page) { active_table.map(page, entry::NO_EXECUTE | entry::WRITABLE); } + active_table.flush_all(); unsafe { - // Update the page table - tlb::flush_all(); - // Copy file data memcpy(segment.p_vaddr as *mut u8, (self.data.as_ptr() as usize + segment.p_offset as usize) as *const u8, @@ -94,26 +91,20 @@ impl<'a> Elf<'a> { for page in Page::range_inclusive(start_page, end_page) { active_table.remap(page, flags); } - - unsafe { - // Update the page table - tlb::flush_all(); - } + active_table.flush_all(); } } + // Map stack + let start_page = Page::containing_address(VirtualAddress::new(0x80000000)); + let end_page = Page::containing_address(VirtualAddress::new(0x80000000 + 64*1024 - 1)); + + for page in Page::range_inclusive(start_page, end_page) { + active_table.map(page, entry::NO_EXECUTE | entry::WRITABLE | entry::USER_ACCESSIBLE); + } + active_table.flush_all(); + unsafe { - // Map stack - let start_page = Page::containing_address(VirtualAddress::new(0x80000000)); - let end_page = Page::containing_address(VirtualAddress::new(0x80000000 + 64*1024 - 1)); - - for page in Page::range_inclusive(start_page, end_page) { - active_table.map(page, entry::NO_EXECUTE | entry::WRITABLE | entry::USER_ACCESSIBLE); - } - - // Update the page table - tlb::flush_all(); - // Clear stack memset(0x80000000 as *mut u8, 0, 64 * 1024); diff --git a/kernel/syscall/process.rs b/kernel/syscall/process.rs index d15c239..f357d36 100644 --- a/kernel/syscall/process.rs +++ b/kernel/syscall/process.rs @@ -34,6 +34,7 @@ pub fn brk(address: usize) -> Result { if active_table.translate_page(page).is_none() { //println!("Not found - mapping"); active_table.map(page, entry::PRESENT | entry::WRITABLE | entry::NO_EXECUTE | entry::USER_ACCESSIBLE); + active_table.flush(page); } else { //println!("Found - skipping"); } @@ -49,6 +50,7 @@ pub fn brk(address: usize) -> Result { if active_table.translate_page(page).is_some() { //println!("Found - unmapping"); active_table.unmap(page); + active_table.flush(page); } else { //println!("Not found - skipping"); } diff --git a/libstd b/libstd index 7ead704..7b20e73 160000 --- a/libstd +++ b/libstd @@ -1 +1 @@ -Subproject commit 7ead704d48411cc66ce71ffe4f1fbe86a6a4cbe4 +Subproject commit 7b20e739903a4877a10b64b875a3fd7a06cdcd16