Add serial init and serial interrupts
This commit is contained in:
parent
722d738254
commit
543ef3d96f
|
@ -43,6 +43,7 @@ pub struct VBEModeInfo {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub static DISPLAY: Mutex<Option<Display>> = Mutex::new(None);
|
pub static DISPLAY: Mutex<Option<Display>> = Mutex::new(None);
|
||||||
|
static FONT: &'static [u8] = include_bytes!("../../../../res/unifont.font");
|
||||||
|
|
||||||
pub unsafe fn init(active_table: &mut ActivePageTable) {
|
pub unsafe fn init(active_table: &mut ActivePageTable) {
|
||||||
active_table.identity_map(Frame::containing_address(PhysicalAddress::new(0x5200)), entry::PRESENT | entry::NO_EXECUTE);
|
active_table.identity_map(Frame::containing_address(PhysicalAddress::new(0x5200)), entry::PRESENT | entry::NO_EXECUTE);
|
||||||
|
@ -108,6 +109,7 @@ impl Display {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Draw a rectangle
|
||||||
pub fn rect(&mut self, x: usize, y: usize, w: usize, h: usize, color: u32) {
|
pub fn rect(&mut self, x: usize, y: usize, w: usize, h: usize, color: u32) {
|
||||||
let start_y = cmp::min(self.height - 1, y);
|
let start_y = cmp::min(self.height - 1, y);
|
||||||
let end_y = cmp::min(self.height, y + h);
|
let end_y = cmp::min(self.height, y + h);
|
||||||
|
@ -123,4 +125,25 @@ impl Display {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Draw a character
|
||||||
|
pub fn char(&mut self, x: usize, y: usize, character: char, color: u32) {
|
||||||
|
if x + 8 <= self.width && y + 16 <= self.height {
|
||||||
|
let mut offset = y * self.width + x;
|
||||||
|
|
||||||
|
let font_i = 16 * (character as usize);
|
||||||
|
if font_i + 16 <= FONT.len() {
|
||||||
|
for row in 0..16 {
|
||||||
|
let row_data = FONT[font_i + row];
|
||||||
|
for col in 0..8 {
|
||||||
|
if (row_data >> (7 - col)) & 1 == 1 {
|
||||||
|
self.data[offset + col] = color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
offset += self.width;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,10 +2,12 @@ use paging::ActivePageTable;
|
||||||
|
|
||||||
pub mod display;
|
pub mod display;
|
||||||
pub mod ps2;
|
pub mod ps2;
|
||||||
|
pub mod serial;
|
||||||
|
|
||||||
pub unsafe fn init(active_table: &mut ActivePageTable){
|
pub unsafe fn init(active_table: &mut ActivePageTable){
|
||||||
display::init(active_table);
|
serial::init();
|
||||||
ps2::init();
|
ps2::init();
|
||||||
|
display::init(active_table);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn init_ap(active_table: &mut ActivePageTable) {
|
pub unsafe fn init_ap(active_table: &mut ActivePageTable) {
|
||||||
|
|
|
@ -15,6 +15,10 @@ bitflags! {
|
||||||
const INPUT_FULL = 1 << 1,
|
const INPUT_FULL = 1 << 1,
|
||||||
const SYSTEM = 1 << 2,
|
const SYSTEM = 1 << 2,
|
||||||
const COMMAND = 1 << 3,
|
const COMMAND = 1 << 3,
|
||||||
|
// Chipset specific
|
||||||
|
const KEYBOARD_LOCK = 1 << 4,
|
||||||
|
// Chipset specific
|
||||||
|
const SECOND_OUTPUT_FULL = 1 << 5,
|
||||||
const TIME_OUT = 1 << 6,
|
const TIME_OUT = 1 << 6,
|
||||||
const PARITY = 1 << 7
|
const PARITY = 1 << 7
|
||||||
}
|
}
|
||||||
|
@ -26,10 +30,12 @@ bitflags! {
|
||||||
const SECOND_INTERRUPT = 1 << 1,
|
const SECOND_INTERRUPT = 1 << 1,
|
||||||
const POST_PASSED = 1 << 2,
|
const POST_PASSED = 1 << 2,
|
||||||
// 1 << 3 should be zero
|
// 1 << 3 should be zero
|
||||||
|
const CONFIG_RESERVED_3 = 1 << 3,
|
||||||
const FIRST_DISABLED = 1 << 4,
|
const FIRST_DISABLED = 1 << 4,
|
||||||
const SECOND_DISABLED = 1 << 5,
|
const SECOND_DISABLED = 1 << 5,
|
||||||
const FIRST_TRANSLATE = 1 << 6,
|
const FIRST_TRANSLATE = 1 << 6,
|
||||||
// 1 << 7 should be zero
|
// 1 << 7 should be zero
|
||||||
|
const CONFIG_RESERVED_7 = 1 << 7,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
118
arch/x86_64/src/device/serial.rs
Normal file
118
arch/x86_64/src/device/serial.rs
Normal file
|
@ -0,0 +1,118 @@
|
||||||
|
use core::fmt::{self, Write};
|
||||||
|
use spin::Mutex;
|
||||||
|
|
||||||
|
use io::{Io, Pio, ReadOnly};
|
||||||
|
|
||||||
|
pub static COM1: Mutex<SerialPort> = Mutex::new(SerialPort::new(0x3F8));
|
||||||
|
pub static COM2: Mutex<SerialPort> = Mutex::new(SerialPort::new(0x2F8));
|
||||||
|
|
||||||
|
pub unsafe fn init() {
|
||||||
|
COM1.lock().init();
|
||||||
|
COM2.lock().init();
|
||||||
|
}
|
||||||
|
|
||||||
|
bitflags! {
|
||||||
|
/// Interrupt enable flags
|
||||||
|
flags IntEnFlags: u8 {
|
||||||
|
const RECEIVED = 1,
|
||||||
|
const SENT = 1 << 1,
|
||||||
|
const ERRORED = 1 << 2,
|
||||||
|
const STATUS_CHANGE = 1 << 3,
|
||||||
|
// 4 to 7 are unused
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bitflags! {
|
||||||
|
/// Line status flags
|
||||||
|
flags LineStsFlags: u8 {
|
||||||
|
const INPUT_FULL = 1,
|
||||||
|
// 1 to 4 unknown
|
||||||
|
const OUTPUT_EMPTY = 1 << 5,
|
||||||
|
// 6 and 7 unknown
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct SerialPort {
|
||||||
|
/// Data register, read to receive, write to send
|
||||||
|
data: Pio<u8>,
|
||||||
|
/// Interrupt enable
|
||||||
|
int_en: Pio<u8>,
|
||||||
|
/// FIFO control
|
||||||
|
fifo_ctrl: Pio<u8>,
|
||||||
|
/// Line control
|
||||||
|
line_ctrl: Pio<u8>,
|
||||||
|
/// Modem control
|
||||||
|
modem_ctrl: Pio<u8>,
|
||||||
|
/// Line status
|
||||||
|
line_sts: ReadOnly<Pio<u8>>,
|
||||||
|
/// Modem status
|
||||||
|
modem_sts: ReadOnly<Pio<u8>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SerialPort {
|
||||||
|
const fn new(base: u16) -> SerialPort {
|
||||||
|
SerialPort {
|
||||||
|
data: Pio::new(base),
|
||||||
|
int_en: Pio::new(base + 1),
|
||||||
|
fifo_ctrl: Pio::new(base + 2),
|
||||||
|
line_ctrl: Pio::new(base + 3),
|
||||||
|
modem_ctrl: Pio::new(base + 4),
|
||||||
|
line_sts: ReadOnly::new(Pio::new(base + 5)),
|
||||||
|
modem_sts: ReadOnly::new(Pio::new(base + 6))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn int_en(&self) -> IntEnFlags {
|
||||||
|
IntEnFlags::from_bits_truncate(self.int_en.read())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn line_sts(&self) -> LineStsFlags {
|
||||||
|
LineStsFlags::from_bits_truncate(self.line_sts.read())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write(&mut self, data: u8) {
|
||||||
|
while ! self.line_sts().contains(OUTPUT_EMPTY) {}
|
||||||
|
self.data.write(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn init(&mut self) {
|
||||||
|
self.int_en.write(0x00);
|
||||||
|
self.line_ctrl.write(0x80);
|
||||||
|
self.data.write(0x03);
|
||||||
|
self.int_en.write(0x00);
|
||||||
|
self.line_ctrl.write(0x03);
|
||||||
|
self.fifo_ctrl.write(0xC7);
|
||||||
|
self.modem_ctrl.write(0x0B);
|
||||||
|
self.int_en.write(0x01);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn on_receive(&mut self) {
|
||||||
|
let data = self.data.read();
|
||||||
|
write!(self, "SERIAL {:X}\n", data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Write for SerialPort {
|
||||||
|
fn write_str(&mut self, s: &str) -> Result<(), fmt::Error> {
|
||||||
|
for byte in s.bytes() {
|
||||||
|
self.write(byte);
|
||||||
|
|
||||||
|
if byte == 8 {
|
||||||
|
self.write(b' ');
|
||||||
|
self.write(8);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct SerialConsole;
|
||||||
|
|
||||||
|
impl Write for SerialConsole {
|
||||||
|
fn write_str(&mut self, s: &str) -> Result<(), fmt::Error> {
|
||||||
|
COM1.lock().write_str(s);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,6 +1,7 @@
|
||||||
use x86::io;
|
use x86::io;
|
||||||
|
|
||||||
use device::ps2::PS2;
|
use device::ps2::PS2;
|
||||||
|
use device::serial::{COM1, COM2};
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
unsafe fn master_ack() {
|
unsafe fn master_ack() {
|
||||||
|
@ -33,12 +34,12 @@ interrupt!(cascade, {
|
||||||
});
|
});
|
||||||
|
|
||||||
interrupt!(com2, {
|
interrupt!(com2, {
|
||||||
print!("COM2\n");
|
COM2.lock().on_receive();
|
||||||
master_ack();
|
master_ack();
|
||||||
});
|
});
|
||||||
|
|
||||||
interrupt!(com1, {
|
interrupt!(com1, {
|
||||||
print!("COM1\n");
|
COM1.lock().on_receive();
|
||||||
master_ack();
|
master_ack();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,7 @@ extern crate x86;
|
||||||
macro_rules! print {
|
macro_rules! print {
|
||||||
($($arg:tt)*) => ({
|
($($arg:tt)*) => ({
|
||||||
use core::fmt::Write;
|
use core::fmt::Write;
|
||||||
let _ = write!($crate::serial::SerialConsole, $($arg)*);
|
let _ = write!($crate::device::serial::SerialConsole, $($arg)*);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -149,8 +149,5 @@ pub mod paging;
|
||||||
/// Panic
|
/// Panic
|
||||||
pub mod panic;
|
pub mod panic;
|
||||||
|
|
||||||
/// Serial driver and print! support
|
|
||||||
pub mod serial;
|
|
||||||
|
|
||||||
/// Initialization and start function
|
/// Initialization and start function
|
||||||
pub mod start;
|
pub mod start;
|
||||||
|
|
|
@ -1,45 +0,0 @@
|
||||||
use core::fmt;
|
|
||||||
use spin::Mutex;
|
|
||||||
|
|
||||||
use super::io::{Io, Pio};
|
|
||||||
|
|
||||||
static SERIAL_PORT: Mutex<SerialPort> = Mutex::new(SerialPort::new());
|
|
||||||
|
|
||||||
struct SerialPort {
|
|
||||||
status: Pio<u8>,
|
|
||||||
data: Pio<u8>
|
|
||||||
}
|
|
||||||
|
|
||||||
impl SerialPort {
|
|
||||||
pub const fn new() -> SerialPort {
|
|
||||||
SerialPort {
|
|
||||||
status: Pio::new(0x3F8 + 5),
|
|
||||||
data: Pio::new(0x3F8)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn write(&mut self, bytes: &[u8]) {
|
|
||||||
for byte in bytes.iter() {
|
|
||||||
while !self.status.readf(0x20) {}
|
|
||||||
self.data.write(*byte);
|
|
||||||
|
|
||||||
if *byte == 8 {
|
|
||||||
while !self.status.readf(0x20) {}
|
|
||||||
self.data.write(0x20);
|
|
||||||
|
|
||||||
while !self.status.readf(0x20) {}
|
|
||||||
self.data.write(8);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct SerialConsole;
|
|
||||||
|
|
||||||
impl fmt::Write for SerialConsole {
|
|
||||||
fn write_str(&mut self, s: &str) -> Result<(), fmt::Error> {
|
|
||||||
SERIAL_PORT.lock().write(s.as_bytes());
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -197,7 +197,7 @@ pub unsafe extern fn kstart_ap(stack_start: usize, stack_end: usize) -> ! {
|
||||||
|
|
||||||
if let Some(ref mut display) = *device::display::DISPLAY.lock() {
|
if let Some(ref mut display) = *device::display::DISPLAY.lock() {
|
||||||
let width = display.width;
|
let width = display.width;
|
||||||
display.rect(0, ap_number * 32, width, 16, 0xFF00);
|
display.char(0, ap_number * 16, (ap_number as u8 + b'0') as char, 0xFF00);
|
||||||
}
|
}
|
||||||
|
|
||||||
kmain_ap(ap_number);
|
kmain_ap(ap_number);
|
||||||
|
|
BIN
res/unifont.font
Normal file
BIN
res/unifont.font
Normal file
Binary file not shown.
Loading…
Reference in a new issue