Flush TLB correctly when remapping

Seperate mouse and keyboard structs in PS/2 driver
This commit is contained in:
Jeremy Soller 2016-09-11 15:02:35 -06:00
parent 44e8b99b46
commit 8563961f28
8 changed files with 169 additions and 112 deletions

View file

@ -47,7 +47,10 @@ qemu: $(KBUILD)/harddrive.bin
$(QEMU) $(QEMUFLAGS) -kernel $< $(QEMU) $(QEMUFLAGS) -kernel $<
else else
LD=ld 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) ifeq ($(vga),no)
QEMUFLAGS+=-nographic -vga none QEMUFLAGS+=-nographic -vga none
endif endif

View file

@ -3,10 +3,13 @@ use spin::Mutex;
use io::{Io, Pio, ReadOnly, WriteOnly}; use io::{Io, Pio, ReadOnly, WriteOnly};
pub static PS2: Mutex<Ps2> = Mutex::new(Ps2::new()); pub static PS2_KEYBOARD: Mutex<Option<Ps2Keyboard>> = Mutex::new(None);
pub static PS2_MOUSE: Mutex<Option<Ps2Mouse>> = Mutex::new(None);
pub unsafe fn init() { pub unsafe fn init() {
PS2.lock().init(); let (keyboard, mouse) = Ps2::new().init();
*PS2_KEYBOARD.lock() = keyboard;
*PS2_MOUSE.lock() = mouse;
} }
bitflags! { bitflags! {
@ -95,12 +98,36 @@ bitflags! {
} }
} }
pub struct Ps2 { pub struct Ps2Keyboard {
data: Pio<u8>, data: ReadOnly<Pio<u8>>,
status: ReadOnly<Pio<u8>>,
command: WriteOnly<Pio<u8>>,
key: [u8; 3], key: [u8; 3],
key_i: usize, 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<Pio<u8>>,
mouse: [u8; 4], mouse: [u8; 4],
mouse_i: usize, mouse_i: usize,
mouse_extra: bool, mouse_extra: bool,
@ -108,19 +135,76 @@ pub struct Ps2 {
mouse_y: usize 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<u8>,
status: ReadOnly<Pio<u8>>,
command: WriteOnly<Pio<u8>>
}
impl Ps2 { impl Ps2 {
const fn new() -> Ps2 { const fn new() -> Self {
Ps2 { Ps2 {
data: Pio::new(0x60), data: Pio::new(0x60),
status: ReadOnly::new(Pio::new(0x64)), status: ReadOnly::new(Pio::new(0x64)),
command: WriteOnly::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() self.read()
} }
fn init(&mut self) { fn init(&mut self) -> (Option<Ps2Keyboard>, Option<Ps2Mouse>) {
// Disable devices // Disable devices
self.command(Command::DisableFirst); self.command(Command::DisableFirst);
self.command(Command::DisableSecond); 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_data(MouseCommandData::SetSampleRate, 80), 0xFA);
assert_eq!(self.mouse_command(MouseCommand::GetDeviceId), 0xFA); assert_eq!(self.mouse_command(MouseCommand::GetDeviceId), 0xFA);
let mouse_id = self.read(); let mouse_id = self.read();
self.mouse_extra = mouse_id == 3; let mouse_extra = mouse_id == 3;
// Enable extra buttons, TODO // Enable extra buttons, TODO
/* /*
@ -272,57 +356,9 @@ impl Ps2 {
config.insert(SECOND_INTERRUPT); config.insert(SECOND_INTERRUPT);
self.set_config(config); self.set_config(config);
} }
}
pub fn on_keyboard(&mut self) { self.flush_read();
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]; (Some(Ps2Keyboard::new()), Some(Ps2Mouse::new(mouse_extra)))
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;
}
} }
} }

View file

@ -1,6 +1,6 @@
use x86::io; use x86::io;
use device::ps2::PS2; use device::ps2::{PS2_KEYBOARD, PS2_MOUSE};
use device::serial::{COM1, COM2}; use device::serial::{COM1, COM2};
#[inline(always)] #[inline(always)]
@ -19,76 +19,80 @@ interrupt!(pit, {
}); });
interrupt!(keyboard, { interrupt!(keyboard, {
PS2.lock().on_keyboard();
master_ack(); master_ack();
if let Some(ref mut keyboard) = *PS2_KEYBOARD.lock(){
keyboard.on_irq();
}
}); });
interrupt!(cascade, { interrupt!(cascade, {
print!("CASCADE\n");
master_ack(); master_ack();
print!("CASCADE\n");
}); });
interrupt!(com2, { interrupt!(com2, {
COM2.lock().on_receive();
master_ack(); master_ack();
COM2.lock().on_receive();
}); });
interrupt!(com1, { interrupt!(com1, {
COM1.lock().on_receive();
master_ack(); master_ack();
COM1.lock().on_receive();
}); });
interrupt!(lpt2, { interrupt!(lpt2, {
print!("LPT2\n");
master_ack(); master_ack();
print!("LPT2\n");
}); });
interrupt!(floppy, { interrupt!(floppy, {
print!("FLOPPY\n");
master_ack(); master_ack();
print!("FLOPPY\n");
}); });
interrupt!(lpt1, { interrupt!(lpt1, {
print!("LPT1\n");
master_ack(); master_ack();
print!("LPT1\n");
}); });
interrupt!(rtc, { interrupt!(rtc, {
print!("RTC\n");
slave_ack(); slave_ack();
print!("RTC\n");
}); });
interrupt!(pci1, { interrupt!(pci1, {
print!("PCI1\n");
slave_ack(); slave_ack();
print!("PCI1\n");
}); });
interrupt!(pci2, { interrupt!(pci2, {
print!("PCI2\n");
slave_ack(); slave_ack();
print!("PCI2\n");
}); });
interrupt!(pci3, { interrupt!(pci3, {
print!("PCI3\n");
slave_ack(); slave_ack();
print!("PCI3\n");
}); });
interrupt!(mouse, { interrupt!(mouse, {
PS2.lock().on_mouse();
slave_ack(); slave_ack();
if let Some(ref mut mouse) = *PS2_MOUSE.lock() {
mouse.on_irq();
}
}); });
interrupt!(fpu, { interrupt!(fpu, {
print!("FPU\n");
slave_ack(); slave_ack();
print!("FPU\n");
}); });
interrupt!(ata1, { interrupt!(ata1, {
print!("ATA1\n");
slave_ack(); slave_ack();
print!("ATA1\n");
}); });
interrupt!(ata2, { interrupt!(ata2, {
print!("ATA2\n");
slave_ack(); slave_ack();
print!("ATA2\n");
}); });

View file

@ -21,6 +21,8 @@ pub unsafe fn enable() {
} }
/// Set interrupts and halt /// 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)] #[inline(always)]
pub unsafe fn enable_and_halt() { pub unsafe fn enable_and_halt() {
asm!("sti asm!("sti
@ -28,6 +30,16 @@ pub unsafe fn enable_and_halt() {
: : : : "intel", "volatile"); : : : : "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 /// Halt instruction
#[inline(always)] #[inline(always)]
pub unsafe fn halt() { pub unsafe fn halt() {

View file

@ -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())); let frame = Frame::containing_address(PhysicalAddress::new(page.start_address().get()));
active_table.identity_map(frame, PRESENT | NO_EXECUTE); 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); ::externs::memcpy(temporary_page.start_address().get() as *mut u8, page.start_address().get() as *const u8, 4096);
active_table.unmap(page); active_table.unmap(page);
} }
// Copy temporary page to child // Copy temporary page to child
{ {
active_table.map(page, PRESENT | NO_EXECUTE | WRITABLE); 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); ::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)); let end_page = Page::containing_address(VirtualAddress::new(end - 1));
for page in Page::range_inclusive(start_page, end_page) { for page in Page::range_inclusive(start_page, end_page) {
active_table.map(page, PRESENT | NO_EXECUTE | WRITABLE); 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); ::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 active_table
} }
@ -203,11 +205,18 @@ impl ActivePageTable {
old_table 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<F>(&mut self, table: &mut InactivePageTable, temporary_page: &mut temporary_page::TemporaryPage, f: F) pub fn with<F>(&mut self, table: &mut InactivePageTable, temporary_page: &mut temporary_page::TemporaryPage, f: F)
where F: FnOnce(&mut Mapper) where F: FnOnce(&mut Mapper)
{ {
use x86::{controlregs, tlb}; use x86::controlregs;
let flush_tlb = || unsafe { tlb::flush_all() };
{ {
let backup = Frame::containing_address(PhysicalAddress::new(unsafe { controlregs::cr3() } as usize)); let backup = Frame::containing_address(PhysicalAddress::new(unsafe { controlregs::cr3() } as usize));
@ -217,14 +226,14 @@ impl ActivePageTable {
// overwrite recursive mapping // overwrite recursive mapping
self.p4_mut()[511].set(table.p4_frame.clone(), PRESENT | WRITABLE | NO_EXECUTE); self.p4_mut()[511].set(table.p4_frame.clone(), PRESENT | WRITABLE | NO_EXECUTE);
flush_tlb(); self.flush_all();
// execute f in the new context // execute f in the new context
f(self); f(self);
// restore recursive mapping to original p4 table // restore recursive mapping to original p4 table
p4_table[511].set(backup, PRESENT | WRITABLE | NO_EXECUTE); p4_table[511].set(backup, PRESENT | WRITABLE | NO_EXECUTE);
flush_tlb(); self.flush_all();
} }
temporary_page.unmap(self); temporary_page.unmap(self);

View file

@ -13,7 +13,6 @@ use goblin::elf64::{header, program_header};
use arch::externs::{memcpy, memset}; use arch::externs::{memcpy, memset};
use arch::paging::{entry, ActivePageTable, Page, VirtualAddress}; use arch::paging::{entry, ActivePageTable, Page, VirtualAddress};
use arch::start::usermode; use arch::start::usermode;
use arch::x86::tlb;
/// An ELF executable /// An ELF executable
pub struct Elf<'a> { pub struct Elf<'a> {
@ -63,11 +62,9 @@ impl<'a> Elf<'a> {
for page in Page::range_inclusive(start_page, end_page) { for page in Page::range_inclusive(start_page, end_page) {
active_table.map(page, entry::NO_EXECUTE | entry::WRITABLE); active_table.map(page, entry::NO_EXECUTE | entry::WRITABLE);
} }
active_table.flush_all();
unsafe { unsafe {
// Update the page table
tlb::flush_all();
// Copy file data // Copy file data
memcpy(segment.p_vaddr as *mut u8, memcpy(segment.p_vaddr as *mut u8,
(self.data.as_ptr() as usize + segment.p_offset as usize) as *const 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) { for page in Page::range_inclusive(start_page, end_page) {
active_table.remap(page, flags); active_table.remap(page, flags);
} }
active_table.flush_all();
unsafe {
// Update the page table
tlb::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 { 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 // Clear stack
memset(0x80000000 as *mut u8, 0, 64 * 1024); memset(0x80000000 as *mut u8, 0, 64 * 1024);

View file

@ -34,6 +34,7 @@ pub fn brk(address: usize) -> Result<usize> {
if active_table.translate_page(page).is_none() { if active_table.translate_page(page).is_none() {
//println!("Not found - mapping"); //println!("Not found - mapping");
active_table.map(page, entry::PRESENT | entry::WRITABLE | entry::NO_EXECUTE | entry::USER_ACCESSIBLE); active_table.map(page, entry::PRESENT | entry::WRITABLE | entry::NO_EXECUTE | entry::USER_ACCESSIBLE);
active_table.flush(page);
} else { } else {
//println!("Found - skipping"); //println!("Found - skipping");
} }
@ -49,6 +50,7 @@ pub fn brk(address: usize) -> Result<usize> {
if active_table.translate_page(page).is_some() { if active_table.translate_page(page).is_some() {
//println!("Found - unmapping"); //println!("Found - unmapping");
active_table.unmap(page); active_table.unmap(page);
active_table.flush(page);
} else { } else {
//println!("Not found - skipping"); //println!("Not found - skipping");
} }

2
libstd

@ -1 +1 @@
Subproject commit 7ead704d48411cc66ce71ffe4f1fbe86a6a4cbe4 Subproject commit 7b20e739903a4877a10b64b875a3fd7a06cdcd16