serial kinda working!
This commit is contained in:
parent
3cd0c8d767
commit
9ede9b1299
|
@ -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,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
49
src/main.rs
49
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);
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
static DATA_PORT: u16 = 0x60;
|
||||
static COMMAND_PORT: u16 = 0x64;
|
||||
|
Loading…
Reference in New Issue