compiles. In progress new custom allocator
This commit is contained in:
parent
a46f795b5a
commit
b2475a7b27
16 changed files with 763 additions and 23 deletions
|
@ -1,5 +1,5 @@
|
|||
[unstable]
|
||||
build-std = ["core", "compiler_builtins"] # recompile these
|
||||
build-std = ["alloc", "core", "compiler_builtins"] # recompile these
|
||||
build-std-features = [ "compiler-builtins-mem" ]
|
||||
|
||||
[build]
|
||||
|
|
160
Cargo.lock
generated
160
Cargo.lock
generated
|
@ -1,6 +1,6 @@
|
|||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
version = 4
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
|
@ -20,6 +20,27 @@ version = "2.9.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd"
|
||||
|
||||
[[package]]
|
||||
name = "derive_more"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4a9b99b9cbbe49445b21764dc0625032a89b145a2642e67603e1c936f5458d05"
|
||||
dependencies = [
|
||||
"derive_more-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "derive_more-impl"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cb7330aeadfbe296029522e6c40f315320aba36fc43a5b3632f3795348f3bd22"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.101",
|
||||
"unicode-xid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.5.0"
|
||||
|
@ -39,6 +60,89 @@ dependencies = [
|
|||
"scopeguard",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.27"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94"
|
||||
|
||||
[[package]]
|
||||
name = "multiboot2"
|
||||
version = "0.23.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "43fcee184de68e344a888bc4f2b9d6b2f2f527cae8cedbb4d62a4df727d1ceae"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"derive_more",
|
||||
"log",
|
||||
"multiboot2-common",
|
||||
"ptr_meta",
|
||||
"uefi-raw",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "multiboot2-common"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fbabf8d9980d55576ba487924fa0b9a467fc0012b996b93d2319904f168ed8ab"
|
||||
dependencies = [
|
||||
"derive_more",
|
||||
"ptr_meta",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pc-keyboard"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f0ca629cbb3f0d5b699c338f0129ff78c9bfd7ea8b1258ad529bff490dc8ed5a"
|
||||
|
||||
[[package]]
|
||||
name = "pic8259"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "62d9a86c292b165f757e47e7fd66855def189b2564609bc4203727b27c33db22"
|
||||
dependencies = [
|
||||
"x86_64",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.95"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ptr_meta"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bcada80daa06c42ed5f48c9a043865edea5dc44cbf9ac009fda3b89526e28607"
|
||||
dependencies = [
|
||||
"ptr_meta_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ptr_meta_derive"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bca9224df2e20e7c5548aeb5f110a0f3b77ef05f8585139b7148b59056168ed2"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.40"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rlibc"
|
||||
version = "1.0.0"
|
||||
|
@ -50,6 +154,9 @@ name = "rustboot"
|
|||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"lazy_static",
|
||||
"multiboot2",
|
||||
"pc-keyboard",
|
||||
"pic8259",
|
||||
"rlibc",
|
||||
"spin 0.10.0",
|
||||
"volatile 0.3.0",
|
||||
|
@ -83,6 +190,57 @@ dependencies = [
|
|||
"lock_api",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.109"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.101"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ce2b7fc941b3a24138a0a7cf8e858bfc6a992e7978a068a5c760deb0ed43caf"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "uefi-raw"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b463030b802e1265a3800fab24df95d3229c202c2e408832a206f05b4d1496ca"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"ptr_meta",
|
||||
"uguid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "uguid"
|
||||
version = "2.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0c8352f8c05e47892e7eaf13b34abd76a7f4aeaf817b716e88789381927f199c"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-xid"
|
||||
version = "0.2.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853"
|
||||
|
||||
[[package]]
|
||||
name = "volatile"
|
||||
version = "0.3.0"
|
||||
|
|
13
Cargo.toml
13
Cargo.toml
|
@ -16,17 +16,14 @@ test-timeout = 30 # in seconds
|
|||
crate-type = ["staticlib"] # library that contains all dependencies
|
||||
|
||||
[dependencies]
|
||||
multiboot2 = "0.23"
|
||||
pc-keyboard = "0.8"
|
||||
pic8259 = "0.11"
|
||||
rlibc = "1.0"
|
||||
spin = "0.10"
|
||||
volatile = "0.3" # newest functional version
|
||||
x86_64 = "0.15"
|
||||
volatile = "0.3" # 0.3 is newest functional version
|
||||
x86_64 = "0.15" # 0.14 is newest functional version
|
||||
|
||||
[dependencies.lazy_static]
|
||||
version = "1.5"
|
||||
features = ["spin_no_std"]
|
||||
|
||||
[profile.dev]
|
||||
panic = "abort"
|
||||
|
||||
[profile.release]
|
||||
panic = "abort"
|
||||
|
|
BIN
build/os.iso
BIN
build/os.iso
Binary file not shown.
6
flake.lock
generated
6
flake.lock
generated
|
@ -2,11 +2,11 @@
|
|||
"nodes": {
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1746576598,
|
||||
"narHash": "sha256-FshoQvr6Aor5SnORVvh/ZdJ1Sa2U4ZrIMwKBX5k2wu0=",
|
||||
"lastModified": 1747060738,
|
||||
"narHash": "sha256-ByfPRQuqj+nhtVV0koinEpmJw0KLzNbgcgi9EF+NVow=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "b3582c75c7f21ce0b429898980eddbbf05c68e55",
|
||||
"rev": "eaeed9530c76ce5f1d2d8232e08bec5e26f18ec1",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
|
2
justfile
2
justfile
|
@ -1,5 +1,7 @@
|
|||
all: setup asm rust link image clean
|
||||
|
||||
mkrun: all run
|
||||
|
||||
setup:
|
||||
mkdir temp
|
||||
|
||||
|
|
|
@ -7,6 +7,14 @@ SECTIONS {
|
|||
}
|
||||
.text :
|
||||
{
|
||||
*(.text)
|
||||
*(.text .text.*)
|
||||
}
|
||||
.rodata :
|
||||
{
|
||||
*(.rodata .rodata.*)
|
||||
}
|
||||
.data.rel.ro :
|
||||
{
|
||||
*(.data.rel.ro.local*) *(.data.rel.ro .data.rel.ro.*)
|
||||
}
|
||||
}
|
||||
|
|
56
src/'
Normal file
56
src/'
Normal file
|
@ -0,0 +1,56 @@
|
|||
#![no_std]
|
||||
#![feature(abi_x86_interrupt)]
|
||||
|
||||
extern crate alloc;
|
||||
extern crate multiboot2;
|
||||
extern crate rlibc;
|
||||
|
||||
mod allocator;
|
||||
mod gdt;
|
||||
mod interrupt;
|
||||
mod vga_buffer;
|
||||
|
||||
use core::panic::PanicInfo;
|
||||
use multiboot2::{BootInformation, BootInformationHeader};
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
pub extern "C" fn rust_main(multiboot_information_address: usize) {
|
||||
println!("Hello World!");
|
||||
// println!(
|
||||
// "This program booted itself from assembly. This println function manipulates individual bytes in a vga buffer. My power is beyond your understanding\n0\n1\n2\n3\n4\n5\n6\n7\n8\n9"
|
||||
// );
|
||||
let boot_info = unsafe {
|
||||
BootInformation::load(multiboot_information_address as *const BootInformationHeader)
|
||||
.unwrap()
|
||||
};
|
||||
let memory_map_tag = boot_info.memory_map_tag().expect("Memory map tag required");
|
||||
init();
|
||||
println!("Got past");
|
||||
halt()
|
||||
}
|
||||
|
||||
pub fn init() {
|
||||
allocator::init_heap
|
||||
|
||||
println!("got to gdt::init()");
|
||||
gdt::init();
|
||||
println!("got to interrupt::init_idt();");
|
||||
interrupt::init_idt();
|
||||
println!("got to PICS.lock()");
|
||||
unsafe { interrupt::PICS.lock().initialize() };
|
||||
println!("got to enable inst");
|
||||
x86_64::instructions::interrupts::enable();
|
||||
}
|
||||
|
||||
#[panic_handler]
|
||||
pub fn panic(info: &PanicInfo) -> ! {
|
||||
println!("Panic happened: {}", info);
|
||||
halt()
|
||||
}
|
||||
|
||||
pub fn halt() -> ! {
|
||||
println!("we've halted");
|
||||
loop {
|
||||
x86_64::instructions::hlt();
|
||||
}
|
||||
}
|
114
src/allocator/linked_list.rs
Normal file
114
src/allocator/linked_list.rs
Normal file
|
@ -0,0 +1,114 @@
|
|||
use super::{Locked, align_up};
|
||||
use alloc::alloc::{GlobalAlloc, Layout};
|
||||
use core::{mem, ptr};
|
||||
|
||||
pub struct LinkedListAllocator {
|
||||
head: ListNode,
|
||||
}
|
||||
|
||||
impl LinkedListAllocator {
|
||||
pub const fn new() -> Self {
|
||||
Self {
|
||||
head: ListNode::new(0),
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn init(&mut self, heap_start: usize, heap_size: usize) {
|
||||
unsafe { self.add_free_region(heap_start, heap_size) };
|
||||
}
|
||||
|
||||
unsafe fn add_free_region(&mut self, addr: usize, size: usize) {
|
||||
assert_eq!(align_up(addr, mem::align_of::<ListNode>()), addr);
|
||||
assert!(size >= mem::size_of::<ListNode>());
|
||||
let mut node = ListNode::new(size);
|
||||
node.next = self.head.next.take();
|
||||
let node_ptr = addr as *mut ListNode;
|
||||
unsafe {
|
||||
node_ptr.write(node);
|
||||
self.head.next = Some(&mut *node_ptr)
|
||||
}
|
||||
}
|
||||
|
||||
fn alloc_from_region(region: &ListNode, size: usize, align: usize) -> Result<usize, ()> {
|
||||
let alloc_start = align_up(region.start_addr(), align);
|
||||
let alloc_end = alloc_start.checked_add(size).ok_or(())?;
|
||||
|
||||
if alloc_end > region.end_addr() {
|
||||
return Err(());
|
||||
}
|
||||
|
||||
let excess_size = region.end_addr() - alloc_end;
|
||||
if excess_size > 0 && excess_size < mem::size_of::<ListNode>() {
|
||||
return Err(());
|
||||
}
|
||||
Ok(alloc_start)
|
||||
}
|
||||
|
||||
fn find_region(&mut self, size: usize, align: usize) -> Option<(&'static mut ListNode, usize)> {
|
||||
let mut current = &mut self.head;
|
||||
while let Some(ref mut region) = current.next {
|
||||
if let Ok(alloc_start) = Self::alloc_from_region(®ion, size, align) {
|
||||
let next = region.next.take();
|
||||
let ret = Some((current.next.take().unwrap(), alloc_start));
|
||||
current.next = next;
|
||||
return ret;
|
||||
} else {
|
||||
current = current.next.as_mut().unwrap();
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
fn size_align(layout: Layout) -> (usize, usize) {
|
||||
let layout = layout
|
||||
.align_to(mem::align_of::<ListNode>())
|
||||
.expect("adjusting alignment failed")
|
||||
.pad_to_align();
|
||||
let size = layout.size().max(mem::align_of::<ListNode>());
|
||||
(size, layout.align())
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl GlobalAlloc for Locked<LinkedListAllocator> {
|
||||
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
|
||||
let (size, align) = LinkedListAllocator::size_align(layout);
|
||||
let mut allocator = self.lock();
|
||||
|
||||
if let Some((region, alloc_start)) = allocator.find_region(size, align) {
|
||||
let alloc_end = alloc_start.checked_add(size).expect("overflow");
|
||||
let excess_size = region.end_addr() - alloc_end;
|
||||
if excess_size > 0 {
|
||||
unsafe {
|
||||
allocator.add_free_region(alloc_end, excess_size);
|
||||
}
|
||||
}
|
||||
alloc_start as *mut u8
|
||||
} else {
|
||||
ptr::null_mut()
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
|
||||
let (size, _) = LinkedListAllocator::size_align(layout);
|
||||
unsafe { self.lock().add_free_region(ptr as usize, size) }
|
||||
}
|
||||
}
|
||||
|
||||
struct ListNode {
|
||||
size: usize,
|
||||
next: Option<&'static mut ListNode>,
|
||||
}
|
||||
|
||||
impl ListNode {
|
||||
const fn new(size: usize) -> Self {
|
||||
ListNode { size, next: None }
|
||||
}
|
||||
|
||||
fn start_addr(&self) -> usize {
|
||||
self as *const Self as usize
|
||||
}
|
||||
|
||||
fn end_addr(&self) -> usize {
|
||||
self.start_addr() + self.size
|
||||
}
|
||||
}
|
62
src/allocator/mod.rs
Normal file
62
src/allocator/mod.rs
Normal file
|
@ -0,0 +1,62 @@
|
|||
use crate::memory::area_frame_allocator;
|
||||
use linked_list::LinkedListAllocator;
|
||||
use x86_64::VirtAddr;
|
||||
use x86_64::structures::paging::mapper::MapToError;
|
||||
use x86_64::structures::paging::{FrameAllocator, Mapper, Page, PageTableFlags, Size4KiB};
|
||||
|
||||
pub mod linked_list;
|
||||
|
||||
pub const HEAP_START: usize = 0x_4444_4444_0000;
|
||||
pub const HEAP_SIZE: usize = 100 * 1024; // 100KiB
|
||||
|
||||
#[global_allocator]
|
||||
static ALLOCATOR: Locked<LinkedListAllocator> = Locked::new(LinkedListAllocator::new());
|
||||
|
||||
pub struct Locked<A> {
|
||||
inner: spin::Mutex<A>,
|
||||
}
|
||||
|
||||
impl<A> Locked<A> {
|
||||
pub const fn new(inner: A) -> Self {
|
||||
Locked {
|
||||
inner: spin::Mutex::new(inner),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn lock(&self) -> spin::MutexGuard<A> {
|
||||
self.inner.lock()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn init_heap(
|
||||
mapper: &mut impl Mapper<Size4KiB>,
|
||||
frame_allocator: &mut impl FrameAllocator<Size4KiB>,
|
||||
) -> Result<(), MapToError<Size4KiB>> {
|
||||
let page_range = {
|
||||
let heap_start = VirtAddr::new(HEAP_START as u64);
|
||||
let heap_end = heap_start + HEAP_SIZE as u64 - 1u64;
|
||||
let heap_start_page = Page::containing_address(heap_start);
|
||||
let heap_end_page = Page::containing_address(heap_end);
|
||||
Page::range_inclusive(heap_start_page, heap_end_page)
|
||||
};
|
||||
for page in page_range {
|
||||
let frame = frame_allocator
|
||||
.allocate_frame()
|
||||
.ok_or(MapToError::FrameAllocationFailed)?;
|
||||
let flags = PageTableFlags::PRESENT | PageTableFlags::WRITABLE;
|
||||
unsafe { mapper.map_to(page, frame, flags, frame_allocator)?.flush() };
|
||||
}
|
||||
unsafe {
|
||||
ALLOCATOR.lock().init(HEAP_START, HEAP_SIZE);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn align_up(addr: usize, align: usize) -> usize {
|
||||
let remainder = addr % align;
|
||||
if remainder == 0 {
|
||||
addr
|
||||
} else {
|
||||
addr - remainder + align
|
||||
}
|
||||
}
|
52
src/gdt/mod.rs
Normal file
52
src/gdt/mod.rs
Normal file
|
@ -0,0 +1,52 @@
|
|||
use lazy_static::lazy_static;
|
||||
use x86_64::VirtAddr;
|
||||
use x86_64::structures::gdt::{Descriptor, GlobalDescriptorTable, SegmentSelector};
|
||||
use x86_64::structures::tss::TaskStateSegment;
|
||||
|
||||
// selector returned by GDT
|
||||
// code_selector: where CS register goes in case of DF
|
||||
// tss_selector: where TSS starts in case of DF
|
||||
struct Selectors {
|
||||
code_selector: SegmentSelector,
|
||||
tss_selector: SegmentSelector,
|
||||
}
|
||||
|
||||
// location of double fault emergency stac
|
||||
pub const DOUBLE_FAULT_1ST_INDEX: u16 = 0;
|
||||
|
||||
pub fn init() {
|
||||
use x86_64::instructions::segmentation::{CS, Segment};
|
||||
use x86_64::instructions::tables::load_tss;
|
||||
GDT.0.load();
|
||||
|
||||
unsafe {
|
||||
CS::set_reg(GDT.1.code_selector);
|
||||
load_tss(GDT.1.tss_selector);
|
||||
}
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
static ref GDT: (GlobalDescriptorTable, Selectors) = {
|
||||
let mut gdt = GlobalDescriptorTable::new();
|
||||
let code_selector = gdt.append(Descriptor::kernel_code_segment());
|
||||
let tss_selector = gdt.append(Descriptor::tss_segment(&TSS));
|
||||
(
|
||||
gdt,
|
||||
Selectors {
|
||||
code_selector,
|
||||
tss_selector,
|
||||
},
|
||||
)
|
||||
};
|
||||
|
||||
static ref TSS: TaskStateSegment = {
|
||||
let mut tss = TaskStateSegment::new();
|
||||
tss.interrupt_stack_table[DOUBLE_FAULT_1ST_INDEX as usize] = {
|
||||
const STACK_SIZE: usize = 4096 * 5;
|
||||
static mut STACK: [u8; STACK_SIZE] = [0; STACK_SIZE]; // TODO make real stack
|
||||
let stack_start = VirtAddr::from_ptr(&raw const STACK);
|
||||
stack_start + STACK_SIZE as u64 // end of stack
|
||||
};
|
||||
tss
|
||||
};
|
||||
}
|
110
src/interrupt/mod.rs
Normal file
110
src/interrupt/mod.rs
Normal file
|
@ -0,0 +1,110 @@
|
|||
use crate::{print, println};
|
||||
use lazy_static::lazy_static;
|
||||
use pic8259::ChainedPics;
|
||||
use x86_64::structures::idt::{InterruptDescriptorTable, InterruptStackFrame, PageFaultErrorCode};
|
||||
|
||||
pub fn init_idt() {
|
||||
IDT.load();
|
||||
}
|
||||
|
||||
pub const PIC_1_OFFSET: u8 = 32;
|
||||
pub const PIC_2_OFFSET: u8 = PIC_1_OFFSET + 8;
|
||||
|
||||
pub static PICS: spin::Mutex<ChainedPics> =
|
||||
spin::Mutex::new(unsafe { ChainedPics::new(PIC_1_OFFSET, PIC_2_OFFSET) });
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
#[repr(u8)]
|
||||
pub enum InterruptIndex {
|
||||
Timer = PIC_1_OFFSET,
|
||||
Keyboard,
|
||||
}
|
||||
|
||||
impl InterruptIndex {
|
||||
fn as_u8(self) -> u8 {
|
||||
self as u8
|
||||
}
|
||||
fn as_usize(self) -> usize {
|
||||
usize::from(self.as_u8())
|
||||
}
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
static ref IDT: InterruptDescriptorTable = {
|
||||
let mut idt = InterruptDescriptorTable::new();
|
||||
idt.breakpoint.set_handler_fn(breakpoint_handler);
|
||||
unsafe {
|
||||
idt.double_fault
|
||||
.set_handler_fn(double_fault_handler)
|
||||
.set_stack_index(crate::gdt::DOUBLE_FAULT_1ST_INDEX);
|
||||
}
|
||||
idt[InterruptIndex::Timer.as_u8()].set_handler_fn(timer_interrupt_handler);
|
||||
idt[InterruptIndex::Keyboard.as_u8()].set_handler_fn(keyboard_interrupt_handler);
|
||||
idt.page_fault.set_handler_fn(page_fault_handler);
|
||||
idt
|
||||
};
|
||||
}
|
||||
|
||||
extern "x86-interrupt" fn breakpoint_handler(stack_frame: InterruptStackFrame) {
|
||||
println!("EXCEPTION: BREAKPOINT\n{:#?}", stack_frame);
|
||||
}
|
||||
|
||||
extern "x86-interrupt" fn double_fault_handler(
|
||||
stack_frame: InterruptStackFrame,
|
||||
_error_code: u64,
|
||||
) -> ! {
|
||||
panic!("EXCEPTION: DOUBLE FAULT\n{:#?}", stack_frame);
|
||||
}
|
||||
|
||||
extern "x86-interrupt" fn keyboard_interrupt_handler(_keyboard_stack_frame: InterruptStackFrame) {
|
||||
use pc_keyboard::{DecodedKey, HandleControl, Keyboard, ScancodeSet1, layouts};
|
||||
use spin::Mutex;
|
||||
use x86_64::instructions::port::Port;
|
||||
|
||||
lazy_static! {
|
||||
static ref KEYBOARD: Mutex<Keyboard<layouts::Us104Key, ScancodeSet1>> =
|
||||
Mutex::new(Keyboard::new(
|
||||
ScancodeSet1::new(),
|
||||
layouts::Us104Key,
|
||||
HandleControl::Ignore
|
||||
));
|
||||
}
|
||||
|
||||
let mut keyboard = KEYBOARD.lock();
|
||||
let mut port = Port::new(0x60);
|
||||
|
||||
let scancode: u8 = unsafe { port.read() };
|
||||
if let Ok(Some(key_event)) = keyboard.add_byte(scancode) {
|
||||
if let Some(key) = keyboard.process_keyevent(key_event) {
|
||||
match key {
|
||||
DecodedKey::Unicode(character) => print!("{}", character),
|
||||
DecodedKey::RawKey(key) => print!("{:?}", key),
|
||||
}
|
||||
}
|
||||
}
|
||||
unsafe {
|
||||
PICS.lock()
|
||||
.notify_end_of_interrupt(InterruptIndex::Keyboard.as_u8());
|
||||
}
|
||||
}
|
||||
|
||||
extern "x86-interrupt" fn page_fault_handler(
|
||||
stack_frame: InterruptStackFrame,
|
||||
error_code: PageFaultErrorCode,
|
||||
) {
|
||||
use x86_64::registers::control::Cr2;
|
||||
|
||||
println!("EXCEPTION: PAGE FAULT");
|
||||
println!("Accessed Address: {:?}", Cr2::read());
|
||||
println!("Error Code: {:?}?", error_code);
|
||||
println!("{:#?}", stack_frame);
|
||||
crate::halt();
|
||||
}
|
||||
|
||||
extern "x86-interrupt" fn timer_interrupt_handler(_stack_frame: InterruptStackFrame) {
|
||||
print!(".");
|
||||
unsafe {
|
||||
PICS.lock()
|
||||
.notify_end_of_interrupt(InterruptIndex::Timer.as_u8());
|
||||
}
|
||||
}
|
83
src/lib.rs
83
src/lib.rs
|
@ -1,26 +1,93 @@
|
|||
#![no_std]
|
||||
#![feature(abi_x86_interrupt)]
|
||||
|
||||
extern crate alloc;
|
||||
extern crate multiboot2;
|
||||
extern crate rlibc;
|
||||
|
||||
mod allocator;
|
||||
mod gdt;
|
||||
mod interrupt;
|
||||
mod memory;
|
||||
mod vga_buffer;
|
||||
|
||||
use core::panic::PanicInfo;
|
||||
|
||||
pub fn halt() -> ! {
|
||||
println!("we've halted");
|
||||
loop {
|
||||
x86_64::instructions::hlt();
|
||||
}
|
||||
}
|
||||
use multiboot2::{BootInformation, BootInformationHeader};
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
pub extern "C" fn rust_main(_multiboot_information_address: usize) {
|
||||
pub extern "C" fn rust_main(multiboot_information_address: usize) {
|
||||
println!("Hello World!");
|
||||
|
||||
// get multiboot info
|
||||
let boot_info = unsafe {
|
||||
BootInformation::load(multiboot_information_address as *const BootInformationHeader)
|
||||
.unwrap()
|
||||
};
|
||||
let memory_map_tag = boot_info.memory_map_tag().expect("Memory map tag required");
|
||||
println!("memory areas:");
|
||||
for area in memory_map_tag.memory_areas() {
|
||||
println!(
|
||||
" start: 0x{:x}, length: 0x{:x}",
|
||||
area.start_address(),
|
||||
area.size()
|
||||
);
|
||||
}
|
||||
|
||||
let elf_sections_tag = boot_info
|
||||
.elf_sections_tag()
|
||||
.expect("Elf sections tag required");
|
||||
println!("kernel sections:");
|
||||
for section in elf_sections_tag.sections() {
|
||||
println!(
|
||||
" addr: 0x{:x}, size: 0x{:x}, flags: 0x{:x}",
|
||||
section.start_address(),
|
||||
section.size(),
|
||||
section.flags()
|
||||
);
|
||||
}
|
||||
|
||||
let kernel_start = elf_sections_tag
|
||||
.sections()
|
||||
.map(|s| s.start_address())
|
||||
.min()
|
||||
.unwrap();
|
||||
let kernel_end = elf_sections_tag
|
||||
.sections()
|
||||
.map(|s| s.end_address())
|
||||
.max()
|
||||
.unwrap();
|
||||
let multiboot_start = multiboot_information_address;
|
||||
let multiboot_end = multiboot_start + boot_info.total_size() as usize;
|
||||
|
||||
println!(
|
||||
"kernel_start: 0x{:x} kernel_end: 0x{:x} kernel_size: {}B\nmultiboot_start: 0x{:x} multiboot_end: 0x{:x} multiboot_size: {}B",
|
||||
kernel_start,
|
||||
kernel_end,
|
||||
kernel_end - kernel_start,
|
||||
multiboot_start,
|
||||
multiboot_end,
|
||||
multiboot_end - multiboot_start
|
||||
);
|
||||
//init();
|
||||
halt()
|
||||
}
|
||||
|
||||
pub fn init() {
|
||||
gdt::init();
|
||||
interrupt::init_idt();
|
||||
unsafe { interrupt::PICS.lock().initialize() };
|
||||
x86_64::instructions::interrupts::enable();
|
||||
}
|
||||
|
||||
#[panic_handler]
|
||||
pub fn panic(info: &PanicInfo) -> ! {
|
||||
println!("Panic happened: {}", info);
|
||||
halt()
|
||||
}
|
||||
|
||||
pub fn halt() -> ! {
|
||||
println!("we've halted");
|
||||
loop {
|
||||
x86_64::instructions::hlt();
|
||||
}
|
||||
}
|
||||
|
|
95
src/memory/area_frame_allocator.rs
Normal file
95
src/memory/area_frame_allocator.rs
Normal file
|
@ -0,0 +1,95 @@
|
|||
use core::alloc::{GlobalAlloc, Layout};
|
||||
use core::{mem, ptr};
|
||||
use multiboot2::{BootInformation, BootInformationHeader};
|
||||
|
||||
use super::{Frame, PAGE_SIZE};
|
||||
use crate::allocator::{HEAP_SIZE, HEAP_START, Locked};
|
||||
|
||||
pub struct AreaFrameAllocator {
|
||||
next_free_frame: Frame,
|
||||
kernel_start: Frame,
|
||||
kernel_end: Frame,
|
||||
multiboot_start: Frame,
|
||||
multiboot_end: Frame,
|
||||
}
|
||||
|
||||
impl AreaFrameAllocator {
|
||||
pub const fn new() -> Self {
|
||||
Self {
|
||||
next_free_frame: Frame::new(),
|
||||
kernel_start: Frame::new(),
|
||||
kernel_end: Frame::new(),
|
||||
multiboot_start: Frame::new(),
|
||||
multiboot_end: Frame::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn init(&mut self, multiboot_information_address: usize) -> Self {
|
||||
let boot_info = unsafe {
|
||||
BootInformation::load(multiboot_information_address as *const BootInformationHeader)
|
||||
.unwrap()
|
||||
};
|
||||
//let memory_map_tag = boot_info.memory_map_tag().expect("Memory map tag required");
|
||||
let elf_sections_tag = boot_info
|
||||
.elf_sections_tag()
|
||||
.expect("Elf sections tag required");
|
||||
let kernel_start = elf_sections_tag
|
||||
.sections()
|
||||
.map(|s| s.start_address())
|
||||
.min()
|
||||
.unwrap();
|
||||
let kernel_end = elf_sections_tag
|
||||
.sections()
|
||||
.map(|s| s.end_address())
|
||||
.max()
|
||||
.unwrap();
|
||||
let multiboot_start = multiboot_information_address;
|
||||
let multiboot_end = multiboot_start + boot_info.total_size();
|
||||
|
||||
AreaFrameAllocator {
|
||||
next_free_frame: Frame { number: 0 },
|
||||
kernel_start: Frame {
|
||||
number: kernel_start as usize,
|
||||
},
|
||||
kernel_end: Frame {
|
||||
number: kernel_end as usize,
|
||||
},
|
||||
multiboot_start: Frame {
|
||||
number: multiboot_start,
|
||||
},
|
||||
multiboot_end: Frame {
|
||||
number: multiboot_end,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn find_frame(&mut self, size: usize, align: usize) -> Option<(Frame, usize)> {
|
||||
let next_addr = self.next_free_frame.number * PAGE_SIZE + HEAP_START;
|
||||
if &next_addr + core::mem::align_of::<Frame>() <= PAGE_SIZE + HEAP_START {
|
||||
Some((Frame::containing_address(next_addr), next_addr))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn size_align(layout: Layout) -> (usize, usize) {
|
||||
let layout = layout
|
||||
.align_to(mem::align_of::<Frame>())
|
||||
.expect("adjusting alignment failed")
|
||||
.pad_to_align();
|
||||
let size = layout.size().max(mem::align_of::<Frame>());
|
||||
(size, layout.align())
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl GlobalAlloc for Locked<AreaFrameAllocator> {
|
||||
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
|
||||
let (size, align) = AreaFrameAllocator::size_align(layout);
|
||||
let mut allocator = self.lock();
|
||||
match allocator.find_frame(size, align) {
|
||||
Some((_, addr)) => addr as *mut u8,
|
||||
None => ptr::null_mut(),
|
||||
}
|
||||
}
|
||||
unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {}
|
||||
}
|
19
src/memory/mod.rs
Normal file
19
src/memory/mod.rs
Normal file
|
@ -0,0 +1,19 @@
|
|||
pub mod area_frame_allocator;
|
||||
|
||||
pub const PAGE_SIZE: usize = 4096;
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub struct Frame {
|
||||
number: usize,
|
||||
}
|
||||
|
||||
impl Frame {
|
||||
pub const fn new() -> Self {
|
||||
Self { number: 0 }
|
||||
}
|
||||
fn containing_address(address: usize) -> Frame {
|
||||
Frame {
|
||||
number: address / PAGE_SIZE,
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue