diff --git a/src/internals/mod.rs b/src/internals/mod.rs new file mode 100644 index 0000000..f8b5fce --- /dev/null +++ b/src/internals/mod.rs @@ -0,0 +1,29 @@ +pub mod WhyDoTheyCallItOvenWhenYouOfInTheColdFoodOfOutHotEatTheFood { + pub enum ErrorKind { + HardwareFuckUp, + } + + pub enum ErrorLevel { + HugeFuckUp, + MinorFuckUp, + Warning, + } + + pub struct KernelError { + pub kind: ErrorKind, + pub level: ErrorLevel, + pub desc: &'static str, + pub nerdinfo: &'static str, + } + + impl KernelError { + pub fn new(kind: ErrorKind, level: ErrorLevel, desc: &'static str, nerdinfo: &'static str) -> KernelError { + KernelError { + kind: kind, + level: level, + desc: desc, + nerdinfo: nerdinfo, + } + } + } +} \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index c9176ba..dc53459 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,8 +4,11 @@ use bootloader::{entry_point, BootInfo, boot_info}; use core::panic::PanicInfo; use bootloader::boot_info::{FrameBuffer, FrameBufferInfo, PixelFormat}; +use crate::serial::potential_serial_ports; mod font; +mod serial; +mod internals; #[derive(Clone, Copy)] @@ -25,9 +28,17 @@ struct Colour { const RAINBOW : [Colour; 6] = [Colour{r:255,g:0,b:0}, Colour{r:255,g:127,b:0}, Colour{r:255,g:255,b:0}, Colour{r:0,g:255,b:0}, Colour{r:0,g:255,b:255}, Colour{r:0,g:0,b:255}]; + #[panic_handler] -fn panic(_info: &PanicInfo) -> ! { - loop {} +fn panic(_info: &PanicInfo) -> ! { loop {} } + +fn KernelPanic(msg: &str, fb: &mut FrameBuffer) { + // cover the screen in red + for y in 0..fb.info().vertical_resolution { + for x in 0..fb.info().horizontal_resolution { + put_pixel(x, y, Colour{r:255,g:0,b:0}, fb); + } + } } fn put_pixel(x: usize, y: usize, color: Colour, fb: &mut FrameBuffer) { @@ -109,6 +120,21 @@ fn draw_string(x: usize, y: usize, s: &str, color: Colour, fb: &mut FrameBuffer) } } +fn draw_horizcentre_string(y: usize, s: &str, color: Colour, fb: &mut FrameBuffer) { + let mut x_tmp = (fb.info().horizontal_resolution - s.len() * 8) / 2; + let mut y_tmp = y; + + for c in s.chars() { + if c == '\n' { + x_tmp = (fb.info().horizontal_resolution - s.len() * 8) / 2; + y_tmp += 8; + } else { + draw_char(x_tmp, y_tmp, c, color, fb); + x_tmp += 8; + } + } +} + fn draw_rainbow_string(x: usize, y: usize, s: &str, fb: &mut FrameBuffer) { let mut x_tmp = x; let mut y_tmp = y; @@ -143,9 +169,24 @@ fn main(boot_info: &'static mut BootInfo) -> ! { //draw_string(20, 20, "i love drinking cum\nnewline test", Colour { r: 255, g: 0, b: 255 }, framebuffer); //draw_rainbow_string(20, 40, "gay sex", framebuffer); - draw_string(20,20, "),:\n\n\n\nuh oh! windows error! your computer is not compatible with windows 12\n\ncontact billgate@realmicrosoft.com to fix this issue!", Colour { r: 255, g: 255, b: 255}, framebuffer); + //draw_string(20,20, "),:\n\n\n\nuh oh! windows error! your computer is not compatible with windows 12\n\ncontact billgate@realmicrosoft.com to fix this issue!", Colour { r: 255, g: 255, b: 255}, framebuffer); - draw_rainbow_string((fb_width/2) - ((7*8)/2), (fb_height/2) - 4, "gay sex", framebuffer); + draw_horizcentre_string(((fb_height/2)-4)-16, "welcome to windows 12! here is info:", Colour { r: 255, g: 255, b: 255 }, framebuffer); + + // time for some funny com port stuff + let serial_ports = serial::init_serial(); + draw_horizcentre_string(((fb_height/2)-4)-8, "serial ports:", Colour { r: 255, g: 255, b: 255 }, framebuffer); + + for port in 0..serial_ports.ports_enabled.len() { + if serial_ports.ports_enabled[port] { + draw_horizcentre_string(((fb_height/2)-4)+(port as usize*8), serial_ports.ports[port].base.to_string(), Colour { r: 255, g: 255, b: 255 }, framebuffer); + } else { // draw in grey + draw_horizcentre_string(((fb_height/2)-4)+(port as usize*8), serial_ports.ports[port].base.to_string(), Colour { r: 255, g: 0, b: 0 }, framebuffer); + } + } + + + //draw_rainbow_string((fb_width/2) - ((7*8)/2), (fb_height/2) - 4, "gay sex", framebuffer); } diff --git a/src/serial/mod.rs b/src/serial/mod.rs new file mode 100644 index 0000000..31cfcd9 --- /dev/null +++ b/src/serial/mod.rs @@ -0,0 +1,147 @@ +#![feature(asm_const)] + +use core::arch::asm; +use core::borrow::{Borrow, BorrowMut}; +use core::ops::Deref; + +pub mod ps2; + +#[derive(Clone, Copy, PartialEq)] +pub enum potential_serial_ports { + COM1 = 0x3F8, + COM2 = 0x2F8, + COM3 = 0x3E8, + COM4 = 0x2E8, + COM5 = 0x5F8, + COM6 = 0x4F8, + COM7 = 0x5E8, + COM8 = 0x4E8, +} + +impl potential_serial_ports { + pub fn to_string<'a>(&self) -> &'a str { + match self { + potential_serial_ports::COM1 => "COM1", + potential_serial_ports::COM2 => "COM2", + potential_serial_ports::COM3 => "COM3", + potential_serial_ports::COM4 => "COM4", + potential_serial_ports::COM5 => "COM5", + potential_serial_ports::COM6 => "COM6", + potential_serial_ports::COM7 => "COM7", + potential_serial_ports::COM8 => "COM8", + _ => { + panic!("Invalid potential_serial_ports"); + } + } + } +} + +enum serial_offsets { + DATA = 0, + INTERRUPT_ID = 1, + FIFO_CTRL = 2, + LINE_CTRL = 3, + MODEM_CTRL = 4, + LINE_STATUS = 5, + MODEM_STATUS = 6, + SCRATCH = 7, +} + +#[derive(Copy, Clone)] +pub struct Port { + pub base: potential_serial_ports, +} + +pub struct SerialPorts { + pub ports_enabled: [bool; 8], + pub ports: [Port; 8], +} + +#[cfg(any(target_arch="x86", target_arch="x86_64"))] +fn outb(port: u16, data: u8) { + unsafe { + asm!("out dx, al", in("al") data, in("dx") port); + } +} + +#[cfg(any(target_arch="x86", target_arch="x86_64"))] +fn inb(port: u16) -> u8 { + let mut data: u8; + unsafe { + asm!("in al, dx", out("al") data, in("dx") port); + } + data +} + +impl Port { + fn is_transmit_empty(&self) -> bool { + let status = inb(self.base as u16 + serial_offsets::LINE_STATUS as u16); + status & 0x20 == 0x20 + } + + pub fn transmit(&self, data: u8) { + while !self.is_transmit_empty() {} + outb(self.base as u16 + serial_offsets::DATA as u16, data); + } + + fn is_recv_full(&self) -> bool { + let status = inb(self.base as u16 + serial_offsets::LINE_STATUS as u16); + status & 0x01 == 0x01 + } + + pub fn receive(&self, mut timeout: u16) -> u8 { + if timeout != 0 { + while !self.is_recv_full() { + timeout -= 1; + if timeout == 0 { + return 0; + } + } + } else { + while !self.is_recv_full() {} + } + inb(self.base as u16 + serial_offsets::DATA as u16) + } + + pub fn transrecv(&self, data: u8) -> u8 { + self.transmit(data); + self.receive(0) + } +} + +pub fn test_port(port: potential_serial_ports) -> bool { + let mut port: u16 = port as u16; + outb(port + serial_offsets::INTERRUPT_ID as u16, 0x00); // disable interrupts + outb(port + serial_offsets::LINE_CTRL as u16, 0x80); // enable DLAB + outb(port + serial_offsets::DATA as u16, 0x03); // set divisor to 3 (lo byte) + outb(port + serial_offsets::LINE_CTRL as u16, 0x03); // set divisor to 3 (hi byte) + outb(port + serial_offsets::FIFO_CTRL as u16, 0xC7); // enable FIFO, clear them, with 14-byte threshold + outb(port + serial_offsets::MODEM_CTRL as u16, 0x0B); // IRQs enabled, RTS/DSR set + outb(port + serial_offsets::MODEM_CTRL as u16, 0x1E); // loopback mode + + // test serial + outb(port + serial_offsets::DATA as u16, 0xAE); + // check if we received the correct byte + if inb(port + serial_offsets::DATA as u16) != 0xAE { + return false; + } else { + // set stuffz idk + outb(port + serial_offsets::MODEM_CTRL as u16, 0x0F); + return true; + } +} + +pub fn init_serial() -> SerialPorts { + // this is so fucking cursed + let mut ports_tmp : [Port; 8] = [Port { base: potential_serial_ports::COM1 }, Port { base: potential_serial_ports::COM2 }, Port { base: potential_serial_ports::COM3 }, Port { base: potential_serial_ports::COM4 }, Port { base: potential_serial_ports::COM5 }, Port { base: potential_serial_ports::COM6 }, Port { base: potential_serial_ports::COM7 }, Port { base: potential_serial_ports::COM8 }]; + let mut ports_enabled_tmp : [bool; 8] = [false; 8]; + for i in 0..8 { + if test_port(ports_tmp[i].base) { + ports_enabled_tmp[i] = true; + } + } + SerialPorts { + ports_enabled: ports_enabled_tmp, + ports: ports_tmp, + } +} \ No newline at end of file diff --git a/src/serial/ps2/mod.rs b/src/serial/ps2/mod.rs new file mode 100644 index 0000000..f187b81 --- /dev/null +++ b/src/serial/ps2/mod.rs @@ -0,0 +1,70 @@ +use super::*; +use crate::internals::WhyDoTheyCallItOvenWhenYouOfInTheColdFoodOfOutHotEatTheFood::{KernelError, ErrorKind, ErrorLevel}; + +pub enum PS2Type { + AncientKeyboard, + Keyboard, + Mouse, + FiveButtonMouse, + ScrollWheelMouse, + Unknown, +} + +enum Messages { + MSGDisableScanning = 0xF5, + MSGIdentify = 0xF2, + MSGACK = 0xFA, +} + +pub fn probePort(port : Port) -> Result { + let mut response : u8; + response = port.transrecv(Messages::MSGDisableScanning as u8); + // check for ACK + if response != Messages::MSGACK as u8 { + return Err(KernelError::new(ErrorKind::HardwareFuckUp, ErrorLevel::Warning, "Did not receive ACK", port.base.to_string())); + } + response = port.transrecv(Messages::MSGIdentify as u8); + // check for ACK + if response != Messages::MSGACK as u8 { + return Err(KernelError::new(ErrorKind::HardwareFuckUp, ErrorLevel::MinorFuckUp, "Did not receive ACK after asking port to identify", port.base.to_string())); + } + // read the response with a timeout of x cpu cycles, this can be quite low as it will only matter on slow machines + response = port.receive(0xFFFF); + // if there's no response, it's a really old keyboard (IBM or whoever, why did you have to do this??)\ + if response == 0 { + return Ok(PS2Type::AncientKeyboard); + } else { + // switch on the response + match response { + 0x00 => { // standard mouse + return Ok(PS2Type::Mouse); + }, + 0x03 => { // mouse with scroll wheel + return Ok(PS2Type::ScrollWheelMouse); + }, + 0x04 => { // 5 button mouse + return Ok(PS2Type::FiveButtonMouse); + }, + 0xAB => { // some type of keyboard, we'll need to read another byte to be sure + response = port.receive(0xFFFF); + match response { + 0x41 => { // some keyboard idfk + return Ok(PS2Type::Keyboard); + }, + 0xC1 => { // same as above + return Ok(PS2Type::Keyboard); + }, + 0x83 => { // keyboard after taking normal pills + return Ok(PS2Type::Keyboard); + }, + _ => { // what? + return Ok(PS2Type::Unknown); + } + } + }, + _ => { // some other device idk + return Ok(PS2Type::Unknown); + } + } + } +} \ No newline at end of file diff --git a/src/serial/ps2controller.rs b/src/serial/ps2controller.rs new file mode 100644 index 0000000..ca3f6bf --- /dev/null +++ b/src/serial/ps2controller.rs @@ -0,0 +1,3 @@ +static DATA_PORT: u16 = 0x60; +static COMMAND_PORT: u16 = 0x64; + diff --git a/src/serial/ps2keyboard.rs b/src/serial/ps2keyboard.rs new file mode 100644 index 0000000..e69de29