Move arch to seperate crate

This commit is contained in:
Jeremy Soller 2016-08-14 11:45:47 -06:00
parent 3967c0f291
commit 2730144e2a
22 changed files with 156 additions and 101 deletions

6
arch/x86_64/Cargo.toml Normal file
View file

@ -0,0 +1,6 @@
[package]
name = "arch"
version = "0.1.0"
[dependencies]
bitflags = "*"

31
arch/x86_64/src/gdt.rs Normal file
View file

@ -0,0 +1,31 @@
pub const GDT_NULL: usize = 0;
pub const GDT_KERNEL_CODE: usize = 1;
pub const GDT_KERNEL_DATA: usize = 2;
pub const GDT_USER_CODE: usize = 3;
pub const GDT_USER_DATA: usize = 4;
pub const GDT_USER_TLS: usize = 5;
pub const GDT_TSS: usize = 6;
#[repr(packed)]
pub struct GdtDescriptor {
pub size: u16,
pub ptr: u64
}
#[repr(packed)]
pub struct GdtEntry {
pub limitl: u16,
pub basel: u16,
pub basem: u8,
pub attribute: u8,
pub flags_limith: u8,
pub baseh: u8
}
impl GdtEntry {
pub fn set_base(&mut self, base: usize) {
self.basel = base as u16;
self.basem = (base >> 16) as u8;
self.baseh = (base >> 24) as u8;
}
}

75
arch/x86_64/src/idt.rs Normal file
View file

@ -0,0 +1,75 @@
use core::mem;
pub static mut IDTR: IdtDescriptor = IdtDescriptor {
size: 0,
offset: 0
};
pub static mut IDT: [IdtEntry; 256] = [IdtEntry::new(); 256];
bitflags! {
pub flags IdtFlags: u8 {
const IDT_PRESENT = 1 << 7,
const IDT_RING_0 = 0 << 5,
const IDT_RING_1 = 1 << 5,
const IDT_RING_2 = 2 << 5,
const IDT_RING_3 = 3 << 5,
const IDT_SS = 1 << 4,
const IDT_INTERRUPT = 0xE,
const IDT_TRAP = 0xF,
}
}
#[repr(packed)]
pub struct IdtDescriptor {
size: u16,
offset: u64
}
impl IdtDescriptor {
pub fn set_slice(&mut self, slice: &'static [IdtEntry]) {
self.size = (slice.len() * mem::size_of::<IdtEntry>() - 1) as u16;
self.offset = slice.as_ptr() as u64;
}
pub unsafe fn load(&self) {
asm!("lidt [rax]" : : "{rax}"(self as *const _ as usize) : : "intel", "volatile");
}
}
#[derive(Copy, Clone, Debug)]
#[repr(packed)]
pub struct IdtEntry {
offsetl: u16,
selector: u16,
zero: u8,
attribute: u8,
offsetm: u16,
offseth: u32,
zero2: u32
}
impl IdtEntry {
pub const fn new() -> IdtEntry {
IdtEntry {
offsetl: 0,
selector: 0,
zero: 0,
attribute: 0,
offsetm: 0,
offseth: 0,
zero2: 0
}
}
pub fn set_flags(&mut self, flags: IdtFlags) {
self.attribute = flags.bits;
}
pub fn set_offset(&mut self, selector: u16, base: usize) {
self.selector = selector;
self.offsetl = base as u16;
self.offsetm = (base >> 16) as u16;
self.offseth = (base >> 32) as u32;
}
}

View file

@ -0,0 +1,19 @@
//! Interrupt instructions
/// Clear interrupts
#[inline(always)]
pub unsafe fn clear_interrupts() {
asm!("cli" : : : : "intel", "volatile");
}
/// Set interrupts
#[inline(always)]
pub unsafe fn set_interrupts() {
asm!("sti" : : : : "intel", "volatile");
}
/// Halt instruction
#[inline(always)]
pub unsafe fn halt() {
asm!("hlt" : : : : "intel", "volatile");
}

61
arch/x86_64/src/io/io.rs Normal file
View file

@ -0,0 +1,61 @@
use core::cmp::PartialEq;
use core::ops::{BitAnd, BitOr, Not};
pub trait Io {
type Value: Copy + PartialEq + BitAnd<Output = Self::Value> + BitOr<Output = Self::Value> + Not<Output = Self::Value>;
fn read(&self) -> Self::Value;
fn write(&mut self, value: Self::Value);
fn readf(&self, flags: Self::Value) -> bool {
(self.read() & flags) as Self::Value == flags
}
fn writef(&mut self, flags: Self::Value, value: bool) {
let tmp: Self::Value = match value {
true => self.read() | flags,
false => self.read() & !flags,
};
self.write(tmp);
}
}
pub struct ReadOnly<I: Io> {
inner: I
}
impl<I: Io> ReadOnly<I> {
pub fn new(inner: I) -> ReadOnly<I> {
ReadOnly {
inner: inner
}
}
pub fn read(&self) -> I::Value {
self.inner.read()
}
pub fn readf(&self, flags: I::Value) -> bool {
self.inner.readf(flags)
}
}
pub struct WriteOnly<I: Io> {
inner: I
}
impl<I: Io> WriteOnly<I> {
pub fn new(inner: I) -> WriteOnly<I> {
WriteOnly {
inner: inner
}
}
pub fn write(&mut self, value: I::Value) {
self.inner.write(value)
}
pub fn writef(&mut self, flags: I::Value, value: bool) {
self.inner.writef(flags, value)
}
}

View file

@ -0,0 +1,31 @@
use core::intrinsics::{volatile_load, volatile_store};
use core::mem::uninitialized;
use core::ops::{BitAnd, BitOr, Not};
use super::io::Io;
#[repr(packed)]
pub struct Mmio<T> {
value: T,
}
impl<T> Mmio<T> {
/// Create a new Mmio without initializing
pub fn new() -> Self {
Mmio {
value: unsafe { uninitialized() }
}
}
}
impl<T> Io for Mmio<T> where T: Copy + PartialEq + BitAnd<Output = T> + BitOr<Output = T> + Not<Output = T> {
type Value = T;
fn read(&self) -> T {
unsafe { volatile_load(&self.value) }
}
fn write(&mut self, value: T) {
unsafe { volatile_store(&mut self.value, value) };
}
}

View file

@ -0,0 +1,9 @@
/// I/O functions
pub use self::io::*;
pub use self::mmio::*;
pub use self::pio::*;
mod io;
mod mmio;
mod pio;

83
arch/x86_64/src/io/pio.rs Normal file
View file

@ -0,0 +1,83 @@
use core::marker::PhantomData;
use super::io::Io;
/// Generic PIO
#[derive(Copy, Clone)]
pub struct Pio<T> {
port: u16,
value: PhantomData<T>,
}
impl<T> Pio<T> {
/// Create a PIO from a given port
pub fn new(port: u16) -> Self {
Pio::<T> {
port: port,
value: PhantomData,
}
}
}
/// Read/Write for byte PIO
impl Io for Pio<u8> {
type Value = u8;
/// Read
fn read(&self) -> u8 {
let value: u8;
unsafe {
asm!("in $0, $1" : "={al}"(value) : "{dx}"(self.port) : "memory" : "intel", "volatile");
}
value
}
/// Write
fn write(&mut self, value: u8) {
unsafe {
asm!("out $1, $0" : : "{al}"(value), "{dx}"(self.port) : "memory" : "intel", "volatile");
}
}
}
/// Read/Write for word PIO
impl Io for Pio<u16> {
type Value = u16;
/// Read
fn read(&self) -> u16 {
let value: u16;
unsafe {
asm!("in $0, $1" : "={ax}"(value) : "{dx}"(self.port) : "memory" : "intel", "volatile");
}
value
}
/// Write
fn write(&mut self, value: u16) {
unsafe {
asm!("out $1, $0" : : "{ax}"(value), "{dx}"(self.port) : "memory" : "intel", "volatile");
}
}
}
/// Read/Write for doubleword PIO
impl Io for Pio<u32> {
type Value = u32;
/// Read
fn read(&self) -> u32 {
let value: u32;
unsafe {
asm!("in $0, $1" : "={eax}"(value) : "{dx}"(self.port) : "memory" : "intel", "volatile");
}
value
}
/// Write
fn write(&mut self, value: u32) {
unsafe {
asm!("out $1, $0" : : "{eax}"(value), "{dx}"(self.port) : "memory" : "intel", "volatile");
}
}
}

10
arch/x86_64/src/irq.rs Normal file
View file

@ -0,0 +1,10 @@
//! # IRQ handling
//!
//! This module defines IRQ handling functions. These functions should all be #[naked],
//! unsafe, extern, and end in `iretq`
/// Interupt Request handler.
#[naked]
pub unsafe extern fn irq() {
}

55
arch/x86_64/src/lib.rs Normal file
View file

@ -0,0 +1,55 @@
//! Architecture support for x86_64
#![feature(asm)]
#![feature(const_fn)]
#![feature(core_intrinsics)]
#![feature(naked_functions)]
#![no_std]
#[macro_use]
extern crate bitflags;
/// Print to console
#[macro_export]
macro_rules! print {
($($arg:tt)*) => ({
use core::fmt::Write;
let _ = write!($crate::serial::SerialConsole::new(), $($arg)*);
});
}
/// Print with new line to console
#[macro_export]
macro_rules! println {
($fmt:expr) => (print!(concat!($fmt, "\n")));
($fmt:expr, $($arg:tt)*) => (print!(concat!($fmt, "\n"), $($arg)*));
}
/// Global descriptor table
pub mod gdt;
/// Interrupt descriptor table
pub mod idt;
/// IO Handling
pub mod io;
/// IRQ Handling
pub mod irq;
/// Interrupt instructions
pub mod interrupt;
/// Initialization and main function
pub mod main;
/// Memcpy, memmove, etc.
pub mod mem;
/// Serial driver and print! support
pub mod serial;
/// Task state segment
pub mod tss;
pub mod physical;

78
arch/x86_64/src/main.rs Normal file
View file

@ -0,0 +1,78 @@
/// This function is where the kernel sets up IRQ handlers
/// It is increcibly unsafe, and should be minimal in nature
/// It must create the IDT with the correct entries, those entries are
/// defined in other files inside of the `arch` module
use super::idt::{IDTR, IDT, IDT_PRESENT, IDT_RING_0, IDT_INTERRUPT};
use super::mem::memset;
extern {
/// The starting byte of the text (code) data segment.
static mut __text_start: u8;
/// The ending byte of the text (code) data segment.
static mut __text_end: u8;
/// The starting byte of the _.rodata_ (read-only data) segment.
static mut __rodata_start: u8;
/// The ending byte of the _.rodata_ (read-only data) segment.
static mut __rodata_end: u8;
/// The starting byte of the _.data_ segment.
static mut __data_start: u8;
/// The ending byte of the _.data_ segment.
static mut __data_end: u8;
/// The starting byte of the _.bss_ (uninitialized data) segment.
static mut __bss_start: u8;
/// The ending byte of the _.bss_ (uninitialized data) segment.
static mut __bss_end: u8;
}
/// Test of zero values in BSS.
static BSS_TEST_ZERO: usize = 0;
/// Test of non-zero values in BSS.
static BSS_TEST_NONZERO: usize = 0xFFFFFFFFFFFFFFFF;
extern {
fn kmain() -> !;
}
#[no_mangle]
pub unsafe extern fn kstart() -> ! {
asm!("xchg bx, bx" : : : : "intel", "volatile");
// Zero BSS, this initializes statics that are set to 0
{
let start_ptr = &mut __bss_start as *mut u8;
let end_ptr = & __bss_end as *const u8 as usize;
if start_ptr as usize <= end_ptr {
let size = end_ptr - start_ptr as usize;
memset(start_ptr, 0, size);
}
debug_assert_eq!(BSS_TEST_ZERO, 0);
debug_assert_eq!(BSS_TEST_NONZERO, 0xFFFFFFFFFFFFFFFF);
}
asm!("xchg bx, bx" : : : : "intel", "volatile");
//Set up IDT
for entry in IDT.iter_mut() {
entry.set_flags(IDT_PRESENT | IDT_RING_0 | IDT_INTERRUPT);
entry.set_offset(8, blank as usize);
}
IDTR.set_slice(&IDT);
IDTR.load();
asm!("xchg bx, bx" : : : : "intel", "volatile");
asm!("int 0xFF" : : : : "intel", "volatile");
asm!("xchg bx, bx" : : : : "intel", "volatile");
kmain();
}
#[naked]
pub unsafe extern fn blank() {
asm!("xchg bx, bx" : : : : "intel", "volatile");
asm!("iretq" : : : : "intel", "volatile");
}

70
arch/x86_64/src/mem.rs Normal file
View file

@ -0,0 +1,70 @@
/// Memcpy
///
/// Copy N bytes of memory from one location to another.
#[no_mangle]
pub unsafe extern fn memcpy(dest: *mut u8, src: *const u8,
n: usize) -> *mut u8 {
let mut i = 0;
while i < n {
*dest.offset(i as isize) = *src.offset(i as isize);
i += 1;
}
dest
}
/// Memmove
///
/// Copy N bytes of memory from src to dest. The memory areas may overlap.
#[no_mangle]
pub unsafe extern fn memmove(dest: *mut u8, src: *const u8,
n: usize) -> *mut u8 {
if src < dest as *const u8 {
let mut i = n;
while i != 0 {
i -= 1;
*dest.offset(i as isize) = *src.offset(i as isize);
}
} else {
let mut i = 0;
while i < n {
*dest.offset(i as isize) = *src.offset(i as isize);
i += 1;
}
}
dest
}
/// Memset
///
/// Fill a block of memory with a specified value.
#[no_mangle]
pub unsafe extern fn memset(s: *mut u8, c: i32, n: usize) -> *mut u8 {
let mut i = 0;
while i < n {
*s.offset(i as isize) = c as u8;
i += 1;
}
s
}
/// Memcmp
///
/// Compare two blocks of memory.
#[no_mangle]
pub unsafe extern fn memcmp(s1: *const u8, s2: *const u8, n: usize) -> i32 {
let mut i = 0;
while i < n {
let a = *s1.offset(i as isize);
let b = *s2.offset(i as isize);
if a != b {
return a as i32 - b as i32
}
i += 1;
}
0
}

View file

@ -0,0 +1,11 @@
//! Typestrong address segregation.
/// A physical address in memory.
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Physical {
/// The position.
///
/// Note that we do not use a pointer here to avoid simple mistakes where the programmer
/// confuse virtual and physical.
pub inner: u64,
}

39
arch/x86_64/src/serial.rs Normal file
View file

@ -0,0 +1,39 @@
use core::fmt;
use super::io::{Io, Pio};
pub struct SerialConsole {
status: Pio<u8>,
data: Pio<u8>
}
impl SerialConsole {
pub fn new() -> SerialConsole {
SerialConsole {
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);
}
}
}
}
impl fmt::Write for SerialConsole {
fn write_str(&mut self, s: &str) -> Result<(), fmt::Error> {
self.write(s.as_bytes());
Ok(())
}
}

20
arch/x86_64/src/tss.rs Normal file
View file

@ -0,0 +1,20 @@
#[repr(packed)]
pub struct Tss {
pub reserved1: u32,
pub sp0: u64,
pub sp1: u64,
pub sp2: u64,
pub reserved2: u32,
pub reserved3: u32,
pub ist1: u64,
pub ist2: u64,
pub ist3: u64,
pub ist4: u64,
pub ist5: u64,
pub ist6: u64,
pub ist7: u64,
pub reserved4: u32,
pub reserved5: u32,
pub reserved6: u16,
pub iomap_base: u16,
}