much stuff
This commit is contained in:
parent
61ab5d8bda
commit
ddd1a8ab12
10 changed files with 304 additions and 32 deletions
23
Cargo.lock
generated
23
Cargo.lock
generated
|
@ -13,11 +13,28 @@ name = "kernel"
|
|||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"bootloader",
|
||||
"lazy_static",
|
||||
"spin",
|
||||
"volatile",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "volatile"
|
||||
version = "0.4.5"
|
||||
name = "lazy_static"
|
||||
version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e3ca98349dda8a60ae74e04fd90c7fb4d6a4fbe01e6d3be095478aa0b76f6c0c"
|
||||
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||
dependencies = [
|
||||
"spin",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "spin"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d"
|
||||
|
||||
[[package]]
|
||||
name = "volatile"
|
||||
version = "0.2.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f6b06ad3ed06fef1713569d547cdbdb439eafed76341820fb0e0344f29a41945"
|
||||
|
|
|
@ -5,10 +5,17 @@ edition = "2018"
|
|||
|
||||
[profile.dev]
|
||||
panic = "abort"
|
||||
overflow-checks = false
|
||||
|
||||
[profile.release]
|
||||
panic = "abort"
|
||||
|
||||
|
||||
[dependencies.lazy_static]
|
||||
version = "1.0"
|
||||
features = ["spin_no_std"]
|
||||
|
||||
[dependencies]
|
||||
bootloader = "0.9.23"
|
||||
volatile = "0.4.5"
|
||||
volatile = "0.2.6"
|
||||
spin = "0.5.2"
|
2
run.sh
2
run.sh
|
@ -1,5 +1,5 @@
|
|||
#!/bin/sh
|
||||
|
||||
cargo +nightly build
|
||||
cargo +nightly build || exit 1
|
||||
cargo +nightly bootimage
|
||||
qemu-system-x86_64 -drive format=raw,file=target/x86_64-none-generic/debug/bootimage-kernel.bin
|
91
src/interrupts.rs
Normal file
91
src/interrupts.rs
Normal file
|
@ -0,0 +1,91 @@
|
|||
// IDT - Interrupt Descriptor Table
|
||||
|
||||
use core::arch::asm;
|
||||
use core::mem::size_of;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub struct IdtEntry {
|
||||
pub offset_low: u16,
|
||||
pub selector: u16,
|
||||
pub flags: u8,
|
||||
pub offset_middle: u16,
|
||||
pub offset_high: u32,
|
||||
pub zero: u32,
|
||||
}
|
||||
|
||||
pub struct InterruptStackFrame {
|
||||
pub instruction_pointer: u64,
|
||||
pub code_segment: u64,
|
||||
pub cpu_flags: u64,
|
||||
pub stack_pointer: u64,
|
||||
pub stack_segment: u64,
|
||||
}
|
||||
|
||||
pub type HandlerFunc = extern "C" fn(&mut InterruptStackFrame);
|
||||
|
||||
pub struct Idt {
|
||||
pub entries: [IdtEntry; 256],
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
impl Idt {
|
||||
pub fn new() -> Idt {
|
||||
Idt {
|
||||
entries: [IdtEntry {
|
||||
offset_low: 0,
|
||||
selector: 0,
|
||||
flags: 0,
|
||||
offset_middle: 0,
|
||||
offset_high: 0,
|
||||
zero: 0,
|
||||
}; 256],
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_handler(&mut self, index: u8, handler: HandlerFunc) {
|
||||
let offset = handler as u64;
|
||||
let offset_low = offset as u16;
|
||||
let offset_middle = (offset >> 16) as u16;
|
||||
let offset_high = (offset >> 32) as u32;
|
||||
|
||||
self.entries[index as usize] = IdtEntry {
|
||||
offset_low,
|
||||
selector: 0x08,
|
||||
flags: 0x8e,
|
||||
offset_middle,
|
||||
offset_high,
|
||||
zero: 0,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn load(&self) {
|
||||
let mut idtr: [u16; 3] = [0; 3];
|
||||
idtr[0] = (size_of::<Idt>() - 1) as u16;
|
||||
idtr[1] = self as *const _ as u16;
|
||||
idtr[2] = (self as *const _ as u32 >> 16) as u16;
|
||||
unsafe {
|
||||
asm!(
|
||||
"lidt ({0})",
|
||||
in(reg) &idtr,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn load_idt() -> Idt {
|
||||
let mut idt = Idt::new();
|
||||
idt.load();
|
||||
idt
|
||||
}
|
||||
|
||||
pub fn enable_interrupts() {
|
||||
unsafe {
|
||||
asm!("sti");
|
||||
}
|
||||
}
|
||||
|
||||
pub fn disable_interrupts() {
|
||||
unsafe {
|
||||
asm!("cli");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1 +1,3 @@
|
|||
use core::arch::asm;
|
||||
|
||||
pub mod vga;
|
|
@ -1,3 +1,5 @@
|
|||
use core::fmt;
|
||||
use volatile::Volatile;
|
||||
use crate::io::vga::colors::ColorCode;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
|
@ -12,13 +14,13 @@ const BUFFER_WIDTH: usize = 80;
|
|||
|
||||
#[repr(transparent)]
|
||||
pub struct Buffer {
|
||||
chars: [[ScreenChar; BUFFER_WIDTH]; BUFFER_HEIGHT],
|
||||
chars: [[Volatile<ScreenChar>; BUFFER_WIDTH]; BUFFER_HEIGHT],
|
||||
}
|
||||
|
||||
pub struct Writer {
|
||||
pub(crate) column_position: usize,
|
||||
pub(crate) color_code: ColorCode,
|
||||
pub(crate) buffer: &'static mut Buffer,
|
||||
pub column_position: usize,
|
||||
pub color_code: ColorCode,
|
||||
pub buffer: &'static mut Buffer,
|
||||
}
|
||||
|
||||
impl Writer {
|
||||
|
@ -34,22 +36,36 @@ impl Writer {
|
|||
let col = self.column_position;
|
||||
|
||||
let color_code = self.color_code;
|
||||
self.buffer.chars[row][col] = ScreenChar {
|
||||
self.buffer.chars[row][col].write(ScreenChar {
|
||||
ascii_character: byte,
|
||||
color_code,
|
||||
};
|
||||
});
|
||||
self.column_position += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn new_line(&mut self) {
|
||||
unimplemented!();
|
||||
pub fn new_line(&mut self) {
|
||||
for row in 1..BUFFER_HEIGHT {
|
||||
for col in 0..BUFFER_WIDTH {
|
||||
let character = self.buffer.chars[row][col].read();
|
||||
self.buffer.chars[row - 1][col].write(character);
|
||||
}
|
||||
}
|
||||
self.clear_row(BUFFER_HEIGHT - 1);
|
||||
self.column_position = 0;
|
||||
}
|
||||
|
||||
pub fn clear_row(&mut self, row: usize) {
|
||||
let blank = ScreenChar {
|
||||
ascii_character: b' ',
|
||||
color_code: self.color_code,
|
||||
};
|
||||
for col in 0..BUFFER_WIDTH {
|
||||
self.buffer.chars[row][col].write(blank);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl Writer {
|
||||
pub fn write_string(&mut self, s: &str) {
|
||||
for byte in s.bytes() {
|
||||
match byte {
|
||||
|
@ -58,7 +74,14 @@ impl Writer {
|
|||
// not part of printable ASCII range
|
||||
_ => self.write_byte(0xfe),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
impl fmt::Write for Writer {
|
||||
fn write_str(&mut self, s: &str) -> fmt::Result {
|
||||
self.write_string(s);
|
||||
Ok(())
|
||||
}
|
||||
}
|
|
@ -1,2 +1,31 @@
|
|||
pub mod colors;
|
||||
pub mod buffer;
|
||||
|
||||
use core::fmt;
|
||||
use lazy_static::lazy_static;
|
||||
use spin::Mutex;
|
||||
|
||||
lazy_static! {
|
||||
pub static ref WRITER: Mutex<buffer::Writer> = Mutex::new(buffer::Writer {
|
||||
column_position: 0,
|
||||
color_code: colors::ColorCode::new(colors::Color::Yellow, colors::Color::Black),
|
||||
buffer: unsafe { &mut *(0xb8000 as *mut buffer::Buffer) },
|
||||
});
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! println {
|
||||
() => (print!("\n"));
|
||||
($($arg:tt)*) => (print!("{}\n", format_args!($($arg)*)));
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! print {
|
||||
($($arg:tt)*) => ($crate::io::vga::_print(format_args!($($arg)*)));
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub fn _print(args: fmt::Arguments) {
|
||||
use core::fmt::Write;
|
||||
WRITER.lock().write_fmt(args).unwrap();
|
||||
}
|
32
src/main.rs
32
src/main.rs
|
@ -1,27 +1,31 @@
|
|||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
use core::arch::asm;
|
||||
use core::panic::PanicInfo;
|
||||
use crate::io::vga::buffer::{Buffer, Writer};
|
||||
use bootloader::{BootInfo, entry_point};
|
||||
use crate::io::vga::colors::{Color, ColorCode};
|
||||
|
||||
mod io;
|
||||
mod mem;
|
||||
mod interrupts;
|
||||
|
||||
entry_point!(kernel_main);
|
||||
fn kernel_main(boot_info: &'static BootInfo) -> ! {
|
||||
mem::gdt::init();
|
||||
let mut idt = interrupts::Idt::new();
|
||||
fn test_interrupt_handler(_stack_frame: &mut interrupts::InterruptStackFrame) {
|
||||
println!("test interrupt handler");
|
||||
}
|
||||
|
||||
loop {}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
#[panic_handler]
|
||||
pub extern "C" fn panic_handler(_info: &PanicInfo) -> ! {
|
||||
loop {}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn _start() -> ! {
|
||||
let mut writer = Writer {
|
||||
column_position: 0,
|
||||
color_code: ColorCode::new(Color::Yellow, Color::Black),
|
||||
buffer: unsafe { &mut *(0xb8000 as *mut Buffer) }
|
||||
};
|
||||
|
||||
writer.write_string("Hello World\n");
|
||||
|
||||
io::vga::WRITER.lock().color_code = ColorCode::new(Color::Red, Color::Black);
|
||||
println!("\n!!! PANIC !!!");
|
||||
println!("{}", _info);
|
||||
loop {}
|
||||
}
|
98
src/mem/gdt.rs
Normal file
98
src/mem/gdt.rs
Normal file
|
@ -0,0 +1,98 @@
|
|||
use core::arch::asm;
|
||||
|
||||
pub const GDT_NULL: u64 = 0x0000000000000000; // Null descriptor
|
||||
pub const GDT_KERNEL_CODE: u64 = 0x00af9a000000ffff; // Kernel code descriptor
|
||||
pub const GDT_KERNEL_DATA: u64 = 0x00cf92000000ffff; // Kernel data descriptor
|
||||
pub const GDT_USER_CODE: u64 = 0x00afba000000ffff; // User code descriptor
|
||||
pub const GDT_USER_DATA: u64 = 0x00cfb2000000ffff; // User data descriptor
|
||||
pub const GDT_TSS: u64 = 0x0080890000000067; // TSS descriptor
|
||||
|
||||
pub struct GdtEntry {
|
||||
pub limit_low: u16,
|
||||
pub base_low: u16,
|
||||
pub base_middle: u8,
|
||||
pub access: u8,
|
||||
pub granularity: u8,
|
||||
pub base_high: u8,
|
||||
}
|
||||
|
||||
pub struct Gdt {
|
||||
pub entries: [GdtEntry; 6],
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
impl Gdt {
|
||||
pub fn new() -> Gdt {
|
||||
Gdt {
|
||||
entries: [
|
||||
GdtEntry {
|
||||
limit_low: 0,
|
||||
base_low: 0,
|
||||
base_middle: 0,
|
||||
access: 0,
|
||||
granularity: 0,
|
||||
base_high: 0,
|
||||
},
|
||||
GdtEntry {
|
||||
limit_low: 0,
|
||||
base_low: 0,
|
||||
base_middle: 0,
|
||||
access: 0x9a,
|
||||
granularity: 0xa0,
|
||||
base_high: 0,
|
||||
},
|
||||
GdtEntry {
|
||||
limit_low: 0,
|
||||
base_low: 0,
|
||||
base_middle: 0,
|
||||
access: 0x92,
|
||||
granularity: 0xc0,
|
||||
base_high: 0,
|
||||
},
|
||||
GdtEntry {
|
||||
limit_low: 0,
|
||||
base_low: 0,
|
||||
base_middle: 0,
|
||||
access: 0xfa,
|
||||
granularity: 0xa0,
|
||||
base_high: 0,
|
||||
},
|
||||
GdtEntry {
|
||||
limit_low: 0,
|
||||
base_low: 0,
|
||||
base_middle: 0,
|
||||
access: 0xf2,
|
||||
granularity: 0xc0,
|
||||
base_high: 0,
|
||||
},
|
||||
GdtEntry {
|
||||
limit_low: 0,
|
||||
base_low: 0,
|
||||
base_middle: 0,
|
||||
access: 0x89,
|
||||
granularity: 0x67,
|
||||
base_high: 0,
|
||||
},
|
||||
],
|
||||
}
|
||||
}
|
||||
|
||||
pub fn load(&self) {
|
||||
let mut gdtr: [u16; 3] = [0; 3];
|
||||
gdtr[0] = (core::mem::size_of::<Gdt>() - 1) as u16;
|
||||
gdtr[1] = self as *const _ as u16;
|
||||
gdtr[2] = (self as *const _ as u32 >> 16) as u16;
|
||||
unsafe {
|
||||
asm!(
|
||||
"lgdt ({0})",
|
||||
in(reg) gdtr.as_ptr(),
|
||||
options(nostack)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn init() {
|
||||
let gdt = Gdt::new();
|
||||
gdt.load();
|
||||
}
|
1
src/mem/mod.rs
Normal file
1
src/mem/mod.rs
Normal file
|
@ -0,0 +1 @@
|
|||
pub mod gdt;
|
Loading…
Reference in a new issue