serial kinda working!

This commit is contained in:
husky 2022-04-19 00:01:52 -07:00
parent 3cd0c8d767
commit 9ede9b1299
Signed by: MlCROSOFT
GPG Key ID: E00F7FA3381F0647
6 changed files with 294 additions and 4 deletions

29
src/internals/mod.rs Normal file
View File

@ -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,
}
}
}
}

View File

@ -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);
}

147
src/serial/mod.rs Normal file
View File

@ -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,
}
}

70
src/serial/ps2/mod.rs Normal file
View File

@ -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<PS2Type, KernelError> {
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);
}
}
}
}

View File

@ -0,0 +1,3 @@
static DATA_PORT: u16 = 0x60;
static COMMAND_PORT: u16 = 0x64;

View File