I really need to commit more, but made good progress! Untested memory manager implemented.
This commit is contained in:
parent
2da90ef035
commit
25528c9952
14 changed files with 702 additions and 65 deletions
|
@ -3,6 +3,10 @@
|
||||||
(
|
(
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
|
if [[ -n "$KERNEL_DIR" ]]; then
|
||||||
|
export KERNEL_DIR=$(readlink -e .)
|
||||||
|
fi
|
||||||
|
|
||||||
DIR="${BASH_SOURCE%/*}"
|
DIR="${BASH_SOURCE%/*}"
|
||||||
if [[ ! -d "$DIR" ]]; then DIR="$PWD"; fi
|
if [[ ! -d "$DIR" ]]; then DIR="$PWD"; fi
|
||||||
|
|
||||||
|
@ -34,7 +38,8 @@
|
||||||
cd ../kernel
|
cd ../kernel
|
||||||
|
|
||||||
for target in $TARGETS; do
|
for target in $TARGETS; do
|
||||||
cargo build --target "$target" --release -Zbuild-std --bin entrypoint
|
real_target=${!target}
|
||||||
|
cargo build --target "$real_target" --release -Zbuild-std --bin entrypoint_$target
|
||||||
done
|
done
|
||||||
# build the kernel's entrypoint
|
# build the kernel's entrypoint
|
||||||
|
|
||||||
|
|
|
@ -31,4 +31,7 @@ CONFIG_PREUSER_OUTPUT_FATAL=true
|
||||||
|
|
||||||
# Whether to build an iso with GRUB. Used in ./build.
|
# Whether to build an iso with GRUB. Used in ./build.
|
||||||
CONFIG_BUILD_GRUB=true
|
CONFIG_BUILD_GRUB=true
|
||||||
|
|
||||||
|
# The precision of the allocator. The size of the allocated region is divided by this to get how much to change it by each time.
|
||||||
|
CONFIG_ALLOC_PRECISION=4
|
||||||
# End configs
|
# End configs
|
|
@ -3,10 +3,27 @@
|
||||||
#![allow(unexpected_cfgs)]
|
#![allow(unexpected_cfgs)]
|
||||||
#![allow(static_mut_refs)]
|
#![allow(static_mut_refs)]
|
||||||
|
|
||||||
|
use core::alloc::{Allocator, Layout};
|
||||||
|
|
||||||
use crate::output::*;
|
use crate::output::*;
|
||||||
|
|
||||||
|
const MEM_TEST_SIZES: [usize; 8] = [1, 2, 4, 8, 16, 32, 64, 128];
|
||||||
|
|
||||||
/// The real entrypoint to the kernel. `internel/arch/*/entry.rs` files eventually call this.
|
/// The real entrypoint to the kernel. `internel/arch/*/entry.rs` files eventually call this.
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
pub fn _entry(display: Option<&dyn crate::display::TextDisplay>, BI: &crate::boot::BootInfo) -> ! {
|
pub fn _entry(display: Option<&dyn crate::display::TextDisplay>, BI: &crate::boot::BootInfo) -> ! {
|
||||||
|
let mut mem_map = BI.memory_map.unwrap();
|
||||||
|
let allocator = crate::mem::MemoryMapAlloc::new(&mut mem_map).unwrap();
|
||||||
|
tdebugsln("Testing allocator...", display.unwrap());
|
||||||
|
|
||||||
|
for size in MEM_TEST_SIZES {
|
||||||
|
tdebugs("Allocating ", display.unwrap());
|
||||||
|
tdebugbnp(&crate::usize_as_u8_slice(size), display.unwrap());
|
||||||
|
tdebugsnpln(" bytes of memory...", display.unwrap());
|
||||||
|
if let Err(_) = allocator.allocate(Layout::from_size_align(size, 1).unwrap()) {
|
||||||
|
terrors("Failed to allocate: ",display.unwrap());
|
||||||
|
unsafe { crate::mem::LAST_MEMMAP_ERR.unwrap_err().display_np(display.unwrap()) }
|
||||||
|
}
|
||||||
|
}
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
|
@ -5,7 +5,7 @@
|
||||||
/// except for memory with type [MemoryType::Free]
|
/// except for memory with type [MemoryType::Free]
|
||||||
/// or [MemoryType::HardwareSpecific] memory with
|
/// or [MemoryType::HardwareSpecific] memory with
|
||||||
/// the boolean argument set.
|
/// the boolean argument set.
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||||
pub enum MemoryType {
|
pub enum MemoryType {
|
||||||
/// Free RAM with no use.
|
/// Free RAM with no use.
|
||||||
Free,
|
Free,
|
||||||
|
@ -23,27 +23,76 @@ pub enum MemoryType {
|
||||||
/// whether memory can be allocated in this region.
|
/// whether memory can be allocated in this region.
|
||||||
HardwareSpecific(u32, bool),
|
HardwareSpecific(u32, bool),
|
||||||
/// Flash/semi-permanent memory. Generally used in embedded systems.
|
/// Flash/semi-permanent memory. Generally used in embedded systems.
|
||||||
Permanent
|
Permanent,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A single memory mapping for [MemoryMap].
|
/// A single memory mapping for [MemoryMap].
|
||||||
pub trait MemoryMapping {
|
#[derive(Clone, Copy)]
|
||||||
|
pub struct MemoryMapping {
|
||||||
/// Returns the type of the memory.
|
/// Returns the type of the memory.
|
||||||
fn get_type(&self) -> MemoryType;
|
pub mem_type: MemoryType,
|
||||||
/// Returns the beginning of the memory.
|
/// Returns the beginning of the memory.
|
||||||
fn get_start(&self) -> u64;
|
pub start: u64,
|
||||||
/// Returns the length of the memory.
|
/// Returns the length of the memory.
|
||||||
fn get_length(&self) -> u64;
|
pub len: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Memory mapping.
|
#[derive(Clone, Copy)]
|
||||||
pub trait _MemoryMap: core::iter::Iterator<Item = &'static dyn MemoryMapping> + core::ops::Index<usize, Output = dyn MemoryMapping> {
|
pub struct MemoryMap {
|
||||||
/// Returns the number of [MemoryMapping]s in the MemoryMap. This is total, not remainder.
|
pub len: u64,
|
||||||
fn len(&self) -> usize;
|
pub size_pages: u64,
|
||||||
|
pub page_size: u64,
|
||||||
|
|
||||||
|
/// All sections.
|
||||||
|
pub sections: &'static [MemoryMapping],
|
||||||
|
|
||||||
|
/// Iterator's index.
|
||||||
|
pub idx: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Memory mapping. Used so that we can downcast.
|
impl MemoryMap {
|
||||||
pub trait MemoryMap: _MemoryMap + core::any::Any {}
|
pub fn len(&self) -> u64 {
|
||||||
|
self.sections.len() as u64
|
||||||
|
}
|
||||||
|
pub fn reset_iter(&mut self) {
|
||||||
|
self.idx = 0;
|
||||||
|
}
|
||||||
|
pub fn mem_size(&mut self) -> u64 {
|
||||||
|
let curr_idx = self.idx;
|
||||||
|
self.reset_iter();
|
||||||
|
let mut out = 0u64;
|
||||||
|
for ele in self.sections {
|
||||||
|
if ele.mem_type == crate::boot::MemoryType::Free {
|
||||||
|
out += ele.len;
|
||||||
|
} else if let crate::boot::MemoryType::HardwareSpecific(_, free) = ele.mem_type {
|
||||||
|
if free {
|
||||||
|
out += ele.len;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.idx = curr_idx;
|
||||||
|
out
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl core::ops::Index<usize> for MemoryMap {
|
||||||
|
type Output = MemoryMapping;
|
||||||
|
|
||||||
|
fn index(&self, index: usize) -> &Self::Output {
|
||||||
|
&self.sections[index]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl core::iter::Iterator for MemoryMap {
|
||||||
|
type Item = MemoryMapping;
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
self.idx += 1;
|
||||||
|
if self.sections.len()<=self.idx-1 {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
Some(self.sections[self.idx-1].into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Bootloader-independent information.
|
/// Bootloader-independent information.
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
|
@ -51,13 +100,13 @@ pub struct BootInfo<'a> {
|
||||||
/// The commandline of the kernel.
|
/// The commandline of the kernel.
|
||||||
/// See <https://aphrodite-os.github.io/book/command-line.html> for the format.
|
/// See <https://aphrodite-os.github.io/book/command-line.html> for the format.
|
||||||
pub cmdline: Option<&'static str>,
|
pub cmdline: Option<&'static str>,
|
||||||
|
|
||||||
/// The memory map provided by the bootloader. If None, the kernel will attempt to generate it.
|
/// The memory map provided by the bootloader. If None, the kernel will attempt to generate it.
|
||||||
pub memory_map: Option<&'a dyn MemoryMap>,
|
pub memory_map: Option<MemoryMap>,
|
||||||
|
|
||||||
/// The name of the bootloader(for example, "GRUB 2.12").
|
/// The name of the bootloader(for example, "GRUB 2.12").
|
||||||
pub bootloader_name: Option<&'static str>,
|
pub bootloader_name: Option<&'static str>,
|
||||||
|
|
||||||
/// Provides a way to display text.
|
/// Provides a way to display text.
|
||||||
pub output: Option<&'a dyn crate::display::TextDisplay>,
|
pub output: Option<&'a dyn crate::display::TextDisplay>,
|
||||||
}
|
}
|
||||||
|
|
13
kernel/src/include/cfg.rs
Normal file
13
kernel/src/include/cfg.rs
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
//! Config-related stuff.
|
||||||
|
//!
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! cfg_int {
|
||||||
|
($cfg:literal, $type:ident) => {
|
||||||
|
paste::paste! {
|
||||||
|
{
|
||||||
|
let cfg = env!($cfg).as_bytes();
|
||||||
|
crate::[< str_as_ $type >](cfg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
104
kernel/src/include/cmdline.rs
Normal file
104
kernel/src/include/cmdline.rs
Normal file
|
@ -0,0 +1,104 @@
|
||||||
|
//! Provide functions and structs for parsing a kernel command line.
|
||||||
|
|
||||||
|
/// A value of an argument.
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
pub enum ArgumentValue {
|
||||||
|
/// A string argument with the preceeding and following single quotes removed, and any \' replaced with '.
|
||||||
|
Str(&'static str),
|
||||||
|
/// A float argument.
|
||||||
|
Float(f128),
|
||||||
|
/// A signed argument.
|
||||||
|
Signed(i128),
|
||||||
|
/// A unsigned argument.
|
||||||
|
Unsigned(u128),
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A single argument in a [Cmdline].
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
pub struct Argument {
|
||||||
|
/// The name of an argument.
|
||||||
|
pub name: &'static str,
|
||||||
|
/// The value of an argument.
|
||||||
|
pub value: ArgumentValue
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A single flag in a [Cmdline].
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
pub struct Flag {
|
||||||
|
/// The name of a flag.
|
||||||
|
pub name: &'static str
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A kernel command line.
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct Cmdline {
|
||||||
|
/// The arguments of the Cmdline.
|
||||||
|
pub arguments: &'static [Argument],
|
||||||
|
/// The flags of the Cmdline.
|
||||||
|
pub flags: &'static [Flag],
|
||||||
|
|
||||||
|
/// The argument validators. When using [CmdlineValidator], it will check all of them
|
||||||
|
/// and if ALL of them report ANY of the arguments incorrect, then it will return an error.
|
||||||
|
pub argument_validators: &'static [&'static dyn ArgumentValidator],
|
||||||
|
|
||||||
|
/// The flag validators. When using [CmdlineValidator], it will check all of them
|
||||||
|
/// and if ALL of them report ANY of the flags incorrect, then it will return an error.
|
||||||
|
pub flag_validators: &'static [&'static dyn FlagValidator],
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A validator of one of the types in this module.
|
||||||
|
pub trait Validator {
|
||||||
|
/// The type that the trait validates.
|
||||||
|
type Validates;
|
||||||
|
|
||||||
|
/// Validate a value.
|
||||||
|
fn validate<'a>(&self, value: Self::Validates) -> Result<(), crate::Error<'a>>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A [Validator] that validates arguments.
|
||||||
|
pub trait ArgumentValidator: Validator<Validates = Argument> {}
|
||||||
|
|
||||||
|
/// A [Validator] that validates flags.
|
||||||
|
pub trait FlagValidator: Validator<Validates = Flag> {}
|
||||||
|
|
||||||
|
/// A [Validator] that validates cmdlines.
|
||||||
|
pub struct CmdlineValidator {}
|
||||||
|
|
||||||
|
/// Error returned by [CmdlineValidator::validate] when an argument is incorrect
|
||||||
|
pub const ERR_INVALID_ARGUMENT: i16 = -1;
|
||||||
|
|
||||||
|
/// Error returned by [CmdlineValidator::validate] when a flag is incorrect
|
||||||
|
pub const ERR_INVALID_FLAG: i16 = -2;
|
||||||
|
|
||||||
|
impl Validator for CmdlineValidator {
|
||||||
|
type Validates = Cmdline;
|
||||||
|
|
||||||
|
fn validate<'a>(&self, value: Self::Validates) -> Result<(), crate::Error<'a>> {
|
||||||
|
for arg in value.arguments {
|
||||||
|
let mut correct = false;
|
||||||
|
for validator in value.argument_validators {
|
||||||
|
if validator.validate(*arg).is_ok() {
|
||||||
|
correct = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !correct {
|
||||||
|
return Err(crate::Error::new("invalid argument in command line", ERR_INVALID_ARGUMENT));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for arg in value.flags {
|
||||||
|
let mut correct = false;
|
||||||
|
for validator in value.flag_validators {
|
||||||
|
if validator.validate(*arg).is_ok() {
|
||||||
|
correct = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !correct {
|
||||||
|
return Err(crate::Error::new("invalid flag in command line", ERR_INVALID_FLAG));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,6 +1,9 @@
|
||||||
//! Stuff related to errors.
|
//! Stuff related to errors.
|
||||||
|
|
||||||
|
use crate::display::TextDisplay;
|
||||||
|
|
||||||
/// An error used by aphrodite
|
/// An error used by aphrodite
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
pub struct Error<'a> {
|
pub struct Error<'a> {
|
||||||
message: &'a str,
|
message: &'a str,
|
||||||
code: i16
|
code: i16
|
||||||
|
@ -13,6 +16,14 @@ impl<'a> Error<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Error<'_> {
|
||||||
|
pub fn display_np(&self, display: &dyn TextDisplay) {
|
||||||
|
crate::output::terrorbnp(&crate::i16_as_u8_slice(self.code), display);
|
||||||
|
crate::output::terrorsnp(": ", display);
|
||||||
|
crate::output::terrorsnpln(self.message, display);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl core::fmt::Debug for Error<'_> {
|
impl core::fmt::Debug for Error<'_> {
|
||||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||||
f.write_str(core::str::from_utf8(&crate::i16_as_u8_slice(self.code)).unwrap())?;
|
f.write_str(core::str::from_utf8(&crate::i16_as_u8_slice(self.code)).unwrap())?;
|
||||||
|
|
343
kernel/src/include/mem.rs
Normal file
343
kernel/src/include/mem.rs
Normal file
|
@ -0,0 +1,343 @@
|
||||||
|
//! Memory allocation.
|
||||||
|
|
||||||
|
use core::{
|
||||||
|
alloc::{Allocator, GlobalAlloc},
|
||||||
|
num::NonZero,
|
||||||
|
ops::Range,
|
||||||
|
ptr::{NonNull, null_mut},
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::boot::MemoryType;
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
struct Allocation {
|
||||||
|
pub used: bool,
|
||||||
|
pub addr: u64,
|
||||||
|
pub len: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
struct AllocationHeader {
|
||||||
|
pub used: bool,
|
||||||
|
pub addr: u64,
|
||||||
|
pub len: u64,
|
||||||
|
pub num_allocations: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct AllocationIter {
|
||||||
|
ptr: *const Allocation,
|
||||||
|
num_allocations: u64,
|
||||||
|
idx: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Iterator for AllocationIter {
|
||||||
|
type Item = *mut Allocation;
|
||||||
|
fn next(&mut self) -> Option<<Self as Iterator>::Item> {
|
||||||
|
if self.idx >= self.num_allocations {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
Some(&unsafe {
|
||||||
|
*((self.ptr as usize + (size_of::<Allocation>() * self.idx as usize))
|
||||||
|
as *const Allocation)
|
||||||
|
} as *const Allocation as *mut Allocation)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A implementation of a physical memory allocator that uses a [crate::boot::MemoryMap].
|
||||||
|
pub struct MemoryMapAlloc<'a> {
|
||||||
|
/// The memory map to use to allocate memory.
|
||||||
|
pub memory_map: &'a mut crate::boot::MemoryMap,
|
||||||
|
|
||||||
|
allocationheader: *mut AllocationHeader,
|
||||||
|
allocations: *mut Allocation,
|
||||||
|
max_allocations_size: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Too many allocations have been created, pushing the size of [MemoryMapAlloc::allocations] over [MemoryMapAlloc::max_allocations_size].
|
||||||
|
const TOO_MANY_ALLOCATIONS: i16 = -2;
|
||||||
|
|
||||||
|
/// There isn't enough space for 32 allocations(the minimum available).
|
||||||
|
pub const ALLOCATIONS_NOT_ENOUGH_SPACE: i16 = -3;
|
||||||
|
|
||||||
|
/// The index provided to [MemoryMapAlloc::extend_allocation] is too big.
|
||||||
|
const EXTEND_ALLOCATION_INVALID_INDEX: i16 = -4;
|
||||||
|
|
||||||
|
/// The allocation provided to [MemoryMapAlloc::extend_allocation] is unused.
|
||||||
|
const EXTEND_ALLOCATION_ALLOCATION_UNUSED: i16 = -5;
|
||||||
|
|
||||||
|
/// The allocation provided to [MemoryMapAlloc::extend_allocation], if extended, would extend into another allocation.
|
||||||
|
const EXTEND_ALLOCATION_OTHER_ALLOCATION: i16 = -6;
|
||||||
|
|
||||||
|
impl<'a> MemoryMapAlloc<'a> {
|
||||||
|
/// Creates a new [MemoryMapAlloc]. Please call this method instead of creating it manually!
|
||||||
|
/// This method uses the memory mapping to
|
||||||
|
pub fn new(
|
||||||
|
memory_map: &'a mut crate::boot::MemoryMap,
|
||||||
|
) -> Result<MemoryMapAlloc<'a>, crate::Error<'a>> {
|
||||||
|
let mut out = MemoryMapAlloc {
|
||||||
|
memory_map,
|
||||||
|
allocations: core::ptr::null_mut(),
|
||||||
|
allocationheader: core::ptr::null_mut(),
|
||||||
|
max_allocations_size: 0,
|
||||||
|
};
|
||||||
|
out.memory_map.reset_iter();
|
||||||
|
for mapping in &mut *out.memory_map {
|
||||||
|
if mapping.len < (size_of::<Allocation>() * 32) as u64 {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if mapping.mem_type == MemoryType::Free {
|
||||||
|
out.allocationheader = core::ptr::from_raw_parts_mut(
|
||||||
|
core::ptr::without_provenance_mut::<()>(mapping.start as usize),
|
||||||
|
(),
|
||||||
|
);
|
||||||
|
out.allocations = core::ptr::from_raw_parts_mut(
|
||||||
|
core::ptr::without_provenance_mut::<()>(mapping.start as usize+size_of::<AllocationHeader>()),
|
||||||
|
(),
|
||||||
|
);
|
||||||
|
out.max_allocations_size = mapping.len;
|
||||||
|
} else if let MemoryType::HardwareSpecific(_, allocatable) = mapping.mem_type {
|
||||||
|
if allocatable {
|
||||||
|
out.allocationheader = core::ptr::from_raw_parts_mut(
|
||||||
|
core::ptr::without_provenance_mut::<()>(mapping.start as usize),
|
||||||
|
(),
|
||||||
|
);
|
||||||
|
out.allocations = core::ptr::from_raw_parts_mut(
|
||||||
|
core::ptr::without_provenance_mut::<()>(mapping.start as usize+size_of::<AllocationHeader>()),
|
||||||
|
(),
|
||||||
|
);
|
||||||
|
out.max_allocations_size = mapping.len;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if out.allocations == core::ptr::null_mut() {
|
||||||
|
return Err(crate::Error::new(
|
||||||
|
"no free memory with space for 32 allocations",
|
||||||
|
ALLOCATIONS_NOT_ENOUGH_SPACE,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
unsafe {
|
||||||
|
(*out.allocations) = Allocation {
|
||||||
|
used: false,
|
||||||
|
addr: 0,
|
||||||
|
len: 0,
|
||||||
|
};
|
||||||
|
(*out.allocationheader) = AllocationHeader {
|
||||||
|
used: true,
|
||||||
|
addr: out.allocations as usize as u64,
|
||||||
|
len: (size_of::<Allocation>() * 32) as u64,
|
||||||
|
num_allocations: 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(out)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a [AllocationIter] to iterate over the current allocations.
|
||||||
|
fn allocations_iter(&self) -> AllocationIter {
|
||||||
|
AllocationIter {
|
||||||
|
ptr: self.allocations,
|
||||||
|
num_allocations: unsafe { *self.allocationheader }.num_allocations,
|
||||||
|
idx: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Add an allocation to [MemoryMapAlloc::allocations]. It will overwrite allocations with `used` set to false.
|
||||||
|
fn add_allocation(&self, allocation: Allocation) -> Result<(), crate::Error<'static>> {
|
||||||
|
let mut created_allocation = false;
|
||||||
|
for alloc in self.allocations_iter() {
|
||||||
|
if !unsafe { *alloc }.used {
|
||||||
|
unsafe { (*alloc) = allocation }
|
||||||
|
created_allocation = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if created_allocation {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe { *self.allocationheader }.num_allocations += 1;
|
||||||
|
|
||||||
|
let num_allocations = unsafe { *self.allocationheader }.num_allocations;
|
||||||
|
|
||||||
|
if unsafe { *self.allocations }.len
|
||||||
|
< (size_of::<Allocation>() as u64 * (num_allocations))
|
||||||
|
{
|
||||||
|
if unsafe { *self.allocationheader }.len + size_of::<Allocation>() as u64 >= self.max_allocations_size {
|
||||||
|
return Err(crate::Error::new(
|
||||||
|
"not enough space for another allocation",
|
||||||
|
TOO_MANY_ALLOCATIONS,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
let res = self.extend_allocation(0, size_of::<Allocation>() as u64);
|
||||||
|
if let Err(err) = res {
|
||||||
|
unsafe { *self.allocationheader }.num_allocations -= 1;
|
||||||
|
return Err(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let new_alloc = (self.allocations as usize
|
||||||
|
+ (size_of::<Allocation>() * (num_allocations) as usize))
|
||||||
|
as *const Allocation as *mut Allocation;
|
||||||
|
|
||||||
|
unsafe { (*new_alloc) = allocation }
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Extend an allocation. This has numerous checks, so please use this
|
||||||
|
/// instead of manually changing [Allocation::len]!
|
||||||
|
#[inline(always)]
|
||||||
|
fn extend_allocation(&self, idx: u64, by: u64) -> Result<(), crate::Error<'static>> {
|
||||||
|
if idx > unsafe { *self.allocationheader }.num_allocations {
|
||||||
|
return Err(crate::Error::new(
|
||||||
|
"the index provided to extend_allocation is too large",
|
||||||
|
EXTEND_ALLOCATION_INVALID_INDEX,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
let alloc = (self.allocations as usize + (size_of::<Allocation>() * idx as usize))
|
||||||
|
as *const Allocation as *mut Allocation;
|
||||||
|
|
||||||
|
if !unsafe { *alloc }.used {
|
||||||
|
return Err(crate::Error::new(
|
||||||
|
"the allocation provided to extend_allocation is unused",
|
||||||
|
EXTEND_ALLOCATION_ALLOCATION_UNUSED,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.check_range(
|
||||||
|
(unsafe { *alloc }.addr + unsafe { *alloc }.len)
|
||||||
|
..(unsafe { *alloc }.addr + unsafe { *alloc }.len + by),
|
||||||
|
) {
|
||||||
|
return Err(crate::Error::new(
|
||||||
|
"the allocation, if extended, would extend into another allocation",
|
||||||
|
EXTEND_ALLOCATION_OTHER_ALLOCATION,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
(*alloc).len += by;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Check to see if any allocations contain the given address. Returns true if so.
|
||||||
|
fn check_addr(&self, addr: u64) -> bool {
|
||||||
|
for ele in self.allocations_iter() {
|
||||||
|
let alloc = unsafe { *ele };
|
||||||
|
if addr > alloc.addr && addr < alloc.addr + alloc.len {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Check to see if a range of addresses have any allocations within. Returns true if so.
|
||||||
|
fn check_range(&self, addr: Range<u64>) -> bool {
|
||||||
|
for addr in addr {
|
||||||
|
// REALLY inefficient, but I don't think there's a better way.
|
||||||
|
if self.check_addr(addr) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Error returned when free memory is not available.
|
||||||
|
pub const FREE_MEMORY_UNAVAILABLE: i16 = -1;
|
||||||
|
|
||||||
|
/// Error returned when memory wasn't allocated.
|
||||||
|
pub const MEMORY_NOT_ALLOCATED: i16 = -7;
|
||||||
|
|
||||||
|
unsafe impl<'a> GlobalAlloc for MemoryMapAlloc<'a> {
|
||||||
|
unsafe fn alloc(&self, layout: core::alloc::Layout) -> *mut u8 {
|
||||||
|
let result = self.allocate(layout);
|
||||||
|
if result.is_err() {
|
||||||
|
return null_mut();
|
||||||
|
}
|
||||||
|
result.unwrap().as_mut_ptr() as *mut u8
|
||||||
|
}
|
||||||
|
unsafe fn dealloc(&self, ptr: *mut u8, layout: core::alloc::Layout) {
|
||||||
|
unsafe {
|
||||||
|
self.deallocate(
|
||||||
|
NonNull::without_provenance(NonZero::new(ptr as usize).unwrap()),
|
||||||
|
layout,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The last status of memory allocation or deallocation for a [MemoryMapAlloc].
|
||||||
|
/// This can be used for more insight to why an allocation or deallocation failed.
|
||||||
|
pub static mut LAST_MEMMAP_ERR: Result<(), crate::Error<'static>> = Ok(());
|
||||||
|
|
||||||
|
unsafe impl<'a> Allocator for MemoryMapAlloc<'a> {
|
||||||
|
fn allocate(
|
||||||
|
&self,
|
||||||
|
layout: core::alloc::Layout,
|
||||||
|
) -> Result<core::ptr::NonNull<[u8]>, core::alloc::AllocError> {
|
||||||
|
unsafe { LAST_MEMMAP_ERR = Ok(()) }
|
||||||
|
if self.allocations == core::ptr::null_mut() {
|
||||||
|
unsafe {
|
||||||
|
LAST_MEMMAP_ERR = Err(crate::Error::new(
|
||||||
|
"Allocations storage not set up",
|
||||||
|
FREE_MEMORY_UNAVAILABLE,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
return Err(core::alloc::AllocError {});
|
||||||
|
}
|
||||||
|
let mut addr = 0u64;
|
||||||
|
for mapping in self.memory_map.clone() {
|
||||||
|
if mapping.len < layout.size() as u64 {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let mut allocatable = false;
|
||||||
|
if mapping.mem_type == MemoryType::Free {
|
||||||
|
allocatable = true;
|
||||||
|
} else if let MemoryType::HardwareSpecific(_, alloc) = mapping.mem_type {
|
||||||
|
allocatable = alloc;
|
||||||
|
}
|
||||||
|
if allocatable {
|
||||||
|
addr = mapping.start+mapping.len-layout.size() as u64;
|
||||||
|
while self.check_range(addr..addr+layout.size() as u64) && (addr as usize % layout.align() != 0) {
|
||||||
|
addr -= layout.size() as u64/crate::cfg_int!("CONFIG_ALLOC_PRECISION", u64);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Err(err) = self.add_allocation(Allocation { used: true, addr, len: layout.size() as u64 }) {
|
||||||
|
unsafe { LAST_MEMMAP_ERR = Err(err) }
|
||||||
|
return Err(core::alloc::AllocError {});
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(NonNull::from_raw_parts(
|
||||||
|
NonNull::<u8>::without_provenance(NonZero::new(addr as usize).unwrap()),
|
||||||
|
layout.size(),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
unsafe fn deallocate(&self, ptr: core::ptr::NonNull<u8>, _layout: core::alloc::Layout) {
|
||||||
|
unsafe { LAST_MEMMAP_ERR = Ok(()) }
|
||||||
|
let addr = ptr.addr().get() as u64;
|
||||||
|
if !self.check_addr(addr) { // Memory not allocated, something is up
|
||||||
|
unsafe { LAST_MEMMAP_ERR = Err(crate::Error::new("memory not allocated", MEMORY_NOT_ALLOCATED)) }
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if self.allocations == core::ptr::null_mut() {
|
||||||
|
unsafe {
|
||||||
|
LAST_MEMMAP_ERR = Err(crate::Error::new(
|
||||||
|
"Allocations storage not set up",
|
||||||
|
FREE_MEMORY_UNAVAILABLE,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for allocation in self.allocations_iter() {
|
||||||
|
if !unsafe { *allocation }.used {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if unsafe { *allocation }.addr == addr {
|
||||||
|
unsafe { *allocation }.used = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,6 +3,11 @@
|
||||||
#![warn(missing_docs)]
|
#![warn(missing_docs)]
|
||||||
#![feature(ptr_metadata)]
|
#![feature(ptr_metadata)]
|
||||||
#![feature(const_trait_impl)]
|
#![feature(const_trait_impl)]
|
||||||
|
#![feature(f128)]
|
||||||
|
#![feature(ptr_alignment_type)]
|
||||||
|
#![feature(allocator_api)]
|
||||||
|
#![feature(slice_ptr_get)]
|
||||||
|
#![feature(nonnull_provenance)]
|
||||||
|
|
||||||
mod constants;
|
mod constants;
|
||||||
mod util;
|
mod util;
|
||||||
|
@ -15,6 +20,13 @@ pub mod output;
|
||||||
pub mod boot;
|
pub mod boot;
|
||||||
pub mod psfont;
|
pub mod psfont;
|
||||||
pub mod display;
|
pub mod display;
|
||||||
|
pub mod cmdline;
|
||||||
|
pub mod mem;
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
mod cfg;
|
||||||
|
|
||||||
|
pub use cfg::*;
|
||||||
|
|
||||||
#[allow(unused_imports)] // if there are no constants, then it gives a warning
|
#[allow(unused_imports)] // if there are no constants, then it gives a warning
|
||||||
pub use constants::*;
|
pub use constants::*;
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
//! Definitions of structs for multiboot2 information. Mostly used during pre-userspace.
|
//! Definitions of structs for multiboot2 information. Mostly used during pre-userspace.
|
||||||
|
|
||||||
|
use crate::boot::MemoryMapping;
|
||||||
|
|
||||||
/// Used for Multiboot2 tags. This shouldn't be used after a [crate::boot::BootInfo] struct has been initalized, but it still can be used.
|
/// Used for Multiboot2 tags. This shouldn't be used after a [crate::boot::BootInfo] struct has been initalized, but it still can be used.
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
|
@ -35,7 +37,7 @@ pub struct Module {
|
||||||
|
|
||||||
/// One memory section provided by a Multiboot2 bootloader.
|
/// One memory section provided by a Multiboot2 bootloader.
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Clone)]
|
#[derive(Clone, Copy)]
|
||||||
pub struct MemorySection {
|
pub struct MemorySection {
|
||||||
/// The base address of the section.
|
/// The base address of the section.
|
||||||
pub base_addr: u64,
|
pub base_addr: u64,
|
||||||
|
@ -48,22 +50,20 @@ pub struct MemorySection {
|
||||||
reserved: u32,
|
reserved: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl crate::boot::MemoryMapping for MemorySection {
|
impl Into<crate::boot::MemoryMapping> for MemorySection {
|
||||||
fn get_type(&self) -> crate::boot::MemoryType {
|
fn into(self) -> crate::boot::MemoryMapping {
|
||||||
match self.mem_type {
|
MemoryMapping {
|
||||||
1 => crate::boot::MemoryType::Free,
|
mem_type: match self.mem_type {
|
||||||
2 => crate::boot::MemoryType::HardwareReserved,
|
1 => crate::boot::MemoryType::Free,
|
||||||
3 => crate::boot::MemoryType::HardwareSpecific(3, false),
|
2 => crate::boot::MemoryType::HardwareReserved,
|
||||||
5 => crate::boot::MemoryType::Faulty,
|
3 => crate::boot::MemoryType::HardwareSpecific(3, false),
|
||||||
_ => crate::boot::MemoryType::Reserved
|
5 => crate::boot::MemoryType::Faulty,
|
||||||
|
_ => crate::boot::MemoryType::Reserved
|
||||||
|
},
|
||||||
|
start: self.base_addr,
|
||||||
|
len: self.length
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn get_start(&self) -> u64 {
|
|
||||||
self.base_addr
|
|
||||||
}
|
|
||||||
fn get_length(&self) -> u64 {
|
|
||||||
self.length
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The raw memory map provided by a Multiboot2 bootloader. This is interpreted
|
/// The raw memory map provided by a Multiboot2 bootloader. This is interpreted
|
||||||
|
@ -87,39 +87,33 @@ pub struct RawMemoryMap {
|
||||||
pub struct MemoryMap {
|
pub struct MemoryMap {
|
||||||
/// The version of the memory map. Should be disregarded as it's 0.
|
/// The version of the memory map. Should be disregarded as it's 0.
|
||||||
pub version: u32, // currently is 0, future Multiboot2 versions may increment
|
pub version: u32, // currently is 0, future Multiboot2 versions may increment
|
||||||
/// Size of one entry(one [MemorySection] for Aphrodite)
|
/// Size of one entry(one [MemorySection] for Aphrodite's Multiboot2 support)
|
||||||
pub entry_size: u32,
|
pub entry_size: u32,
|
||||||
/// All sections.
|
/// All sections.
|
||||||
pub sections: &'static [MemorySection],
|
pub sections: &'static [crate::boot::MemoryMapping],
|
||||||
|
|
||||||
/// Iterator's index.
|
/// Iterator's index.
|
||||||
pub idx: usize,
|
pub idx: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl crate::boot::MemoryMap for MemoryMap {}
|
impl MemoryMap {
|
||||||
|
pub fn reset_iter(&mut self) {
|
||||||
impl crate::boot::_MemoryMap for MemoryMap {
|
self.idx = 0;
|
||||||
fn len(&self) -> usize {
|
|
||||||
self.sections.len()
|
|
||||||
}
|
}
|
||||||
}
|
pub fn mem_size(&mut self) -> u64 {
|
||||||
|
let curr_idx = self.idx;
|
||||||
impl core::ops::Index<usize> for MemoryMap {
|
self.reset_iter();
|
||||||
type Output = dyn crate::boot::MemoryMapping;
|
let mut out = 0u64;
|
||||||
|
for ele in self.sections {
|
||||||
fn index(&self, index: usize) -> &Self::Output {
|
if ele.mem_type == crate::boot::MemoryType::Free {
|
||||||
&self.sections[index] as &'static dyn crate::boot::MemoryMapping
|
out += ele.len;
|
||||||
}
|
} else if let crate::boot::MemoryType::HardwareSpecific(_, free) = ele.mem_type {
|
||||||
}
|
if free {
|
||||||
|
out += ele.len;
|
||||||
impl core::iter::Iterator for MemoryMap {
|
}
|
||||||
type Item = &'static dyn crate::boot::MemoryMapping;
|
}
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
|
||||||
self.idx += 1;
|
|
||||||
if self.sections.len()<=self.idx-1 {
|
|
||||||
return None;
|
|
||||||
}
|
}
|
||||||
Some(&self.sections[self.idx-1])
|
self.idx = curr_idx;
|
||||||
|
out
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
//! Utility functions
|
//! Utility functions
|
||||||
|
|
||||||
/// Converts an i16 to an [u8; 6].
|
/// Converts an i16 to an [u8; 6].
|
||||||
pub fn i16_as_u8_slice(mut value: i16) -> [u8; 6] {
|
pub const fn i16_as_u8_slice(mut value: i16) -> [u8; 6] {
|
||||||
let mut buf = [0u8; 6];
|
let mut buf = [0u8; 6];
|
||||||
let mut i = 0;
|
let mut i = 0;
|
||||||
if value < 0 {
|
if value < 0 {
|
||||||
|
@ -23,7 +23,7 @@ pub fn i16_as_u8_slice(mut value: i16) -> [u8; 6] {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Converts an u32 to an [u8; 10].
|
/// Converts an u32 to an [u8; 10].
|
||||||
pub fn u32_as_u8_slice(mut value: u32) -> [u8; 10] {
|
pub const fn u32_as_u8_slice(mut value: u32) -> [u8; 10] {
|
||||||
let mut buf = [0u8; 10];
|
let mut buf = [0u8; 10];
|
||||||
let mut i = 9;
|
let mut i = 9;
|
||||||
if value == 0 {
|
if value == 0 {
|
||||||
|
@ -40,7 +40,7 @@ pub fn u32_as_u8_slice(mut value: u32) -> [u8; 10] {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Converts an u8 to an [u8; 3].
|
/// Converts an u8 to an [u8; 3].
|
||||||
pub fn u8_as_u8_slice(mut value: u8) -> [u8; 3] {
|
pub const fn u8_as_u8_slice(mut value: u8) -> [u8; 3] {
|
||||||
let mut buf = [0u8; 3];
|
let mut buf = [0u8; 3];
|
||||||
let mut i = 2;
|
let mut i = 2;
|
||||||
if value == 0 {
|
if value == 0 {
|
||||||
|
@ -57,7 +57,7 @@ pub fn u8_as_u8_slice(mut value: u8) -> [u8; 3] {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Converts an usize(32 or 64 bit) to an [u8; 10].
|
/// Converts an usize(32 or 64 bit) to an [u8; 10].
|
||||||
pub fn usize_as_u8_slice(mut value: usize) -> [u8; 20] {
|
pub const fn usize_as_u8_slice(mut value: usize) -> [u8; 20] {
|
||||||
let mut buf = [0u8; 20];
|
let mut buf = [0u8; 20];
|
||||||
let mut i = 19;
|
let mut i = 19;
|
||||||
if value == 0 {
|
if value == 0 {
|
||||||
|
@ -74,7 +74,7 @@ pub fn usize_as_u8_slice(mut value: usize) -> [u8; 20] {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Converts an u64 to an [u8; 10].
|
/// Converts an u64 to an [u8; 10].
|
||||||
pub fn u64_as_u8_slice(mut value: u64) -> [u8; 20] {
|
pub const fn u64_as_u8_slice(mut value: u64) -> [u8; 20] {
|
||||||
let mut buf = [0u8; 20];
|
let mut buf = [0u8; 20];
|
||||||
let mut i = 19;
|
let mut i = 19;
|
||||||
if value == 0 {
|
if value == 0 {
|
||||||
|
@ -89,3 +89,77 @@ pub fn u64_as_u8_slice(mut value: u64) -> [u8; 20] {
|
||||||
}
|
}
|
||||||
buf
|
buf
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Converts an &mut \[u8] to a i16. `value` is clobbered.
|
||||||
|
pub fn str_as_i16(mut value: &mut [u8]) -> i16 {
|
||||||
|
let mut out = 0i16;
|
||||||
|
let negative = core::str::from_utf8(value).unwrap().starts_with("-");
|
||||||
|
if negative {
|
||||||
|
value = &mut value[1..];
|
||||||
|
}
|
||||||
|
value.reverse();
|
||||||
|
for byte in value {
|
||||||
|
let byte = *byte;
|
||||||
|
if byte == b'_' {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
out *= 10;
|
||||||
|
out += (byte-b'0') as i16;
|
||||||
|
}
|
||||||
|
if negative {
|
||||||
|
out = -out;
|
||||||
|
}
|
||||||
|
out
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Converts an &mut \[u8] to a u32. `value` is clobbered.
|
||||||
|
pub fn str_as_u32(value: &mut [u8]) -> u32 {
|
||||||
|
let mut out = 0u32;
|
||||||
|
value.reverse();
|
||||||
|
for byte in value {
|
||||||
|
let byte = *byte;
|
||||||
|
if byte == b'_' {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
out *= 10;
|
||||||
|
out += (byte-b'0') as u32;
|
||||||
|
}
|
||||||
|
out
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Converts an &mut \[u8] to a u128. `value` is clobbered.
|
||||||
|
pub fn str_as_u128(value: &mut [u8]) -> u128 {
|
||||||
|
let mut out = 0u128;
|
||||||
|
value.reverse();
|
||||||
|
for byte in value {
|
||||||
|
let byte = *byte;
|
||||||
|
if byte == b'_' {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
out *= 10;
|
||||||
|
out += (byte-b'0') as u128;
|
||||||
|
}
|
||||||
|
out
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Converts an &mut \[u8] to a u64.
|
||||||
|
pub fn str_as_u64(value: &[u8]) -> u64 {
|
||||||
|
let mut out = 0u64;
|
||||||
|
for byte in value {
|
||||||
|
let byte = *byte;
|
||||||
|
if byte < b'0' || byte > b'9' {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
out *= 10;
|
||||||
|
out += (byte-b'0') as u64;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut reversed = 0;
|
||||||
|
|
||||||
|
while out != 0 {
|
||||||
|
reversed = reversed * 10 + out % 10;
|
||||||
|
out /= 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
reversed
|
||||||
|
}
|
|
@ -1,4 +1,5 @@
|
||||||
//! The entrypoint to the kernel; placed before all other code.
|
//! The entrypoint to the kernel; placed before all other code.
|
||||||
|
#![cfg(any(target_arch = "x86"))]
|
||||||
#![no_std]
|
#![no_std]
|
||||||
#![no_main]
|
#![no_main]
|
||||||
#![warn(missing_docs)]
|
#![warn(missing_docs)]
|
||||||
|
@ -13,6 +14,7 @@ use aphrodite::multiboot2::{FramebufferInfo, MemoryMap, MemorySection, RawMemory
|
||||||
use aphrodite::arch::output::*;
|
use aphrodite::arch::output::*;
|
||||||
use aphrodite::arch::egatext as egatext;
|
use aphrodite::arch::egatext as egatext;
|
||||||
use aphrodite::output::*;
|
use aphrodite::output::*;
|
||||||
|
use aphrodite::display::COLOR_DEFAULT;
|
||||||
|
|
||||||
#[cfg(not(CONFIG_DISABLE_MULTIBOOT2_SUPPORT))]
|
#[cfg(not(CONFIG_DISABLE_MULTIBOOT2_SUPPORT))]
|
||||||
#[unsafe(link_section = ".multiboot2")]
|
#[unsafe(link_section = ".multiboot2")]
|
||||||
|
@ -152,7 +154,14 @@ extern "C" fn _start() -> ! {
|
||||||
sections: &*core::ptr::from_raw_parts((&(*rawmemorymap).sections[0]) as &MemorySection, (*rawmemorymap).sections.len()),
|
sections: &*core::ptr::from_raw_parts((&(*rawmemorymap).sections[0]) as &MemorySection, (*rawmemorymap).sections.len()),
|
||||||
idx: 0
|
idx: 0
|
||||||
};
|
};
|
||||||
BI.memory_map = Some(&MM);
|
let mm2 = aphrodite::boot::MemoryMap {
|
||||||
|
len: MM.sections.len() as u64,
|
||||||
|
size_pages: 1,
|
||||||
|
page_size: MM.mem_size(),
|
||||||
|
sections: MM.sections,
|
||||||
|
idx: 0
|
||||||
|
};
|
||||||
|
BI.memory_map = Some(mm2);
|
||||||
},
|
},
|
||||||
2 => { // Bootloader name
|
2 => { // Bootloader name
|
||||||
if current_tag.tag_len < 8 { // Unexpected size, something is probably up
|
if current_tag.tag_len < 8 { // Unexpected size, something is probably up
|
||||||
|
@ -248,9 +257,9 @@ extern "C" fn _start() -> ! {
|
||||||
|
|
||||||
sdebugsln("Beginning output to screen...");
|
sdebugsln("Beginning output to screen...");
|
||||||
|
|
||||||
let ega: &dyn aphrodite::TextDisplay = &framebuffer_info;
|
let ega: &dyn aphrodite::display::TextDisplay = &framebuffer_info;
|
||||||
framebuffer_info.disable_cursor();
|
framebuffer_info.disable_cursor();
|
||||||
ega.clear_screen(aphrodite::COLOR_DEFAULT);
|
ega.clear_screen(COLOR_DEFAULT);
|
||||||
toutputsln("Testing EGA Text framebuffer...", ega).unwrap();
|
toutputsln("Testing EGA Text framebuffer...", ega).unwrap();
|
||||||
toutputsln("Testing EGA Text framebuffer...", ega).unwrap();
|
toutputsln("Testing EGA Text framebuffer...", ega).unwrap();
|
||||||
toutputsln("Testing EGA Text framebuffer...", ega).unwrap();
|
toutputsln("Testing EGA Text framebuffer...", ega).unwrap();
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
# Targets used for documentation.
|
# Targets used for documentation.
|
||||||
x86=$KERNEL_DIR/i686-unknown-none.json
|
x86=$KERNEL_DIR/i686-unknown-none.json
|
||||||
|
|
||||||
TARGETS=$x86
|
TARGETS=x86
|
3
kernel/validate-cfg
Normal file
3
kernel/validate-cfg
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
set -e
|
Loading…
Add table
Reference in a new issue