Working even more on making things architecture independent and really leaning into kernel items
This commit is contained in:
parent
f6b3f935ef
commit
ff12b11b9f
7 changed files with 335 additions and 24 deletions
|
@ -59,9 +59,11 @@ static mut MAGIC: u32 = 0xFFFFFFFF;
|
|||
|
||||
#[unsafe(link_section = ".start")]
|
||||
#[unsafe(no_mangle)]
|
||||
#[aphrodite_proc_macros::kernel_item(ArchBootEntry)]
|
||||
extern "C" fn _start() -> ! {
|
||||
unsafe { // Copy values provided by the bootloader out
|
||||
// Aphrodite bootloaders pass values in eax and ebx, however rust doesn't know that it can't overwrite those.
|
||||
// (if necessary, we'll store all of the registers for other bootloaders and identify which one it is later)
|
||||
// we force using ebx and eax as the output of an empty assembly block to let it know.
|
||||
asm!(
|
||||
"", out("ebx") O, // Bootloader-specific data(ebx)
|
||||
|
|
110
kernel/src/kernel/arch/example_impl/mod.rs
Normal file
110
kernel/src/kernel/arch/example_impl/mod.rs
Normal file
|
@ -0,0 +1,110 @@
|
|||
//! An example implementation of an architecture. DO NOT use this module!
|
||||
//! Everything must be implemented via either kernel items, or for constants
|
||||
//! making them public.
|
||||
//!
|
||||
//! This is commented out for obvious reasons, but make sure to have this at
|
||||
//! the top of the all files in your arch(with "arch" replaced with the
|
||||
//! actual architecture, of course):
|
||||
//! #![cfg(any(target_arch = "arch"))]
|
||||
|
||||
pub mod interrupts {
|
||||
//! Interrupt-related functions.
|
||||
|
||||
use core::mem::MaybeUninit;
|
||||
|
||||
/// Must be a u16 or castable to a u16.
|
||||
/// Value used in x86 shown here as an example.
|
||||
pub const USER_SYSCALL_VECTOR: u16 = 0xA0;
|
||||
|
||||
/// Returns whether interrupts are enabled or not.
|
||||
#[aphrodite_proc_macros::kernel_item(InterruptsCheck)]
|
||||
fn interrupts_enabled() -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
/// Enables interrupts.
|
||||
#[aphrodite_proc_macros::kernel_item(InterruptsEnable)]
|
||||
fn enable_interrupts() {
|
||||
|
||||
}
|
||||
|
||||
/// Disables interrupts.
|
||||
#[aphrodite_proc_macros::kernel_item(InterruptsDisable)]
|
||||
fn disable_interrupts() {
|
||||
|
||||
}
|
||||
|
||||
/// Disables interrupts and a value that can be used to restore them
|
||||
/// with [restore_irq].
|
||||
#[aphrodite_proc_macros::kernel_item(InterruptsPop)]
|
||||
fn pop_irq() -> u64 {
|
||||
0
|
||||
}
|
||||
|
||||
/// Restores interrupts after a [pop_irq] call.
|
||||
#[aphrodite_proc_macros::kernel_item(InterruptsRestore)]
|
||||
fn restore_irq(irq: u64) {
|
||||
irq;
|
||||
}
|
||||
|
||||
/// Activates an IDT.
|
||||
#[aphrodite_proc_macros::kernel_item(ActivateIDT)]
|
||||
fn activate_idt(idt: Idt) {
|
||||
idt;
|
||||
}
|
||||
|
||||
/// An IDT.
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct Idt {
|
||||
vectors: [u16; 256],
|
||||
funcs: [MaybeUninit<fn ()>; 256],
|
||||
len: usize,
|
||||
}
|
||||
|
||||
/// An IDT builder. The only way to create
|
||||
/// an IDT.
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct IdtBuilder {
|
||||
vectors: [u16; 256],
|
||||
funcs: [MaybeUninit<fn ()>; 256],
|
||||
idx: usize,
|
||||
}
|
||||
|
||||
impl IdtBuilder {
|
||||
/// Start creating a new IDT.
|
||||
pub fn new() -> Self {
|
||||
IdtBuilder {
|
||||
vectors: [0; 256],
|
||||
funcs: [MaybeUninit::uninit(); 256],
|
||||
idx: 0,
|
||||
}
|
||||
}
|
||||
/// Add a function to the IDT.
|
||||
pub fn add_fn(&mut self, vector: u16, func: fn()) -> &mut Self {
|
||||
self.vectors[self.idx] = vector;
|
||||
self.funcs[self.idx].write(func);
|
||||
self.idx += 1;
|
||||
self
|
||||
}
|
||||
/// Create the IDT from the IDT builder.
|
||||
pub fn finish(&self) -> Idt {
|
||||
Idt {
|
||||
vectors: self.vectors,
|
||||
funcs: self.funcs,
|
||||
len: self.idx
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub mod output {
|
||||
//! Not shown here(see [crate::arch::x86] for an example), but a
|
||||
//! LOT of output functions must be implemented. Using macros to
|
||||
//! implement these is HIGHLY recommended.
|
||||
}
|
||||
|
||||
/// Returns whether paging is available for this architecture.
|
||||
#[aphrodite_proc_macros::kernel_item(PagingAvailabe)]
|
||||
pub fn paging_available() -> bool {
|
||||
true
|
||||
}
|
|
@ -1,5 +1,8 @@
|
|||
//! Arch-specific code. This module re-exports all code from the architecture being used.
|
||||
//!
|
||||
//! See [example_impl] for everything that has to be implemented by an architecture module.
|
||||
|
||||
mod x86;
|
||||
pub mod example_impl;
|
||||
|
||||
pub use x86::*;
|
|
@ -2,4 +2,4 @@
|
|||
#![cfg(any(target_arch = "x86"))]
|
||||
|
||||
/// The assembly port number to output debug messages to.
|
||||
pub const DEBUG_PORT: u16 = 0xE9;
|
||||
pub(super) const DEBUG_PORT: u16 = 0xE9;
|
|
@ -1,9 +1,13 @@
|
|||
//! Provides interrupt-related functions
|
||||
#![cfg(any(target_arch = "x86"))]
|
||||
|
||||
use core::arch::asm;
|
||||
use core::{alloc::{Allocator, Layout}, arch::asm, mem::MaybeUninit};
|
||||
|
||||
/// The syscall vector.
|
||||
pub const USER_SYSCALL_VECTOR: u16 = 0xA0;
|
||||
|
||||
/// Returns whether interrupts are enabled or not.
|
||||
#[aphrodite_proc_macros::kernel_item(InterruptsCheck)]
|
||||
pub fn interrupts_enabled() -> bool {
|
||||
let flags: u32;
|
||||
unsafe {
|
||||
|
@ -16,6 +20,7 @@ pub fn interrupts_enabled() -> bool {
|
|||
}
|
||||
|
||||
/// Disables interrupts.
|
||||
#[aphrodite_proc_macros::kernel_item(InterruptsDisable)]
|
||||
pub fn disable_interrupts() {
|
||||
unsafe {
|
||||
asm!("cli")
|
||||
|
@ -23,7 +28,8 @@ pub fn disable_interrupts() {
|
|||
}
|
||||
|
||||
/// Disables interrupts and returns the value of them.
|
||||
pub fn pop_irq() -> u32 {
|
||||
#[aphrodite_proc_macros::kernel_item(InterruptsPop)]
|
||||
pub fn pop_irq() -> u64 {
|
||||
let flags: u32;
|
||||
unsafe {
|
||||
asm!(
|
||||
|
@ -32,11 +38,13 @@ pub fn pop_irq() -> u32 {
|
|||
"pop {0:e}", out(reg) flags
|
||||
)
|
||||
}
|
||||
flags
|
||||
flags as u64
|
||||
}
|
||||
|
||||
/// Restores interrupts after a [pop_irq] call.
|
||||
pub fn restore_irq(flags: u32) {
|
||||
#[aphrodite_proc_macros::kernel_item(InterruptsRestore)]
|
||||
pub fn restore_irq(flags: u64) {
|
||||
let flags = flags as u32;
|
||||
unsafe {
|
||||
asm!(
|
||||
"push {0:e}", in(reg) flags
|
||||
|
@ -48,21 +56,83 @@ pub fn restore_irq(flags: u32) {
|
|||
}
|
||||
|
||||
/// The IDTR. Used internally in [load_idt].
|
||||
#[repr(packed)]
|
||||
#[repr(C)]
|
||||
struct IDTR {
|
||||
base: *const u8,
|
||||
size: usize
|
||||
}
|
||||
|
||||
unsafe impl Send for IDTR {}
|
||||
unsafe impl Sync for IDTR {}
|
||||
|
||||
/// Loads an interrupt descriptor table.
|
||||
pub fn load_idt(base: *const u8, size: usize) {
|
||||
let idtr = IDTR {
|
||||
fn load_idt(base: *const u8, size: usize) {
|
||||
static mut IDTR: MaybeUninit<IDTR> = MaybeUninit::uninit();
|
||||
unsafe {
|
||||
IDTR.write(IDTR {
|
||||
base,
|
||||
size
|
||||
};
|
||||
});
|
||||
}
|
||||
unsafe {
|
||||
asm!(
|
||||
"lidt {}", in(reg) &idtr
|
||||
"lidt {}", in(reg) IDTR.as_ptr() as usize
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// Activate an IDT.
|
||||
#[aphrodite_proc_macros::kernel_item(ActivateIDT)]
|
||||
fn activate_idt(idt: Idt, alloc: crate::mem::MemoryMapAlloc) {
|
||||
let mem = alloc.allocate(unsafe { Layout::from_size_align_unchecked(8*idt.len, 1) }).unwrap().as_mut_ptr();
|
||||
for i in 0..idt.len {
|
||||
let vector = idt.vectors[i];
|
||||
let func = unsafe { idt.funcs[i].assume_init() } as usize as u32;
|
||||
let user_callable = idt.user_callable[i];
|
||||
let output: u64 = func & 0b1111111111111111;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct Idt {
|
||||
vectors: [u16; 256],
|
||||
funcs: [MaybeUninit<fn ()>; 256],
|
||||
user_callable: [bool; 256],
|
||||
len: usize,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct IdtBuilder {
|
||||
vectors: [u16; 256],
|
||||
funcs: [MaybeUninit<fn ()>; 256],
|
||||
user_callable: [bool; 256],
|
||||
idx: usize,
|
||||
}
|
||||
|
||||
impl IdtBuilder {
|
||||
pub fn new() -> Self {
|
||||
IdtBuilder {
|
||||
vectors: [0; 256],
|
||||
funcs: [MaybeUninit::uninit(); 256],
|
||||
user_callable: [false; 256],
|
||||
idx: 0,
|
||||
}
|
||||
}
|
||||
pub fn add_fn(&mut self, vector: u16, func: fn(), user_callable: bool) -> &mut Self {
|
||||
self.vectors[self.idx] = vector;
|
||||
self.funcs[self.idx].write(func);
|
||||
self.user_callable[self.idx] = user_callable;
|
||||
self.idx += 1;
|
||||
self
|
||||
}
|
||||
pub fn finish(&self) -> Idt {
|
||||
Idt {
|
||||
vectors: self.vectors,
|
||||
funcs: self.funcs,
|
||||
user_callable: self.user_callable,
|
||||
len: self.idx
|
||||
}
|
||||
}
|
||||
}
|
|
@ -11,10 +11,15 @@ pub mod paging;
|
|||
|
||||
mod constants;
|
||||
|
||||
pub use constants::*;
|
||||
pub(self) use constants::*;
|
||||
use interrupts::{pop_irq, restore_irq};
|
||||
use ports::{inb, outb};
|
||||
|
||||
#[aphrodite_proc_macros::kernel_item(PagingAvailabe)]
|
||||
pub fn paging_available() -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
/// Returns information from the CPUID command in the form
|
||||
/// (ebx, edx, ecx).
|
||||
pub fn cpuid(id: u32) -> (u32, u32, u32) {
|
||||
|
@ -160,14 +165,3 @@ pub fn enable_a20() -> bool {
|
|||
|
||||
return test_a20();
|
||||
}
|
||||
|
||||
/// Disables paging by clearing bit 31 in the cr0 register.
|
||||
pub fn disable_paging() {
|
||||
unsafe {
|
||||
asm!(
|
||||
"mov eax, cr0",
|
||||
"and eax, 01111111111111111111111111111111b",
|
||||
"mov cr0, eax"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1 +1,133 @@
|
|||
//! Functions and types related to paging.
|
||||
|
||||
use core::arch::asm;
|
||||
|
||||
use aphrodite_proc_macros::kernel_item;
|
||||
|
||||
pub enum PageDirectoryEntry {
|
||||
FourMb(u32),
|
||||
Other(u32),
|
||||
}
|
||||
|
||||
impl PageDirectoryEntry {
|
||||
const fn create_fourmb(
|
||||
mut bits32to22: u16,
|
||||
bits39to32: u8,
|
||||
pat: bool,
|
||||
mut available: u8,
|
||||
global: bool,
|
||||
dirty: bool,
|
||||
accessed: bool,
|
||||
disable_cache: bool,
|
||||
write_through: bool,
|
||||
user: bool,
|
||||
can_write: bool,
|
||||
present: bool,
|
||||
) -> Self {
|
||||
let mut out = 0u32;
|
||||
if present {
|
||||
out |= 1 << 0;
|
||||
}
|
||||
if can_write {
|
||||
out |= 1 << 1;
|
||||
}
|
||||
if user {
|
||||
out |= 1 << 2;
|
||||
}
|
||||
if write_through {
|
||||
out |= 1 << 3;
|
||||
}
|
||||
if disable_cache {
|
||||
out |= 1 << 4;
|
||||
}
|
||||
if accessed {
|
||||
out |= 1 << 5;
|
||||
}
|
||||
if dirty {
|
||||
out |= 1 << 6;
|
||||
}
|
||||
out |= 1 << 7;
|
||||
if global {
|
||||
out |= 1 << 8;
|
||||
}
|
||||
available &= 0b111;
|
||||
out |= (available as u32) << 9;
|
||||
if pat {
|
||||
out |= 1 << 12;
|
||||
}
|
||||
out |= (bits39to32 as u32) << 13;
|
||||
bits32to22 &= 0b1111111111;
|
||||
out |= (bits32to22 as u32) << 22;
|
||||
Self::FourMb(out)
|
||||
}
|
||||
|
||||
const fn create_other(
|
||||
mut bits31to12: u32,
|
||||
pat: bool,
|
||||
mut available: u8,
|
||||
global: bool,
|
||||
accessed: bool,
|
||||
disable_cache: bool,
|
||||
write_through: bool,
|
||||
user: bool,
|
||||
can_write: bool,
|
||||
present: bool,
|
||||
) -> Self {
|
||||
let mut out = 0u32;
|
||||
if present {
|
||||
out |= 1 << 0;
|
||||
}
|
||||
if can_write {
|
||||
out |= 1 << 1;
|
||||
}
|
||||
if user {
|
||||
out |= 1 << 2;
|
||||
}
|
||||
if write_through {
|
||||
out |= 1 << 3;
|
||||
}
|
||||
if disable_cache {
|
||||
out |= 1 << 4;
|
||||
}
|
||||
if accessed {
|
||||
out |= 1 << 5;
|
||||
}
|
||||
if available & 1 != 0 {
|
||||
out |= 1 << 6;
|
||||
}
|
||||
out |= 0 << 7;
|
||||
if global {
|
||||
out |= 1 << 8;
|
||||
}
|
||||
available &= 0b11110;
|
||||
out |= (available as u32) << 8;
|
||||
if pat {
|
||||
out |= 1 << 12;
|
||||
}
|
||||
bits31to12 &= 0b1111111111111111111;
|
||||
out |= bits31to12 << 13;
|
||||
Self::Other(out)
|
||||
}
|
||||
}
|
||||
|
||||
/// Kind of cursed, but DSTs aren't allowed in statics.
|
||||
static mut PAGE_DIRECTORY: PageDirectoryEntry =
|
||||
PageDirectoryEntry::create_other(0, false, 0, false, false, false, false, false, false, false);
|
||||
|
||||
#[kernel_item(PagingInit)]
|
||||
pub fn initalize_paging() {
|
||||
|
||||
}
|
||||
|
||||
|
||||
/// Disables paging by clearing bit 31 in the cr0 register.
|
||||
#[kernel_item(PagingDeinit)]
|
||||
pub fn disable_paging() {
|
||||
unsafe {
|
||||
asm!(
|
||||
"mov eax, cr0",
|
||||
"and eax, 01111111111111111111111111111111b",
|
||||
"mov cr0, eax"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue