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"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bootloader",
|
"bootloader",
|
||||||
|
"lazy_static",
|
||||||
|
"spin",
|
||||||
"volatile",
|
"volatile",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "volatile"
|
name = "lazy_static"
|
||||||
version = "0.4.5"
|
version = "1.4.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
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]
|
[profile.dev]
|
||||||
panic = "abort"
|
panic = "abort"
|
||||||
|
overflow-checks = false
|
||||||
|
|
||||||
[profile.release]
|
[profile.release]
|
||||||
panic = "abort"
|
panic = "abort"
|
||||||
|
|
||||||
|
|
||||||
|
[dependencies.lazy_static]
|
||||||
|
version = "1.0"
|
||||||
|
features = ["spin_no_std"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
bootloader = "0.9.23"
|
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
|
#!/bin/sh
|
||||||
|
|
||||||
cargo +nightly build
|
cargo +nightly build || exit 1
|
||||||
cargo +nightly bootimage
|
cargo +nightly bootimage
|
||||||
qemu-system-x86_64 -drive format=raw,file=target/x86_64-none-generic/debug/bootimage-kernel.bin
|
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;
|
pub mod vga;
|
|
@ -1,3 +1,5 @@
|
||||||
|
use core::fmt;
|
||||||
|
use volatile::Volatile;
|
||||||
use crate::io::vga::colors::ColorCode;
|
use crate::io::vga::colors::ColorCode;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
@ -12,13 +14,13 @@ const BUFFER_WIDTH: usize = 80;
|
||||||
|
|
||||||
#[repr(transparent)]
|
#[repr(transparent)]
|
||||||
pub struct Buffer {
|
pub struct Buffer {
|
||||||
chars: [[ScreenChar; BUFFER_WIDTH]; BUFFER_HEIGHT],
|
chars: [[Volatile<ScreenChar>; BUFFER_WIDTH]; BUFFER_HEIGHT],
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Writer {
|
pub struct Writer {
|
||||||
pub(crate) column_position: usize,
|
pub column_position: usize,
|
||||||
pub(crate) color_code: ColorCode,
|
pub color_code: ColorCode,
|
||||||
pub(crate) buffer: &'static mut Buffer,
|
pub buffer: &'static mut Buffer,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Writer {
|
impl Writer {
|
||||||
|
@ -34,22 +36,36 @@ impl Writer {
|
||||||
let col = self.column_position;
|
let col = self.column_position;
|
||||||
|
|
||||||
let color_code = self.color_code;
|
let color_code = self.color_code;
|
||||||
self.buffer.chars[row][col] = ScreenChar {
|
self.buffer.chars[row][col].write(ScreenChar {
|
||||||
ascii_character: byte,
|
ascii_character: byte,
|
||||||
color_code,
|
color_code,
|
||||||
};
|
});
|
||||||
self.column_position += 1;
|
self.column_position += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new_line(&mut self) {
|
pub fn new_line(&mut self) {
|
||||||
unimplemented!();
|
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) {
|
pub fn write_string(&mut self, s: &str) {
|
||||||
for byte in s.bytes() {
|
for byte in s.bytes() {
|
||||||
match byte {
|
match byte {
|
||||||
|
@ -58,7 +74,14 @@ impl Writer {
|
||||||
// not part of printable ASCII range
|
// not part of printable ASCII range
|
||||||
_ => self.write_byte(0xfe),
|
_ => 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 colors;
|
||||||
pub mod buffer;
|
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_std]
|
||||||
#![no_main]
|
#![no_main]
|
||||||
|
|
||||||
|
use core::arch::asm;
|
||||||
use core::panic::PanicInfo;
|
use core::panic::PanicInfo;
|
||||||
use crate::io::vga::buffer::{Buffer, Writer};
|
use bootloader::{BootInfo, entry_point};
|
||||||
use crate::io::vga::colors::{Color, ColorCode};
|
use crate::io::vga::colors::{Color, ColorCode};
|
||||||
|
|
||||||
mod io;
|
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]
|
#[no_mangle]
|
||||||
#[panic_handler]
|
#[panic_handler]
|
||||||
pub extern "C" fn panic_handler(_info: &PanicInfo) -> ! {
|
pub extern "C" fn panic_handler(_info: &PanicInfo) -> ! {
|
||||||
loop {}
|
io::vga::WRITER.lock().color_code = ColorCode::new(Color::Red, Color::Black);
|
||||||
}
|
println!("\n!!! PANIC !!!");
|
||||||
|
println!("{}", _info);
|
||||||
#[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");
|
|
||||||
|
|
||||||
loop {}
|
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