Merge branch 'master' of github.com:redox-os/kernel
This commit is contained in:
commit
04f6e7b558
|
@ -9,7 +9,6 @@ crate-type = ["staticlib"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
bitflags = "*"
|
bitflags = "*"
|
||||||
ransid = "*"
|
|
||||||
spin = "*"
|
spin = "*"
|
||||||
|
|
||||||
[dependencies.goblin]
|
[dependencies.goblin]
|
||||||
|
|
|
@ -5,8 +5,9 @@ version = "0.1.0"
|
||||||
[dependencies]
|
[dependencies]
|
||||||
bitflags = "*"
|
bitflags = "*"
|
||||||
hole_list_allocator = { path = "../../alloc/hole_list_allocator"}
|
hole_list_allocator = { path = "../../alloc/hole_list_allocator"}
|
||||||
|
ransid = "*"
|
||||||
spin = "*"
|
spin = "*"
|
||||||
|
|
||||||
[dependencies.x86]
|
[dependencies.x86]
|
||||||
default-features = false
|
|
||||||
version = "0.7.1"
|
version = "0.7.1"
|
||||||
|
default-features = false
|
||||||
|
|
26
arch/x86_64/src/console.rs
Normal file
26
arch/x86_64/src/console.rs
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
use core::fmt::{self, Write};
|
||||||
|
use spin::Mutex;
|
||||||
|
|
||||||
|
use device::display::DISPLAY;
|
||||||
|
use device::serial::COM1;
|
||||||
|
|
||||||
|
pub static CONSOLE: Mutex<Console> = Mutex::new(Console::new());
|
||||||
|
|
||||||
|
pub struct Console;
|
||||||
|
|
||||||
|
impl Console {
|
||||||
|
const fn new() -> Self {
|
||||||
|
Console
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Write for Console {
|
||||||
|
fn write_str(&mut self, s: &str) -> Result<(), fmt::Error> {
|
||||||
|
if let Some(ref mut display) = *DISPLAY.lock() {
|
||||||
|
display.write(s.as_bytes());
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
COM1.lock().write_str(s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,3 @@
|
||||||
use core::mem;
|
|
||||||
use core::sync::atomic::{AtomicBool, ATOMIC_BOOL_INIT, Ordering};
|
use core::sync::atomic::{AtomicBool, ATOMIC_BOOL_INIT, Ordering};
|
||||||
|
|
||||||
/// This must be used by the kernel to ensure that context switches are done atomically
|
/// This must be used by the kernel to ensure that context switches are done atomically
|
||||||
|
@ -52,8 +51,6 @@ impl Context {
|
||||||
#[inline(never)]
|
#[inline(never)]
|
||||||
#[naked]
|
#[naked]
|
||||||
pub unsafe fn switch_to(&mut self, next: &mut Context) {
|
pub unsafe fn switch_to(&mut self, next: &mut Context) {
|
||||||
asm!("xchg bx, bx" : : : "memory" : "intel", "volatile");
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
asm!("fxsave [$0]" : : "r"(self.fx) : "memory" : "intel", "volatile");
|
asm!("fxsave [$0]" : : "r"(self.fx) : "memory" : "intel", "volatile");
|
||||||
self.loadable = true;
|
self.loadable = true;
|
||||||
|
|
182
arch/x86_64/src/device/display.rs
Normal file
182
arch/x86_64/src/device/display.rs
Normal file
|
@ -0,0 +1,182 @@
|
||||||
|
use core::{cmp, slice};
|
||||||
|
use ransid::Console;
|
||||||
|
use spin::Mutex;
|
||||||
|
|
||||||
|
use externs::memset;
|
||||||
|
use memory::Frame;
|
||||||
|
use paging::{ActivePageTable, PhysicalAddress, entry};
|
||||||
|
|
||||||
|
/// The info of the VBE mode
|
||||||
|
#[derive(Copy, Clone, Default, Debug)]
|
||||||
|
#[repr(packed)]
|
||||||
|
pub struct VBEModeInfo {
|
||||||
|
attributes: u16,
|
||||||
|
win_a: u8,
|
||||||
|
win_b: u8,
|
||||||
|
granularity: u16,
|
||||||
|
winsize: u16,
|
||||||
|
segment_a: u16,
|
||||||
|
segment_b: u16,
|
||||||
|
winfuncptr: u32,
|
||||||
|
bytesperscanline: u16,
|
||||||
|
pub xresolution: u16,
|
||||||
|
pub yresolution: u16,
|
||||||
|
xcharsize: u8,
|
||||||
|
ycharsize: u8,
|
||||||
|
numberofplanes: u8,
|
||||||
|
bitsperpixel: u8,
|
||||||
|
numberofbanks: u8,
|
||||||
|
memorymodel: u8,
|
||||||
|
banksize: u8,
|
||||||
|
numberofimagepages: u8,
|
||||||
|
unused: u8,
|
||||||
|
redmasksize: u8,
|
||||||
|
redfieldposition: u8,
|
||||||
|
greenmasksize: u8,
|
||||||
|
greenfieldposition: u8,
|
||||||
|
bluemasksize: u8,
|
||||||
|
bluefieldposition: u8,
|
||||||
|
rsvdmasksize: u8,
|
||||||
|
rsvdfieldposition: u8,
|
||||||
|
directcolormodeinfo: u8,
|
||||||
|
physbaseptr: u32,
|
||||||
|
offscreenmemoryoffset: u32,
|
||||||
|
offscreenmemsize: u16,
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
let mode_info = &*(0x5200 as *const VBEModeInfo);
|
||||||
|
if mode_info.physbaseptr > 0 {
|
||||||
|
let width = mode_info.xresolution as usize;
|
||||||
|
let height = mode_info.yresolution as usize;
|
||||||
|
let start = mode_info.physbaseptr as usize;
|
||||||
|
let size = width * height;
|
||||||
|
|
||||||
|
{
|
||||||
|
let start_frame = Frame::containing_address(PhysicalAddress::new(start));
|
||||||
|
let end_frame = Frame::containing_address(PhysicalAddress::new(start + size * 4 - 1));
|
||||||
|
for frame in Frame::range_inclusive(start_frame, end_frame) {
|
||||||
|
active_table.identity_map(frame, entry::PRESENT | entry::WRITABLE | entry::NO_EXECUTE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(start as *mut u8, 0, size * 4);
|
||||||
|
|
||||||
|
*DISPLAY.lock() = Some(Display::new(width, height, slice::from_raw_parts_mut(start as *mut u32, size)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn init_ap(active_table: &mut ActivePageTable) {
|
||||||
|
active_table.identity_map(Frame::containing_address(PhysicalAddress::new(0x5200)), entry::PRESENT | entry::NO_EXECUTE);
|
||||||
|
|
||||||
|
let mode_info = &*(0x5200 as *const VBEModeInfo);
|
||||||
|
if mode_info.physbaseptr > 0 {
|
||||||
|
let width = mode_info.xresolution as usize;
|
||||||
|
let height = mode_info.yresolution as usize;
|
||||||
|
let start = mode_info.physbaseptr as usize;
|
||||||
|
let size = width * height;
|
||||||
|
|
||||||
|
{
|
||||||
|
let start_frame = Frame::containing_address(PhysicalAddress::new(start));
|
||||||
|
let end_frame = Frame::containing_address(PhysicalAddress::new(start + size * 4 - 1));
|
||||||
|
for frame in Frame::range_inclusive(start_frame, end_frame) {
|
||||||
|
active_table.identity_map(frame, entry::PRESENT | entry::WRITABLE | entry::NO_EXECUTE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A display
|
||||||
|
pub struct Display {
|
||||||
|
pub width: usize,
|
||||||
|
pub height: usize,
|
||||||
|
pub data: &'static mut [u32],
|
||||||
|
console: Console,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display {
|
||||||
|
fn new(width: usize, height: usize, data: &'static mut [u32]) -> Self {
|
||||||
|
Display {
|
||||||
|
width: width,
|
||||||
|
height: height,
|
||||||
|
data: data,
|
||||||
|
console: Console::new(width/8, height/16)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Draw a rectangle
|
||||||
|
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);
|
||||||
|
|
||||||
|
let start_x = cmp::min(self.width - 1, x);
|
||||||
|
let len = cmp::min(self.width, x + w) - start_x;
|
||||||
|
|
||||||
|
for y in start_y..end_y {
|
||||||
|
let offset = y * self.width + start_x;
|
||||||
|
let row = &mut self.data[offset..offset + len];
|
||||||
|
for pixel in row.iter_mut() {
|
||||||
|
*pixel = color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Draw a character
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn write(&mut self, bytes: &[u8]) {
|
||||||
|
self.console.write(bytes);
|
||||||
|
if self.console.redraw {
|
||||||
|
self.console.redraw = false;
|
||||||
|
|
||||||
|
for y in 0..self.console.h {
|
||||||
|
if self.console.changed[y] {
|
||||||
|
self.console.changed[y] = false;
|
||||||
|
|
||||||
|
for x in 0..self.console.w {
|
||||||
|
let block = self.console.display[y * self.console.w + x];
|
||||||
|
|
||||||
|
let (bg, fg) = if self.console.cursor && self.console.y == y && self.console.x == x {
|
||||||
|
(block.fg.data, block.bg.data)
|
||||||
|
}else{
|
||||||
|
(block.bg.data, block.fg.data)
|
||||||
|
};
|
||||||
|
|
||||||
|
self.rect(x * 8, y * 16, 8, 16, bg);
|
||||||
|
|
||||||
|
if block.c != ' ' {
|
||||||
|
self.char(x * 8, y * 16, block.c, fg);
|
||||||
|
}
|
||||||
|
|
||||||
|
if block.underlined {
|
||||||
|
self.rect(x * 8, y * 16 + 14, 8, 1, fg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
15
arch/x86_64/src/device/mod.rs
Normal file
15
arch/x86_64/src/device/mod.rs
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
use paging::ActivePageTable;
|
||||||
|
|
||||||
|
pub mod display;
|
||||||
|
pub mod ps2;
|
||||||
|
pub mod serial;
|
||||||
|
|
||||||
|
pub unsafe fn init(active_table: &mut ActivePageTable){
|
||||||
|
serial::init();
|
||||||
|
ps2::init();
|
||||||
|
display::init(active_table);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn init_ap(active_table: &mut ActivePageTable) {
|
||||||
|
display::init_ap(active_table);
|
||||||
|
}
|
304
arch/x86_64/src/device/ps2.rs
Normal file
304
arch/x86_64/src/device/ps2.rs
Normal file
|
@ -0,0 +1,304 @@
|
||||||
|
use core::cmp;
|
||||||
|
use spin::Mutex;
|
||||||
|
|
||||||
|
use io::{Io, Pio, ReadOnly, WriteOnly};
|
||||||
|
|
||||||
|
pub static PS2: Mutex<Ps2> = Mutex::new(Ps2::new());
|
||||||
|
|
||||||
|
pub unsafe fn init() {
|
||||||
|
PS2.lock().init();
|
||||||
|
}
|
||||||
|
|
||||||
|
bitflags! {
|
||||||
|
flags StatusFlags: u8 {
|
||||||
|
const OUTPUT_FULL = 1,
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bitflags! {
|
||||||
|
flags ConfigFlags: u8 {
|
||||||
|
const FIRST_INTERRUPT = 1,
|
||||||
|
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,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(u8)]
|
||||||
|
#[allow(dead_code)]
|
||||||
|
enum Command {
|
||||||
|
ReadConfig = 0x20,
|
||||||
|
WriteConfig = 0x60,
|
||||||
|
DisableSecond = 0xA7,
|
||||||
|
EnableSecond = 0xA8,
|
||||||
|
TestSecond = 0xA9,
|
||||||
|
TestController = 0xAA,
|
||||||
|
TestFirst = 0xAB,
|
||||||
|
Diagnostic = 0xAC,
|
||||||
|
DisableFirst = 0xAD,
|
||||||
|
EnableFirst = 0xAE,
|
||||||
|
WriteSecond = 0xD4
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(u8)]
|
||||||
|
#[allow(dead_code)]
|
||||||
|
enum KeyboardCommand {
|
||||||
|
EnableReporting = 0xF4,
|
||||||
|
SetDefaults = 0xF6,
|
||||||
|
Reset = 0xFF
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(u8)]
|
||||||
|
#[allow(dead_code)]
|
||||||
|
enum MouseCommand {
|
||||||
|
GetDeviceId = 0xF2,
|
||||||
|
EnableReporting = 0xF4,
|
||||||
|
SetDefaults = 0xF6,
|
||||||
|
Reset = 0xFF
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(u8)]
|
||||||
|
enum MouseCommandData {
|
||||||
|
SetSampleRate = 0xF3,
|
||||||
|
}
|
||||||
|
|
||||||
|
bitflags! {
|
||||||
|
flags MousePacketFlags: u8 {
|
||||||
|
const LEFT_BUTTON = 1,
|
||||||
|
const RIGHT_BUTTON = 1 << 1,
|
||||||
|
const MIDDLE_BUTTON = 1 << 2,
|
||||||
|
const ALWAYS_ON = 1 << 3,
|
||||||
|
const X_SIGN = 1 << 4,
|
||||||
|
const Y_SIGN = 1 << 5,
|
||||||
|
const X_OVERFLOW = 1 << 6,
|
||||||
|
const Y_OVERFLOW = 1 << 7
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Ps2 {
|
||||||
|
data: Pio<u8>,
|
||||||
|
status: ReadOnly<Pio<u8>>,
|
||||||
|
command: WriteOnly<Pio<u8>>,
|
||||||
|
mouse: [u8; 4],
|
||||||
|
mouse_i: usize,
|
||||||
|
mouse_extra: bool,
|
||||||
|
mouse_x: usize,
|
||||||
|
mouse_y: usize
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Ps2 {
|
||||||
|
const fn new() -> Ps2 {
|
||||||
|
Ps2 {
|
||||||
|
data: Pio::new(0x60),
|
||||||
|
status: ReadOnly::new(Pio::new(0x64)),
|
||||||
|
command: WriteOnly::new(Pio::new(0x64)),
|
||||||
|
mouse: [0; 4],
|
||||||
|
mouse_i: 0,
|
||||||
|
mouse_extra: false,
|
||||||
|
mouse_x: 0,
|
||||||
|
mouse_y: 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn status(&mut self) -> StatusFlags {
|
||||||
|
StatusFlags::from_bits_truncate(self.status.read())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn wait_write(&mut self) {
|
||||||
|
while self.status().contains(INPUT_FULL) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn wait_read(&mut self) {
|
||||||
|
while ! self.status().contains(OUTPUT_FULL) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn flush_read(&mut self) {
|
||||||
|
while self.status().contains(OUTPUT_FULL) {
|
||||||
|
print!("FLUSH: {:X}\n", self.data.read());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn command(&mut self, command: Command) {
|
||||||
|
self.wait_write();
|
||||||
|
self.command.write(command as u8);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read(&mut self) -> u8 {
|
||||||
|
self.wait_read();
|
||||||
|
self.data.read()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write(&mut self, data: u8) {
|
||||||
|
self.wait_write();
|
||||||
|
self.data.write(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn config(&mut self) -> ConfigFlags {
|
||||||
|
self.command(Command::ReadConfig);
|
||||||
|
ConfigFlags::from_bits_truncate(self.read())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_config(&mut self, config: ConfigFlags) {
|
||||||
|
self.command(Command::WriteConfig);
|
||||||
|
self.write(config.bits());
|
||||||
|
}
|
||||||
|
|
||||||
|
fn keyboard_command(&mut self, command: KeyboardCommand) -> u8 {
|
||||||
|
self.write(command as u8);
|
||||||
|
self.read()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mouse_command(&mut self, command: MouseCommand) -> u8 {
|
||||||
|
self.command(Command::WriteSecond);
|
||||||
|
self.write(command as u8);
|
||||||
|
self.read()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mouse_command_data(&mut self, command: MouseCommandData, data: u8) -> u8 {
|
||||||
|
self.command(Command::WriteSecond);
|
||||||
|
self.write(command as u8);
|
||||||
|
self.read();
|
||||||
|
self.command(Command::WriteSecond);
|
||||||
|
self.write(data as u8);
|
||||||
|
self.read()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn init(&mut self) {
|
||||||
|
// Disable devices
|
||||||
|
self.command(Command::DisableFirst);
|
||||||
|
self.command(Command::DisableSecond);
|
||||||
|
|
||||||
|
// Clear remaining data
|
||||||
|
self.flush_read();
|
||||||
|
|
||||||
|
// Disable clocks, disable interrupts, and disable translate
|
||||||
|
{
|
||||||
|
let mut config = self.config();
|
||||||
|
config.insert(FIRST_DISABLED);
|
||||||
|
config.insert(SECOND_DISABLED);
|
||||||
|
config.remove(FIRST_TRANSLATE);
|
||||||
|
config.remove(FIRST_INTERRUPT);
|
||||||
|
config.remove(SECOND_INTERRUPT);
|
||||||
|
self.set_config(config);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Perform the self test
|
||||||
|
self.command(Command::TestController);
|
||||||
|
let self_test = self.read();
|
||||||
|
if self_test != 0x55 {
|
||||||
|
// TODO: Do reset on failure
|
||||||
|
print!("PS/2 Self Test Failure: {:X}\n", self_test);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enable devices
|
||||||
|
self.command(Command::EnableFirst);
|
||||||
|
self.command(Command::EnableSecond);
|
||||||
|
|
||||||
|
// Reset and enable scanning on keyboard
|
||||||
|
// TODO: Check for ack
|
||||||
|
print!("KEYBOARD RESET {:X}\n", self.keyboard_command(KeyboardCommand::Reset));
|
||||||
|
print!("KEYBOARD RESET RESULT {:X} == 0xAA\n", self.read());
|
||||||
|
self.flush_read();
|
||||||
|
|
||||||
|
// Reset and enable scanning on mouse
|
||||||
|
// TODO: Check for ack
|
||||||
|
print!("MOUSE RESET {:X}\n", self.mouse_command(MouseCommand::Reset));
|
||||||
|
print!("MOUSE RESET RESULT {:X} == 0xAA\n", self.read());
|
||||||
|
print!("MOUSE RESET ID {:X} == 0x00\n", self.read());
|
||||||
|
self.flush_read();
|
||||||
|
|
||||||
|
// Enable extra packet on mouse
|
||||||
|
print!("SAMPLE 200 {:X}\n", self.mouse_command_data(MouseCommandData::SetSampleRate, 200));
|
||||||
|
print!("SAMPLE 100 {:X}\n", self.mouse_command_data(MouseCommandData::SetSampleRate, 100));
|
||||||
|
print!("SAMPLE 80 {:X}\n", self.mouse_command_data(MouseCommandData::SetSampleRate, 80));
|
||||||
|
print!("GET ID {:X}\n", self.mouse_command(MouseCommand::GetDeviceId));
|
||||||
|
let mouse_id = self.read();
|
||||||
|
print!("MOUSE ID: {:X} == 0x03\n", mouse_id);
|
||||||
|
self.mouse_extra = mouse_id == 3;
|
||||||
|
|
||||||
|
// Enable extra buttons, TODO
|
||||||
|
/*
|
||||||
|
if self.mouse_extra {
|
||||||
|
print!("SAMPLE 200 {:X}\n", self.mouse_command_data(MouseCommandData::SetSampleRate, 200));
|
||||||
|
print!("SAMPLE 200 {:X}\n", self.mouse_command_data(MouseCommandData::SetSampleRate, 200));
|
||||||
|
print!("SAMPLE 80 {:X}\n", self.mouse_command_data(MouseCommandData::SetSampleRate, 80));
|
||||||
|
print!("GET ID {:X}\n", self.mouse_command(MouseCommand::GetDeviceId));
|
||||||
|
let mouse_id = self.read();
|
||||||
|
print!("MOUSE ID: {:X} == 0x04\n", mouse_id);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Set sample rate to maximum
|
||||||
|
print!("SAMPLE 200 {:X}\n", self.mouse_command_data(MouseCommandData::SetSampleRate, 200));
|
||||||
|
|
||||||
|
// Enable data reporting
|
||||||
|
print!("KEYBOARD ENABLE {:X}\n", self.keyboard_command(KeyboardCommand::EnableReporting));
|
||||||
|
print!("MOUSE ENABLE {:X}\n", self.mouse_command(MouseCommand::EnableReporting));
|
||||||
|
|
||||||
|
// Enable clocks and interrupts
|
||||||
|
{
|
||||||
|
let mut config = self.config();
|
||||||
|
config.remove(FIRST_DISABLED);
|
||||||
|
config.remove(SECOND_DISABLED);
|
||||||
|
config.insert(FIRST_INTERRUPT);
|
||||||
|
config.insert(SECOND_INTERRUPT);
|
||||||
|
self.set_config(config);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn on_keyboard(&mut self) {
|
||||||
|
let data = self.data.read();
|
||||||
|
print!("KEY {:X}\n", data);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn on_mouse(&mut self) {
|
||||||
|
self.mouse[self.mouse_i] = self.data.read();
|
||||||
|
self.mouse_i += 1;
|
||||||
|
if self.mouse_i >= self.mouse.len() || (!self.mouse_extra && self.mouse_i >= 3) {
|
||||||
|
self.mouse_i = 0;
|
||||||
|
|
||||||
|
let flags = MousePacketFlags::from_bits_truncate(self.mouse[0]);
|
||||||
|
|
||||||
|
let mut dx = self.mouse[1] as isize;
|
||||||
|
if flags.contains(X_SIGN) {
|
||||||
|
dx -= 0x100;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut dy = self.mouse[2] as isize;
|
||||||
|
if flags.contains(Y_SIGN) {
|
||||||
|
dy -= 0x100;
|
||||||
|
}
|
||||||
|
|
||||||
|
let _extra = if self.mouse_extra {
|
||||||
|
self.mouse[3]
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
};
|
||||||
|
|
||||||
|
//print!("MOUSE {:?}, {}, {}, {}\n", flags, dx, dy, extra);
|
||||||
|
|
||||||
|
if let Some(ref mut display) = *super::display::DISPLAY.lock() {
|
||||||
|
self.mouse_x = cmp::max(0, cmp::min(display.width as isize - 1, self.mouse_x as isize + dx)) as usize;
|
||||||
|
self.mouse_y = cmp::max(0, cmp::min(display.height as isize - 1, self.mouse_y as isize - dy)) as usize;
|
||||||
|
let offset = self.mouse_y * display.width + self.mouse_x;
|
||||||
|
display.data[offset as usize] = 0xFF0000;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
106
arch/x86_64/src/device/serial.rs
Normal file
106
arch/x86_64/src/device/serial.rs
Normal file
|
@ -0,0 +1,106 @@
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
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 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) {
|
||||||
|
//TODO: Cleanup
|
||||||
|
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();
|
||||||
|
let _ = 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(())
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,91 +0,0 @@
|
||||||
use core::slice;
|
|
||||||
use spin::Mutex;
|
|
||||||
|
|
||||||
use externs::memset;
|
|
||||||
use memory::Frame;
|
|
||||||
use paging::{ActivePageTable, PhysicalAddress, entry};
|
|
||||||
|
|
||||||
/// The info of the VBE mode
|
|
||||||
#[derive(Copy, Clone, Default, Debug)]
|
|
||||||
#[repr(packed)]
|
|
||||||
pub struct VBEModeInfo {
|
|
||||||
attributes: u16,
|
|
||||||
win_a: u8,
|
|
||||||
win_b: u8,
|
|
||||||
granularity: u16,
|
|
||||||
winsize: u16,
|
|
||||||
segment_a: u16,
|
|
||||||
segment_b: u16,
|
|
||||||
winfuncptr: u32,
|
|
||||||
bytesperscanline: u16,
|
|
||||||
pub xresolution: u16,
|
|
||||||
pub yresolution: u16,
|
|
||||||
xcharsize: u8,
|
|
||||||
ycharsize: u8,
|
|
||||||
numberofplanes: u8,
|
|
||||||
bitsperpixel: u8,
|
|
||||||
numberofbanks: u8,
|
|
||||||
memorymodel: u8,
|
|
||||||
banksize: u8,
|
|
||||||
numberofimagepages: u8,
|
|
||||||
unused: u8,
|
|
||||||
redmasksize: u8,
|
|
||||||
redfieldposition: u8,
|
|
||||||
greenmasksize: u8,
|
|
||||||
greenfieldposition: u8,
|
|
||||||
bluemasksize: u8,
|
|
||||||
bluefieldposition: u8,
|
|
||||||
rsvdmasksize: u8,
|
|
||||||
rsvdfieldposition: u8,
|
|
||||||
directcolormodeinfo: u8,
|
|
||||||
physbaseptr: u32,
|
|
||||||
offscreenmemoryoffset: u32,
|
|
||||||
offscreenmemsize: u16,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub static DISPLAY: Mutex<Option<Display>> = Mutex::new(None);
|
|
||||||
|
|
||||||
pub unsafe fn init(active_table: &mut ActivePageTable) {
|
|
||||||
active_table.identity_map(Frame::containing_address(PhysicalAddress::new(0x5200)), entry::PRESENT | entry::NO_EXECUTE);
|
|
||||||
|
|
||||||
let mode_info = &*(0x5200 as *const VBEModeInfo);
|
|
||||||
if mode_info.physbaseptr > 0 {
|
|
||||||
let width = mode_info.xresolution as usize;
|
|
||||||
let height = mode_info.yresolution as usize;
|
|
||||||
let start = mode_info.physbaseptr as usize;
|
|
||||||
let size = width * height;
|
|
||||||
|
|
||||||
{
|
|
||||||
let start_frame = Frame::containing_address(PhysicalAddress::new(start));
|
|
||||||
let end_frame = Frame::containing_address(PhysicalAddress::new(start + size * 4 - 1));
|
|
||||||
for frame in Frame::range_inclusive(start_frame, end_frame) {
|
|
||||||
active_table.identity_map(frame, entry::PRESENT | entry::WRITABLE | entry::NO_EXECUTE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for i in 0..size {
|
|
||||||
let c = ((i * 256)/size) as u32 & 0xFF;
|
|
||||||
*(start as *mut u32).offset(i as isize) = (c << 16) | (c << 8) | c;
|
|
||||||
}
|
|
||||||
//memset(start as *mut u8, 0, size * 4);
|
|
||||||
|
|
||||||
*DISPLAY.lock() = Some(Display::new(width, height, slice::from_raw_parts_mut(start as *mut u32, size)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A display
|
|
||||||
pub struct Display {
|
|
||||||
pub width: usize,
|
|
||||||
pub height: usize,
|
|
||||||
pub data: &'static mut [u32],
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display {
|
|
||||||
fn new(width: usize, height: usize, data: &'static mut [u32]) -> Self {
|
|
||||||
Display {
|
|
||||||
width: width,
|
|
||||||
height: height,
|
|
||||||
data: data,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,7 +1,7 @@
|
||||||
use core::mem;
|
use core::mem;
|
||||||
use x86::dtables::{self, DescriptorTablePointer};
|
use x86::dtables::{self, DescriptorTablePointer};
|
||||||
|
|
||||||
use interrupt::halt;
|
use interrupt::*;
|
||||||
|
|
||||||
pub static mut IDTR: DescriptorTablePointer = DescriptorTablePointer {
|
pub static mut IDTR: DescriptorTablePointer = DescriptorTablePointer {
|
||||||
limit: 0,
|
limit: 0,
|
||||||
|
@ -14,69 +14,56 @@ pub unsafe fn init() {
|
||||||
IDTR.limit = (IDT.len() * mem::size_of::<IdtEntry>() - 1) as u16;
|
IDTR.limit = (IDT.len() * mem::size_of::<IdtEntry>() - 1) as u16;
|
||||||
IDTR.base = IDT.as_ptr() as u64;
|
IDTR.base = IDT.as_ptr() as u64;
|
||||||
|
|
||||||
for entry in IDT[0..32].iter_mut() {
|
// Set up exceptions
|
||||||
entry.set_flags(IDT_PRESENT | IDT_RING_0 | IDT_INTERRUPT);
|
IDT[0].set_func(exception::divide_by_zero);
|
||||||
entry.set_offset(8, exception as usize);
|
IDT[1].set_func(exception::debug);
|
||||||
}
|
IDT[2].set_func(exception::non_maskable);
|
||||||
IDT[13].set_offset(8, protection_fault as usize);
|
IDT[3].set_func(exception::breakpoint);
|
||||||
IDT[14].set_offset(8, page_fault as usize);
|
IDT[4].set_func(exception::overflow);
|
||||||
for entry in IDT[32..].iter_mut() {
|
IDT[5].set_func(exception::bound_range);
|
||||||
entry.set_flags(IDT_PRESENT | IDT_RING_0 | IDT_INTERRUPT);
|
IDT[6].set_func(exception::invalid_opcode);
|
||||||
entry.set_offset(8, blank as usize);
|
IDT[7].set_func(exception::device_not_available);
|
||||||
}
|
IDT[8].set_func(exception::double_fault);
|
||||||
IDT[0x80].set_offset(8, syscall as usize);
|
// 9 no longer available
|
||||||
|
IDT[10].set_func(exception::invalid_tss);
|
||||||
|
IDT[11].set_func(exception::segment_not_present);
|
||||||
|
IDT[12].set_func(exception::stack_segment);
|
||||||
|
IDT[13].set_func(exception::protection);
|
||||||
|
IDT[14].set_func(exception::page);
|
||||||
|
// 15 reserved
|
||||||
|
IDT[16].set_func(exception::fpu);
|
||||||
|
IDT[17].set_func(exception::alignment_check);
|
||||||
|
IDT[18].set_func(exception::machine_check);
|
||||||
|
IDT[19].set_func(exception::simd);
|
||||||
|
IDT[20].set_func(exception::virtualization);
|
||||||
|
// 21 through 29 reserved
|
||||||
|
IDT[30].set_func(exception::security);
|
||||||
|
// 31 reserved
|
||||||
|
|
||||||
|
// Set up IRQs
|
||||||
|
IDT[32].set_func(irq::pit);
|
||||||
|
IDT[33].set_func(irq::keyboard);
|
||||||
|
IDT[34].set_func(irq::cascade);
|
||||||
|
IDT[35].set_func(irq::com2);
|
||||||
|
IDT[36].set_func(irq::com1);
|
||||||
|
IDT[37].set_func(irq::lpt2);
|
||||||
|
IDT[38].set_func(irq::floppy);
|
||||||
|
IDT[39].set_func(irq::lpt1);
|
||||||
|
IDT[40].set_func(irq::rtc);
|
||||||
|
IDT[41].set_func(irq::pci1);
|
||||||
|
IDT[42].set_func(irq::pci2);
|
||||||
|
IDT[43].set_func(irq::pci3);
|
||||||
|
IDT[44].set_func(irq::mouse);
|
||||||
|
IDT[45].set_func(irq::fpu);
|
||||||
|
IDT[46].set_func(irq::ata1);
|
||||||
|
IDT[47].set_func(irq::ata2);
|
||||||
|
|
||||||
|
// Set syscall function
|
||||||
|
IDT[0x80].set_func(syscall::syscall);
|
||||||
|
|
||||||
dtables::lidt(&IDTR);
|
dtables::lidt(&IDTR);
|
||||||
}
|
}
|
||||||
|
|
||||||
interrupt!(blank, {
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
interrupt!(exception, {
|
|
||||||
println!("EXCEPTION");
|
|
||||||
loop {
|
|
||||||
halt();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
interrupt_error!(protection_fault, {
|
|
||||||
println!("PROTECTION FAULT");
|
|
||||||
loop {
|
|
||||||
halt();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
interrupt_error!(page_fault, {
|
|
||||||
println!("PAGE FAULT");
|
|
||||||
loop {
|
|
||||||
halt();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
#[naked]
|
|
||||||
pub unsafe extern fn syscall() {
|
|
||||||
extern {
|
|
||||||
fn syscall(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize) -> usize;
|
|
||||||
}
|
|
||||||
|
|
||||||
let a;
|
|
||||||
let b;
|
|
||||||
let c;
|
|
||||||
let d;
|
|
||||||
let e;
|
|
||||||
let f;
|
|
||||||
asm!("" : "={rax}"(a), "={rbx}"(b), "={rcx}"(c), "={rdx}"(d), "={rsi}"(e), "={rdi}"(f)
|
|
||||||
: : : "intel", "volatile");
|
|
||||||
|
|
||||||
let a = syscall(a, b, c, d, e, f);
|
|
||||||
|
|
||||||
asm!("" : : "{rax}"(a) : : "intel", "volatile");
|
|
||||||
|
|
||||||
// Pop scratch registers, error code, and return
|
|
||||||
asm!("iretq" : : : : "intel", "volatile");
|
|
||||||
}
|
|
||||||
|
|
||||||
bitflags! {
|
bitflags! {
|
||||||
pub flags IdtFlags: u8 {
|
pub flags IdtFlags: u8 {
|
||||||
const IDT_PRESENT = 1 << 7,
|
const IDT_PRESENT = 1 << 7,
|
||||||
|
@ -142,4 +129,10 @@ impl IdtEntry {
|
||||||
self.offsetm = (base >> 16) as u16;
|
self.offsetm = (base >> 16) as u16;
|
||||||
self.offseth = (base >> 32) as u32;
|
self.offseth = (base >> 32) as u32;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// A function to set the offset more easily
|
||||||
|
pub fn set_func(&mut self, func: unsafe extern fn()) {
|
||||||
|
self.set_flags(IDT_PRESENT | IDT_RING_0 | IDT_INTERRUPT);
|
||||||
|
self.set_offset(8, func as usize);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,118 +0,0 @@
|
||||||
//! Interrupt instructions
|
|
||||||
|
|
||||||
/// Clear interrupts
|
|
||||||
#[inline(always)]
|
|
||||||
pub unsafe fn disable() {
|
|
||||||
asm!("cli" : : : : "intel", "volatile");
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Set interrupts
|
|
||||||
#[inline(always)]
|
|
||||||
pub unsafe fn enable() {
|
|
||||||
asm!("sti" : : : : "intel", "volatile");
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Set interrupts and halt
|
|
||||||
#[inline(always)]
|
|
||||||
pub unsafe fn enable_and_halt() {
|
|
||||||
asm!("sti
|
|
||||||
hlt"
|
|
||||||
: : : : "intel", "volatile");
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Halt instruction
|
|
||||||
#[inline(always)]
|
|
||||||
pub unsafe fn halt() {
|
|
||||||
asm!("hlt" : : : : "intel", "volatile");
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Pause instruction
|
|
||||||
/// Safe because it is similar to a NOP, and has no memory effects
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn pause() {
|
|
||||||
unsafe { asm!("pause" : : : : "intel", "volatile"); }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get a stack trace
|
|
||||||
//TODO: Check for stack being mapped before dereferencing
|
|
||||||
#[inline(never)]
|
|
||||||
pub unsafe fn stack_trace() {
|
|
||||||
let mut rbp: usize;
|
|
||||||
asm!("xchg bx, bx" : "={rbp}"(rbp) : : : "intel", "volatile");
|
|
||||||
|
|
||||||
println!("TRACE: {:>016X}", rbp);
|
|
||||||
//Maximum 64 frames
|
|
||||||
for _frame in 0..64 {
|
|
||||||
let rip = *(rbp as *const usize).offset(1);
|
|
||||||
println!(" {:>016X}: {:>016X}", rbp, rip);
|
|
||||||
if rip == 0 {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
rbp = *(rbp as *const usize);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// x86 External Interrupts (1-16).
|
|
||||||
pub static EXCEPTIONS: [Descriptor; 21] = [
|
|
||||||
Descriptor::new("Division error", Kind::Fault),
|
|
||||||
Descriptor::new("Debug trap", Kind::Trap),
|
|
||||||
Descriptor::new("Unmaskable interrupt", Kind::Unmaskable),
|
|
||||||
Descriptor::new("Breakpoint", Kind::Trap),
|
|
||||||
Descriptor::new("Overflow", Kind::Trap),
|
|
||||||
Descriptor::new("Out of bound", Kind::Fault),
|
|
||||||
Descriptor::new("Invalid opcode", Kind::Fault),
|
|
||||||
Descriptor::new("Device unavailable", Kind::Fault),
|
|
||||||
Descriptor::new("Double fault", Kind::Fault),
|
|
||||||
Descriptor::new("Coprocessor segment overrun", Kind::Fault),
|
|
||||||
Descriptor::new("Invalid TSS", Kind::Fault),
|
|
||||||
Descriptor::new("Segment not present", Kind::Fault),
|
|
||||||
Descriptor::new("Stack-segment fault", Kind::Fault),
|
|
||||||
Descriptor::new("General protection", Kind::Fault),
|
|
||||||
Descriptor::new("Page fault", Kind::Fault),
|
|
||||||
Descriptor::new("Reserved", Kind::Reserved),
|
|
||||||
Descriptor::new("x87 FPU", Kind::Fault),
|
|
||||||
Descriptor::new("Unaligned memory access", Kind::Fault),
|
|
||||||
Descriptor::new("Machine check", Kind::Abort),
|
|
||||||
Descriptor::new("SIMD floating-point", Kind::Fault),
|
|
||||||
Descriptor::new("Virtualization violation", Kind::Fault),
|
|
||||||
];
|
|
||||||
|
|
||||||
/// An interrupt description.
|
|
||||||
#[derive(Debug, Copy, Clone)]
|
|
||||||
pub struct Descriptor {
|
|
||||||
/// The description of this interrupt.
|
|
||||||
pub desc: &'static str,
|
|
||||||
/// The interrupt type.
|
|
||||||
pub kind: Kind,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Descriptor {
|
|
||||||
/// Create a new interrupt description.
|
|
||||||
pub const fn new(desc: &'static str, kind: Kind) -> Descriptor {
|
|
||||||
Descriptor {
|
|
||||||
desc: desc,
|
|
||||||
kind: kind,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The interrupt kind.
|
|
||||||
#[derive(Debug, Copy, Clone)]
|
|
||||||
pub enum Kind {
|
|
||||||
/// A fault.
|
|
||||||
///
|
|
||||||
/// This can have multiple sources, but is often a result of a program error of some sort.
|
|
||||||
Fault,
|
|
||||||
/// A trap.
|
|
||||||
///
|
|
||||||
/// These are often for debugging purposes.
|
|
||||||
Trap,
|
|
||||||
/// A deliberate abort.
|
|
||||||
Abort,
|
|
||||||
/// An unmaskable interrupt.
|
|
||||||
///
|
|
||||||
/// This is a forced interrupt which need to be handled immediately.
|
|
||||||
Unmaskable,
|
|
||||||
/// Reserved or deprecated.
|
|
||||||
Reserved,
|
|
||||||
}
|
|
97
arch/x86_64/src/interrupt/exception.rs
Normal file
97
arch/x86_64/src/interrupt/exception.rs
Normal file
|
@ -0,0 +1,97 @@
|
||||||
|
use super::halt;
|
||||||
|
|
||||||
|
interrupt!(divide_by_zero, {
|
||||||
|
print!("Divide by zero fault\n");
|
||||||
|
loop { halt(); }
|
||||||
|
});
|
||||||
|
|
||||||
|
interrupt!(debug, {
|
||||||
|
print!("Debug trap\n");
|
||||||
|
});
|
||||||
|
|
||||||
|
interrupt!(non_maskable, {
|
||||||
|
print!("Non-maskable interrupt\n");
|
||||||
|
});
|
||||||
|
|
||||||
|
interrupt!(breakpoint, {
|
||||||
|
print!("Breakpoint trap\n");
|
||||||
|
});
|
||||||
|
|
||||||
|
interrupt!(overflow, {
|
||||||
|
print!("Overflow trap\n");
|
||||||
|
});
|
||||||
|
|
||||||
|
interrupt!(bound_range, {
|
||||||
|
print!("Bound range exceeded fault\n");
|
||||||
|
loop { halt(); }
|
||||||
|
});
|
||||||
|
|
||||||
|
interrupt!(invalid_opcode, {
|
||||||
|
print!("Invalid opcode fault\n");
|
||||||
|
loop { halt(); }
|
||||||
|
});
|
||||||
|
|
||||||
|
interrupt!(device_not_available, {
|
||||||
|
print!("Device not available fault\n");
|
||||||
|
loop { halt(); }
|
||||||
|
});
|
||||||
|
|
||||||
|
interrupt_error!(double_fault, {
|
||||||
|
print!("Double fault\n");
|
||||||
|
loop { halt(); }
|
||||||
|
});
|
||||||
|
|
||||||
|
interrupt_error!(invalid_tss, {
|
||||||
|
print!("Invalid TSS fault\n");
|
||||||
|
loop { halt(); }
|
||||||
|
});
|
||||||
|
|
||||||
|
interrupt_error!(segment_not_present, {
|
||||||
|
print!("Segment not present fault\n");
|
||||||
|
loop { halt(); }
|
||||||
|
});
|
||||||
|
|
||||||
|
interrupt_error!(stack_segment, {
|
||||||
|
print!("Stack segment fault\n");
|
||||||
|
loop { halt(); }
|
||||||
|
});
|
||||||
|
|
||||||
|
interrupt_error!(protection, {
|
||||||
|
print!("Protection fault\n");
|
||||||
|
loop { halt(); }
|
||||||
|
});
|
||||||
|
|
||||||
|
interrupt_error!(page, {
|
||||||
|
print!("Page fault\n");
|
||||||
|
loop { halt(); }
|
||||||
|
});
|
||||||
|
|
||||||
|
interrupt!(fpu, {
|
||||||
|
print!("FPU floating point fault\n");
|
||||||
|
loop { halt(); }
|
||||||
|
});
|
||||||
|
|
||||||
|
interrupt_error!(alignment_check, {
|
||||||
|
print!("Alignment check fault\n");
|
||||||
|
loop { halt(); }
|
||||||
|
});
|
||||||
|
|
||||||
|
interrupt!(machine_check, {
|
||||||
|
print!("Machine check fault\n");
|
||||||
|
loop { halt(); }
|
||||||
|
});
|
||||||
|
|
||||||
|
interrupt!(simd, {
|
||||||
|
print!("SIMD floating point fault\n");
|
||||||
|
loop { halt(); }
|
||||||
|
});
|
||||||
|
|
||||||
|
interrupt!(virtualization, {
|
||||||
|
print!("Virtualization fault\n");
|
||||||
|
loop { halt(); }
|
||||||
|
});
|
||||||
|
|
||||||
|
interrupt_error!(security, {
|
||||||
|
print!("Security exception\n");
|
||||||
|
loop { halt(); }
|
||||||
|
});
|
99
arch/x86_64/src/interrupt/irq.rs
Normal file
99
arch/x86_64/src/interrupt/irq.rs
Normal file
|
@ -0,0 +1,99 @@
|
||||||
|
use x86::io;
|
||||||
|
|
||||||
|
use device::ps2::PS2;
|
||||||
|
use device::serial::{COM1, COM2};
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
unsafe fn master_ack() {
|
||||||
|
io::outb(0x20, 0x20);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
unsafe fn slave_ack() {
|
||||||
|
io::outb(0xA0, 0x20);
|
||||||
|
master_ack();
|
||||||
|
}
|
||||||
|
|
||||||
|
interrupt!(pit, {
|
||||||
|
io::outb(0x43, 0);
|
||||||
|
let low = io::inb(0x40);
|
||||||
|
let high = io::inb(0x40);
|
||||||
|
let count = (high as u16) << 8 | (low as u16);
|
||||||
|
let _missed = 5370 - count;
|
||||||
|
master_ack();
|
||||||
|
});
|
||||||
|
|
||||||
|
interrupt!(keyboard, {
|
||||||
|
PS2.lock().on_keyboard();
|
||||||
|
master_ack();
|
||||||
|
});
|
||||||
|
|
||||||
|
interrupt!(cascade, {
|
||||||
|
print!("CASCADE\n");
|
||||||
|
master_ack();
|
||||||
|
});
|
||||||
|
|
||||||
|
interrupt!(com2, {
|
||||||
|
COM2.lock().on_receive();
|
||||||
|
master_ack();
|
||||||
|
});
|
||||||
|
|
||||||
|
interrupt!(com1, {
|
||||||
|
COM1.lock().on_receive();
|
||||||
|
master_ack();
|
||||||
|
});
|
||||||
|
|
||||||
|
interrupt!(lpt2, {
|
||||||
|
print!("LPT2\n");
|
||||||
|
master_ack();
|
||||||
|
});
|
||||||
|
|
||||||
|
interrupt!(floppy, {
|
||||||
|
print!("FLOPPY\n");
|
||||||
|
master_ack();
|
||||||
|
});
|
||||||
|
|
||||||
|
interrupt!(lpt1, {
|
||||||
|
print!("LPT1\n");
|
||||||
|
master_ack();
|
||||||
|
});
|
||||||
|
|
||||||
|
interrupt!(rtc, {
|
||||||
|
print!("RTC\n");
|
||||||
|
slave_ack();
|
||||||
|
});
|
||||||
|
|
||||||
|
interrupt!(pci1, {
|
||||||
|
print!("PCI1\n");
|
||||||
|
slave_ack();
|
||||||
|
});
|
||||||
|
|
||||||
|
interrupt!(pci2, {
|
||||||
|
print!("PCI2\n");
|
||||||
|
slave_ack();
|
||||||
|
});
|
||||||
|
|
||||||
|
interrupt!(pci3, {
|
||||||
|
print!("PCI3\n");
|
||||||
|
slave_ack();
|
||||||
|
});
|
||||||
|
|
||||||
|
interrupt!(mouse, {
|
||||||
|
PS2.lock().on_mouse();
|
||||||
|
slave_ack();
|
||||||
|
});
|
||||||
|
|
||||||
|
interrupt!(fpu, {
|
||||||
|
print!("FPU\n");
|
||||||
|
slave_ack();
|
||||||
|
});
|
||||||
|
|
||||||
|
interrupt!(ata1, {
|
||||||
|
print!("ATA1\n");
|
||||||
|
slave_ack();
|
||||||
|
});
|
||||||
|
|
||||||
|
interrupt!(ata2, {
|
||||||
|
print!("ATA2\n");
|
||||||
|
slave_ack();
|
||||||
|
});
|
57
arch/x86_64/src/interrupt/mod.rs
Normal file
57
arch/x86_64/src/interrupt/mod.rs
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
//! Interrupt instructions
|
||||||
|
|
||||||
|
pub mod exception;
|
||||||
|
pub mod irq;
|
||||||
|
pub mod syscall;
|
||||||
|
|
||||||
|
/// Clear interrupts
|
||||||
|
#[inline(always)]
|
||||||
|
pub unsafe fn disable() {
|
||||||
|
asm!("cli" : : : : "intel", "volatile");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set interrupts
|
||||||
|
#[inline(always)]
|
||||||
|
pub unsafe fn enable() {
|
||||||
|
asm!("sti" : : : : "intel", "volatile");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set interrupts and halt
|
||||||
|
#[inline(always)]
|
||||||
|
pub unsafe fn enable_and_halt() {
|
||||||
|
asm!("sti
|
||||||
|
hlt"
|
||||||
|
: : : : "intel", "volatile");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Halt instruction
|
||||||
|
#[inline(always)]
|
||||||
|
pub unsafe fn halt() {
|
||||||
|
asm!("hlt" : : : : "intel", "volatile");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Pause instruction
|
||||||
|
/// Safe because it is similar to a NOP, and has no memory effects
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn pause() {
|
||||||
|
unsafe { asm!("pause" : : : : "intel", "volatile"); }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get a stack trace
|
||||||
|
//TODO: Check for stack being mapped before dereferencing
|
||||||
|
#[inline(never)]
|
||||||
|
pub unsafe fn stack_trace() {
|
||||||
|
let mut rbp: usize;
|
||||||
|
asm!("xchg bx, bx" : "={rbp}"(rbp) : : : "intel", "volatile");
|
||||||
|
|
||||||
|
println!("TRACE: {:>016X}", rbp);
|
||||||
|
//Maximum 64 frames
|
||||||
|
for _frame in 0..64 {
|
||||||
|
let rip = *(rbp as *const usize).offset(1);
|
||||||
|
println!(" {:>016X}: {:>016X}", rbp, rip);
|
||||||
|
if rip == 0 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
rbp = *(rbp as *const usize);
|
||||||
|
}
|
||||||
|
}
|
22
arch/x86_64/src/interrupt/syscall.rs
Normal file
22
arch/x86_64/src/interrupt/syscall.rs
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
#[naked]
|
||||||
|
pub unsafe extern fn syscall() {
|
||||||
|
extern {
|
||||||
|
fn syscall(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize) -> usize;
|
||||||
|
}
|
||||||
|
|
||||||
|
let a;
|
||||||
|
let b;
|
||||||
|
let c;
|
||||||
|
let d;
|
||||||
|
let e;
|
||||||
|
let f;
|
||||||
|
asm!("" : "={rax}"(a), "={rbx}"(b), "={rcx}"(c), "={rdx}"(d), "={rsi}"(e), "={rdi}"(f)
|
||||||
|
: : : "intel", "volatile");
|
||||||
|
|
||||||
|
let a = syscall(a, b, c, d, e, f);
|
||||||
|
|
||||||
|
asm!("" : : "{rax}"(a) : : "intel", "volatile");
|
||||||
|
|
||||||
|
// Pop scratch registers, error code, and return
|
||||||
|
asm!("iretq" : : : : "intel", "volatile");
|
||||||
|
}
|
|
@ -7,10 +7,12 @@ pub trait Io {
|
||||||
fn read(&self) -> Self::Value;
|
fn read(&self) -> Self::Value;
|
||||||
fn write(&mut self, value: Self::Value);
|
fn write(&mut self, value: Self::Value);
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
fn readf(&self, flags: Self::Value) -> bool {
|
fn readf(&self, flags: Self::Value) -> bool {
|
||||||
(self.read() & flags) as Self::Value == flags
|
(self.read() & flags) as Self::Value == flags
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
fn writef(&mut self, flags: Self::Value, value: bool) {
|
fn writef(&mut self, flags: Self::Value, value: bool) {
|
||||||
let tmp: Self::Value = match value {
|
let tmp: Self::Value = match value {
|
||||||
true => self.read() | flags,
|
true => self.read() | flags,
|
||||||
|
@ -25,16 +27,18 @@ pub struct ReadOnly<I: Io> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<I: Io> ReadOnly<I> {
|
impl<I: Io> ReadOnly<I> {
|
||||||
pub fn new(inner: I) -> ReadOnly<I> {
|
pub const fn new(inner: I) -> ReadOnly<I> {
|
||||||
ReadOnly {
|
ReadOnly {
|
||||||
inner: inner
|
inner: inner
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
pub fn read(&self) -> I::Value {
|
pub fn read(&self) -> I::Value {
|
||||||
self.inner.read()
|
self.inner.read()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
pub fn readf(&self, flags: I::Value) -> bool {
|
pub fn readf(&self, flags: I::Value) -> bool {
|
||||||
self.inner.readf(flags)
|
self.inner.readf(flags)
|
||||||
}
|
}
|
||||||
|
@ -45,16 +49,18 @@ pub struct WriteOnly<I: Io> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<I: Io> WriteOnly<I> {
|
impl<I: Io> WriteOnly<I> {
|
||||||
pub fn new(inner: I) -> WriteOnly<I> {
|
pub const fn new(inner: I) -> WriteOnly<I> {
|
||||||
WriteOnly {
|
WriteOnly {
|
||||||
inner: inner
|
inner: inner
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
pub fn write(&mut self, value: I::Value) {
|
pub fn write(&mut self, value: I::Value) {
|
||||||
self.inner.write(value)
|
self.inner.write(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
pub fn writef(&mut self, flags: I::Value, value: bool) {
|
pub fn writef(&mut self, flags: I::Value, value: bool) {
|
||||||
self.inner.writef(flags, value)
|
self.inner.writef(flags, value)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
use core::marker::PhantomData;
|
use core::marker::PhantomData;
|
||||||
|
use x86::io;
|
||||||
|
|
||||||
use super::io::Io;
|
use super::io::Io;
|
||||||
|
|
||||||
|
@ -24,19 +25,15 @@ impl Io for Pio<u8> {
|
||||||
type Value = u8;
|
type Value = u8;
|
||||||
|
|
||||||
/// Read
|
/// Read
|
||||||
|
#[inline(always)]
|
||||||
fn read(&self) -> u8 {
|
fn read(&self) -> u8 {
|
||||||
let value: u8;
|
unsafe { io::inb(self.port) }
|
||||||
unsafe {
|
|
||||||
asm!("in $0, $1" : "={al}"(value) : "{dx}"(self.port) : "memory" : "intel", "volatile");
|
|
||||||
}
|
|
||||||
value
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Write
|
/// Write
|
||||||
|
#[inline(always)]
|
||||||
fn write(&mut self, value: u8) {
|
fn write(&mut self, value: u8) {
|
||||||
unsafe {
|
unsafe { io::outb(self.port, value) }
|
||||||
asm!("out $1, $0" : : "{al}"(value), "{dx}"(self.port) : "memory" : "intel", "volatile");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -45,19 +42,15 @@ impl Io for Pio<u16> {
|
||||||
type Value = u16;
|
type Value = u16;
|
||||||
|
|
||||||
/// Read
|
/// Read
|
||||||
|
#[inline(always)]
|
||||||
fn read(&self) -> u16 {
|
fn read(&self) -> u16 {
|
||||||
let value: u16;
|
unsafe { io::inw(self.port) }
|
||||||
unsafe {
|
|
||||||
asm!("in $0, $1" : "={ax}"(value) : "{dx}"(self.port) : "memory" : "intel", "volatile");
|
|
||||||
}
|
|
||||||
value
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Write
|
/// Write
|
||||||
|
#[inline(always)]
|
||||||
fn write(&mut self, value: u16) {
|
fn write(&mut self, value: u16) {
|
||||||
unsafe {
|
unsafe { io::outw(self.port, value) }
|
||||||
asm!("out $1, $0" : : "{ax}"(value), "{dx}"(self.port) : "memory" : "intel", "volatile");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -66,18 +59,14 @@ impl Io for Pio<u32> {
|
||||||
type Value = u32;
|
type Value = u32;
|
||||||
|
|
||||||
/// Read
|
/// Read
|
||||||
|
#[inline(always)]
|
||||||
fn read(&self) -> u32 {
|
fn read(&self) -> u32 {
|
||||||
let value: u32;
|
unsafe { io::inl(self.port) }
|
||||||
unsafe {
|
|
||||||
asm!("in $0, $1" : "={eax}"(value) : "{dx}"(self.port) : "memory" : "intel", "volatile");
|
|
||||||
}
|
|
||||||
value
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Write
|
/// Write
|
||||||
|
#[inline(always)]
|
||||||
fn write(&mut self, value: u32) {
|
fn write(&mut self, value: u32) {
|
||||||
unsafe {
|
unsafe { io::outl(self.port, value) }
|
||||||
asm!("out $1, $0" : : "{eax}"(value), "{dx}"(self.port) : "memory" : "intel", "volatile");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
#![feature(concat_idents)]
|
#![feature(concat_idents)]
|
||||||
#![feature(const_fn)]
|
#![feature(const_fn)]
|
||||||
#![feature(core_intrinsics)]
|
#![feature(core_intrinsics)]
|
||||||
|
#![feature(drop_types_in_const)]
|
||||||
#![feature(lang_items)]
|
#![feature(lang_items)]
|
||||||
#![feature(naked_functions)]
|
#![feature(naked_functions)]
|
||||||
#![feature(thread_local)]
|
#![feature(thread_local)]
|
||||||
|
@ -13,6 +14,7 @@
|
||||||
extern crate hole_list_allocator as allocator;
|
extern crate hole_list_allocator as allocator;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate bitflags;
|
extern crate bitflags;
|
||||||
|
extern crate ransid;
|
||||||
extern crate spin;
|
extern crate spin;
|
||||||
extern crate x86;
|
extern crate x86;
|
||||||
|
|
||||||
|
@ -21,7 +23,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::console::CONSOLE.lock(), $($arg)*);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -44,8 +46,7 @@ macro_rules! interrupt {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Push scratch registers
|
// Push scratch registers
|
||||||
asm!("xchg bx, bx
|
asm!("push rax
|
||||||
push rax
|
|
||||||
push rcx
|
push rcx
|
||||||
push rdx
|
push rdx
|
||||||
push rdi
|
push rdi
|
||||||
|
@ -86,8 +87,7 @@ macro_rules! interrupt_error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Push scratch registers
|
// Push scratch registers
|
||||||
asm!("xchg bx, bx
|
asm!("push rax
|
||||||
push rax
|
|
||||||
push rcx
|
push rcx
|
||||||
push rdx
|
push rdx
|
||||||
push rdi
|
push rdi
|
||||||
|
@ -121,11 +121,14 @@ macro_rules! interrupt_error {
|
||||||
/// ACPI table parsing
|
/// ACPI table parsing
|
||||||
pub mod acpi;
|
pub mod acpi;
|
||||||
|
|
||||||
|
/// Console handling
|
||||||
|
pub mod console;
|
||||||
|
|
||||||
/// Context switching
|
/// Context switching
|
||||||
pub mod context;
|
pub mod context;
|
||||||
|
|
||||||
/// Display handling
|
/// Devices
|
||||||
pub mod display;
|
pub mod device;
|
||||||
|
|
||||||
/// Memcpy, memmove, etc.
|
/// Memcpy, memmove, etc.
|
||||||
pub mod externs;
|
pub mod externs;
|
||||||
|
@ -151,8 +154,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(())
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -7,7 +7,7 @@ use core::sync::atomic::{AtomicBool, ATOMIC_BOOL_INIT, AtomicUsize, ATOMIC_USIZE
|
||||||
|
|
||||||
use acpi;
|
use acpi;
|
||||||
use allocator::{HEAP_START, HEAP_SIZE};
|
use allocator::{HEAP_START, HEAP_SIZE};
|
||||||
use display;
|
use device;
|
||||||
use externs::memset;
|
use externs::memset;
|
||||||
use gdt;
|
use gdt;
|
||||||
use idt;
|
use idt;
|
||||||
|
@ -92,17 +92,11 @@ pub unsafe extern fn kstart() -> ! {
|
||||||
assert_eq!(TDATA_TEST_NONZERO, 0xFFFFFFFFFFFFFFFE);
|
assert_eq!(TDATA_TEST_NONZERO, 0xFFFFFFFFFFFFFFFE);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize display
|
|
||||||
display::init(&mut active_table);
|
|
||||||
|
|
||||||
// Reset AP variables
|
// Reset AP variables
|
||||||
AP_COUNT.store(0, Ordering::SeqCst);
|
AP_COUNT.store(0, Ordering::SeqCst);
|
||||||
BSP_READY.store(false, Ordering::SeqCst);
|
BSP_READY.store(false, Ordering::SeqCst);
|
||||||
HEAP_FRAME.store(0, Ordering::SeqCst);
|
HEAP_FRAME.store(0, Ordering::SeqCst);
|
||||||
|
|
||||||
// Read ACPI tables, starts APs
|
|
||||||
acpi::init(&mut active_table);
|
|
||||||
|
|
||||||
// Map heap
|
// Map heap
|
||||||
{
|
{
|
||||||
let heap_start_page = Page::containing_address(VirtualAddress::new(HEAP_START));
|
let heap_start_page = Page::containing_address(VirtualAddress::new(HEAP_START));
|
||||||
|
@ -129,6 +123,12 @@ pub unsafe extern fn kstart() -> ! {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Initialize devices
|
||||||
|
device::init(&mut active_table);
|
||||||
|
|
||||||
|
// Read ACPI tables, starts APs
|
||||||
|
acpi::init(&mut active_table);
|
||||||
|
|
||||||
BSP_READY.store(true, Ordering::SeqCst);
|
BSP_READY.store(true, Ordering::SeqCst);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -184,6 +184,9 @@ pub unsafe extern fn kstart_ap(stack_start: usize, stack_end: usize) -> ! {
|
||||||
entry.set(frame, entry::PRESENT | entry::WRITABLE);
|
entry.set(frame, entry::PRESENT | entry::WRITABLE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Init devices for AP
|
||||||
|
device::init_ap(&mut active_table);
|
||||||
}
|
}
|
||||||
|
|
||||||
let ap_number = AP_COUNT.fetch_add(1, Ordering::SeqCst);
|
let ap_number = AP_COUNT.fetch_add(1, Ordering::SeqCst);
|
||||||
|
|
|
@ -1,15 +0,0 @@
|
||||||
use ransid::Console;
|
|
||||||
use spin::{Once, Mutex, MutexGuard};
|
|
||||||
|
|
||||||
/// Console
|
|
||||||
static CONSOLE: Once<Mutex<Console>> = Once::new();
|
|
||||||
|
|
||||||
/// Initialize console, called if needed
|
|
||||||
fn init_console() -> Mutex<Console> {
|
|
||||||
Mutex::new(Console::new(0, 0))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get the global console
|
|
||||||
pub fn console() -> MutexGuard<'static, Console> {
|
|
||||||
CONSOLE.call_once(init_console).lock()
|
|
||||||
}
|
|
|
@ -80,7 +80,7 @@ impl ContextList {
|
||||||
}
|
}
|
||||||
context.arch.set_stack(stack.as_ptr() as usize + offset);
|
context.arch.set_stack(stack.as_ptr() as usize + offset);
|
||||||
context.kstack = Some(stack);
|
context.kstack = Some(stack);
|
||||||
print!("{}", format!("{}: {:X}\n", context.id, func as usize));
|
println!("{}: {:X}", context.id, func as usize);
|
||||||
}
|
}
|
||||||
Ok(context_lock)
|
Ok(context_lock)
|
||||||
}
|
}
|
||||||
|
@ -151,13 +151,11 @@ pub unsafe fn switch() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe {
|
|
||||||
(&mut *from_ptr).running = false;
|
(&mut *from_ptr).running = false;
|
||||||
(&mut *to_ptr).running = true;
|
(&mut *to_ptr).running = true;
|
||||||
CONTEXT_ID.store((&mut *to_ptr).id, Ordering::SeqCst);
|
CONTEXT_ID.store((&mut *to_ptr).id, Ordering::SeqCst);
|
||||||
|
|
||||||
(&mut *from_ptr).arch.switch_to(&mut (&mut *to_ptr).arch);
|
(&mut *from_ptr).arch.switch_to(&mut (&mut *to_ptr).arch);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A context, which identifies either a process or a thread
|
/// A context, which identifies either a process or a thread
|
||||||
|
|
|
@ -97,12 +97,8 @@ extern crate collections;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate bitflags;
|
extern crate bitflags;
|
||||||
extern crate goblin;
|
extern crate goblin;
|
||||||
extern crate ransid;
|
|
||||||
extern crate spin;
|
extern crate spin;
|
||||||
|
|
||||||
/// Console
|
|
||||||
pub mod console;
|
|
||||||
|
|
||||||
/// Context management
|
/// Context management
|
||||||
pub mod context;
|
pub mod context;
|
||||||
|
|
||||||
|
@ -134,9 +130,10 @@ pub extern fn context_test() {
|
||||||
pub extern fn kmain() {
|
pub extern fn kmain() {
|
||||||
context::init();
|
context::init();
|
||||||
|
|
||||||
print!("{}", format!("BSP: {:?}\n", syscall::getpid()));
|
let pid = syscall::getpid();
|
||||||
|
println!("BSP: {:?}", pid);
|
||||||
|
|
||||||
if let Ok(context_lock) = context::contexts_mut().spawn(context_test) {
|
if let Ok(_context_lock) = context::contexts_mut().spawn(context_test) {
|
||||||
print!("Spawned context\n");
|
print!("Spawned context\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -153,7 +150,8 @@ pub extern fn kmain() {
|
||||||
pub extern fn kmain_ap(id: usize) {
|
pub extern fn kmain_ap(id: usize) {
|
||||||
context::init();
|
context::init();
|
||||||
|
|
||||||
print!("{}", format!("AP {}: {:?}\n", id, syscall::getpid()));
|
let pid = syscall::getpid();
|
||||||
|
println!("AP {}: {:?}", id, pid);
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
unsafe { interrupt::enable_and_halt() }
|
unsafe { interrupt::enable_and_halt() }
|
||||||
|
|
BIN
res/unifont.font
Normal file
BIN
res/unifont.font
Normal file
Binary file not shown.
Loading…
Reference in a new issue