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]
|
||||
crate-type = ["staticlib"]
|
||||
|
||||
[dependencies]
|
||||
bitflags = "*"
|
||||
|
||||
[profile.dev]
|
||||
panic = "abort"
|
||||
|
||||
|
|
6
Makefile
6
Makefile
|
@ -10,16 +10,16 @@ bochs: build/harddrive.bin
|
|||
bochs -f bochs.$(ARCH)
|
||||
|
||||
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:
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
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
|
||||
iend
|
||||
.end:
|
||||
|
||||
%include "interrupts-i386.asm"
|
||||
|
|
|
@ -73,11 +73,8 @@ long_mode:
|
|||
xor rax, rax
|
||||
mov eax, [kernel_base + 0x18]
|
||||
mov rbx, gdtr
|
||||
xchg bx, bx
|
||||
jmp rax
|
||||
.lp:
|
||||
sti
|
||||
hlt
|
||||
jmp .lp
|
||||
|
||||
gdtr:
|
||||
dw gdt.end + 1 ; size
|
||||
|
@ -179,5 +176,3 @@ long_mode:
|
|||
at TSS.iomap_base, dw 0xFFFF
|
||||
iend
|
||||
.end:
|
||||
|
||||
%include "interrupts-x86_64.asm"
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
//! Architecture specific items
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
pub use self::x86_64::*;
|
||||
|
||||
#[cfg(target_arch = "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];
|
||||
|
||||
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 {
|
||||
pub size: u16,
|
||||
pub offset: u64
|
||||
size: u16,
|
||||
offset: u64
|
||||
}
|
||||
|
||||
impl IdtDescriptor {
|
||||
|
@ -18,18 +31,22 @@ impl IdtDescriptor {
|
|||
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 {
|
||||
pub offsetl: u16,
|
||||
pub selector: u16,
|
||||
pub zero: u8,
|
||||
pub attribute: u8,
|
||||
pub offsetm: u16,
|
||||
pub offseth: u32,
|
||||
pub zero2: u32
|
||||
offsetl: u16,
|
||||
selector: u16,
|
||||
zero: u8,
|
||||
attribute: u8,
|
||||
offsetm: u16,
|
||||
offseth: u32,
|
||||
zero2: u32
|
||||
}
|
||||
|
||||
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.offsetm = (base >> 16) as u16;
|
||||
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
|
||||
/// 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]
|
||||
pub unsafe extern "C" fn kmain() {
|
||||
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.attribute = 1 << 7 | 0xE;
|
||||
entry.selector = 8;
|
||||
entry.set_offset(blank as usize);
|
||||
entry.zero = 0;
|
||||
entry.zero2 = 0;
|
||||
entry.set_flags(IDT_PRESENT | IDT_RING_0 | IDT_INTERRUPT);
|
||||
entry.set_offset(8, blank as usize);
|
||||
}
|
||||
IDTR.set_slice(&IDT);
|
||||
asm!("lidt [rax]" : : "{rax}"(&IDTR as *const _ as usize) : : "intel", "volatile");
|
||||
IDTR.load();
|
||||
|
||||
asm!("xchg bx, bx" : : : : "intel", "volatile");
|
||||
|
||||
asm!("int 0xFF" : : : : "intel", "volatile");
|
||||
|
||||
asm!("xchg bx, bx" : : : : "intel", "volatile");
|
||||
|
||||
print!("TEST\n");
|
||||
|
||||
loop{
|
||||
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
|
||||
pub mod idt;
|
||||
|
||||
/// IO Handling
|
||||
pub mod io;
|
||||
|
||||
/// IRQ Handling
|
||||
pub mod irq;
|
||||
|
||||
/// 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;
|
||||
|
|
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(const_fn)]
|
||||
#![feature(core_intrinsics)]
|
||||
#![feature(lang_items)]
|
||||
#![feature(naked_functions)]
|
||||
#![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
|
||||
pub mod arch;
|
||||
|
||||
|
@ -81,3 +99,10 @@ extern "C" fn eh_personality() {}
|
|||
/// Required to handle panics
|
||||
#[lang = "panic_fmt"]
|
||||
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