mirror of
https://github.com/XunilGroup/XunilOS.git
synced 2026-04-25 11:49:03 +02:00
Remove micromath dependency, improve primitive drawing speed by 300x,
add mouse support and interrupts on x86_64 using a ps2 mouse which needed pic unmasking, add span filling to framebuffer, add back without_interrupts to serial console and framebuffer, add a mouse rectangle which tracks the mouse position and test the performance of the drawing.
This commit is contained in:
7
kernel/Cargo.lock
generated
7
kernel/Cargo.lock
generated
@@ -9,7 +9,6 @@ dependencies = [
|
||||
"font8x8",
|
||||
"lazy_static",
|
||||
"limine",
|
||||
"micromath",
|
||||
"pc-keyboard",
|
||||
"pic8259",
|
||||
"spin 0.10.0",
|
||||
@@ -67,12 +66,6 @@ dependencies = [
|
||||
"scopeguard",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "micromath"
|
||||
version = "2.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c3c8dda44ff03a2f238717214da50f65d5a53b45cd213a7370424ffdb6fae815"
|
||||
|
||||
[[package]]
|
||||
name = "pc-keyboard"
|
||||
version = "0.8.0"
|
||||
|
||||
@@ -12,7 +12,6 @@ bench = false
|
||||
font8x8 = { version = "0.3.1", default-features = false }
|
||||
lazy_static = { version = "1.5.0", features = ["spin_no_std"] }
|
||||
limine = "0.5"
|
||||
micromath = "2.1.0"
|
||||
pc-keyboard = "0.8.0"
|
||||
pic8259 = "0.11.0"
|
||||
spin = "0.10.0"
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
use crate::arch::x86_64::gdt::load_gdt_x86_64;
|
||||
use crate::arch::x86_64::interrupts::{InterruptIndex, PICS, init_idt_x86_64};
|
||||
use crate::{
|
||||
arch::x86_64::{
|
||||
gdt::load_gdt_x86_64,
|
||||
interrupts::{PICS, init_idt_x86_64},
|
||||
mouse::setup_mouse,
|
||||
},
|
||||
driver::mouse::MOUSE,
|
||||
};
|
||||
use limine::response::{HhdmResponse, MemoryMapResponse};
|
||||
use x86_64::instructions::interrupts::without_interrupts;
|
||||
use x86_64::instructions::{interrupts, port::Port};
|
||||
@@ -49,9 +55,12 @@ pub fn init_x86_64<'a>(
|
||||
unsafe {
|
||||
let mut pics = PICS.lock();
|
||||
pics.initialize();
|
||||
pics.write_masks(0xFC, 0xFF);
|
||||
let master_mask = 0xF8; // unmask cascade to slave
|
||||
let slave_mask = 0xEF; // unmask mouse interrupt (clear bit 4)
|
||||
pics.write_masks(master_mask, slave_mask);
|
||||
}
|
||||
|
||||
let mouse_status = setup_mouse();
|
||||
set_pit_interval();
|
||||
|
||||
interrupts::enable();
|
||||
@@ -63,5 +72,7 @@ pub fn init_x86_64<'a>(
|
||||
.ok()
|
||||
.expect("Failed to initalize heap");
|
||||
|
||||
MOUSE.set_status(mouse_status);
|
||||
|
||||
return (mapper, frame_allocator);
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
use crate::arch::x86_64::mouse::mouse_interrupt;
|
||||
use crate::driver::mouse::MOUSE;
|
||||
use crate::driver::timer::TIMER;
|
||||
use crate::{arch::x86_64::gdt, driver::keyboard::keyboard_interrupt_handler, println};
|
||||
use lazy_static::lazy_static;
|
||||
@@ -20,16 +22,16 @@ pub static PICS: Mutex<ChainedPics> =
|
||||
pub enum InterruptIndex {
|
||||
Timer = PIC_1_OFFSET,
|
||||
Keyboard = PIC_1_OFFSET + 1,
|
||||
Mouse = PIC_2_OFFSET + 4,
|
||||
// RTC = PIC_2_OFFSET,
|
||||
// ATA_primary = PIC_2_OFFSET + 7
|
||||
// ATA_secondary = PIC_2_OFFSET + 8
|
||||
}
|
||||
|
||||
impl InterruptIndex {
|
||||
pub fn as_u8(self) -> u8 {
|
||||
self as u8
|
||||
}
|
||||
|
||||
fn as_usize(self) -> usize {
|
||||
usize::from(self.as_u8())
|
||||
}
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
@@ -45,6 +47,7 @@ lazy_static! {
|
||||
idt.page_fault.set_handler_fn(page_fault_handler);
|
||||
idt.general_protection_fault.set_handler_fn(gpf_handler);
|
||||
idt[InterruptIndex::Keyboard.as_u8()].set_handler_fn(keyboard_interrupt_handler);
|
||||
idt[InterruptIndex::Mouse.as_u8()].set_handler_fn(mouse_interrupt_handler);
|
||||
idt
|
||||
};
|
||||
}
|
||||
@@ -91,3 +94,22 @@ extern "x86-interrupt" fn timer_interrupt_handler(_stack_frame: InterruptStackFr
|
||||
.notify_end_of_interrupt(InterruptIndex::Timer.as_u8());
|
||||
}
|
||||
}
|
||||
|
||||
extern "x86-interrupt" fn mouse_interrupt_handler(_stack_frame: InterruptStackFrame) {
|
||||
let interrupt_result = mouse_interrupt();
|
||||
|
||||
if let Some(interrupt_result) = interrupt_result {
|
||||
MOUSE.interrupt(
|
||||
interrupt_result.0,
|
||||
interrupt_result.1,
|
||||
interrupt_result.2,
|
||||
interrupt_result.3,
|
||||
interrupt_result.4,
|
||||
);
|
||||
}
|
||||
|
||||
unsafe {
|
||||
PICS.lock()
|
||||
.notify_end_of_interrupt(InterruptIndex::Mouse.as_u8());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,4 +2,5 @@ pub mod gdt;
|
||||
pub mod heap;
|
||||
pub mod init;
|
||||
pub mod interrupts;
|
||||
pub mod mouse;
|
||||
pub mod paging;
|
||||
|
||||
230
kernel/src/arch/x86_64/mouse.rs
Normal file
230
kernel/src/arch/x86_64/mouse.rs
Normal file
@@ -0,0 +1,230 @@
|
||||
// Comment to self: WHY IS THIS SOO HARD
|
||||
|
||||
use crate::util::get_bit;
|
||||
use core::sync::atomic::{AtomicU8, Ordering};
|
||||
|
||||
use x86_64::instructions::{interrupts::without_interrupts, port::Port};
|
||||
|
||||
static CURRENTLY_RECEIVING_STATE: AtomicU8 = AtomicU8::new(0);
|
||||
static FLAGS_BYTE: AtomicU8 = AtomicU8::new(0);
|
||||
static X_DELTA_BYTE: AtomicU8 = AtomicU8::new(0);
|
||||
static Y_DELTA_BYTE: AtomicU8 = AtomicU8::new(0);
|
||||
|
||||
fn wait_input_buffer_clear(command_port: &mut Port<u8>) {
|
||||
unsafe {
|
||||
loop {
|
||||
let status = command_port.read();
|
||||
// IBF is bit 1: clear means we can write
|
||||
if (status & 0b10) == 0 {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn wait_output_buffer_full(command_port: &mut Port<u8>) {
|
||||
unsafe {
|
||||
loop {
|
||||
let status = command_port.read();
|
||||
// OBF is bit 0: 1 = data available to read
|
||||
if (status & 0b1) != 0 {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn read_ccb(command_port: &mut Port<u8>, data_port: &mut Port<u8>) -> u8 {
|
||||
unsafe {
|
||||
wait_input_buffer_clear(command_port);
|
||||
command_port.write(0x20);
|
||||
wait_output_buffer_full(command_port);
|
||||
return data_port.read();
|
||||
}
|
||||
}
|
||||
fn write_ccb(command_port: &mut Port<u8>, data_port: &mut Port<u8>, value: u8) {
|
||||
unsafe {
|
||||
wait_input_buffer_clear(command_port);
|
||||
command_port.write(0x60);
|
||||
wait_input_buffer_clear(command_port);
|
||||
data_port.write(value);
|
||||
}
|
||||
}
|
||||
|
||||
fn check_clear_and_write(command_port: &mut Port<u8>, inst: u8) {
|
||||
unsafe {
|
||||
wait_input_buffer_clear(command_port);
|
||||
command_port.write(inst);
|
||||
}
|
||||
}
|
||||
|
||||
fn write_and_expect_output(
|
||||
command_port: &mut Port<u8>,
|
||||
data_port: &mut Port<u8>,
|
||||
inst: u8,
|
||||
expected_output: u8,
|
||||
) -> bool {
|
||||
unsafe {
|
||||
check_clear_and_write(command_port, inst);
|
||||
wait_output_buffer_full(command_port);
|
||||
return data_port.read() == expected_output;
|
||||
}
|
||||
}
|
||||
|
||||
fn clear_and_expect_output(
|
||||
command_port: &mut Port<u8>,
|
||||
data_port: &mut Port<u8>,
|
||||
expected_output: u8,
|
||||
) -> bool {
|
||||
unsafe {
|
||||
wait_input_buffer_clear(command_port);
|
||||
wait_output_buffer_full(command_port);
|
||||
return data_port.read() == expected_output;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn setup_mouse() -> u8 {
|
||||
without_interrupts(|| {
|
||||
let mut command_port: Port<u8> = Port::new(0x64);
|
||||
let mut data_port: Port<u8> = Port::new(0x60);
|
||||
|
||||
unsafe {
|
||||
check_clear_and_write(&mut command_port, 0xAD); // disable port 1
|
||||
check_clear_and_write(&mut command_port, 0xA7); // disable port 2
|
||||
|
||||
let mut ccb = read_ccb(&mut command_port, &mut data_port);
|
||||
|
||||
ccb = ccb | 0b00000001; // enable keyboard IRQ
|
||||
ccb = ccb | 0b00000010; // enable mouse IRQ
|
||||
ccb = ccb & 0b11011111; // disable mouse gating
|
||||
ccb = ccb & 0b10111111; // disable scancode translation
|
||||
|
||||
write_ccb(&mut command_port, &mut data_port, ccb);
|
||||
|
||||
check_clear_and_write(&mut command_port, 0xAE); // enable port 1
|
||||
check_clear_and_write(&mut command_port, 0xA8); // enable port 2
|
||||
|
||||
if !write_and_expect_output(&mut command_port, &mut data_port, 0xA9, 0x00) {
|
||||
// mouse test reply doesnt work!
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Reset Mouse
|
||||
wait_input_buffer_clear(&mut command_port);
|
||||
command_port.write(0xD4);
|
||||
wait_input_buffer_clear(&mut command_port);
|
||||
data_port.write(0xFF);
|
||||
|
||||
if !clear_and_expect_output(&mut command_port, &mut data_port, 0xFA) {
|
||||
// ACK
|
||||
return 2;
|
||||
}
|
||||
if !clear_and_expect_output(&mut command_port, &mut data_port, 0xAA) {
|
||||
// Self-test passed
|
||||
return 3;
|
||||
}
|
||||
if !clear_and_expect_output(&mut command_port, &mut data_port, 0x00) {
|
||||
// Mouse ID
|
||||
return 4;
|
||||
}
|
||||
|
||||
// Enable data reporting
|
||||
wait_input_buffer_clear(&mut command_port);
|
||||
command_port.write(0xD4);
|
||||
wait_input_buffer_clear(&mut command_port);
|
||||
data_port.write(0xF4);
|
||||
|
||||
if !clear_and_expect_output(&mut command_port, &mut data_port, 0xFA) {
|
||||
return 5; // ACK
|
||||
}
|
||||
|
||||
return 6;
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn reset_state() {
|
||||
CURRENTLY_RECEIVING_STATE.store(0, Ordering::Relaxed);
|
||||
FLAGS_BYTE.store(0, Ordering::Relaxed);
|
||||
X_DELTA_BYTE.store(0, Ordering::Relaxed);
|
||||
Y_DELTA_BYTE.store(0, Ordering::Relaxed);
|
||||
}
|
||||
|
||||
pub fn mouse_interrupt() -> Option<(u8, u8, u8, i16, i16)> {
|
||||
let mut command_port: Port<u8> = Port::new(0x64);
|
||||
let mut data_port: Port<u8> = Port::new(0x60);
|
||||
unsafe {
|
||||
if (command_port.read() & 0x20) == 0 {
|
||||
// if this interrupt is not for the mouse, return
|
||||
return None;
|
||||
}
|
||||
|
||||
let byte = data_port.read();
|
||||
|
||||
let state_idx = CURRENTLY_RECEIVING_STATE.fetch_add(1, Ordering::Relaxed);
|
||||
|
||||
if state_idx == 0 {
|
||||
if (byte & 0x08) == 0 {
|
||||
// if sync bit unset, return
|
||||
reset_state();
|
||||
return None;
|
||||
}
|
||||
|
||||
if (byte & 0b0100_0000) != 0 {
|
||||
// if x overflow set, return
|
||||
reset_state();
|
||||
return None;
|
||||
}
|
||||
|
||||
if (byte & 0b1000_0000) != 0 {
|
||||
// if y overflow set, return
|
||||
reset_state();
|
||||
return None;
|
||||
}
|
||||
|
||||
FLAGS_BYTE.store(byte, Ordering::Relaxed);
|
||||
None
|
||||
} else if state_idx == 1 {
|
||||
X_DELTA_BYTE.store(byte, Ordering::Relaxed);
|
||||
None
|
||||
} else if state_idx == 2 {
|
||||
Y_DELTA_BYTE.store(byte, Ordering::Relaxed);
|
||||
let flags = FLAGS_BYTE.load(Ordering::Relaxed);
|
||||
let left_button_pressed = get_bit(flags, 0);
|
||||
let right_button_pressed = get_bit(flags, 1);
|
||||
let middle_button_pressed = get_bit(flags, 2);
|
||||
let x_delta_sign = get_bit(flags, 4);
|
||||
let y_delta_sign = get_bit(flags, 5);
|
||||
|
||||
let x_delta: i16 = {
|
||||
let x_delta = X_DELTA_BYTE.load(Ordering::Relaxed);
|
||||
if x_delta_sign == 1 {
|
||||
(x_delta as i16) - 256
|
||||
} else {
|
||||
x_delta as i16
|
||||
}
|
||||
};
|
||||
|
||||
let y_delta: i16 = -{
|
||||
let y_delta = Y_DELTA_BYTE.load(Ordering::Relaxed);
|
||||
if y_delta_sign == 1 {
|
||||
(y_delta as i16) - 256
|
||||
} else {
|
||||
y_delta as i16
|
||||
}
|
||||
};
|
||||
|
||||
reset_state();
|
||||
|
||||
Some((
|
||||
left_button_pressed,
|
||||
right_button_pressed,
|
||||
middle_button_pressed,
|
||||
x_delta,
|
||||
y_delta,
|
||||
))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -32,6 +32,7 @@ impl Framebuffer {
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn put_pixel(&mut self, x: usize, y: usize, color: u32) {
|
||||
if x >= self.width || y >= self.height {
|
||||
return;
|
||||
@@ -45,6 +46,20 @@ impl Framebuffer {
|
||||
self.back_buffer[idx] = color;
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn fill_span(&mut self, x: usize, y: usize, len: usize, color: u32) {
|
||||
if y >= self.height || x >= self.width || len == 0 {
|
||||
return;
|
||||
}
|
||||
let max_len = self.width - x;
|
||||
let len = core::cmp::min(len, max_len);
|
||||
let start = y * self.pitch + x;
|
||||
let end = start + len;
|
||||
unsafe {
|
||||
self.back_buffer.get_unchecked_mut(start..end).fill(color);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn swap(&mut self) {
|
||||
unsafe {
|
||||
core::ptr::copy_nonoverlapping(
|
||||
@@ -69,8 +84,10 @@ pub fn init_framebuffer(raw: &LimineFramebuffer) {
|
||||
}
|
||||
|
||||
pub fn with_framebuffer<F: FnOnce(&mut Framebuffer)>(f: F) {
|
||||
without_interrupts(|| {
|
||||
let mut guard = FRAMEBUFFER.lock();
|
||||
if let Some(fb) = guard.as_mut() {
|
||||
f(fb);
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1,9 +1,19 @@
|
||||
use crate::driver::graphics::{base::rgb, font_render::render_text, framebuffer::Framebuffer};
|
||||
use alloc::{format, string::ToString};
|
||||
use core::f32::consts::PI;
|
||||
use micromath::F32Ext;
|
||||
use crate::driver::graphics::framebuffer::Framebuffer;
|
||||
|
||||
pub fn line(framebuffer: &mut Framebuffer, x0: usize, y0: usize, x1: usize, y1: usize, color: u32) {
|
||||
if y0 == y1 {
|
||||
let (xa, xb) = if x0 <= x1 { (x0, x1) } else { (x1, x0) };
|
||||
framebuffer.fill_span(xa, y0, xb - xa + 1, color);
|
||||
return;
|
||||
}
|
||||
if x0 == x1 {
|
||||
let (ya, yb) = if y0 <= y1 { (y0, y1) } else { (y1, y0) };
|
||||
for yy in ya..=yb {
|
||||
framebuffer.put_pixel(x0, yy, color);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
let mut x0 = x0 as isize;
|
||||
let mut y0 = y0 as isize;
|
||||
let x1 = x1 as isize;
|
||||
@@ -58,23 +68,58 @@ pub fn triangle_outline(
|
||||
line(framebuffer, x2, y2, x3, y3, color);
|
||||
}
|
||||
|
||||
pub fn circle_outline(framebuffer: &mut Framebuffer, x: usize, y: usize, radius: f32, color: u32) {
|
||||
let mut i: f32 = 0.0;
|
||||
pub fn circle_outline(
|
||||
framebuffer: &mut Framebuffer,
|
||||
cx: usize,
|
||||
cy: usize,
|
||||
radius: usize,
|
||||
color: u32,
|
||||
) {
|
||||
let mut x = radius as isize;
|
||||
let mut y: isize = 0;
|
||||
let mut d = 1 - x;
|
||||
let cx = cx as isize;
|
||||
let cy = cy as isize;
|
||||
|
||||
loop {
|
||||
i += 0.1;
|
||||
#[inline(always)]
|
||||
fn plot_points(
|
||||
framebuffer: &mut Framebuffer,
|
||||
cx: isize,
|
||||
cy: isize,
|
||||
x: isize,
|
||||
y: isize,
|
||||
color: u32,
|
||||
) {
|
||||
framebuffer.put_pixel((cx + x) as usize, (cy + y) as usize, color);
|
||||
framebuffer.put_pixel((cx + y) as usize, (cy + x) as usize, color);
|
||||
framebuffer.put_pixel((cx - y) as usize, (cy + x) as usize, color);
|
||||
framebuffer.put_pixel((cx - x) as usize, (cy + y) as usize, color);
|
||||
framebuffer.put_pixel((cx - x) as usize, (cy - y) as usize, color);
|
||||
framebuffer.put_pixel((cx - y) as usize, (cy - x) as usize, color);
|
||||
framebuffer.put_pixel((cx + y) as usize, (cy - x) as usize, color);
|
||||
framebuffer.put_pixel((cx + x) as usize, (cy - y) as usize, color);
|
||||
}
|
||||
|
||||
let x1: f32 = radius * (i * core::f32::consts::PI / 180.0).cos();
|
||||
let y1: f32 = radius * (i * PI / 180.0).sin();
|
||||
framebuffer.put_pixel((x as f32 + x1) as usize, (y as f32 + y1) as usize, color);
|
||||
while y <= x {
|
||||
plot_points(framebuffer, cx, cy, x, y, color);
|
||||
y += 1;
|
||||
|
||||
if i >= 360.0 {
|
||||
break;
|
||||
if d <= 0 {
|
||||
d += 2 * y + 1;
|
||||
} else {
|
||||
x -= 1;
|
||||
d += 2 * (y - x) + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn circle_filled(framebuffer: &mut Framebuffer, x0: usize, y0: usize, radius: f32, color: u32) {
|
||||
pub fn circle_filled(
|
||||
framebuffer: &mut Framebuffer,
|
||||
x0: usize,
|
||||
y0: usize,
|
||||
radius: usize,
|
||||
color: u32,
|
||||
) {
|
||||
let mut x = radius as isize;
|
||||
let mut y: isize = 0;
|
||||
let mut x_change: isize = 1 - (radius as isize * 2);
|
||||
@@ -113,10 +158,8 @@ pub fn rectangle_filled(
|
||||
height: usize,
|
||||
color: u32,
|
||||
) {
|
||||
for fb_x in x..x + width {
|
||||
for fb_y in y..y + height {
|
||||
framebuffer.put_pixel(fb_x, fb_y, color);
|
||||
}
|
||||
for yy in y..y + height {
|
||||
framebuffer.fill_span(x, yy, width, color);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
pub mod graphics;
|
||||
pub mod keyboard;
|
||||
pub mod mouse;
|
||||
pub mod serial;
|
||||
pub mod timer;
|
||||
|
||||
67
kernel/src/driver/mouse.rs
Normal file
67
kernel/src/driver/mouse.rs
Normal file
@@ -0,0 +1,67 @@
|
||||
use core::sync::atomic::{AtomicI16, AtomicU8, Ordering};
|
||||
|
||||
use spin::Mutex;
|
||||
|
||||
pub struct Mouse {
|
||||
left_button_pressed: AtomicU8,
|
||||
right_button_pressed: AtomicU8,
|
||||
middle_button_pressed: AtomicU8,
|
||||
x_delta: AtomicI16,
|
||||
y_delta: AtomicI16,
|
||||
status: AtomicU8,
|
||||
}
|
||||
|
||||
impl Mouse {
|
||||
const fn new() -> Mouse {
|
||||
Mouse {
|
||||
left_button_pressed: AtomicU8::new(0),
|
||||
right_button_pressed: AtomicU8::new(0),
|
||||
middle_button_pressed: AtomicU8::new(0),
|
||||
x_delta: AtomicI16::new(0),
|
||||
y_delta: AtomicI16::new(0),
|
||||
status: AtomicU8::new(0),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn interrupt(
|
||||
&self,
|
||||
left_button_pressed: u8,
|
||||
right_button_pressed: u8,
|
||||
middle_button_pressed: u8,
|
||||
x_delta: i16,
|
||||
y_delta: i16,
|
||||
) {
|
||||
self.left_button_pressed
|
||||
.store(left_button_pressed, Ordering::Relaxed);
|
||||
self.right_button_pressed
|
||||
.store(right_button_pressed, Ordering::Relaxed);
|
||||
self.middle_button_pressed
|
||||
.store(middle_button_pressed, Ordering::Relaxed);
|
||||
self.x_delta.fetch_add(x_delta, Ordering::Relaxed);
|
||||
self.y_delta.fetch_add(y_delta, Ordering::Relaxed);
|
||||
}
|
||||
|
||||
pub fn is_left_button_pressed(&self) -> u8 {
|
||||
self.left_button_pressed.load(Ordering::Relaxed)
|
||||
}
|
||||
pub fn is_right_button_pressed(&self) -> u8 {
|
||||
self.right_button_pressed.load(Ordering::Relaxed)
|
||||
}
|
||||
pub fn is_middle_button_pressed(&self) -> u8 {
|
||||
self.middle_button_pressed.load(Ordering::Relaxed)
|
||||
}
|
||||
pub fn get_x_delta(&self) -> i16 {
|
||||
self.x_delta.swap(0, Ordering::Relaxed)
|
||||
}
|
||||
pub fn get_y_delta(&self) -> i16 {
|
||||
self.y_delta.swap(0, Ordering::Relaxed)
|
||||
}
|
||||
pub fn set_status(&self, status: u8) {
|
||||
self.status.store(status, Ordering::Relaxed);
|
||||
}
|
||||
pub fn get_status(&self) -> u8 {
|
||||
self.status.load(Ordering::Relaxed)
|
||||
}
|
||||
}
|
||||
|
||||
pub static MOUSE: Mouse = Mouse::new();
|
||||
@@ -73,8 +73,10 @@ pub fn init_serial_console(start_x: usize, start_y: usize) {
|
||||
}
|
||||
|
||||
pub fn with_serial_console<F: FnOnce(&mut SerialConsole)>(f: F) {
|
||||
without_interrupts(|| {
|
||||
let mut guard = SERIAL_CONSOLE.lock();
|
||||
if let Some(fb) = guard.as_mut() {
|
||||
f(fb);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ use limine::request::{
|
||||
DateAtBootRequest, FramebufferRequest, HhdmRequest, MemoryMapRequest, MpRequest,
|
||||
RequestsEndMarker, RequestsStartMarker,
|
||||
};
|
||||
use x86_64::instructions::interrupts::without_interrupts;
|
||||
pub mod arch;
|
||||
pub mod driver;
|
||||
pub mod util;
|
||||
@@ -20,6 +21,7 @@ use crate::driver::graphics::framebuffer::{init_framebuffer, with_framebuffer};
|
||||
use crate::driver::graphics::primitives::{
|
||||
circle_filled, circle_outline, rectangle_filled, rectangle_outline, triangle_outline,
|
||||
};
|
||||
use crate::driver::mouse::MOUSE;
|
||||
use crate::driver::serial::{ConsoleWriter, init_serial_console, with_serial_console};
|
||||
use crate::driver::timer::TIMER;
|
||||
use crate::util::test_performance;
|
||||
@@ -89,7 +91,6 @@ pub fn _print(args: core::fmt::Arguments) {
|
||||
};
|
||||
let _ = writer.write_fmt(args);
|
||||
});
|
||||
fb.swap();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -99,9 +100,12 @@ unsafe extern "C" fn kmain() -> ! {
|
||||
// removed by the linker.
|
||||
assert!(BASE_REVISION.is_supported());
|
||||
|
||||
let mapper;
|
||||
let frame_allocator;
|
||||
|
||||
if let Some(hhdm_response) = HHDM_REQUEST.get_response() {
|
||||
if let Some(memory_map_response) = MEMORY_MAP_REQUEST.get_response() {
|
||||
let (mapper, frame_allocator) = init(hhdm_response, memory_map_response);
|
||||
(mapper, frame_allocator) = init(hhdm_response, memory_map_response);
|
||||
} else {
|
||||
kernel_crash(); // Could not get required info from Limine's memory map.
|
||||
}
|
||||
@@ -134,25 +138,67 @@ unsafe extern "C" fn kmain() -> ! {
|
||||
|
||||
sleep(500);
|
||||
|
||||
let mut current_mouse_x: usize = 100;
|
||||
let mut current_mouse_y: usize = 100;
|
||||
let mut mouse_status = 0;
|
||||
let mut width = 0;
|
||||
let mut height = 0;
|
||||
let mut x_delta = 0;
|
||||
let mut y_delta = 0;
|
||||
|
||||
loop {
|
||||
with_serial_console(|serial_console| serial_console.clear(0, 0));
|
||||
|
||||
with_framebuffer(|fb| fb.clear(rgb(253, 129, 0)));
|
||||
test_performance(|| {
|
||||
with_framebuffer(|mut fb| {
|
||||
fb.clear(rgb(253, 129, 0));
|
||||
width = fb.width;
|
||||
height = fb.height;
|
||||
|
||||
// rectangle_filled(&mut fb, 700, 400, 200, 200, rgb(0, 0, 0));
|
||||
// rectangle_outline(&mut fb, 400, 400, 100, 100, rgb(0, 0, 0));
|
||||
// circle_filled(&mut fb, 200, 200, 100.0, rgb(0, 0, 0));
|
||||
|
||||
circle_outline(&mut fb, 400, 200, 100.0, rgb(0, 0, 0));
|
||||
rectangle_filled(&mut fb, 700, 400, 200, 200, rgb(0, 0, 0));
|
||||
rectangle_outline(&mut fb, 400, 400, 100, 100, rgb(0, 0, 0));
|
||||
circle_filled(&mut fb, 200, 200, 100, rgb(0, 0, 0));
|
||||
circle_outline(&mut fb, 400, 200, 100, rgb(0, 0, 0));
|
||||
triangle_outline(&mut fb, 100, 400, 200, 400, 150, 600, rgb(0, 0, 0));
|
||||
});
|
||||
|
||||
let (hours, minutes, seconds) =
|
||||
unix_to_hms(TIMER.get_date_at_boot() + (TIMER.now().elapsed()) / 1000);
|
||||
|
||||
print!("{:?}:{:?}:{:?}", hours, minutes, seconds);
|
||||
mouse_status = MOUSE.get_status();
|
||||
x_delta = MOUSE.get_x_delta() / 5;
|
||||
y_delta = MOUSE.get_y_delta() / 5;
|
||||
if x_delta != 0 {
|
||||
current_mouse_x = (current_mouse_x as isize + x_delta as isize).max(0) as usize;
|
||||
}
|
||||
|
||||
if y_delta != 0 {
|
||||
current_mouse_y = (current_mouse_y as isize + y_delta as isize).max(0) as usize;
|
||||
}
|
||||
|
||||
if current_mouse_x > width {
|
||||
current_mouse_x = width - 15;
|
||||
}
|
||||
|
||||
if current_mouse_y > height {
|
||||
current_mouse_y = height - 15;
|
||||
}
|
||||
|
||||
print!(
|
||||
"{:?}:{:?}:{:?}\n{:?} {:?} {:?} {:?} {:?}",
|
||||
hours,
|
||||
minutes,
|
||||
seconds,
|
||||
mouse_status,
|
||||
current_mouse_x,
|
||||
current_mouse_y,
|
||||
x_delta,
|
||||
y_delta
|
||||
);
|
||||
});
|
||||
with_framebuffer(|fb| {
|
||||
rectangle_filled(fb, current_mouse_x, current_mouse_y, 15, 15, rgb(0, 255, 0));
|
||||
fb.swap();
|
||||
});
|
||||
sleep(16);
|
||||
}
|
||||
}
|
||||
@@ -183,6 +229,8 @@ fn boot_animation() {
|
||||
|
||||
i += 1;
|
||||
|
||||
with_framebuffer(|fb| fb.swap());
|
||||
|
||||
sleep(200);
|
||||
}
|
||||
|
||||
|
||||
@@ -42,3 +42,7 @@ pub fn test_performance<F: FnOnce()>(function: F) {
|
||||
println!("took {} ms", (TIMER.now() - start).elapsed());
|
||||
ret
|
||||
}
|
||||
|
||||
pub fn get_bit(value: u8, position: u8) -> u8 {
|
||||
(value >> position) & 1
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user