Add serial init and serial interrupts

This commit is contained in:
Jeremy Soller 2016-09-01 11:10:56 -06:00
parent 722d738254
commit 543ef3d96f
9 changed files with 155 additions and 53 deletions

View file

@ -43,6 +43,7 @@ pub struct VBEModeInfo {
}
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) {
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) {
let start_y = cmp::min(self.height - 1, y);
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;
}
}
}
}
}

View file

@ -2,10 +2,12 @@ use paging::ActivePageTable;
pub mod display;
pub mod ps2;
pub mod serial;
pub unsafe fn init(active_table: &mut ActivePageTable){
display::init(active_table);
serial::init();
ps2::init();
display::init(active_table);
}
pub unsafe fn init_ap(active_table: &mut ActivePageTable) {

View file

@ -15,6 +15,10 @@ bitflags! {
const INPUT_FULL = 1 << 1,
const SYSTEM = 1 << 2,
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 PARITY = 1 << 7
}
@ -26,10 +30,12 @@ bitflags! {
const SECOND_INTERRUPT = 1 << 1,
const POST_PASSED = 1 << 2,
// 1 << 3 should be zero
const CONFIG_RESERVED_3 = 1 << 3,
const FIRST_DISABLED = 1 << 4,
const SECOND_DISABLED = 1 << 5,
const FIRST_TRANSLATE = 1 << 6,
// 1 << 7 should be zero
const CONFIG_RESERVED_7 = 1 << 7,
}
}

View 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(())
}
}

View file

@ -1,6 +1,7 @@
use x86::io;
use device::ps2::PS2;
use device::serial::{COM1, COM2};
#[inline(always)]
unsafe fn master_ack() {
@ -33,12 +34,12 @@ interrupt!(cascade, {
});
interrupt!(com2, {
print!("COM2\n");
COM2.lock().on_receive();
master_ack();
});
interrupt!(com1, {
print!("COM1\n");
COM1.lock().on_receive();
master_ack();
});

View file

@ -21,7 +21,7 @@ extern crate x86;
macro_rules! print {
($($arg:tt)*) => ({
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
pub mod panic;
/// Serial driver and print! support
pub mod serial;
/// Initialization and start function
pub mod start;

View file

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

View file

@ -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() {
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);

BIN
res/unifont.font Normal file

Binary file not shown.