many changes and especially identify ps/2
This commit is contained in:
parent
a643b5ba1e
commit
70bd58e5ec
32
Cargo.lock
generated
32
Cargo.lock
generated
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -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
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
@ -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
38
src/kernel/pit.rs
Normal 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));
|
||||
}
|
@ -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
|
||||
}
|
Loading…
Reference in New Issue
Block a user