Skip to content

Commit 4e33054

Browse files
author
Andreas Wessing
committed
refactor: systemcall inspired by linux design
1 parent 2913b39 commit 4e33054

2 files changed

Lines changed: 60 additions & 15 deletions

File tree

src/arch/x86_64/kernel/pc_keyboard.rs

Lines changed: 45 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
use alloc::collections::VecDeque;
2-
use core::num::NonZero;
2+
use core::num::NonZeroU8;
33

44
use hermit_sync::{InterruptTicketMutex, Lazy};
55
use x86_64::instructions::port::Port;
66

77
use crate::kernel::interrupts;
8+
use crate::synch::semaphore::Semaphore;
89

910
const PS2_DATA_PORT: u16 = 0x60;
1011
const PS2_CMD_PORT: u16 = 0x64;
@@ -13,10 +14,13 @@ const PS2_CMD_WRITE_CNFG: u8 = 0x60;
1314
const PS2_CMD_DISABLE_KEYBOARD: u8 = 0xad;
1415
const PS2_CMD_DISABLE_MOUSE: u8 = 0xa7;
1516
const PS2_CMD_ENABLE_KEYBOARD: u8 = 0xae;
17+
#[allow(dead_code)]
18+
const PS2_CMD_ENABLE_MOUSE: u8 = 0xa8;
1619
const PS2_CNFG_ENABLE_KEYBOARD_INTERRUPT: u8 = 0x01;
1720
const PS2_BUFFER_FULL: u8 = 0x01;
1821

1922
const BUFFER_SIZE: usize = 256;
23+
static KEYBOARD_SEMAPHORE: Semaphore = Semaphore::new(0);
2024

2125
struct Ps2;
2226
impl Ps2 {
@@ -37,26 +41,34 @@ impl Ps2 {
3741
}
3842
}
3943

40-
static KEYBOARD_BUFFER: Lazy<InterruptTicketMutex<VecDeque<u8>>> =
44+
static KEYBOARD_BUFFER: Lazy<InterruptTicketMutex<VecDeque<NonZeroU8>>> =
4145
Lazy::new(|| InterruptTicketMutex::new(VecDeque::with_capacity(BUFFER_SIZE)));
4246

4347
fn keyboard_handler() {
4448
let scancode = Ps2::read_data();
45-
let mut buffer = KEYBOARD_BUFFER.lock();
46-
47-
// Don't allow the buffer to grow infinitely, pop the oldest scancode if the buffer is full.
48-
if buffer.len() >= BUFFER_SIZE {
49-
buffer.pop_front();
49+
if let Some(valid_scancode) = NonZeroU8::new(scancode) {
50+
let mut sem = true;
51+
{
52+
let mut buffer = KEYBOARD_BUFFER.lock();
53+
54+
// Pop the oldest scancode if the buffer is full.
55+
if buffer.len() >= BUFFER_SIZE {
56+
buffer.pop_front();
57+
sem = false;
58+
}
59+
buffer.push_back(valid_scancode);
60+
}
61+
if sem {
62+
KEYBOARD_SEMAPHORE.release();
63+
}
5064
}
51-
52-
buffer.push_back(scancode);
5365
}
5466

5567
pub(crate) fn get_keyboard_handler() -> (u8, fn()) {
5668
Ps2::write_cmd(PS2_CMD_DISABLE_KEYBOARD);
5769
Ps2::write_cmd(PS2_CMD_DISABLE_MOUSE);
5870

59-
// Ensure an empty buffer to guard against stuck data
71+
// Ensure an empty buffer to guard against stuck/garbage data
6072
while (Ps2::read_status() & PS2_BUFFER_FULL) != 0 {
6173
let _ = Ps2::read_data();
6274
}
@@ -79,7 +91,27 @@ pub(crate) fn get_keyboard_handler() -> (u8, fn()) {
7991
(1, keyboard_handler)
8092
}
8193

82-
/// Pops a scancode from the keyboard buffer, returning None if the buffer is empty.
83-
pub fn pop_scancode() -> Option<NonZero<u8>> {
84-
KEYBOARD_BUFFER.lock().pop_front()
94+
/// Pops scancodes from the keyboard buffer into the provided slice. If `nonblocking` is false, the
95+
/// function will sleep the current thread until a scancode has been received. Returns the number of scancodes
96+
/// popped into the slice.
97+
pub fn pop_scancodes(slice: &mut [u8], nonblocking: bool) -> usize {
98+
if slice.is_empty() {
99+
return 0;
100+
}
101+
if nonblocking {
102+
if !KEYBOARD_SEMAPHORE.try_acquire() {
103+
return 0;
104+
}
105+
} else {
106+
KEYBOARD_SEMAPHORE.acquire(None);
107+
}
108+
let mut amount: usize = 1;
109+
while amount < slice.len() && KEYBOARD_SEMAPHORE.try_acquire() {
110+
amount += 1;
111+
}
112+
let mut buffer = KEYBOARD_BUFFER.lock();
113+
for scancode in slice[..amount].iter_mut() {
114+
*scancode = buffer.pop_front().unwrap().get();
115+
}
116+
amount
85117
}

src/syscalls/system.rs

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use crate::arch::mm::paging::{BasePageSize, PageSize};
2+
use crate::errno::Errno;
23

34
/// Returns the base page size, in bytes, of the current system.
45
#[hermit_macro::system]
@@ -10,6 +11,18 @@ pub extern "C" fn sys_getpagesize() -> i32 {
1011
#[cfg(all(target_arch = "x86_64", feature = "pc-keyboard"))]
1112
#[hermit_macro::system]
1213
#[unsafe(no_mangle)]
13-
pub extern "C" fn sys_read_keyboard() -> u8 {
14-
crate::kernel::pc_keyboard::pop_scancode().unwrap_or(0)
14+
pub unsafe extern "C" fn sys_read_keyboard(buffer: *mut u8, size: usize, nonblock: bool) -> isize {
15+
if buffer.is_null() {
16+
return -(Errno::Fault as isize);
17+
}
18+
if size == 0 {
19+
return 0;
20+
}
21+
let buffer_slice: &mut [u8] = unsafe { core::slice::from_raw_parts_mut(buffer, size) };
22+
let result = crate::kernel::pc_keyboard::pop_scancodes(buffer_slice, nonblock);
23+
if result == 0 && nonblock {
24+
-(Errno::Again as isize)
25+
} else {
26+
result as isize
27+
}
1528
}

0 commit comments

Comments
 (0)