Compare commits
9 Commits
40ad5dbbf4
..
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 72fe78cbc6 | |||
| f9bc75c4f3 | |||
| 494d00c53b | |||
| 114c70ffe9 | |||
| 361c67764d | |||
| 36cb118933 | |||
| 7b3ba170f0 | |||
| 49880fa9d7 | |||
| 0bbbf653f8 |
+1
-1
@@ -3,7 +3,7 @@ target = "x86_64-kernel"
|
||||
target-dir = "build/target"
|
||||
|
||||
[unstable]
|
||||
build-std = ["core", "compiler_builtins"]
|
||||
build-std = ["core", "compiler_builtins", "alloc"]
|
||||
build-std-features = ["compiler-builtins-mem"]
|
||||
|
||||
[env]
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
on: [push, pull_request]
|
||||
on:
|
||||
push:
|
||||
branches: [ main ]
|
||||
pull-request:
|
||||
branches: [ main ]
|
||||
|
||||
name: Continuous integration
|
||||
|
||||
|
||||
@@ -10,3 +10,6 @@
|
||||
[submodule "lib/lib_serial"]
|
||||
path = lib/lib_serial
|
||||
url = https://git.zxq5.dev/OsDev/FoundryOS-lib_serial.git
|
||||
[submodule "lib/lib_alloc"]
|
||||
path = lib/lib_alloc
|
||||
url = https://git.zxq5.dev/OsDev/FoundryOS-lib_alloc.git
|
||||
|
||||
Generated
+34
@@ -34,10 +34,12 @@ name = "foundry_os"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"lib_alloc",
|
||||
"lib_ascii",
|
||||
"lib_framebuffer",
|
||||
"lib_serial",
|
||||
"limine",
|
||||
"pc-keyboard",
|
||||
"pic8259",
|
||||
"spin",
|
||||
"x86_64",
|
||||
@@ -52,6 +54,14 @@ dependencies = [
|
||||
"spin",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lib_alloc"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"linked_list_allocator",
|
||||
"x86_64",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lib_application"
|
||||
version = "0.1.0"
|
||||
@@ -95,6 +105,15 @@ dependencies = [
|
||||
"bitflags",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "linked_list_allocator"
|
||||
version = "0.10.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9afa463f5405ee81cdb9cc2baf37e08ec7e4c8209442b5d72c04cfb2cd6e6286"
|
||||
dependencies = [
|
||||
"spinning_top",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lock_api"
|
||||
version = "0.4.12"
|
||||
@@ -105,6 +124,12 @@ dependencies = [
|
||||
"scopeguard",
|
||||
]
|
||||
|
||||
[[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"
|
||||
@@ -141,6 +166,15 @@ dependencies = [
|
||||
"lock_api",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "spinning_top"
|
||||
version = "0.2.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5b9eb1a2f4c41445a3a0ff9abc5221c5fcd28e1f13cd7c0397706f9ac938ddb0"
|
||||
dependencies = [
|
||||
"lock_api",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "volatile"
|
||||
version = "0.4.6"
|
||||
|
||||
@@ -5,6 +5,7 @@ members = [
|
||||
"lib/lib_ascii",
|
||||
"kernel",
|
||||
"lib/lib_application",
|
||||
"lib/lib_alloc",
|
||||
]
|
||||
resolver = "2"
|
||||
|
||||
|
||||
@@ -8,9 +8,11 @@ limine = "0.3.1"
|
||||
lib_framebuffer = { path = "../lib/lib_framebuffer" }
|
||||
lib_serial = { path = "../lib/lib_serial" }
|
||||
lib_ascii = { path = "../lib/lib_ascii" }
|
||||
lib_alloc = { path = "../lib/lib_alloc" }
|
||||
x86_64 = "0.15.2"
|
||||
spin = "0.9.8"
|
||||
pic8259 = "0.11.0"
|
||||
pc-keyboard = "0.8.0"
|
||||
|
||||
[build-dependencies]
|
||||
cc = "1.2.14"
|
||||
|
||||
@@ -1,4 +1,12 @@
|
||||
use x86_64::{structures::tss::TaskStateSegment, VirtAddr};
|
||||
use x86_64::{
|
||||
instructions::tables::load_tss,
|
||||
registers::segmentation::{Segment, CS, DS, ES, SS},
|
||||
structures::{
|
||||
gdt::{Descriptor, GlobalDescriptorTable, SegmentSelector},
|
||||
tss::TaskStateSegment,
|
||||
},
|
||||
VirtAddr,
|
||||
};
|
||||
|
||||
use spin::Lazy;
|
||||
|
||||
@@ -16,3 +24,46 @@ static TSS: Lazy<TaskStateSegment> = Lazy::new(|| {
|
||||
};
|
||||
tss
|
||||
});
|
||||
|
||||
static GDT: Lazy<(GlobalDescriptorTable, Selectors)> = Lazy::new(|| {
|
||||
let mut gdt = GlobalDescriptorTable::new();
|
||||
let code_selector = gdt.append(Descriptor::kernel_code_segment());
|
||||
let data_selector = gdt.append(Descriptor::kernel_data_segment());
|
||||
|
||||
let user_code_selector = gdt.append(Descriptor::user_code_segment());
|
||||
let user_data_selector = gdt.append(Descriptor::user_data_segment());
|
||||
|
||||
let tss_selector = gdt.append(Descriptor::tss_segment(&TSS));
|
||||
|
||||
(
|
||||
gdt,
|
||||
Selectors {
|
||||
code_selector,
|
||||
data_selector,
|
||||
user_code_selector,
|
||||
user_data_selector,
|
||||
tss_selector,
|
||||
},
|
||||
)
|
||||
});
|
||||
|
||||
struct Selectors {
|
||||
code_selector: SegmentSelector,
|
||||
data_selector: SegmentSelector,
|
||||
user_code_selector: SegmentSelector,
|
||||
user_data_selector: SegmentSelector,
|
||||
tss_selector: SegmentSelector,
|
||||
}
|
||||
|
||||
pub fn init() {
|
||||
GDT.0.load();
|
||||
|
||||
unsafe {
|
||||
CS::set_reg(GDT.1.code_selector);
|
||||
load_tss(GDT.1.tss_selector);
|
||||
|
||||
DS::set_reg(self::GDT.1.data_selector);
|
||||
ES::set_reg(self::GDT.1.data_selector);
|
||||
SS::set_reg(self::GDT.1.data_selector);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use lib_ascii::println_log;
|
||||
use lib_ascii::{print, println_log};
|
||||
use lib_serial::serial_println;
|
||||
use x86_64::instructions::port::Port;
|
||||
use x86_64::registers::control::Cr2;
|
||||
@@ -7,10 +7,18 @@ use x86_64::structures::idt::{InterruptDescriptorTable, InterruptStackFrame, Pag
|
||||
use pic8259::ChainedPics;
|
||||
use spin::{Lazy, Mutex};
|
||||
|
||||
use super::gdt;
|
||||
|
||||
static IDT: Lazy<InterruptDescriptorTable> = Lazy::new(|| {
|
||||
let mut idt = InterruptDescriptorTable::new();
|
||||
idt.breakpoint.set_handler_fn(breakpoint_handler);
|
||||
idt.double_fault.set_handler_fn(double_fault_handler);
|
||||
|
||||
unsafe {
|
||||
idt.double_fault
|
||||
.set_handler_fn(double_fault_handler)
|
||||
.set_stack_index(gdt::DOUBLE_FAULT_1ST_INDEX);
|
||||
}
|
||||
|
||||
idt.general_protection_fault
|
||||
.set_handler_fn(general_protection_fault_handler);
|
||||
idt.page_fault.set_handler_fn(page_fault_handler);
|
||||
@@ -73,8 +81,31 @@ extern "x86-interrupt" fn double_fault_handler(
|
||||
}
|
||||
|
||||
extern "x86-interrupt" fn keyboard_interrupt_handler(_stack_frame: InterruptStackFrame) {
|
||||
use pc_keyboard::{layouts, DecodedKey, HandleControl, Keyboard, ScancodeSet1};
|
||||
use spin::Mutex;
|
||||
use x86_64::instructions::port::Port;
|
||||
|
||||
static KEYBOARD: Lazy<Mutex<Keyboard<layouts::Us104Key, ScancodeSet1>>> = Lazy::new(|| {
|
||||
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() };
|
||||
|
||||
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());
|
||||
|
||||
@@ -0,0 +1,134 @@
|
||||
use lib_alloc::allocator::FoundryAllocator;
|
||||
use limine::{memory_map::EntryType, response::MemoryMapResponse};
|
||||
use x86_64::{
|
||||
addr,
|
||||
registers::control::Cr3,
|
||||
structures::paging::{
|
||||
page_table::FrameError, FrameAllocator, OffsetPageTable, PageTable, PhysFrame, Size4KiB,
|
||||
},
|
||||
PhysAddr, VirtAddr,
|
||||
};
|
||||
|
||||
/// Returns a mutable reference to the current level 4 page table.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The caller must ensure that the level 4 page table is not modified
|
||||
/// simultaneously. The caller must also ensure that the physical memory offset
|
||||
/// is correct, to ensure that the correct virtual address is constructed.
|
||||
unsafe fn active_l4_table(physical_memory_offset: VirtAddr) -> &'static mut PageTable {
|
||||
let (level_4_frame, _) = Cr3::read();
|
||||
|
||||
let phys_addr = level_4_frame.start_address();
|
||||
let virt = phys_addr.as_u64() + physical_memory_offset.as_u64();
|
||||
&mut *(virt as *mut PageTable)
|
||||
}
|
||||
|
||||
/// Initializes the `OffsetPageTable` for the current CPU architecture.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// This function must be called only once and should be called before any
|
||||
/// memory operations are performed that rely on virtual memory management.
|
||||
/// The provided `physical_memory_offset` must be accurate to ensure correct
|
||||
/// translation of physical addresses.
|
||||
///
|
||||
/// # Parameters
|
||||
///
|
||||
/// - `physical_memory_offset`: The offset to convert physical addresses to
|
||||
/// virtual addresses in the higher-half direct map.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// Returns an `OffsetPageTable` that allows for manipulation of the page
|
||||
/// tables for the current CPU architecture.
|
||||
pub unsafe fn init(physical_memory_offset: VirtAddr) -> OffsetPageTable<'static> {
|
||||
let l4_table = active_l4_table(physical_memory_offset);
|
||||
OffsetPageTable::new(l4_table, physical_memory_offset)
|
||||
}
|
||||
|
||||
pub(crate) struct FoundryOSFrameAllocator {
|
||||
memory_map: &'static MemoryMapResponse,
|
||||
next: usize,
|
||||
}
|
||||
|
||||
impl FoundryOSFrameAllocator {
|
||||
/// Creates a new `FoundryOSFrameAllocator` from a memory map.
|
||||
///
|
||||
/// This function takes a reference to a `MemoryMapResponse` and initializes a
|
||||
/// `FoundryOSFrameAllocator` with it. The `next` field is set to 0, indicating that
|
||||
/// the first frame to be allocated is the first frame in the memory map.
|
||||
pub unsafe fn init(memory_map: &'static MemoryMapResponse) -> FoundryOSFrameAllocator {
|
||||
FoundryOSFrameAllocator {
|
||||
memory_map,
|
||||
next: 0,
|
||||
}
|
||||
}
|
||||
|
||||
/// An iterator over all usable frames in the memory map.
|
||||
///
|
||||
/// Yields one `PhysFrame` for each available 4KiB frame in the memory map.
|
||||
///
|
||||
/// This function is used to allocate frames for the pagemap.
|
||||
fn usable_frames(&self) -> impl Iterator<Item = PhysFrame> {
|
||||
let regions = self.memory_map.entries().iter();
|
||||
let usable_regions = regions.filter(|region| region.entry_type == EntryType::USABLE);
|
||||
|
||||
let addr_ranges = usable_regions.map(|region| region.base..region.base + region.length);
|
||||
|
||||
let frame_addresses = addr_ranges.flat_map(|r| r.step_by(4096));
|
||||
|
||||
frame_addresses.map(|addr| PhysFrame::from_start_address(PhysAddr::new(addr)).unwrap())
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl FrameAllocator<Size4KiB> for FoundryOSFrameAllocator {
|
||||
/// Allocates a frame from the list of usable frames.
|
||||
///
|
||||
/// This function returns the next available `PhysFrame` from the memory map,
|
||||
/// if one exists. Once a frame is allocated, the internal counter is incremented
|
||||
/// to point to the next frame for future allocations.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// - `Some(PhysFrame)`: If a usable frame is available.
|
||||
/// - `None`: If there are no more usable frames to allocate.
|
||||
|
||||
fn allocate_frame(&mut self) -> Option<PhysFrame> {
|
||||
let frame = self.usable_frames().nth(self.next);
|
||||
self.next += 1;
|
||||
frame
|
||||
}
|
||||
}
|
||||
|
||||
// pub unsafe fn translate_addr(addr: VirtAddr, physical_memory_offset: VirtAddr) -> Option<PhysAddr> {
|
||||
// translate_addr_inner(addr, physical_memory_offset)
|
||||
// }
|
||||
|
||||
// fn translate_addr_inner(addr: VirtAddr, physical_memory_offset: VirtAddr) -> Option<PhysAddr> {
|
||||
// let (l4_table_frame, _) = Cr3::read();
|
||||
|
||||
// let table_indexes = [
|
||||
// addr.p4_index(),
|
||||
// addr.p3_index(),
|
||||
// addr.p2_index(),
|
||||
// addr.p1_index(),
|
||||
// ];
|
||||
// let mut frame = l4_table_frame;
|
||||
|
||||
// for &i in &table_indexes {
|
||||
// let virt = physical_memory_offset + frame.start_address().as_u64();
|
||||
// let table_ptr: *const PageTable = virt.as_ptr();
|
||||
// let table = unsafe { &*table_ptr };
|
||||
|
||||
// let entry = &table[i];
|
||||
|
||||
// frame = match entry.frame() {
|
||||
// Ok(frame) => frame,
|
||||
// Err(FrameError::FrameNotPresent) => return None,
|
||||
// Err(FrameError::HugeFrame) => panic!("huge frames are not supported!"),
|
||||
// };
|
||||
// }
|
||||
|
||||
// Some(frame.start_address() + u64::from(addr.page_offset()))
|
||||
// }
|
||||
@@ -1,3 +1,7 @@
|
||||
pub mod gdt;
|
||||
|
||||
pub mod interrupts;
|
||||
|
||||
pub mod memory;
|
||||
|
||||
pub(crate) mod memmap;
|
||||
|
||||
+39
-2
@@ -1,12 +1,17 @@
|
||||
#![no_std]
|
||||
#![feature(abi_x86_interrupt)]
|
||||
|
||||
extern crate alloc;
|
||||
|
||||
use core::arch::asm;
|
||||
use lib_alloc::allocator::init_heap;
|
||||
use limine::request::{RequestsEndMarker, RequestsStartMarker};
|
||||
use limine::BaseRevision;
|
||||
|
||||
pub use lib_ascii::{print, print_log, println, println_log, WRITER};
|
||||
pub use lib_serial::{serial_print, serial_println, serial_read};
|
||||
use x86_64::structures::paging::Translate;
|
||||
use x86_64::{PhysAddr, VirtAddr};
|
||||
|
||||
mod arch;
|
||||
|
||||
@@ -28,6 +33,8 @@ static _END_MARKER: RequestsEndMarker = RequestsEndMarker::new();
|
||||
|
||||
#[panic_handler]
|
||||
fn rust_panic(_info: &core::panic::PanicInfo) -> ! {
|
||||
println!("Kernel panic: {}", _info);
|
||||
serial_println!("Kernel panic: {}", _info);
|
||||
hcf();
|
||||
}
|
||||
|
||||
@@ -49,10 +56,40 @@ pub fn boot() -> Result<(), &'static str> {
|
||||
return Err("base revision not supported");
|
||||
}
|
||||
|
||||
lib_serial::init()?;
|
||||
arch::x86_64::interrupts::init_idt();
|
||||
use arch::x86_64::{gdt, interrupts, memmap, memory};
|
||||
|
||||
let memory_map = memmap::get_memory_map();
|
||||
|
||||
print_log!(" Initialising Serial... ");
|
||||
lib_serial::init()?;
|
||||
println_log!("[Success]");
|
||||
|
||||
print_log!(" Setting Up Global Descriptor Table... ");
|
||||
gdt::init();
|
||||
println_log!("[Success]");
|
||||
|
||||
print_log!(" Setting Up Interrupt Descriptor Table... ");
|
||||
interrupts::init_idt();
|
||||
println_log!("[Success]");
|
||||
|
||||
print_log!(" Setting Up Page Table... ");
|
||||
let mut frame_allocator = unsafe { memory::FoundryOSFrameAllocator::init(memory_map) };
|
||||
println_log!("[Success]");
|
||||
|
||||
print_log!(" Initialising Memory Subsystem... ");
|
||||
let physical_memory_offset = VirtAddr::new(*memmap::PHYSICAL_MEMORY_OFFSET);
|
||||
let mut l4_table = unsafe { memory::init(physical_memory_offset) };
|
||||
println_log!("[Success]");
|
||||
|
||||
print_log!(" Initialising Heap... ");
|
||||
if let Err(e) = init_heap(&mut l4_table, &mut frame_allocator) {
|
||||
return Err("Failed to initialise heap");
|
||||
}
|
||||
println_log!("[Success]");
|
||||
|
||||
print_log!(" Enabling Interrupts... ");
|
||||
x86_64::instructions::interrupts::enable();
|
||||
println_log!("[Success]");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
+7
-1
@@ -1,6 +1,10 @@
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
extern crate alloc;
|
||||
|
||||
use alloc::vec::Vec;
|
||||
|
||||
use foundry_os::{println, println_log};
|
||||
|
||||
#[no_mangle]
|
||||
@@ -8,11 +12,13 @@ unsafe extern "C" fn kmain() -> ! {
|
||||
// All limine requests must also be referenced in a called function, otherwise they may be
|
||||
// removed by the linker.
|
||||
|
||||
println_log!(" [ Initialising ] ");
|
||||
println_log!(" [ Initialising Kernel Systems ] ");
|
||||
if let Err(err) = foundry_os::boot() {
|
||||
panic!("{}", err);
|
||||
}
|
||||
|
||||
println_log!("[ Kernel Initialised Successfully ] ");
|
||||
|
||||
let dimensions = lib_ascii::screensize_chars();
|
||||
let dimensions2 = lib_framebuffer::screensize_px();
|
||||
|
||||
|
||||
Submodule
+1
Submodule lib/lib_alloc added at af814bf2ab
+1
-1
Submodule lib/lib_ascii updated: 1ae956efa4...70d528b2e8
+1
-1
Submodule lib/lib_serial updated: 813fc0bfa3...ed2fa6b501
Reference in New Issue
Block a user