diff options
| author | Clément Sibille <claymeuns@protonmail.com> | 2021-10-07 21:13:55 +0200 | 
|---|---|---|
| committer | Clément Sibille <claymeuns@protonmail.com> | 2021-10-07 21:14:05 +0200 | 
| commit | 06d819c3e8e94972bd4261069d2c5239297bba65 (patch) | |
| tree | d14619fccb52246945212d9d75135225a020fd5d | |
| parent | 6277cf1e4fef810d08af1e1f8d64778c94007236 (diff) | |
Add support for serial port output
| -rw-r--r-- | Makefile | 8 | ||||
| -rw-r--r-- | kernel/src/io.rs | 13 | ||||
| -rw-r--r-- | kernel/src/lib.rs | 34 | ||||
| -rw-r--r-- | kernel/src/serial.rs | 66 | ||||
| -rw-r--r-- | kernel/src/terminal.rs | 27 | 
5 files changed, 104 insertions, 44 deletions
@@ -1,7 +1,9 @@  all: target/kernel.o +clean_run: | clean run +  run: target/kernel.o -	qemu-system-i386 -kernel $< -machine type=pc-i440fx-3.1 +	qemu-system-i386 -kernel $< -machine type=pc-i440fx-3.1 -serial stdio  target/boot.o: boot/boot.S  	mkdir -p target @@ -17,5 +19,5 @@ target/i686-lisibleos/release/libkernel.a:  clean:  	RUST_TARGET_PATH=$(shell pwd) xargo clean --target i686-lisibleos -	rm target/kernel.o target/boot.o target/i686-lisibleos/debug/libkernel.a -	rm target/kernel.o target/boot.o target/i686-lisibleos/release/libkernel.a +	rm -f target/kernel.o target/boot.o target/i686-lisibleos/debug/libkernel.a +	rm -f target/kernel.o target/boot.o target/i686-lisibleos/release/libkernel.a diff --git a/kernel/src/io.rs b/kernel/src/io.rs index def8665..a647408 100644 --- a/kernel/src/io.rs +++ b/kernel/src/io.rs @@ -1,5 +1,14 @@  pub unsafe fn out8(address: u16, value: u8) {      asm!( -        "out dx, al", in("dx") address, in("al") value -    ) +    "out dx, al", in("dx") address, in("al") value +    ); +} + +pub unsafe fn in8(address: u16) -> u8 { +    let result: u8; +    asm!( +    "in al, dx", in("dx") address, out("al") result +    ); + +    result  } diff --git a/kernel/src/lib.rs b/kernel/src/lib.rs index edb5704..b1c8cf2 100644 --- a/kernel/src/lib.rs +++ b/kernel/src/lib.rs @@ -6,38 +6,20 @@ use crate::terminal::Terminal;  use core::panic::PanicInfo;  mod io; +mod serial;  mod terminal;  #[no_mangle]  pub extern "C" fn kmain() -> ! {      let mut terminal = Terminal::new();      terminal.clear(); -    terminal.put_string(b"1 LisibleOS\n"); -    terminal.put_string(b"2 > \n"); -    terminal.put_string(b"3\n"); -    terminal.put_string(b"4\n"); -    terminal.put_string(b"5\n"); -    terminal.put_string(b"6\n"); -    terminal.put_string(b"7\n"); -    terminal.put_string(b"8\n"); -    terminal.put_string(b"9\n"); -    terminal.put_string(b"10\n"); -    terminal.put_string(b"11\n"); -    terminal.put_string(b"12\n"); -    terminal.put_string(b"13\n"); -    terminal.put_string(b"14\n"); -    terminal.put_string(b"15\n"); -    terminal.put_string(b"16\n"); -    terminal.put_string(b"17\n"); -    terminal.put_string(b"18\n"); -    terminal.put_string(b"19\n"); -    terminal.put_string(b"20\n"); -    terminal.put_string(b"21\n"); -    terminal.put_string(b"22\n"); -    terminal.put_string(b"23\n"); -    terminal.put_string(b"24\n"); -    terminal.put_string(b"25\n"); -    terminal.put_string(b"26"); +    if let Err(_) = serial::initialize_serial_port() { +        terminal.put_string(b"Serial port initialization failed"); +    } else { +        terminal.put_string(b"Serial port initialization succeeded"); +    } + +    serial::write_bytes(b"This string was sent through the serial port!!");      loop {}  } diff --git a/kernel/src/serial.rs b/kernel/src/serial.rs new file mode 100644 index 0000000..77c15cb --- /dev/null +++ b/kernel/src/serial.rs @@ -0,0 +1,66 @@ +use crate::io::{in8, out8}; +use crate::serial::SerialError::SerialPortInitializationFailed; + +const COM1_PORT: u16 = 0x3F8; +const OFFSET_DATA_REGISTER: u8 = 0; +const OFFSET_INTERRUPT_ENABLE_REGISTER: u8 = 1; +const OFFSET_INTERRUPT_IDENTIFICATION_AND_FIFO_CONTROL_REGISTER: u8 = 2; +const OFFSET_LINE_CONTROL_REGISTER: u8 = 3; +const OFFSET_MODEM_CONTROL_REGISTER: u8 = 4; +const OFFSET_LINE_STATUS_REGISTER: u8 = 5; + +#[derive(Debug)] +pub enum SerialError { +    SerialPortInitializationFailed, +} + +pub fn initialize_serial_port() -> Result<(), SerialError> { +    // Safety: +    // These instructions read and write data on valid COM ports +    unsafe { +        out8(COM1_PORT + OFFSET_INTERRUPT_ENABLE_REGISTER as u16, 0x00); +        out8(COM1_PORT + OFFSET_LINE_CONTROL_REGISTER as u16, 0x80); +        out8(COM1_PORT + OFFSET_DATA_REGISTER as u16, 0x03); +        out8(COM1_PORT + OFFSET_INTERRUPT_ENABLE_REGISTER as u16, 0x00); +        out8(COM1_PORT + OFFSET_LINE_CONTROL_REGISTER as u16, 0x03); +        out8( +            COM1_PORT + OFFSET_INTERRUPT_IDENTIFICATION_AND_FIFO_CONTROL_REGISTER as u16, +            0xC7, +        ); +        out8(COM1_PORT + OFFSET_MODEM_CONTROL_REGISTER as u16, 0x0B); + +        // Testing the serial chip +        out8(COM1_PORT + OFFSET_MODEM_CONTROL_REGISTER as u16, 0x1E); // Enable loopback mode +        out8(COM1_PORT + OFFSET_DATA_REGISTER as u16, 0xAE); +        if in8(COM1_PORT + OFFSET_DATA_REGISTER as u16) != 0xAE { +            return Err(SerialPortInitializationFailed); +        } + +        out8(COM1_PORT + OFFSET_MODEM_CONTROL_REGISTER as u16, 0x0F); // Enable normal mode +    } + +    Ok(()) +} + +pub fn write(byte: u8) { +    while !is_ready_to_send_data() {} +    // Safety: the value is sent on a valid port address, which is the COM port +    // data register address +    unsafe { +        out8(COM1_PORT, byte); +    } +} + +pub fn write_bytes(bytes: &[u8]) { +    for &byte in bytes { +        write(byte); +    } +} + +fn is_ready_to_send_data() -> bool { +    const THRE_BIT: u8 = 0x20; + +    // Safety: the value is sent on a valid port address, which is the COM port +    // line status register address +    return unsafe { in8(COM1_PORT + OFFSET_LINE_STATUS_REGISTER as u16) } & THRE_BIT != 0; +} diff --git a/kernel/src/terminal.rs b/kernel/src/terminal.rs index c64188c..63c7d95 100644 --- a/kernel/src/terminal.rs +++ b/kernel/src/terminal.rs @@ -1,15 +1,15 @@  use crate::io;  use compiler_builtins::mem::memcpy; -const VGA_BUFFER_POINTER: *mut u8 = 0xb8000 as *mut u8; +const VGA_BUFFER_POINTER: *mut u8 = 0xB8000 as *mut u8;  const VGA_BUFFER_SIZE: u16 = 4000; -const ROW_COUNT: u16 = 25; -const COL_COUNT: u16 = 80; -const VALUE_SIZE: u16 = 2; +const ROW_COUNT: u8 = 25; +const COL_COUNT: u8 = 80; +const VALUE_SIZE: u8 = 2;  pub(crate) struct Terminal { -    current_row: u16, -    current_col: u16, +    current_row: u8, +    current_col: u8,  }  impl Terminal { @@ -67,9 +67,9 @@ impl Terminal {          // The end pointer isn't past the VGA character buffer pointer          // The offset doesn't overflow isize          // The offset doesn't rely on wrapping around the address space -        let src = unsafe { VGA_BUFFER_POINTER.offset((COL_COUNT * VALUE_SIZE) as isize) }; +        let src = unsafe { VGA_BUFFER_POINTER.offset(COL_COUNT as isize * VALUE_SIZE as isize) };          let dest = VGA_BUFFER_POINTER; -        let size = (VGA_BUFFER_SIZE - COL_COUNT) * VALUE_SIZE; +        let size = (VGA_BUFFER_SIZE - COL_COUNT as u16) * VALUE_SIZE as u16;          // Safety:          // dest and src are valid pointer to the same object being the VGA character buffer @@ -78,12 +78,13 @@ impl Terminal {          self.clear_line(ROW_COUNT - 1);      } -    pub fn put_char_at(&mut self, c: u8, row: u16, col: u16) { +    pub fn put_char_at(&mut self, c: u8, row: u8, col: u8) {          self.current_row = row;          self.current_col = col;          unsafe {              *VGA_BUFFER_POINTER.offset( -                ((self.current_col + self.current_row * COL_COUNT) * VALUE_SIZE) as isize, +                (self.current_col as isize + self.current_row as isize * COL_COUNT as isize) +                    * VALUE_SIZE as isize,              ) = c;          }      } @@ -96,7 +97,7 @@ impl Terminal {          self.current_row = 0;      } -    fn clear_line(&mut self, row: u16) { +    fn clear_line(&mut self, row: u8) {          for col in 0..COL_COUNT {              self.put_char_at(b' ', row, col);          } @@ -105,8 +106,8 @@ impl Terminal {          self.current_col = 0;      } -    pub fn set_cursor_position(&mut self, row: u16, col: u16) { -        let cursor_position = row * COL_COUNT + col; +    pub fn set_cursor_position(&mut self, row: u8, col: u8) { +        let cursor_position = row as u16 * COL_COUNT as u16 + col as u16;          let address_register = 0x3D4;          let data_register = 0x3D5;          unsafe {  | 
