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(link_section = ".start")]
|
||||||
#[unsafe(no_mangle)]
|
#[unsafe(no_mangle)]
|
||||||
|
#[aphrodite_proc_macros::kernel_item(ArchBootEntry)]
|
||||||
extern "C" fn _start() -> ! {
|
extern "C" fn _start() -> ! {
|
||||||
unsafe { // Copy values provided by the bootloader out
|
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.
|
// 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.
|
// we force using ebx and eax as the output of an empty assembly block to let it know.
|
||||||
asm!(
|
asm!(
|
||||||
"", out("ebx") O, // Bootloader-specific data(ebx)
|
"", 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.
|
//! 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;
|
mod x86;
|
||||||
|
pub mod example_impl;
|
||||||
|
|
||||||
pub use x86::*;
|
pub use x86::*;
|
|
@ -2,4 +2,4 @@
|
||||||
#![cfg(any(target_arch = "x86"))]
|
#![cfg(any(target_arch = "x86"))]
|
||||||
|
|
||||||
/// The assembly port number to output debug messages to.
|
/// 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
|
//! Provides interrupt-related functions
|
||||||
#![cfg(any(target_arch = "x86"))]
|
#![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.
|
/// Returns whether interrupts are enabled or not.
|
||||||
|
#[aphrodite_proc_macros::kernel_item(InterruptsCheck)]
|
||||||
pub fn interrupts_enabled() -> bool {
|
pub fn interrupts_enabled() -> bool {
|
||||||
let flags: u32;
|
let flags: u32;
|
||||||
unsafe {
|
unsafe {
|
||||||
|
@ -16,6 +20,7 @@ pub fn interrupts_enabled() -> bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Disables interrupts.
|
/// Disables interrupts.
|
||||||
|
#[aphrodite_proc_macros::kernel_item(InterruptsDisable)]
|
||||||
pub fn disable_interrupts() {
|
pub fn disable_interrupts() {
|
||||||
unsafe {
|
unsafe {
|
||||||
asm!("cli")
|
asm!("cli")
|
||||||
|
@ -23,7 +28,8 @@ pub fn disable_interrupts() {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Disables interrupts and returns the value of them.
|
/// 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;
|
let flags: u32;
|
||||||
unsafe {
|
unsafe {
|
||||||
asm!(
|
asm!(
|
||||||
|
@ -32,11 +38,13 @@ pub fn pop_irq() -> u32 {
|
||||||
"pop {0:e}", out(reg) flags
|
"pop {0:e}", out(reg) flags
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
flags
|
flags as u64
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Restores interrupts after a [pop_irq] call.
|
/// 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 {
|
unsafe {
|
||||||
asm!(
|
asm!(
|
||||||
"push {0:e}", in(reg) flags
|
"push {0:e}", in(reg) flags
|
||||||
|
@ -48,21 +56,83 @@ pub fn restore_irq(flags: u32) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The IDTR. Used internally in [load_idt].
|
/// The IDTR. Used internally in [load_idt].
|
||||||
|
#[repr(packed)]
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
struct IDTR {
|
struct IDTR {
|
||||||
base: *const u8,
|
base: *const u8,
|
||||||
size: usize
|
size: usize
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsafe impl Send for IDTR {}
|
||||||
|
unsafe impl Sync for IDTR {}
|
||||||
|
|
||||||
/// Loads an interrupt descriptor table.
|
/// Loads an interrupt descriptor table.
|
||||||
pub fn load_idt(base: *const u8, size: usize) {
|
fn load_idt(base: *const u8, size: usize) {
|
||||||
let idtr = IDTR {
|
static mut IDTR: MaybeUninit<IDTR> = MaybeUninit::uninit();
|
||||||
base,
|
unsafe {
|
||||||
size
|
IDTR.write(IDTR {
|
||||||
};
|
base,
|
||||||
|
size
|
||||||
|
});
|
||||||
|
}
|
||||||
unsafe {
|
unsafe {
|
||||||
asm!(
|
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;
|
mod constants;
|
||||||
|
|
||||||
pub use constants::*;
|
pub(self) use constants::*;
|
||||||
use interrupts::{pop_irq, restore_irq};
|
use interrupts::{pop_irq, restore_irq};
|
||||||
use ports::{inb, outb};
|
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
|
/// Returns information from the CPUID command in the form
|
||||||
/// (ebx, edx, ecx).
|
/// (ebx, edx, ecx).
|
||||||
pub fn cpuid(id: u32) -> (u32, u32, u32) {
|
pub fn cpuid(id: u32) -> (u32, u32, u32) {
|
||||||
|
@ -160,14 +165,3 @@ pub fn enable_a20() -> bool {
|
||||||
|
|
||||||
return test_a20();
|
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.
|
//! 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