Compare commits
2 Commits
6944f2203f
...
c54cb174de
Author | SHA1 | Date | |
---|---|---|---|
c54cb174de | |||
273b004851 |
18
Cargo.lock
generated
18
Cargo.lock
generated
@ -8,6 +8,12 @@ version = "0.10.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dcb6dd1c2376d2e096796e234a70e17e94cc2d5d54ff8ce42b28cef1d0d359a4"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8dead7461c1127cf637931a1e50934eb6eee8bff2f74433ac7909e9afcee04a3"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.3.2"
|
||||
@ -19,6 +25,7 @@ name = "julios"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"lazy_static",
|
||||
"multiboot2",
|
||||
"pc-keyboard",
|
||||
"pic8259",
|
||||
"spin",
|
||||
@ -35,6 +42,15 @@ dependencies = [
|
||||
"spin",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "multiboot2"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b209a4456a3cc81fb69ad318ed6d47af81a90b829701f151354e3994d8b216d4"
|
||||
dependencies = [
|
||||
"bitflags 0.4.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pc-keyboard"
|
||||
version = "0.5.1"
|
||||
@ -75,6 +91,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bbc6ed1ed2cd4536b083c34041aff7b84448ee25ac4aa5e9d54802ce226f9815"
|
||||
dependencies = [
|
||||
"bit_field",
|
||||
"bitflags",
|
||||
"bitflags 1.3.2",
|
||||
"volatile 0.4.4",
|
||||
]
|
||||
|
@ -14,6 +14,7 @@ spin = "0.5.2"
|
||||
x86_64 = "0.14.2"
|
||||
pic8259 = "0.10.1"
|
||||
pc-keyboard = "0.5.0"
|
||||
multiboot2 = "0.1.0"
|
||||
|
||||
[dependencies.lazy_static]
|
||||
version = "1.0"
|
||||
|
2
Makefile
2
Makefile
@ -12,7 +12,7 @@ GRUB_CFG = grub/grub.cfg
|
||||
all: $(ISO)
|
||||
|
||||
run: $(ISO)
|
||||
qemu-system-x86_64 -cdrom $< -serial stdio
|
||||
qemu-system-x86_64 -cdrom $< -serial stdio -m 8G
|
||||
|
||||
debug: $(ISO)
|
||||
bochs -q
|
||||
|
@ -15,6 +15,7 @@ bits 32
|
||||
|
||||
_start:
|
||||
mov esp, stack_top
|
||||
mov edi, ebx
|
||||
|
||||
call check_multiboot
|
||||
call check_cpuid
|
||||
@ -27,6 +28,11 @@ _start:
|
||||
jmp gdt64.code:long_mode_start
|
||||
|
||||
set_up_page_tables:
|
||||
; recursively map p4
|
||||
mov eax, p4_table
|
||||
or eax, 0b11 ; present + writeable
|
||||
mov [p4_table + 511 * 8], eax
|
||||
|
||||
; map first P4 entry to P3 table
|
||||
mov eax, p3_table
|
||||
or eax, 0b11 ; present + writable
|
||||
@ -163,9 +169,8 @@ p3_table:
|
||||
p2_table:
|
||||
resb 4096
|
||||
|
||||
section .stack
|
||||
stack_bottom:
|
||||
resb 0x800000
|
||||
resb 4 * 4096
|
||||
stack_top:
|
||||
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
use crate::gdt;
|
||||
use crate::hlt_loop;
|
||||
use crate::vga::{self, Color, ColorCode};
|
||||
use crate::{print, println};
|
||||
use lazy_static::lazy_static;
|
||||
@ -6,6 +7,7 @@ use pc_keyboard::{layouts, DecodedKey, HandleControl, Keyboard, ScancodeSet1};
|
||||
use pic8259::ChainedPics;
|
||||
use spin::{self, Mutex};
|
||||
use x86_64::instructions::port::Port;
|
||||
use x86_64::structures::idt::PageFaultErrorCode;
|
||||
use x86_64::structures::idt::{InterruptDescriptorTable, InterruptStackFrame};
|
||||
|
||||
pub const PIC_1_OFFSET: u8 = 32;
|
||||
@ -37,6 +39,7 @@ lazy_static! {
|
||||
static ref IDT: InterruptDescriptorTable = {
|
||||
let mut idt = InterruptDescriptorTable::new();
|
||||
idt.breakpoint.set_handler_fn(breakpoint_handler);
|
||||
idt.page_fault.set_handler_fn(page_fault_handler);
|
||||
unsafe {
|
||||
idt.double_fault
|
||||
.set_handler_fn(double_fault_handler)
|
||||
@ -66,6 +69,22 @@ extern "x86-interrupt" fn breakpoint_handler(stack_frame: InterruptStackFrame) {
|
||||
vga::change_color(color);
|
||||
}
|
||||
|
||||
extern "x86-interrupt" fn page_fault_handler(
|
||||
stack_frame: InterruptStackFrame,
|
||||
error_code: PageFaultErrorCode,
|
||||
) {
|
||||
let color: vga::ColorCode = vga::get_color();
|
||||
vga::change_color(ColorCode::new(Color::LightRed, Color::Black));
|
||||
use x86_64::registers::control::Cr2;
|
||||
|
||||
println!("EXCEPTION: PAGE FAULT");
|
||||
println!("Accessed Address: {:?}", Cr2::read());
|
||||
println!("Error Code: {:?}", error_code);
|
||||
println!("{:#?}", stack_frame);
|
||||
vga::change_color(color);
|
||||
hlt_loop();
|
||||
}
|
||||
|
||||
extern "x86-interrupt" fn double_fault_handler(
|
||||
stack_frame: InterruptStackFrame,
|
||||
_error_code: u64,
|
||||
@ -74,7 +93,7 @@ extern "x86-interrupt" fn double_fault_handler(
|
||||
}
|
||||
|
||||
extern "x86-interrupt" fn timer_interrupt_handler(_stack_frame: InterruptStackFrame) {
|
||||
print!(".");
|
||||
// print!(".");
|
||||
unsafe {
|
||||
PICS.lock()
|
||||
.notify_end_of_interrupt(InterruptIndex::Timer.as_u8());
|
||||
@ -83,9 +102,8 @@ extern "x86-interrupt" fn timer_interrupt_handler(_stack_frame: InterruptStackFr
|
||||
|
||||
extern "x86-interrupt" fn keyboard_interrupt_handler(_stack_frame: InterruptStackFrame) {
|
||||
lazy_static! {
|
||||
static ref KEYBOARD: Mutex<Keyboard<layouts::Us104Key, ScancodeSet1>> =
|
||||
Mutex::new(Keyboard::new(layouts::Us104Key, ScancodeSet1,
|
||||
HandleControl::Ignore)
|
||||
static ref KEYBOARD: Mutex<Keyboard<layouts::Us104Key, ScancodeSet1>> = Mutex::new(
|
||||
Keyboard::new(layouts::Us104Key, ScancodeSet1, HandleControl::Ignore)
|
||||
);
|
||||
}
|
||||
|
||||
|
35
src/lib.rs
35
src/lib.rs
@ -4,9 +4,12 @@
|
||||
|
||||
mod gdt;
|
||||
mod interrupts;
|
||||
mod memory;
|
||||
mod serial;
|
||||
mod vga;
|
||||
|
||||
extern crate multiboot2;
|
||||
|
||||
use core::panic::PanicInfo;
|
||||
use vga::{Color, ColorCode};
|
||||
|
||||
@ -31,11 +34,39 @@ pub fn init() {
|
||||
vga::change_color(ColorCode::new(Color::LightGreen, Color::Black));
|
||||
}
|
||||
|
||||
fn get_frame_allocator(multiboot_info_addr: usize) -> memory::AreaFrameAllocator {
|
||||
let boot_info = unsafe { multiboot2::load(multiboot_info_addr) };
|
||||
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: u64 = elf_sections_tag.sections().map(|s| s.addr).min().unwrap();
|
||||
let kernel_end: u64 = elf_sections_tag
|
||||
.sections()
|
||||
.map(|s| s.addr + s.size)
|
||||
.max()
|
||||
.unwrap();
|
||||
|
||||
let multiboot_start: u64 = multiboot_info_addr as u64;
|
||||
let multiboot_end: u64 = multiboot_start + (boot_info.total_size as u64);
|
||||
|
||||
memory::AreaFrameAllocator::new( kernel_start, kernel_end, multiboot_start,
|
||||
multiboot_end, memory_map_tag.memory_areas())
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn julios_main() -> ! {
|
||||
pub extern "C" fn julios_main(multiboot_info_addr: usize) -> ! {
|
||||
let boot_info = unsafe { multiboot2::load(multiboot_info_addr) };
|
||||
|
||||
let mut frame_allocator = get_frame_allocator(multiboot_info_addr);
|
||||
|
||||
memory::kernel_remap(&mut frame_allocator, boot_info);
|
||||
|
||||
init();
|
||||
println!("***JuliOS V0.1.0***");
|
||||
serial_println!("Hello serial");
|
||||
|
||||
memory::paging::test_paging(&mut frame_allocator);
|
||||
panic!("Kernel end of flow");
|
||||
}
|
||||
|
@ -1,26 +1,53 @@
|
||||
ENTRY(_start)
|
||||
|
||||
SECTIONS {
|
||||
. = 1M;
|
||||
|
||||
.boot :
|
||||
.rodata :
|
||||
{
|
||||
/* ensure that the multiboot header is at the beginning */
|
||||
*(.multiboot_header)
|
||||
}
|
||||
|
||||
.stack :
|
||||
{
|
||||
*(.stack)
|
||||
}
|
||||
|
||||
.bss :
|
||||
{
|
||||
*(.bss)
|
||||
KEEP(*(.multiboot_header))
|
||||
*(.rodata .rodata.*)
|
||||
. = ALIGN(4K);
|
||||
}
|
||||
|
||||
.text :
|
||||
{
|
||||
*(.text)
|
||||
*(.text .text.*)
|
||||
. = ALIGN(4K);
|
||||
}
|
||||
|
||||
.data :
|
||||
{
|
||||
*(.data .data.*)
|
||||
. = ALIGN(4K);
|
||||
}
|
||||
|
||||
.bss :
|
||||
{
|
||||
*(.bss .bss.*)
|
||||
. = ALIGN(4K);
|
||||
}
|
||||
|
||||
.got :
|
||||
{
|
||||
*(.got)
|
||||
. = ALIGN(4K);
|
||||
}
|
||||
|
||||
.got.plt :
|
||||
{
|
||||
*(.got.plt)
|
||||
. = ALIGN(4K);
|
||||
}
|
||||
|
||||
.data.rel.ro : ALIGN(4K) {
|
||||
*(.data.rel.ro.local*) *(.data.rel.ro .data.rel.ro.*)
|
||||
. = ALIGN(4K);
|
||||
}
|
||||
|
||||
.gcc_except_table : ALIGN(4K) {
|
||||
*(.gcc_except_table)
|
||||
. = ALIGN(4K);
|
||||
}
|
||||
}
|
||||
|
||||
|
94
src/memory/frame_allocator.rs
Normal file
94
src/memory/frame_allocator.rs
Normal file
@ -0,0 +1,94 @@
|
||||
pub use super::PAGE_SIZE;
|
||||
use multiboot2::{MemoryArea, MemoryAreaIter};
|
||||
pub use x86_64::structures::paging::{
|
||||
frame::PhysFrame as Frame, FrameAllocator, FrameDeallocator, Size4KiB,
|
||||
};
|
||||
use x86_64::PhysAddr;
|
||||
|
||||
pub struct AreaFrameAllocator {
|
||||
next_free_frame: Frame,
|
||||
current_area: Option<&'static MemoryArea>,
|
||||
areas: MemoryAreaIter,
|
||||
kernel_start: Frame,
|
||||
kernel_end: Frame,
|
||||
multiboot_start: Frame,
|
||||
multiboot_end: Frame,
|
||||
}
|
||||
|
||||
impl AreaFrameAllocator {
|
||||
pub fn new(kernel_start: u64, kernel_end: u64, multiboot_start: u64, multiboot_end: u64, memory_areas: MemoryAreaIter) -> AreaFrameAllocator {
|
||||
let mut allocator = AreaFrameAllocator {
|
||||
next_free_frame: Frame::containing_address(PhysAddr::new(0)),
|
||||
current_area: None,
|
||||
areas: memory_areas,
|
||||
kernel_start: Frame::containing_address(PhysAddr::new(kernel_start)),
|
||||
kernel_end: Frame::containing_address(PhysAddr::new(kernel_end)),
|
||||
multiboot_start: Frame::containing_address(PhysAddr::new(multiboot_start)),
|
||||
multiboot_end: Frame::containing_address(PhysAddr::new(multiboot_end)),
|
||||
};
|
||||
allocator.choose_next_area();
|
||||
allocator
|
||||
}
|
||||
|
||||
fn choose_next_area(&mut self) {
|
||||
self.current_area = self
|
||||
.areas
|
||||
.clone()
|
||||
.filter(|area| {
|
||||
let address = area.base_addr + area.length - 1;
|
||||
Frame::containing_address(PhysAddr::new(address)) >= self.next_free_frame
|
||||
})
|
||||
.min_by_key(|area| area.base_addr);
|
||||
|
||||
if let Some(area) = self.current_area {
|
||||
let start_frame = Frame::containing_address(PhysAddr::new(area.base_addr));
|
||||
if self.next_free_frame < start_frame {
|
||||
self.next_free_frame = start_frame;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl FrameAllocator<Size4KiB> for AreaFrameAllocator {
|
||||
fn allocate_frame(&mut self) -> Option<Frame> {
|
||||
if let Some(area) = self.current_area {
|
||||
// "Clone" the frame to return it if it's free. Frame doesn't
|
||||
// implement Clone, but we can construct an identical frame.
|
||||
let frame = Frame::containing_address(self.next_free_frame.start_address());
|
||||
|
||||
// the last frame of the current area
|
||||
let current_area_last_frame = {
|
||||
let address = area.base_addr + area.length - 1;
|
||||
Frame::containing_address(PhysAddr::new(address))
|
||||
};
|
||||
|
||||
if frame > current_area_last_frame {
|
||||
// all frames of current area are used, switch to next area
|
||||
self.choose_next_area();
|
||||
} else if frame >= self.kernel_start && frame <= self.kernel_end {
|
||||
// `frame` is used by the kernel
|
||||
self.next_free_frame =
|
||||
Frame::containing_address(self.kernel_end.start_address() + PAGE_SIZE);
|
||||
} else if frame >= self.multiboot_start && frame <= self.multiboot_end {
|
||||
// `frame` is used by the multiboot information structure
|
||||
self.next_free_frame =
|
||||
Frame::containing_address(self.multiboot_end.start_address() + PAGE_SIZE);
|
||||
} else {
|
||||
// frame is unused, increment `next_free_frame` and return it
|
||||
self.next_free_frame =
|
||||
Frame::containing_address(self.next_free_frame.start_address() + PAGE_SIZE);
|
||||
return Some(frame);
|
||||
}
|
||||
// `frame` was not valid, try it again with the updated `next_free_frame`
|
||||
self.allocate_frame()
|
||||
} else {
|
||||
None // no free frames left
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FrameDeallocator<Size4KiB> for AreaFrameAllocator {
|
||||
unsafe fn deallocate_frame(&mut self, _frame: Frame) {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
7
src/memory/mod.rs
Normal file
7
src/memory/mod.rs
Normal file
@ -0,0 +1,7 @@
|
||||
pub use self::frame_allocator::AreaFrameAllocator;
|
||||
pub use paging::kernel_remap;
|
||||
|
||||
pub mod frame_allocator;
|
||||
pub mod paging;
|
||||
|
||||
pub const PAGE_SIZE: usize = 4096;
|
33
src/memory/paging/mod.rs
Normal file
33
src/memory/paging/mod.rs
Normal file
@ -0,0 +1,33 @@
|
||||
use multiboot2::BootInformation;
|
||||
use x86_64::structures::paging::{FrameAllocator, Size4KiB, PageTable, RecursivePageTable, Page, PageTableFlags as Flags, Mapper};
|
||||
use crate::println;
|
||||
use x86_64::VirtAddr;
|
||||
|
||||
pub const P4: *mut PageTable = 0o177777_777_777_777_777_0000 as *mut _;
|
||||
|
||||
pub fn kernel_remap<A>(_allocator: &mut A, _boot_info: &BootInformation)
|
||||
where A: FrameAllocator<Size4KiB>
|
||||
{
|
||||
}
|
||||
|
||||
pub fn test_paging<A>(allocator: &mut A)
|
||||
where A: FrameAllocator<Size4KiB>
|
||||
{
|
||||
let mut page_table = unsafe { RecursivePageTable::new(&mut *P4).expect("Could not create Page Table") };
|
||||
|
||||
let addr = 42 * 512 * 512 * 4096; // 42th P3 entry
|
||||
let page = Page::containing_address(VirtAddr::new(addr));
|
||||
let frame = allocator.allocate_frame().expect("no more frames");
|
||||
println!("None = , map to {:?}", frame);
|
||||
unsafe { page_table.map_to(page, frame, Flags::PRESENT, allocator).expect("Could not map").flush() };
|
||||
println!("next free frame: {:?}", allocator.allocate_frame());
|
||||
|
||||
let page_ptr: *mut u8 = page.start_address().as_mut_ptr();
|
||||
let frame_ptr: *mut u8 = frame.start_address().as_u64() as *mut u8;
|
||||
|
||||
unsafe {
|
||||
println!("Page: {:#?}, Frame: {:#?}", *page_ptr, *frame_ptr);
|
||||
*frame_ptr = 42;
|
||||
println!("Page: {:#?}, Frame: {:#?}", *page_ptr, *frame_ptr);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user