many changes and especially identify ps/2

This commit is contained in:
MeexReay 2025-02-01 19:31:26 +03:00
parent a643b5ba1e
commit 70bd58e5ec
8 changed files with 264 additions and 38 deletions

32
Cargo.lock generated
View File

@ -2,6 +2,12 @@
# It is not intended for manual editing.
version = 4
[[package]]
name = "autocfg"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
[[package]]
name = "bit_field"
version = "0.10.2"
@ -14,11 +20,22 @@ version = "2.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f68f53c83ab957f72c32642f3868eec03eb974d1fb82e453128456482613d36"
[[package]]
name = "lock_api"
version = "0.4.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17"
dependencies = [
"autocfg",
"scopeguard",
]
[[package]]
name = "mxrox"
version = "0.1.0"
dependencies = [
"no-std-compat 0.4.1",
"spin",
"stable-vec",
"x86_64",
]
@ -41,6 +58,21 @@ version = "1.0.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f7c45b9784283f1b2e7fb61b42047c2fd678ef0960d4f6f1eba131594cc369d4"
[[package]]
name = "scopeguard"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
[[package]]
name = "spin"
version = "0.9.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67"
dependencies = [
"lock_api",
]
[[package]]
name = "stable-vec"
version = "0.4.1"

View File

@ -10,6 +10,7 @@ edition = "2021"
stable-vec = "0.4.1"
no-std-compat = {version = "0.4.1", features = ["alloc"]}
x86_64 = {version = "0.15.2", features = ["instructions"]}
spin = "0.9.8"
[profile.dev]
panic = "abort"

View File

@ -37,6 +37,7 @@ Internet resources where I found most information about OS dev
- https://wiki.osdev.org/PS/2
- https://os.phil-opp.com/
- https://wiki.osdev.org/Interrupts_Tutorial
- https://wiki.osdev.org/Interrupt_Vector_Table
### Contributing

View File

@ -1,10 +1,24 @@
use core::ptr::write_volatile;
use core::arch::asm;
const APIC_BASE: *mut u32 = 0xFEE00000 as *mut u32;
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;
const APIC_EOI: *mut u32 = unsafe { APIC_BASE.add(0x0B0) };
const APIC_SVR: *mut u32 = unsafe { APIC_BASE.add(0x0F0) };
#[repr(C, packed)]
#[derive(Clone, Copy)]
@ -33,9 +47,70 @@ static mut IDT: Idt = Idt {
}; IDT_SIZE],
};
fn register_idt(handler: u32) {
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 {
let entry = &mut IDT.entries[32];
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;
@ -45,24 +120,13 @@ fn register_idt(handler: u32) {
}
}
unsafe fn load_idt() {
asm!("lidt [{}]", "sti", in(reg) &IDT as *const _);
}
unsafe fn enable_apic() {
let sv_reg = APIC_SVR as *mut u32;
let mut value = 0x100 | 0x1;
write_volatile(sv_reg, value);
}
unsafe fn send_eoi() {
let eoi_reg = APIC_EOI as *mut u32;
write_volatile(eoi_reg, 0);
}
pub fn init_apic() {
pub fn init_interrupts() {
unsafe {
load_idt();
enable_apic();
init_idt();
if is_apic_available() {
init_apic();
} else {
init_pic();
}
}
}

View File

@ -1,5 +1,6 @@
use irq::init_apic;
use irq::init_interrupts;
use heap::init_heap;
use pit::init_pit;
use ps2::init_ps2;
use vga::{
fill_with_color,
@ -13,7 +14,7 @@ use vga::{
mod vga;
mod ps2;
mod irq;
mod thread;
mod pit;
mod heap;
mod util;
@ -24,8 +25,9 @@ pub fn show_error(message: &str) {
pub fn init_kernel() {
init_heap(16400, 16384);
init_pit();
init_ps2();
init_apic();
init_interrupts();
fill_with_color(VGA_COLOR_BLACK);

38
src/kernel/pit.rs Normal file
View File

@ -0,0 +1,38 @@
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<Vec<Arc<AtomicUsize>>> = 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));
}

View File

@ -1,25 +1,113 @@
use core::ptr::{read_volatile, write_volatile};
const DATA_PORT: *mut u8 = 0x60 as *mut u8;
const STATUS_PORT: *mut u8 = 0x64 as *mut u8;
use alloc::vec::Vec;
fn write_ps2_data(data: u8) {
unsafe { write_volatile(DATA_PORT, data) }
use crate::kernel::irq::register_idt;
use super::{irq::send_eoi, pit::sleep};
const DATA_PORT: u16 = 0x60;
const STATUS_PORT: u16 = 0x64;
const DEVICE1_IRQ: usize = 1;
const DEVICE2_IRQ: usize = 12;
static mut DEVICE1_TYPE: Vec<u8> = Vec::new();
static mut DEVICE2_TYPE: Vec<u8> = Vec::new();
unsafe fn send_data(data: u8) {
write_volatile(DATA_PORT as *mut u8, data)
}
fn read_ps2_data() -> u8 {
unsafe { read_volatile(DATA_PORT) }
unsafe fn read_data() -> u8 {
read_volatile(DATA_PORT as *mut u8)
}
unsafe fn send_command(command: u8) {
write_volatile(STATUS_PORT as *mut u8, command)
}
fn send_ps2_command(command: u8) {
unsafe { write_volatile(STATUS_PORT, command) }
unsafe fn read_status() -> u8 {
read_volatile(STATUS_PORT as *mut u8)
}
fn read_ps2_status() -> u8 {
unsafe { read_volatile(STATUS_PORT) }
}
unsafe fn on_device_1_irq() {
let data = read_data();
send_eoi(DEVICE1_IRQ);
}
unsafe fn on_device_2_irq() {
let data = read_data();
send_eoi(DEVICE2_IRQ);
}
unsafe fn is_data_available() -> bool {
(read_status() >> 0) & 1 == 1
}
// https://togglebit.io/posts/rust-bitwise/
unsafe fn read_identify_reply() -> Vec<u8> {
let mut reply = Vec::new();
for _ in 0..2 {
if is_data_available() {
reply.push(read_data());
} else {
sleep(10);
if is_data_available() {
reply.push(read_data());
} else {
break;
}
}
}
reply
}
unsafe fn send_identify() -> Vec<u8> {
send_data(0xF5); // Disable Scanning command
while !is_data_available() || read_data() != 0xFA {
sleep(1);
}
send_data(0xF2); // Identify command
while !is_data_available() || read_data() != 0xFA {
sleep(1);
}
let reply = read_identify_reply();
send_data(0xF4);
reply
}
unsafe fn is_ps2_2_device_enabled() -> bool {
true
}
pub fn init_ps2() {
unsafe {
send_command(0xAD); // disable device 1
if is_ps2_2_device_enabled() {
DEVICE2_TYPE = send_identify();
send_command(0xA7); // disable device 2
}
todo!()
read_data(); // flush device data
send_command(0x60); // set CCB command
send_command(0x000000u8); // clear CCB
send_command(0xAE); // enable device 1
if is_ps2_2_device_enabled() {
DEVICE1_TYPE = send_identify();
send_command(0xA8); // enable 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
}

View File