Remove interrupt setup from asm bootloader, add io module, memcpy functions, and serial driver
This commit is contained in:
parent
799b77d11a
commit
42c9ba12dc
|
@ -5,6 +5,9 @@ version = "0.1.0"
|
||||||
[lib]
|
[lib]
|
||||||
crate-type = ["staticlib"]
|
crate-type = ["staticlib"]
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
bitflags = "*"
|
||||||
|
|
||||||
[profile.dev]
|
[profile.dev]
|
||||||
panic = "abort"
|
panic = "abort"
|
||||||
|
|
||||||
|
|
6
Makefile
6
Makefile
|
@ -10,16 +10,16 @@ bochs: build/harddrive.bin
|
||||||
bochs -f bochs.$(ARCH)
|
bochs -f bochs.$(ARCH)
|
||||||
|
|
||||||
qemu: build/harddrive.bin
|
qemu: build/harddrive.bin
|
||||||
qemu-system-$(ARCH) -drive file=$<,format=raw,index=0,media=disk
|
qemu-system-$(ARCH) -serial mon:stdio -drive file=$<,format=raw,index=0,media=disk
|
||||||
|
|
||||||
FORCE:
|
FORCE:
|
||||||
|
|
||||||
build/libkernel.a: FORCE
|
build/libkernel.a: FORCE
|
||||||
rustc --crate-type staticlib -C lto -O src/lib.rs -o $@
|
cargo rustc -- -C lto -o $@
|
||||||
#--target $(ARCH)-unknown-none.json
|
#--target $(ARCH)-unknown-none.json
|
||||||
|
|
||||||
build/kernel.bin: build/libkernel.a
|
build/kernel.bin: build/libkernel.a
|
||||||
ld -m elf_$(ARCH) -o $@ -T bootloader/x86/kernel.ld -z max-page-size=0x1000 $<
|
ld -m elf_$(ARCH) --gc-sections -z max-page-size=0x1000 -T bootloader/x86/kernel.ld -o $@ $<
|
||||||
|
|
||||||
build/kernel.list: build/kernel.bin
|
build/kernel.list: build/kernel.bin
|
||||||
objdump -C -M intel -D $< > $@
|
objdump -C -M intel -D $< > $@
|
||||||
|
|
|
@ -1,105 +0,0 @@
|
||||||
struc IDTEntry
|
|
||||||
.offsetl resw 1
|
|
||||||
.selector resw 1
|
|
||||||
.zero resb 1
|
|
||||||
.attribute resb 1
|
|
||||||
.offseth resw 1
|
|
||||||
endstruc
|
|
||||||
|
|
||||||
SECTION .text
|
|
||||||
USE32
|
|
||||||
|
|
||||||
interrupts:
|
|
||||||
.first:
|
|
||||||
mov [.entry], byte 0
|
|
||||||
jmp dword .handle
|
|
||||||
.second:
|
|
||||||
%assign i 1
|
|
||||||
%rep 255
|
|
||||||
mov [.entry], byte i
|
|
||||||
jmp dword .handle
|
|
||||||
%assign i i+1
|
|
||||||
%endrep
|
|
||||||
.handle:
|
|
||||||
push ebp
|
|
||||||
push esi
|
|
||||||
push edi
|
|
||||||
push edx
|
|
||||||
push ecx
|
|
||||||
push ebx
|
|
||||||
push eax
|
|
||||||
|
|
||||||
push esp
|
|
||||||
push dword [.entry]
|
|
||||||
|
|
||||||
mov eax, gdt.kernel_data
|
|
||||||
mov ds, eax
|
|
||||||
mov es, eax
|
|
||||||
mov fs, eax
|
|
||||||
mov gs, eax
|
|
||||||
|
|
||||||
call dword [.handler]
|
|
||||||
|
|
||||||
mov eax, gdt.user_data | 3
|
|
||||||
mov ds, eax
|
|
||||||
mov es, eax
|
|
||||||
mov fs, eax
|
|
||||||
mov eax, gdt.user_tls | 3
|
|
||||||
mov gs, eax
|
|
||||||
|
|
||||||
add esp, 8 ; Skip interrupt code and reg pointer
|
|
||||||
|
|
||||||
pop eax
|
|
||||||
pop ebx
|
|
||||||
pop ecx
|
|
||||||
pop edx
|
|
||||||
pop edi
|
|
||||||
pop esi
|
|
||||||
pop ebp
|
|
||||||
|
|
||||||
iretd
|
|
||||||
|
|
||||||
.handler: dd 0
|
|
||||||
.entry: dd 0
|
|
||||||
|
|
||||||
idtr:
|
|
||||||
dw (idt.end - idt) + 1
|
|
||||||
dd idt
|
|
||||||
|
|
||||||
idt:
|
|
||||||
%assign i 0
|
|
||||||
|
|
||||||
;Below system call
|
|
||||||
%rep 128
|
|
||||||
istruc IDTEntry
|
|
||||||
at IDTEntry.offsetl, dw interrupts+(interrupts.second-interrupts.first)*i
|
|
||||||
at IDTEntry.selector, dw gdt.kernel_code
|
|
||||||
at IDTEntry.zero, db 0
|
|
||||||
at IDTEntry.attribute, db attrib.present | attrib.interrupt32
|
|
||||||
at IDTEntry.offseth, dw 0
|
|
||||||
iend
|
|
||||||
%assign i i+1
|
|
||||||
%endrep
|
|
||||||
|
|
||||||
;System call
|
|
||||||
istruc IDTEntry
|
|
||||||
at IDTEntry.offsetl, dw interrupts+(interrupts.second-interrupts.first)*i
|
|
||||||
at IDTEntry.selector, dw gdt.kernel_code
|
|
||||||
at IDTEntry.zero, db 0
|
|
||||||
at IDTEntry.attribute, db attrib.present | attrib.ring3 | attrib.interrupt32
|
|
||||||
at IDTEntry.offseth, dw 0
|
|
||||||
iend
|
|
||||||
%assign i i+1
|
|
||||||
|
|
||||||
;Above system call
|
|
||||||
%rep 127
|
|
||||||
istruc IDTEntry
|
|
||||||
at IDTEntry.offsetl, dw interrupts+(interrupts.second-interrupts.first)*i
|
|
||||||
at IDTEntry.selector, dw gdt.kernel_code
|
|
||||||
at IDTEntry.zero, db 0
|
|
||||||
at IDTEntry.attribute, db attrib.present | attrib.interrupt32
|
|
||||||
at IDTEntry.offseth, dw 0
|
|
||||||
iend
|
|
||||||
%assign i i+1
|
|
||||||
%endrep
|
|
||||||
.end:
|
|
|
@ -1,130 +0,0 @@
|
||||||
struc IDTEntry
|
|
||||||
.offsetl resw 1
|
|
||||||
.selector resw 1
|
|
||||||
.ist resb 1
|
|
||||||
.attribute resb 1
|
|
||||||
.offsetm resw 1
|
|
||||||
.offseth resd 1
|
|
||||||
.reserved resd 1
|
|
||||||
endstruc
|
|
||||||
|
|
||||||
SECTION .text
|
|
||||||
USE64
|
|
||||||
interrupts:
|
|
||||||
.first:
|
|
||||||
mov [.entry], byte 0
|
|
||||||
jmp qword .handle
|
|
||||||
.second:
|
|
||||||
%assign i 1
|
|
||||||
%rep 255
|
|
||||||
mov [.entry], byte i
|
|
||||||
jmp qword .handle
|
|
||||||
%assign i i+1
|
|
||||||
%endrep
|
|
||||||
.handle:
|
|
||||||
push rbp
|
|
||||||
push r15
|
|
||||||
push r14
|
|
||||||
push r13
|
|
||||||
push r12
|
|
||||||
push r11
|
|
||||||
push r10
|
|
||||||
push r9
|
|
||||||
push r8
|
|
||||||
push rsi
|
|
||||||
push rdi
|
|
||||||
push rdx
|
|
||||||
push rcx
|
|
||||||
push rbx
|
|
||||||
push rax
|
|
||||||
|
|
||||||
mov rsi, rsp
|
|
||||||
push rsi
|
|
||||||
mov rdi, qword [.entry]
|
|
||||||
push rdi
|
|
||||||
|
|
||||||
mov rax, gdt.kernel_data
|
|
||||||
mov ds, rax
|
|
||||||
mov es, rax
|
|
||||||
mov fs, rax
|
|
||||||
mov gs, rax
|
|
||||||
|
|
||||||
call qword [.handler]
|
|
||||||
|
|
||||||
mov rax, gdt.user_data | 3
|
|
||||||
mov ds, rax
|
|
||||||
mov es, rax
|
|
||||||
mov gs, rax
|
|
||||||
mov rax, gdt.user_tls | 3
|
|
||||||
mov fs, rax
|
|
||||||
|
|
||||||
add rsp, 16 ; Skip interrupt code and reg pointer
|
|
||||||
|
|
||||||
pop rax
|
|
||||||
pop rbx
|
|
||||||
pop rcx
|
|
||||||
pop rdx
|
|
||||||
pop rdi
|
|
||||||
pop rsi
|
|
||||||
pop r8
|
|
||||||
pop r9
|
|
||||||
pop r10
|
|
||||||
pop r11
|
|
||||||
pop r12
|
|
||||||
pop r13
|
|
||||||
pop r14
|
|
||||||
pop r15
|
|
||||||
pop rbp
|
|
||||||
|
|
||||||
iretq
|
|
||||||
|
|
||||||
.handler: dq 0
|
|
||||||
.entry: dq 0
|
|
||||||
|
|
||||||
idtr:
|
|
||||||
dw (idt.end - idt) + 1
|
|
||||||
dq idt
|
|
||||||
|
|
||||||
idt:
|
|
||||||
%assign i 0
|
|
||||||
|
|
||||||
;Below syscall
|
|
||||||
%rep 128
|
|
||||||
istruc IDTEntry
|
|
||||||
at IDTEntry.offsetl, dw interrupts+(interrupts.second-interrupts.first)*i
|
|
||||||
at IDTEntry.selector, dw gdt.kernel_code
|
|
||||||
at IDTEntry.ist, db 0
|
|
||||||
at IDTEntry.attribute, db attrib.present | attrib.interrupt64
|
|
||||||
at IDTEntry.offsetm, dw 0
|
|
||||||
at IDTEntry.offseth, dd 0
|
|
||||||
at IDTEntry.reserved, dd 0
|
|
||||||
iend
|
|
||||||
%assign i i+1
|
|
||||||
%endrep
|
|
||||||
|
|
||||||
;Syscall
|
|
||||||
istruc IDTEntry
|
|
||||||
at IDTEntry.offsetl, dw interrupts+(interrupts.second-interrupts.first)*i
|
|
||||||
at IDTEntry.selector, dw gdt.kernel_code
|
|
||||||
at IDTEntry.ist, db 0
|
|
||||||
at IDTEntry.attribute, db attrib.present | attrib.ring3 | attrib.interrupt64
|
|
||||||
at IDTEntry.offsetm, dw 0
|
|
||||||
at IDTEntry.offseth, dd 0
|
|
||||||
at IDTEntry.reserved, dd 0
|
|
||||||
iend
|
|
||||||
%assign i i+1
|
|
||||||
|
|
||||||
;Above syscall
|
|
||||||
%rep 127
|
|
||||||
istruc IDTEntry
|
|
||||||
at IDTEntry.offsetl, dw interrupts+(interrupts.second-interrupts.first)*i
|
|
||||||
at IDTEntry.selector, dw gdt.kernel_code
|
|
||||||
at IDTEntry.ist, db 0
|
|
||||||
at IDTEntry.attribute, db attrib.present | attrib.interrupt64
|
|
||||||
at IDTEntry.offsetm, dw 0
|
|
||||||
at IDTEntry.offseth, dd 0
|
|
||||||
at IDTEntry.reserved, dd 0
|
|
||||||
iend
|
|
||||||
%assign i i+1
|
|
||||||
%endrep
|
|
||||||
.end:
|
|
|
@ -146,5 +146,3 @@ tss:
|
||||||
at TSS.iomap_base, dw 0xFFFF
|
at TSS.iomap_base, dw 0xFFFF
|
||||||
iend
|
iend
|
||||||
.end:
|
.end:
|
||||||
|
|
||||||
%include "interrupts-i386.asm"
|
|
||||||
|
|
|
@ -73,11 +73,8 @@ long_mode:
|
||||||
xor rax, rax
|
xor rax, rax
|
||||||
mov eax, [kernel_base + 0x18]
|
mov eax, [kernel_base + 0x18]
|
||||||
mov rbx, gdtr
|
mov rbx, gdtr
|
||||||
|
xchg bx, bx
|
||||||
jmp rax
|
jmp rax
|
||||||
.lp:
|
|
||||||
sti
|
|
||||||
hlt
|
|
||||||
jmp .lp
|
|
||||||
|
|
||||||
gdtr:
|
gdtr:
|
||||||
dw gdt.end + 1 ; size
|
dw gdt.end + 1 ; size
|
||||||
|
@ -179,5 +176,3 @@ long_mode:
|
||||||
at TSS.iomap_base, dw 0xFFFF
|
at TSS.iomap_base, dw 0xFFFF
|
||||||
iend
|
iend
|
||||||
.end:
|
.end:
|
||||||
|
|
||||||
%include "interrupts-x86_64.asm"
|
|
||||||
|
|
|
@ -1,4 +1,7 @@
|
||||||
//! Architecture specific items
|
//! Architecture specific items
|
||||||
|
|
||||||
|
#[cfg(target_arch = "x86_64")]
|
||||||
|
pub use self::x86_64::*;
|
||||||
|
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
pub mod x86_64;
|
pub mod x86_64;
|
||||||
|
|
|
@ -7,10 +7,23 @@ pub static mut IDTR: IdtDescriptor = IdtDescriptor {
|
||||||
|
|
||||||
pub static mut IDT: [IdtEntry; 256] = [IdtEntry::new(); 256];
|
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)]
|
#[repr(packed)]
|
||||||
pub struct IdtDescriptor {
|
pub struct IdtDescriptor {
|
||||||
pub size: u16,
|
size: u16,
|
||||||
pub offset: u64
|
offset: u64
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IdtDescriptor {
|
impl IdtDescriptor {
|
||||||
|
@ -18,18 +31,22 @@ impl IdtDescriptor {
|
||||||
self.size = (slice.len() * mem::size_of::<IdtEntry>() - 1) as u16;
|
self.size = (slice.len() * mem::size_of::<IdtEntry>() - 1) as u16;
|
||||||
self.offset = slice.as_ptr() as u64;
|
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)]
|
#[derive(Copy, Clone, Debug)]
|
||||||
#[repr(packed)]
|
#[repr(packed)]
|
||||||
pub struct IdtEntry {
|
pub struct IdtEntry {
|
||||||
pub offsetl: u16,
|
offsetl: u16,
|
||||||
pub selector: u16,
|
selector: u16,
|
||||||
pub zero: u8,
|
zero: u8,
|
||||||
pub attribute: u8,
|
attribute: u8,
|
||||||
pub offsetm: u16,
|
offsetm: u16,
|
||||||
pub offseth: u32,
|
offseth: u32,
|
||||||
pub zero2: u32
|
zero2: u32
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IdtEntry {
|
impl IdtEntry {
|
||||||
|
@ -45,7 +62,12 @@ impl IdtEntry {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_offset(&mut self, base: usize) {
|
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.offsetl = base as u16;
|
||||||
self.offsetm = (base >> 16) as u16;
|
self.offsetm = (base >> 16) as u16;
|
||||||
self.offseth = (base >> 32) as u32;
|
self.offseth = (base >> 32) as u32;
|
||||||
|
|
61
src/arch/x86_64/io/io.rs
Normal file
61
src/arch/x86_64/io/io.rs
Normal 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)
|
||||||
|
}
|
||||||
|
}
|
31
src/arch/x86_64/io/mmio.rs
Normal file
31
src/arch/x86_64/io/mmio.rs
Normal 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) };
|
||||||
|
}
|
||||||
|
}
|
9
src/arch/x86_64/io/mod.rs
Normal file
9
src/arch/x86_64/io/mod.rs
Normal 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
src/arch/x86_64/io/pio.rs
Normal file
83
src/arch/x86_64/io/pio.rs
Normal 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");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,27 +3,69 @@
|
||||||
/// It must create the IDT with the correct entries, those entries are
|
/// It must create the IDT with the correct entries, those entries are
|
||||||
/// defined in other files inside of the `arch` module
|
/// defined in other files inside of the `arch` module
|
||||||
|
|
||||||
use super::idt::{IDTR, IDT};
|
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;
|
||||||
|
|
||||||
#[naked]
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn kmain() {
|
pub unsafe extern "C" fn kmain() {
|
||||||
asm!("xchg bx, bx" : : : : "intel", "volatile");
|
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() {
|
for entry in IDT.iter_mut() {
|
||||||
entry.attribute = 1 << 7 | 0xE;
|
entry.set_flags(IDT_PRESENT | IDT_RING_0 | IDT_INTERRUPT);
|
||||||
entry.selector = 8;
|
entry.set_offset(8, blank as usize);
|
||||||
entry.set_offset(blank as usize);
|
|
||||||
entry.zero = 0;
|
|
||||||
entry.zero2 = 0;
|
|
||||||
}
|
}
|
||||||
IDTR.set_slice(&IDT);
|
IDTR.set_slice(&IDT);
|
||||||
asm!("lidt [rax]" : : "{rax}"(&IDTR as *const _ as usize) : : "intel", "volatile");
|
IDTR.load();
|
||||||
|
|
||||||
asm!("xchg bx, bx" : : : : "intel", "volatile");
|
asm!("xchg bx, bx" : : : : "intel", "volatile");
|
||||||
|
|
||||||
asm!("int 0xFF" : : : : "intel", "volatile");
|
asm!("int 0xFF" : : : : "intel", "volatile");
|
||||||
|
|
||||||
|
asm!("xchg bx, bx" : : : : "intel", "volatile");
|
||||||
|
|
||||||
|
print!("TEST\n");
|
||||||
|
|
||||||
loop{
|
loop{
|
||||||
asm!("hlt" : : : : "intel", "volatile");
|
asm!("hlt" : : : : "intel", "volatile");
|
||||||
}
|
}
|
||||||
|
|
70
src/arch/x86_64/mem.rs
Normal file
70
src/arch/x86_64/mem.rs
Normal 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
|
||||||
|
}
|
|
@ -4,8 +4,20 @@ pub mod gdt;
|
||||||
/// Interrupt descriptor table
|
/// Interrupt descriptor table
|
||||||
pub mod idt;
|
pub mod idt;
|
||||||
|
|
||||||
|
/// IO Handling
|
||||||
|
pub mod io;
|
||||||
|
|
||||||
/// IRQ Handling
|
/// IRQ Handling
|
||||||
pub mod irq;
|
pub mod irq;
|
||||||
|
|
||||||
/// Initialization and main function
|
/// Initialization and main function
|
||||||
pub mod main;
|
pub mod main;
|
||||||
|
|
||||||
|
/// Memcpy, memmove, etc.
|
||||||
|
pub mod mem;
|
||||||
|
|
||||||
|
/// Serial driver and print! support
|
||||||
|
pub mod serial;
|
||||||
|
|
||||||
|
/// Task state segment
|
||||||
|
pub mod tss;
|
||||||
|
|
39
src/arch/x86_64/serial.rs
Normal file
39
src/arch/x86_64/serial.rs
Normal 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(())
|
||||||
|
}
|
||||||
|
}
|
25
src/lib.rs
25
src/lib.rs
|
@ -66,10 +66,28 @@
|
||||||
|
|
||||||
#![feature(asm)]
|
#![feature(asm)]
|
||||||
#![feature(const_fn)]
|
#![feature(const_fn)]
|
||||||
|
#![feature(core_intrinsics)]
|
||||||
#![feature(lang_items)]
|
#![feature(lang_items)]
|
||||||
#![feature(naked_functions)]
|
#![feature(naked_functions)]
|
||||||
#![no_std]
|
#![no_std]
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
extern crate bitflags;
|
||||||
|
|
||||||
|
/// Print to console
|
||||||
|
macro_rules! print {
|
||||||
|
($($arg:tt)*) => ({
|
||||||
|
use $crate::core::fmt::Write;
|
||||||
|
let _ = write!($crate::arch::serial::SerialConsole::new(), $($arg)*);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Print with new line to console
|
||||||
|
macro_rules! println {
|
||||||
|
($fmt:expr) => (print!(concat!($fmt, "\n")));
|
||||||
|
($fmt:expr, $($arg:tt)*) => (print!(concat!($fmt, "\n"), $($arg)*));
|
||||||
|
}
|
||||||
|
|
||||||
/// Architecture specific items
|
/// Architecture specific items
|
||||||
pub mod arch;
|
pub mod arch;
|
||||||
|
|
||||||
|
@ -81,3 +99,10 @@ extern "C" fn eh_personality() {}
|
||||||
/// Required to handle panics
|
/// Required to handle panics
|
||||||
#[lang = "panic_fmt"]
|
#[lang = "panic_fmt"]
|
||||||
extern "C" fn panic_fmt() -> ! {loop{}}
|
extern "C" fn panic_fmt() -> ! {loop{}}
|
||||||
|
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
#[no_mangle]
|
||||||
|
/// Required to handle panics
|
||||||
|
pub extern "C" fn _Unwind_Resume() -> ! {
|
||||||
|
loop {}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue