diff --git a/Makefile b/Makefile index 458098e..d7df025 100644 --- a/Makefile +++ b/Makefile @@ -1,25 +1,25 @@ -.PHONY: clean run run-iso build_dir +.PHONY: clean run run-iso build-dir clean-build TARGET_DIR = target/x86-unknown-bare_metal/release -build/mxrox.iso: build/kernel.elf build_dir +build/mxrox.iso: build/kernel.elf build-dir cp 'grub.cfg' build/iso/boot/grub cp '$<' build/iso/boot grub-mkrescue -o '$@' build/iso -build/boot.o: boot.s build_dir +build/boot.o: boot.s build-dir nasm -f elf32 '$<' -o '$@' build/kernel.elf: linker.ld build/boot.o build/libkernel.a i686-elf-gcc -nostdlib -o $@ -T $^ -build/libkernel.a: build_dir +build/libkernel.a: build-dir rm -rf $(TARGET_DIR) rustup override set nightly cargo build --release cp $(TARGET_DIR)/libmxrox.a build/libkernel.a -build_dir: +build-dir: mkdir -p build mkdir -p build/iso mkdir -p build/iso/boot @@ -27,11 +27,13 @@ build_dir: build: build/mxrox.iso -clean: - cargo clean +clean-build: rm -rf build mkdir build +clean: clean-build + cargo clean + run-kernel: build/kernel.elf qemu-system-i386 -kernel '$<' -m 512M diff --git a/README.md b/README.md index 2f0ff10..98215f5 100644 --- a/README.md +++ b/README.md @@ -38,6 +38,7 @@ Internet resources where I found most information about OS dev - https://os.phil-opp.com/ - https://wiki.osdev.org/Interrupts_Tutorial - https://wiki.osdev.org/Interrupt_Vector_Table +- https://wiki.osdev.org/Inline_Assembly/Examples#I/O_access ### Contributing diff --git a/boot.s b/boot.s index c35bfa1..bcbdc3a 100644 --- a/boot.s +++ b/boot.s @@ -16,6 +16,60 @@ align 4 dd MBFLAGS dd CHECKSUM +; %macro isr_err_stub 1 +; isr_stub_%+%1: +; call exception_handler +; iret +; %endmacro + +; %macro isr_no_err_stub 1 +; isr_stub_%+%1: +; call exception_handler +; iret +; %endmacro + +; extern exception_handler +; isr_no_err_stub 0 +; isr_no_err_stub 1 +; isr_no_err_stub 2 +; isr_no_err_stub 3 +; isr_no_err_stub 4 +; isr_no_err_stub 5 +; isr_no_err_stub 6 +; isr_no_err_stub 7 +; isr_err_stub 8 +; isr_no_err_stub 9 +; isr_err_stub 10 +; isr_err_stub 11 +; isr_err_stub 12 +; isr_err_stub 13 +; isr_err_stub 14 +; isr_no_err_stub 15 +; isr_no_err_stub 16 +; isr_err_stub 17 +; isr_no_err_stub 18 +; isr_no_err_stub 19 +; isr_no_err_stub 20 +; isr_no_err_stub 21 +; isr_no_err_stub 22 +; isr_no_err_stub 23 +; isr_no_err_stub 24 +; isr_no_err_stub 25 +; isr_no_err_stub 26 +; isr_no_err_stub 27 +; isr_no_err_stub 28 +; isr_no_err_stub 29 +; isr_err_stub 30 +; isr_no_err_stub 31 + +; global isr_stub_table +; isr_stub_table: +; %assign i 0 +; %rep 32 +; dd isr_stub_%+i ; use DQ instead if targeting 64-bit +; %assign i i+1 +; %endrep + ; The multiboot standard does not define the value of the stack pointer register ; (esp) and it is up to the kernel to provide a stack. This allocates room for a ; small stack by creating a symbol at the bottom of it, then allocating 16384 diff --git a/src/kernel/heap.rs b/src/kernel/heap.rs index 7f8554a..9595ada 100644 --- a/src/kernel/heap.rs +++ b/src/kernel/heap.rs @@ -4,6 +4,8 @@ use core::mem; use core::cell::UnsafeCell; use core::sync::atomic::{AtomicUsize, Ordering}; +use super::terminal::log_info; + struct FreeListNode { size: usize, next: *mut FreeListNode, @@ -119,7 +121,9 @@ pub extern "C" fn memset(dest: *mut u8, value: i32, n: usize) -> *mut u8 { } pub fn init_heap(heap_start: usize, heap_size: usize) { - unsafe { + unsafe { ALLOCATOR.init(heap_start, heap_size); } + + log_info(&format!("Heap initialized on {heap_start} with size {heap_size}")); } diff --git a/src/kernel/interrupt.rs b/src/kernel/interrupt.rs new file mode 100644 index 0000000..1ed8aaf --- /dev/null +++ b/src/kernel/interrupt.rs @@ -0,0 +1,205 @@ +use core::ptr::write_volatile; +use core::arch::asm; + +use crate::kernel::util::{cli, sti}; + +use super::show_error; +use super::terminal::{log_error, log_info}; +use super::util::{inb, io_wait, outb}; + +const APIC_BASE: u32 = 0xFEE00000; +const APIC_EOI: u32 = APIC_BASE + 0x0B0; // End Of Interrupt +const APIC_SVR: u32 = APIC_BASE + 0x0F0; // Spurious Interrupt Vector Register + +const IA32_APIC_BASE_MSR: u32 = 0x1B; +const APIC_BASE_ENABLE: u64 = 1 << 11; + +const PIC1_COMMAND: u16 = 0x0020; +const PIC1_DATA: u16 = 0x0021; +const PIC2_COMMAND: u16 = 0x00A0; +const PIC2_DATA: u16 = 0x00A1; + +const ICW1_ICW4: u8 = 0x01; /* Indicates that ICW4 will be present */ +const ICW1_SINGLE: u8 = 0x02; /* Single (cascade) mode */ +const ICW1_INTERVAL4: u8 = 0x04; /* Call address interval 4 (8) */ +const ICW1_LEVEL: u8 = 0x08; /* Level triggered (edge) mode */ +const ICW1_INIT: u8 = 0x10; /* Initialization - required! */ + +const ICW4_8086: u8 = 0x01; /* 8086/88 (MCS-80/85) mode */ +const ICW4_AUTO: u8 = 0x02; /* Auto (normal) EOI */ +const ICW4_BUF_SLAVE: u8 = 0x08; /* Buffered mode/slave */ +const ICW4_BUF_MASTER: u8 = 0x0C; /* Buffered mode/master */ +const ICW4_SFNM: u8 = 0x10; /* Special fully nested (not) */ + +const PIC_EOI: u8 = 0x20; /* End-of-interrupt command code */ + +const APIC_ENABLED: bool = false; + +#[repr(C, packed)] +struct IDTDescriptor { + limit: u16, + base: u32, +} + +#[repr(C, packed)] +#[derive(Copy, Clone)] +struct IDTEntry { + offset_low: u16, + selector: u16, + ist: u8, + type_attr: u8, + offset_mid: u16, +} + +const IDT_MAX_DESCRIPTORS: usize = 256; +static mut IDT: [IDTEntry; IDT_MAX_DESCRIPTORS] = [IDTEntry { + offset_low: 0, + selector: 0, + ist: 0, + type_attr: 0, + offset_mid: 0, +}; IDT_MAX_DESCRIPTORS]; + +// static mut VECTORS: [bool; 32] = [false; 32]; +static mut IDTR: IDTDescriptor = IDTDescriptor { limit: 0, base: 0 }; + +// extern "C" { +// static ist_stub_table: [u32; 32]; +// } + +pub unsafe fn idt_set_descriptor(vector: u8, handler: u32, type_attr: u8) { + IDT[vector as usize] = IDTEntry { + offset_low: handler as u16, + selector: 0x08, // Kernel code segment + ist: type_attr, + type_attr, + offset_mid: (handler >> 16) as u16 + }; +} + +pub unsafe fn load_idt() { + IDTR.base = &IDT as *const _ as u32; + IDTR.limit = (size_of::() * IDT_MAX_DESCRIPTORS - 1) as u16; + + // for vector in 0..32 { + // idt_set_descriptor(vector, ist_stub_table[vector as usize], 0x8E); + // VECTORS[vector as usize] = true; + // } + + asm!("lidt [{}]", in(reg) &IDTR); + asm!("sti"); +} + +unsafe fn is_apic_available() -> bool { + if !APIC_ENABLED { + return false; + } + + let edx: u32; + + asm!( + "cpuid", + inout("eax") 1 => _, + lateout("edx") edx + ); + + (edx & (1 << 9)) != 0 +} + +pub unsafe extern "C" fn exception_handler() { + log_error("Unknown error"); + asm!("cli; hlt"); + loop {} +} + +unsafe fn send_apic_eoi() { + write_volatile(APIC_EOI as *mut u32, 0); +} + +unsafe fn send_pic_eoi(irq: usize) { + if irq >= 8 { + write_volatile(PIC2_COMMAND as *mut u8, PIC_EOI); + } + write_volatile(PIC1_COMMAND as *mut u8, PIC_EOI); +} + +pub unsafe fn init_pic() { + let offset1 = 0x20; + let offset2 = 0x28; + + let a1 = inb(PIC1_DATA); // save masks + let a2 = inb(PIC2_DATA); + + outb(PIC1_COMMAND, ICW1_INIT | ICW1_ICW4); // starts the initialization sequence (in cascade mode) + io_wait(); + outb(PIC2_COMMAND, ICW1_INIT | ICW1_ICW4); + io_wait(); + outb(PIC1_DATA, offset1); // ICW2: Master PIC vector offset + io_wait(); + outb(PIC2_DATA, offset2); // ICW2: Slave PIC vector offset + io_wait(); + outb(PIC1_DATA, 4); // ICW3: tell Master PIC that there is a slave PIC at IRQ2 (0000 0100) + io_wait(); + outb(PIC2_DATA, 2); // ICW3: tell Slave PIC its cascade identity (0000 0010) + io_wait(); + + outb(PIC1_DATA, ICW4_8086); // ICW4: have the PICs use 8086 mode (and not 8080 mode) + io_wait(); + outb(PIC2_DATA, ICW4_8086); + io_wait(); + + outb(PIC1_DATA, a1); // restore saved masks. + outb(PIC2_DATA, a2); +} + +pub unsafe fn disable_pic() { + outb(PIC1_DATA, 0xff); + outb(PIC2_DATA, 0xff); +} + +pub fn send_eoi(irq: usize) { + unsafe { + if is_apic_available() { + send_apic_eoi() + } else { + send_pic_eoi(irq) + } + } +} + +unsafe fn read_msr(msr: u32) -> u64 { + let low: u32; + let high: u32; + asm!("rdmsr", in("ecx") msr, out("eax") low, out("edx") high); + ((high as u64) << 32) | (low as u64) +} + +unsafe fn write_msr(msr: u32, value: u64) { + let low = value as u32; + let high = (value >> 32) as u32; + asm!("wrmsr", in("ecx") msr, in("eax") low, in("edx") high); +} + +pub unsafe fn init_apic() { + let apic_base = read_msr(IA32_APIC_BASE_MSR) | APIC_BASE_ENABLE; + write_msr(IA32_APIC_BASE_MSR, apic_base); + let svr_value: u32 = 0x1FF; + write_volatile(APIC_SVR as *mut u32, svr_value); + write_volatile(APIC_EOI as *mut u32, 0); +} + +pub fn init_interrupts() { + unsafe { + init_pic(); + log_info("PIC initialized"); + + if is_apic_available() { + disable_pic(); + log_info("Disable PIC"); + init_apic(); + log_info("APIC initialized"); + } + + load_idt(); + } +} diff --git a/src/kernel/irq.rs b/src/kernel/irq.rs deleted file mode 100644 index eed1dd1..0000000 --- a/src/kernel/irq.rs +++ /dev/null @@ -1,132 +0,0 @@ -use core::ptr::write_volatile; -use core::arch::asm; - -const APIC_BASE: u32 = 0xFEE00000; - -const APIC_EOI: u32 = APIC_BASE + 0x0B0; -const APIC_SVR: u32 = APIC_BASE + 0x0F0; - -const PIC1_CMD: u16 = 0x20; -const PIC1_DATA: u16 = 0x21; -const PIC2_CMD: u16 = 0xA0; -const PIC2_DATA: u16 = 0xA1; - -const ICW1_INIT: u8 = 0x10; -const ICW1_ICW4: u8 = 0x01; -const ICW4_8086: u8 = 0x01; - -const PIC_EOI: u8 = 0x20; /* End-of-interrupt command code */ - -const APIC_ENABLED: bool = false; - - -#[repr(C, packed)] -#[derive(Clone, Copy)] -pub struct IdtEntry { - offset_low: u16, - selector: u16, - ist: u8, - type_attr: u8, - offset_middle: u16 -} - -pub const IDT_SIZE: usize = 256; - -#[repr(C)] -pub struct Idt { - entries: [IdtEntry; IDT_SIZE], -} - -static mut IDT: Idt = Idt { - entries: [IdtEntry { - offset_low: 0, - selector: 0, - ist: 0, - type_attr: 0, - offset_middle: 0, - }; IDT_SIZE], -}; - -unsafe fn is_apic_available() -> bool { - if !APIC_ENABLED { - return false; - } - - let edx: u32; - - asm!( - "cpuid", - inout("eax") 1 => _, - lateout("edx") edx - ); - - (edx & (1 << 9)) != 0 -} - -unsafe fn init_idt() { - asm!("lidt [{}]", "sti", in(reg) &IDT as *const _); -} - -unsafe fn init_apic() { - write_volatile(APIC_SVR as *mut u32, 0x100 | 0x1); -} - -unsafe fn send_apic_eoi() { - write_volatile(APIC_EOI as *mut u32, 0); -} - -unsafe fn send_pic_eoi(irq: usize) { - if irq >= 8 { write_volatile(PIC2_CMD as *mut u8, PIC_EOI); } - write_volatile(PIC1_CMD as *mut u8, PIC_EOI); -} - -unsafe fn init_pic() { - write_volatile(PIC1_CMD as *mut u8, ICW1_INIT | ICW1_ICW4); - write_volatile(PIC2_CMD as *mut u8, ICW1_INIT | ICW1_ICW4); - - write_volatile(PIC1_DATA as *mut u8, 0x20); - write_volatile(PIC2_DATA as *mut u8, 0x28); - - write_volatile(PIC1_DATA as *mut u8, 4); - write_volatile(PIC2_DATA as *mut u8, 2); - - write_volatile(PIC1_DATA as *mut u8, ICW4_8086); - write_volatile(PIC2_DATA as *mut u8, ICW4_8086); - - write_volatile(PIC1_DATA as *mut u8, 0xFB); - write_volatile(PIC2_DATA as *mut u8, 0xFF); -} - -pub fn send_eoi(irq: usize) { - unsafe { - if is_apic_available() { - send_apic_eoi() - } else { - send_pic_eoi(irq) - } - } -} - -/// all interrupt vectors you can find here: https://wiki.osdev.org/Interrupt_Vector_Table -pub fn register_idt(handler: u32, int_vec: u8) { - unsafe { - let entry = &mut IDT.entries[int_vec as usize]; - - entry.offset_low = handler as u16; - entry.selector = 0x08; - entry.ist = 0; - entry.type_attr = 0x8E; - entry.offset_middle = (handler >> 16) as u16; - } -} - -pub fn init_interrupts() { - unsafe { - init_idt(); - if is_apic_available() { - init_apic(); - } else { - init_pic(); - } - } -} \ No newline at end of file diff --git a/src/kernel/mod.rs b/src/kernel/mod.rs index 4eb3c05..f4ad3ab 100644 --- a/src/kernel/mod.rs +++ b/src/kernel/mod.rs @@ -1,35 +1,35 @@ -use irq::init_interrupts; +use interrupt::init_interrupts; use heap::init_heap; -use pit::init_pit; +use time::init_pit; use ps2::init_ps2; +use terminal::{log_info, println}; use vga::{ fill_with_color, - put_string, put_string_by_index, VGA_COLOR_BLACK, - VGA_COLOR_LIGHT_MAGENTA, VGA_COLOR_RED }; mod vga; mod ps2; -mod irq; -mod pit; +mod interrupt; +mod time; mod heap; mod util; +mod terminal; pub fn show_error(message: &str) { fill_with_color(VGA_COLOR_BLACK); put_string_by_index(0, message, VGA_COLOR_BLACK, VGA_COLOR_RED); + + loop {} } pub fn init_kernel() { - init_heap(16400, 16384); - init_pit(); - init_ps2(); + init_heap(0x200000, 1048576); init_interrupts(); - - fill_with_color(VGA_COLOR_BLACK); + init_pit(); + // init_ps2(); loop {} } \ No newline at end of file diff --git a/src/kernel/pit.rs b/src/kernel/pit.rs deleted file mode 100644 index 099af5f..0000000 --- a/src/kernel/pit.rs +++ /dev/null @@ -1,38 +0,0 @@ -use core::{ptr::write_volatile, sync::atomic::{AtomicUsize, Ordering}}; -use alloc::{sync::Arc, vec::Vec}; -use spin::RwLock; -use core::sync::atomic::AtomicBool; - -use super::irq::{register_idt, send_eoi}; - -const DIVISOR: u16 = ((1193182u32 + 500u32) / 1000) as u16; - -static TIMERS: RwLock>> = RwLock::new(Vec::new()); - -extern "C" fn pit_handler() { - for t in TIMERS.read().iter() { - t.fetch_add(1, Ordering::SeqCst); - } - send_eoi(0); -} - -pub fn init_pit() { - unsafe { - write_volatile(0x43 as *mut u8, 0x36); - write_volatile(0x40 as *mut u8, (DIVISOR & 0xFF) as u8); - write_volatile(0x40 as *mut u8, ((DIVISOR >> 8) & 0xFF) as u8); - } - register_idt(pit_handler as u32, 0x08); -} - -pub fn sleep(millis: usize) { - let atomic = Arc::new(AtomicUsize::new(0)); - - TIMERS.write().push(atomic.clone()); - - while atomic.load(Ordering::SeqCst) < millis { - core::hint::spin_loop(); // Уменьшаем нагрузку на CPU - } - - TIMERS.write().retain(|t| !Arc::ptr_eq(t, &atomic)); -} \ No newline at end of file diff --git a/src/kernel/ps2.rs b/src/kernel/ps2.rs index bd69920..3bcbe37 100644 --- a/src/kernel/ps2.rs +++ b/src/kernel/ps2.rs @@ -1,10 +1,8 @@ -use core::ptr::{read_volatile, write_volatile}; - use alloc::vec::Vec; -use crate::kernel::irq::register_idt; +use crate::kernel::interrupt::idt_set_descriptor; -use super::{irq::send_eoi, pit::sleep}; +use super::{interrupt::send_eoi, terminal::log_info, time::sleep, util::*}; const DATA_PORT: u16 = 0x60; const STATUS_PORT: u16 = 0x64; @@ -16,23 +14,24 @@ static mut DEVICE1_TYPE: Vec = Vec::new(); static mut DEVICE2_TYPE: Vec = Vec::new(); unsafe fn send_data(data: u8) { - write_volatile(DATA_PORT as *mut u8, data) + outb(DATA_PORT, data) } unsafe fn read_data() -> u8 { - read_volatile(DATA_PORT as *mut u8) + inb(DATA_PORT) } unsafe fn send_command(command: u8) { - write_volatile(STATUS_PORT as *mut u8, command) + outb(STATUS_PORT, command) } unsafe fn read_status() -> u8 { - read_volatile(STATUS_PORT as *mut u8) + inb(STATUS_PORT) } unsafe fn on_device_1_irq() { let data = read_data(); + log_info(&format!("[PS/2] device 1 data: 0x{:X}", data)); send_eoi(DEVICE1_IRQ); } @@ -86,28 +85,43 @@ unsafe fn send_identify() -> Vec { } unsafe fn is_ps2_2_device_enabled() -> bool { - true + false } pub fn init_ps2() { unsafe { send_command(0xAD); // disable device 1 + + log_info("[PS/2] Disabled device 1"); + if is_ps2_2_device_enabled() { - DEVICE2_TYPE = send_identify(); + // DEVICE2_TYPE = send_identify(); + log_info("[PS/2] Inspected device 2 identify"); send_command(0xA7); // disable device 2 + log_info("[PS/2] Disabled device 2"); } read_data(); // flush device data send_command(0x60); // set CCB command send_command(0x000000u8); // clear CCB + log_info("[PS/2] Flush device data and clear CCB"); + send_command(0xAE); // enable device 1 + log_info("[PS/2] Enable device 1"); + // DEVICE1_TYPE = send_identify(); + log_info("[PS/2] Inspected device 1 identify"); + if is_ps2_2_device_enabled() { - DEVICE1_TYPE = send_identify(); send_command(0xA8); // enable device 2 + log_info("[PS/2] Disable device 2"); + } + + idt_set_descriptor(0x21, on_device_1_irq as u32, 0x09); // bind handler for device 1 + log_info("[PS/2] Bind handler for device 1"); + if is_ps2_2_device_enabled() { + idt_set_descriptor(0x8B, on_device_2_irq as u32, 0x74); // bind handler for device 2 + log_info("[PS/2] Bind handler for device 2"); } } - - register_idt(on_device_1_irq as u32, 0x09); // bind handler for device 1 - register_idt(on_device_2_irq as u32, 0x74); // bind handler for device 2 } \ No newline at end of file diff --git a/src/kernel/terminal.rs b/src/kernel/terminal.rs new file mode 100644 index 0000000..974807d --- /dev/null +++ b/src/kernel/terminal.rs @@ -0,0 +1,48 @@ +use alloc::{string::{String, ToString}, vec::Vec}; +use spin::RwLock; + +use super::vga::{put_string, VGA_COLOR_BLACK, VGA_COLOR_WHITE, VGA_HEIGHT, VGA_WIDTH}; +use super::time::get_time_millis; + +static TEXT: RwLock = RwLock::new(String::new()); + +pub fn update() { + let text = TEXT.read().to_string(); + let mut lines: Vec = Vec::new(); + + for line in text.as_str().lines() { + let chars: Vec = line.chars().collect(); + lines.append(&mut chars.chunks(VGA_WIDTH) + .map(|chunk| chunk.iter().collect()) + .collect::>()) + } + + while lines.len() > VGA_HEIGHT { + lines.remove(0); + } + + for y in 0..VGA_HEIGHT { + if let Some(line) = lines.get(y) { + put_string(0, y, &(line.to_string()+&" ".repeat(VGA_WIDTH-line.len())), VGA_COLOR_BLACK, VGA_COLOR_WHITE); + } else { + put_string(0, y, &" ".repeat(VGA_WIDTH), VGA_COLOR_BLACK, VGA_COLOR_BLACK); + } + } +} + +pub fn print(text: &str) { + TEXT.write().push_str(text); + update(); +} + +pub fn println(text: &str) { + print(&format!("{text}\n")) +} + +pub fn log_info(text: &str) { + print(&format!("[{}] [INFO] {text}\n", get_time_millis())) +} + +pub fn log_error(text: &str) { + print(&format!("[{}] [FATAL] {text}\n", get_time_millis())) +} \ No newline at end of file diff --git a/src/kernel/time.rs b/src/kernel/time.rs new file mode 100644 index 0000000..f98689c --- /dev/null +++ b/src/kernel/time.rs @@ -0,0 +1,65 @@ +use core::{ptr::write_volatile, sync::atomic::{AtomicUsize, Ordering}}; +use alloc::{sync::Arc, vec::Vec}; +use spin::RwLock; + +use super::{interrupt::{idt_set_descriptor, load_idt, send_eoi}, terminal::log_info, util::{cli, io_wait, outb, sti}}; + +const DIVISOR: u16 = ((1193182u32 + 500u32) / 100) as u16; + +static TIMERS: RwLock>> = RwLock::new(Vec::new()); +static TIME_MILLIS: AtomicUsize = AtomicUsize::new(0); +static TIME: AtomicUsize = AtomicUsize::new(0); + +extern "C" fn pit_handler() { + for t in TIMERS.read().iter() { + t.fetch_add(1, Ordering::SeqCst); + } + + if TIME_MILLIS.fetch_add(1, Ordering::SeqCst) >= 999 { + TIME_MILLIS.store(0, Ordering::SeqCst); + TIME.fetch_add(1, Ordering::SeqCst); + log_info("proshlo second"); + } + + send_eoi(0); +} + +pub fn get_time_seconds() -> usize { + TIME.load(Ordering::SeqCst) +} + +pub fn get_time_millis() -> usize { + TIME.load(Ordering::SeqCst) * 1000 + TIME_MILLIS.load(Ordering::SeqCst) +} + +pub fn init_pit() { + log_info("PIT initialization"); + + unsafe { + outb(0x43, 0x36); + cli(); + outb(0x40, (DIVISOR & 0xFF) as u8); + outb(0x40, ((DIVISOR & 0xFF) >> 8) as u8); + + log_info("PIT initialized"); + log_info(&format!("{}", pit_handler as u32)); + + idt_set_descriptor(0x20, pit_handler as u32, 0x8E); + log_info("PIT registered"); + load_idt(); + + log_info("PIT loaded idt"); + } +} + +pub fn sleep(millis: usize) { + let atomic = Arc::new(AtomicUsize::new(0)); + + TIMERS.write().push(atomic.clone()); + + while atomic.load(Ordering::SeqCst) < millis { + core::hint::spin_loop(); + } + + TIMERS.write().retain(|t| !Arc::ptr_eq(t, &atomic)); +} \ No newline at end of file diff --git a/src/kernel/util.rs b/src/kernel/util.rs index e69de29..2c57d70 100644 --- a/src/kernel/util.rs +++ b/src/kernel/util.rs @@ -0,0 +1,27 @@ +use core::arch::asm; + +pub unsafe fn outb(port: u16, value: u8) { + asm!("out dx, al", in("dx") port, in("al") value, options(nostack, preserves_flags)); +} + +pub unsafe fn inb(port: u16) -> u8 { + let result: u8; + asm!("inb %dx, %al", in("dx") port, out("al") result, options(nostack, preserves_flags, att_syntax)); + result +} + +pub unsafe fn nop() { + asm!("nop", options(nostack, preserves_flags)); +} + +pub unsafe fn io_wait() { + outb(0x80, 0); +} + +pub unsafe fn sti() { + asm!("sti"); +} + +pub unsafe fn cli() { + asm!("cli"); +} \ No newline at end of file