Merge branch 'master' of github.com:redox-os/kernel

This commit is contained in:
ticki 2016-09-01 21:36:32 +02:00
commit 04f6e7b558
24 changed files with 1015 additions and 392 deletions

View file

@ -9,7 +9,6 @@ crate-type = ["staticlib"]
[dependencies]
bitflags = "*"
ransid = "*"
spin = "*"
[dependencies.goblin]

View file

@ -5,8 +5,9 @@ version = "0.1.0"
[dependencies]
bitflags = "*"
hole_list_allocator = { path = "../../alloc/hole_list_allocator"}
ransid = "*"
spin = "*"
[dependencies.x86]
default-features = false
version = "0.7.1"
default-features = false

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

View file

@ -1,4 +1,3 @@
use core::mem;
use core::sync::atomic::{AtomicBool, ATOMIC_BOOL_INIT, Ordering};
/// This must be used by the kernel to ensure that context switches are done atomically
@ -52,8 +51,6 @@ impl Context {
#[inline(never)]
#[naked]
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");
self.loadable = true;

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

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

View 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;
}
}
}
}

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

View file

@ -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,
}
}
}

View file

@ -1,7 +1,7 @@
use core::mem;
use x86::dtables::{self, DescriptorTablePointer};
use interrupt::halt;
use interrupt::*;
pub static mut IDTR: DescriptorTablePointer = DescriptorTablePointer {
limit: 0,
@ -14,69 +14,56 @@ pub unsafe fn init() {
IDTR.limit = (IDT.len() * mem::size_of::<IdtEntry>() - 1) as u16;
IDTR.base = IDT.as_ptr() as u64;
for entry in IDT[0..32].iter_mut() {
entry.set_flags(IDT_PRESENT | IDT_RING_0 | IDT_INTERRUPT);
entry.set_offset(8, exception as usize);
}
IDT[13].set_offset(8, protection_fault as usize);
IDT[14].set_offset(8, page_fault as usize);
for entry in IDT[32..].iter_mut() {
entry.set_flags(IDT_PRESENT | IDT_RING_0 | IDT_INTERRUPT);
entry.set_offset(8, blank as usize);
}
IDT[0x80].set_offset(8, syscall as usize);
// Set up exceptions
IDT[0].set_func(exception::divide_by_zero);
IDT[1].set_func(exception::debug);
IDT[2].set_func(exception::non_maskable);
IDT[3].set_func(exception::breakpoint);
IDT[4].set_func(exception::overflow);
IDT[5].set_func(exception::bound_range);
IDT[6].set_func(exception::invalid_opcode);
IDT[7].set_func(exception::device_not_available);
IDT[8].set_func(exception::double_fault);
// 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);
}
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! {
pub flags IdtFlags: u8 {
const IDT_PRESENT = 1 << 7,
@ -142,4 +129,10 @@ impl IdtEntry {
self.offsetm = (base >> 16) as u16;
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);
}
}

View file

@ -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,
}

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

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

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

View 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");
}

View file

@ -7,10 +7,12 @@ pub trait Io {
fn read(&self) -> Self::Value;
fn write(&mut self, value: Self::Value);
#[inline(always)]
fn readf(&self, flags: Self::Value) -> bool {
(self.read() & flags) as Self::Value == flags
}
#[inline(always)]
fn writef(&mut self, flags: Self::Value, value: bool) {
let tmp: Self::Value = match value {
true => self.read() | flags,
@ -25,16 +27,18 @@ pub struct ReadOnly<I: Io> {
}
impl<I: Io> ReadOnly<I> {
pub fn new(inner: I) -> ReadOnly<I> {
pub const fn new(inner: I) -> ReadOnly<I> {
ReadOnly {
inner: inner
}
}
#[inline(always)]
pub fn read(&self) -> I::Value {
self.inner.read()
}
#[inline(always)]
pub fn readf(&self, flags: I::Value) -> bool {
self.inner.readf(flags)
}
@ -45,16 +49,18 @@ pub struct WriteOnly<I: Io> {
}
impl<I: Io> WriteOnly<I> {
pub fn new(inner: I) -> WriteOnly<I> {
pub const fn new(inner: I) -> WriteOnly<I> {
WriteOnly {
inner: inner
}
}
#[inline(always)]
pub fn write(&mut self, value: I::Value) {
self.inner.write(value)
}
#[inline(always)]
pub fn writef(&mut self, flags: I::Value, value: bool) {
self.inner.writef(flags, value)
}

View file

@ -1,4 +1,5 @@
use core::marker::PhantomData;
use x86::io;
use super::io::Io;
@ -24,19 +25,15 @@ impl Io for Pio<u8> {
type Value = u8;
/// Read
#[inline(always)]
fn read(&self) -> u8 {
let value: u8;
unsafe {
asm!("in $0, $1" : "={al}"(value) : "{dx}"(self.port) : "memory" : "intel", "volatile");
}
value
unsafe { io::inb(self.port) }
}
/// Write
#[inline(always)]
fn write(&mut self, value: u8) {
unsafe {
asm!("out $1, $0" : : "{al}"(value), "{dx}"(self.port) : "memory" : "intel", "volatile");
}
unsafe { io::outb(self.port, value) }
}
}
@ -45,19 +42,15 @@ impl Io for Pio<u16> {
type Value = u16;
/// Read
#[inline(always)]
fn read(&self) -> u16 {
let value: u16;
unsafe {
asm!("in $0, $1" : "={ax}"(value) : "{dx}"(self.port) : "memory" : "intel", "volatile");
}
value
unsafe { io::inw(self.port) }
}
/// Write
#[inline(always)]
fn write(&mut self, value: u16) {
unsafe {
asm!("out $1, $0" : : "{ax}"(value), "{dx}"(self.port) : "memory" : "intel", "volatile");
}
unsafe { io::outw(self.port, value) }
}
}
@ -66,18 +59,14 @@ impl Io for Pio<u32> {
type Value = u32;
/// Read
#[inline(always)]
fn read(&self) -> u32 {
let value: u32;
unsafe {
asm!("in $0, $1" : "={eax}"(value) : "{dx}"(self.port) : "memory" : "intel", "volatile");
}
value
unsafe { io::inl(self.port) }
}
/// Write
#[inline(always)]
fn write(&mut self, value: u32) {
unsafe {
asm!("out $1, $0" : : "{eax}"(value), "{dx}"(self.port) : "memory" : "intel", "volatile");
}
unsafe { io::outl(self.port, value) }
}
}

View file

@ -4,6 +4,7 @@
#![feature(concat_idents)]
#![feature(const_fn)]
#![feature(core_intrinsics)]
#![feature(drop_types_in_const)]
#![feature(lang_items)]
#![feature(naked_functions)]
#![feature(thread_local)]
@ -13,6 +14,7 @@
extern crate hole_list_allocator as allocator;
#[macro_use]
extern crate bitflags;
extern crate ransid;
extern crate spin;
extern crate x86;
@ -21,7 +23,7 @@ extern crate x86;
macro_rules! print {
($($arg:tt)*) => ({
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
asm!("xchg bx, bx
push rax
asm!("push rax
push rcx
push rdx
push rdi
@ -86,8 +87,7 @@ macro_rules! interrupt_error {
}
// Push scratch registers
asm!("xchg bx, bx
push rax
asm!("push rax
push rcx
push rdx
push rdi
@ -121,11 +121,14 @@ macro_rules! interrupt_error {
/// ACPI table parsing
pub mod acpi;
/// Console handling
pub mod console;
/// Context switching
pub mod context;
/// Display handling
pub mod display;
/// Devices
pub mod device;
/// Memcpy, memmove, etc.
pub mod externs;
@ -151,8 +154,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

@ -7,7 +7,7 @@ use core::sync::atomic::{AtomicBool, ATOMIC_BOOL_INIT, AtomicUsize, ATOMIC_USIZE
use acpi;
use allocator::{HEAP_START, HEAP_SIZE};
use display;
use device;
use externs::memset;
use gdt;
use idt;
@ -92,17 +92,11 @@ pub unsafe extern fn kstart() -> ! {
assert_eq!(TDATA_TEST_NONZERO, 0xFFFFFFFFFFFFFFFE);
}
// Initialize display
display::init(&mut active_table);
// Reset AP variables
AP_COUNT.store(0, Ordering::SeqCst);
BSP_READY.store(false, Ordering::SeqCst);
HEAP_FRAME.store(0, Ordering::SeqCst);
// Read ACPI tables, starts APs
acpi::init(&mut active_table);
// Map heap
{
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);
}
@ -184,6 +184,9 @@ pub unsafe extern fn kstart_ap(stack_start: usize, stack_end: usize) -> ! {
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);

View file

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

View file

@ -80,7 +80,7 @@ impl ContextList {
}
context.arch.set_stack(stack.as_ptr() as usize + offset);
context.kstack = Some(stack);
print!("{}", format!("{}: {:X}\n", context.id, func as usize));
println!("{}: {:X}", context.id, func as usize);
}
Ok(context_lock)
}
@ -151,13 +151,11 @@ pub unsafe fn switch() {
return;
}
unsafe {
(&mut *from_ptr).running = false;
(&mut *to_ptr).running = true;
CONTEXT_ID.store((&mut *to_ptr).id, Ordering::SeqCst);
(&mut *from_ptr).arch.switch_to(&mut (&mut *to_ptr).arch);
}
(&mut *from_ptr).running = false;
(&mut *to_ptr).running = true;
CONTEXT_ID.store((&mut *to_ptr).id, Ordering::SeqCst);
(&mut *from_ptr).arch.switch_to(&mut (&mut *to_ptr).arch);
}
/// A context, which identifies either a process or a thread

View file

@ -97,12 +97,8 @@ extern crate collections;
#[macro_use]
extern crate bitflags;
extern crate goblin;
extern crate ransid;
extern crate spin;
/// Console
pub mod console;
/// Context management
pub mod context;
@ -134,9 +130,10 @@ pub extern fn context_test() {
pub extern fn kmain() {
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");
}
@ -153,7 +150,8 @@ pub extern fn kmain() {
pub extern fn kmain_ap(id: usize) {
context::init();
print!("{}", format!("AP {}: {:?}\n", id, syscall::getpid()));
let pid = syscall::getpid();
println!("AP {}: {:?}", id, pid);
loop {
unsafe { interrupt::enable_and_halt() }

BIN
res/unifont.font Normal file

Binary file not shown.