feat: userspace program loading and task spawning
This commit is contained in:
Generated
+7
@@ -20,6 +20,13 @@ dependencies = [
|
|||||||
name = "dusk-sys"
|
name = "dusk-sys"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "echo"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"dusk-sys",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "limine"
|
name = "limine"
|
||||||
version = "0.6.5"
|
version = "0.6.5"
|
||||||
|
|||||||
@@ -69,10 +69,12 @@ prepare-bin-files:
|
|||||||
compile-user:
|
compile-user:
|
||||||
RUSTFLAGS="-C relocation-model=static" cargo build --package omega3 ${USERSPACE_CARGO_OPTS}
|
RUSTFLAGS="-C relocation-model=static" cargo build --package omega3 ${USERSPACE_CARGO_OPTS}
|
||||||
RUSTFLAGS="-C relocation-model=static" cargo build --package client ${USERSPACE_CARGO_OPTS}
|
RUSTFLAGS="-C relocation-model=static" cargo build --package client ${USERSPACE_CARGO_OPTS}
|
||||||
|
RUSTFLAGS="-C relocation-model=static" cargo build --package echo ${USERSPACE_CARGO_OPTS}
|
||||||
|
|
||||||
copy-initramfs-files: compile-user
|
copy-initramfs-files: compile-user
|
||||||
cp -v target/${ARCH}-unknown-none/${MODE}/omega3 ${INITRAMFS_PATH}/omega3.elf
|
cp -v target/${ARCH}-unknown-none/${MODE}/omega3 ${INITRAMFS_PATH}/omega3.elf
|
||||||
cp -v target/${ARCH}-unknown-none/${MODE}/client ${INITRAMFS_PATH}/client.elf
|
cp -v target/${ARCH}-unknown-none/${MODE}/client ${INITRAMFS_PATH}/client.elf
|
||||||
|
cp -v target/${ARCH}-unknown-none/${MODE}/echo ${INITRAMFS_PATH}/echo.elf
|
||||||
|
|
||||||
compile-initramfs: copy-initramfs-files
|
compile-initramfs: copy-initramfs-files
|
||||||
(cd ${INITRAMFS_PATH} && find . -mindepth 1 | cpio -o -H newc) > ${ARTIFACTS_PATH}/initramfs.img
|
(cd ${INITRAMFS_PATH} && find . -mindepth 1 | cpio -o -H newc) > ${ARTIFACTS_PATH}/initramfs.img
|
||||||
|
|||||||
@@ -36,7 +36,6 @@ const APIC_TIMER_INITIAL_COUNT: u32 = 0x380;
|
|||||||
const APIC_TIMER_CURRENT_COUNT: u32 = 0x390;
|
const APIC_TIMER_CURRENT_COUNT: u32 = 0x390;
|
||||||
const APIC_TIMER_DIVIDE_CONFIG: u32 = 0x3E0;
|
const APIC_TIMER_DIVIDE_CONFIG: u32 = 0x3E0;
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
enum LocalApicAccess {
|
enum LocalApicAccess {
|
||||||
X2Apic,
|
X2Apic,
|
||||||
XApic,
|
XApic,
|
||||||
@@ -88,7 +87,6 @@ pub enum LocalApicError {
|
|||||||
NotBootSystemProcessor,
|
NotBootSystemProcessor,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct LocalApic {
|
pub struct LocalApic {
|
||||||
id: u32,
|
id: u32,
|
||||||
access: LocalApicAccess,
|
access: LocalApicAccess,
|
||||||
|
|||||||
@@ -103,7 +103,7 @@ pub enum CpuFeaturesError {
|
|||||||
InvalidVirtualAddressWidth,
|
InvalidVirtualAddressWidth,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy)]
|
||||||
pub(crate) struct CpuFeatures {
|
pub(crate) struct CpuFeatures {
|
||||||
pub nx_supported: bool,
|
pub nx_supported: bool,
|
||||||
pub nx_enabled: bool,
|
pub nx_enabled: bool,
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ struct IdtPointer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy)]
|
||||||
pub(super) struct InterruptStackFrame {
|
pub(super) struct InterruptStackFrame {
|
||||||
pub instruction_pointer: VirtualAddr,
|
pub instruction_pointer: VirtualAddr,
|
||||||
pub code_segment: u64,
|
pub code_segment: u64,
|
||||||
|
|||||||
@@ -31,7 +31,6 @@ pub struct RedirectionConfig {
|
|||||||
pub trigger: TriggerMode,
|
pub trigger: TriggerMode,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct IoApic {
|
pub struct IoApic {
|
||||||
base: VirtualAddr,
|
base: VirtualAddr,
|
||||||
global_interrupt_base: u32,
|
global_interrupt_base: u32,
|
||||||
|
|||||||
@@ -64,7 +64,6 @@ pub enum InterruptInitError {
|
|||||||
PitNotHandled,
|
PitNotHandled,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct InterruptController {
|
pub struct InterruptController {
|
||||||
local_apic: apic::LocalApic,
|
local_apic: apic::LocalApic,
|
||||||
io_apic: io_apic::IoApic,
|
io_apic: io_apic::IoApic,
|
||||||
@@ -164,8 +163,6 @@ pub unsafe fn enter_user(
|
|||||||
user_instruction_pointer: VirtualAddr,
|
user_instruction_pointer: VirtualAddr,
|
||||||
user_stack_pointer: VirtualAddr,
|
user_stack_pointer: VirtualAddr,
|
||||||
) -> ! {
|
) -> ! {
|
||||||
println!("Entering user mode");
|
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
asm!(
|
asm!(
|
||||||
"mov ds, {user_data_selector:x}",
|
"mov ds, {user_data_selector:x}",
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ use crate::{
|
|||||||
pub const PAGE_SIZE: usize = 4096;
|
pub const PAGE_SIZE: usize = 4096;
|
||||||
pub const PAGE_TABLE_ENTRIES: usize = 512;
|
pub const PAGE_TABLE_ENTRIES: usize = 512;
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy)]
|
||||||
pub struct PagingConfig {
|
pub struct PagingConfig {
|
||||||
physical_address_bits: u8,
|
physical_address_bits: u8,
|
||||||
global_pages: bool,
|
global_pages: bool,
|
||||||
@@ -42,7 +42,7 @@ impl PagingConfig {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy)]
|
||||||
enum PagingMode {
|
enum PagingMode {
|
||||||
FourLevel,
|
FourLevel,
|
||||||
FiveLevel,
|
FiveLevel,
|
||||||
@@ -77,7 +77,7 @@ impl PagingMode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||||
enum PageTableLevel {
|
enum PageTableLevel {
|
||||||
Pml5,
|
Pml5,
|
||||||
Pml4,
|
Pml4,
|
||||||
@@ -106,14 +106,13 @@ impl PageTableLevel {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
enum PageTableEntryError {
|
enum PageTableEntryError {
|
||||||
PhysicalAddressTooLarge,
|
PhysicalAddressTooLarge,
|
||||||
NoExecuteUnsupported,
|
NoExecuteUnsupported,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[repr(transparent)]
|
#[repr(transparent)]
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||||
struct PageTableEntry(u64);
|
struct PageTableEntry(u64);
|
||||||
|
|
||||||
impl PageTableEntry {
|
impl PageTableEntry {
|
||||||
@@ -229,7 +228,6 @@ impl PageTableEntry {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub(crate) enum MapError {
|
pub(crate) enum MapError {
|
||||||
InvalidVirtualAddress,
|
InvalidVirtualAddress,
|
||||||
VirtualAddressUnaligned,
|
VirtualAddressUnaligned,
|
||||||
@@ -264,7 +262,6 @@ pub(crate) enum PageTableCreateError {
|
|||||||
OutOfFrames,
|
OutOfFrames,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct PageTable {
|
pub struct PageTable {
|
||||||
pub direct_map: DirectMap,
|
pub direct_map: DirectMap,
|
||||||
config: PagingConfig,
|
config: PagingConfig,
|
||||||
|
|||||||
@@ -15,7 +15,6 @@ const IA32_KERNEL_GS_BASE: u32 = 0xC000_0102;
|
|||||||
const RFLAGS_MASK: u64 = 0x257FD5; // Clear IF, TF, DF, IOPL, NT, AC
|
const RFLAGS_MASK: u64 = 0x257FD5; // Clear IF, TF, DF, IOPL, NT, AC
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Debug)]
|
|
||||||
struct SyscallFrame {
|
struct SyscallFrame {
|
||||||
pub r15: u64,
|
pub r15: u64,
|
||||||
pub r14: u64,
|
pub r14: u64,
|
||||||
|
|||||||
+82
-400
@@ -1,423 +1,105 @@
|
|||||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
pub struct ElfError;
|
||||||
pub enum ElfIsa {
|
|
||||||
None,
|
|
||||||
Sparc,
|
|
||||||
X86,
|
|
||||||
Mips,
|
|
||||||
Ppc,
|
|
||||||
Arm,
|
|
||||||
SuperH,
|
|
||||||
Ia64,
|
|
||||||
Amd64,
|
|
||||||
AArch64,
|
|
||||||
Riscv,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ElfIsa {
|
#[cfg(target_arch = "x86_64")]
|
||||||
fn from_u16(value: u16) -> Result<Self, ElfError> {
|
const MACHINE: u16 = 62;
|
||||||
match value {
|
#[cfg(target_arch = "aarch64")]
|
||||||
0x00 => Ok(Self::None),
|
const MACHINE: u16 = 183;
|
||||||
0x02 => Ok(Self::Sparc),
|
#[cfg(target_arch = "riscv64")]
|
||||||
0x03 => Ok(Self::X86),
|
const MACHINE: u16 = 243;
|
||||||
0x08 => Ok(Self::Mips),
|
|
||||||
0x14 => Ok(Self::Ppc),
|
|
||||||
0x28 => Ok(Self::Arm),
|
|
||||||
0x2A => Ok(Self::SuperH),
|
|
||||||
0x32 => Ok(Self::Ia64),
|
|
||||||
0x3E => Ok(Self::Amd64),
|
|
||||||
0xB7 => Ok(Self::AArch64),
|
|
||||||
0xF3 => Ok(Self::Riscv),
|
|
||||||
_ => Err(ElfError::InvalidElf),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
|
||||||
pub enum ElfClass {
|
|
||||||
Elf32,
|
|
||||||
Elf64,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ElfClass {
|
|
||||||
fn from_u8(value: u8) -> Result<Self, ElfError> {
|
|
||||||
match value {
|
|
||||||
1 => Ok(Self::Elf32),
|
|
||||||
2 => Ok(Self::Elf64),
|
|
||||||
_ => Err(ElfError::InvalidElf),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const fn header_size(self) -> u16 {
|
|
||||||
match self {
|
|
||||||
Self::Elf32 => 52,
|
|
||||||
Self::Elf64 => 64,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
|
||||||
pub enum Endianness {
|
|
||||||
Little,
|
|
||||||
Big,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Endianness {
|
|
||||||
fn from_u8(value: u8) -> Result<Self, ElfError> {
|
|
||||||
match value {
|
|
||||||
1 => Ok(Self::Little),
|
|
||||||
2 => Ok(Self::Big),
|
|
||||||
_ => Err(ElfError::InvalidElf),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[repr(u16)]
|
|
||||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
|
||||||
pub enum ElfType {
|
|
||||||
Relocatable = 1,
|
|
||||||
Executable = 2,
|
|
||||||
SharedObject = 3,
|
|
||||||
Core = 4,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ElfType {
|
|
||||||
fn from_u16(value: u16) -> Result<Self, ElfError> {
|
|
||||||
match value {
|
|
||||||
1 => Ok(Self::Relocatable),
|
|
||||||
2 => Ok(Self::Executable),
|
|
||||||
3 => Ok(Self::SharedObject),
|
|
||||||
4 => Ok(Self::Core),
|
|
||||||
_ => Err(ElfError::InvalidElf),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
#[allow(unused)]
|
|
||||||
pub struct ElfHeader {
|
|
||||||
magic: [u8; 4],
|
|
||||||
pub class: ElfClass,
|
|
||||||
endianness: Endianness,
|
|
||||||
version: u8,
|
|
||||||
os_abi: u8,
|
|
||||||
_reserved: [u8; 8],
|
|
||||||
pub object_type: ElfType,
|
|
||||||
pub machine: ElfIsa,
|
|
||||||
version_1: u32,
|
|
||||||
entry: u64, // 2115136
|
|
||||||
program_header_offset: u64, // 64
|
|
||||||
section_header_offset: u64, // 2759752
|
|
||||||
flags: u32, // 0
|
|
||||||
header_size: u16, // 64
|
|
||||||
program_header_entry_size: u16, // 56
|
|
||||||
program_header_count: u16, // 6
|
|
||||||
section_header_entry_size: u16, // 64
|
|
||||||
section_header_count: u16, // 17
|
|
||||||
section_name_index: u16, // 15
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub enum ElfError {
|
|
||||||
InvalidElf,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ElfHeader {
|
|
||||||
pub fn parse(bytes: &[u8]) -> Result<Self, ElfError> {
|
|
||||||
let mut reader = Reader::new(bytes);
|
|
||||||
|
|
||||||
let magic = reader.read_array()?;
|
|
||||||
if magic != *b"\x7fELF" {
|
|
||||||
return Err(ElfError::InvalidElf);
|
|
||||||
}
|
|
||||||
|
|
||||||
let class = ElfClass::from_u8(reader.read_u8()?)?;
|
|
||||||
let endianness = Endianness::from_u8(reader.read_u8()?)?;
|
|
||||||
reader.set_endianness(endianness);
|
|
||||||
|
|
||||||
let version = reader.read_u8()?;
|
|
||||||
let os_abi = reader.read_u8()?;
|
|
||||||
let reserved = reader.read_array()?;
|
|
||||||
let object_type = ElfType::from_u16(reader.read_u16()?)?;
|
|
||||||
let machine = ElfIsa::from_u16(reader.read_u16()?)?;
|
|
||||||
let version_1 = reader.read_u32()?;
|
|
||||||
let entry = reader.read_word(class)?;
|
|
||||||
let program_header_offset = reader.read_word(class)?;
|
|
||||||
let section_header_offset = reader.read_word(class)?;
|
|
||||||
let flags = reader.read_u32()?;
|
|
||||||
let header_size = reader.read_u16()?;
|
|
||||||
let program_header_entry_size = reader.read_u16()?;
|
|
||||||
let program_header_count = reader.read_u16()?;
|
|
||||||
let section_header_entry_size = reader.read_u16()?;
|
|
||||||
let section_header_count = reader.read_u16()?;
|
|
||||||
let section_name_index = reader.read_u16()?;
|
|
||||||
|
|
||||||
if header_size != class.header_size() {
|
|
||||||
return Err(ElfError::InvalidElf);
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(Self {
|
|
||||||
magic,
|
|
||||||
class,
|
|
||||||
endianness,
|
|
||||||
version,
|
|
||||||
os_abi,
|
|
||||||
_reserved: reserved,
|
|
||||||
object_type,
|
|
||||||
machine,
|
|
||||||
version_1,
|
|
||||||
entry,
|
|
||||||
program_header_offset,
|
|
||||||
section_header_offset,
|
|
||||||
flags,
|
|
||||||
header_size,
|
|
||||||
program_header_entry_size,
|
|
||||||
program_header_count,
|
|
||||||
section_header_entry_size,
|
|
||||||
section_header_count,
|
|
||||||
section_name_index,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[repr(u32)]
|
|
||||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
|
||||||
pub enum ProgramHeaderType {
|
|
||||||
Null = 0,
|
|
||||||
Load = 1,
|
|
||||||
Dynamic = 2,
|
|
||||||
Interpreter = 3,
|
|
||||||
Note = 4,
|
|
||||||
Shlib = 5,
|
|
||||||
Phdr = 6,
|
|
||||||
GnuStack = 0x6474e551,
|
|
||||||
Relro = 0x6474e552,
|
|
||||||
Other(u32),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ProgramHeaderType {
|
|
||||||
fn from_u32(value: u32) -> Self {
|
|
||||||
match value {
|
|
||||||
0 => Self::Null,
|
|
||||||
1 => Self::Load,
|
|
||||||
2 => Self::Dynamic,
|
|
||||||
3 => Self::Interpreter,
|
|
||||||
4 => Self::Note,
|
|
||||||
5 => Self::Shlib,
|
|
||||||
6 => Self::Phdr,
|
|
||||||
0x6474e551 => Self::GnuStack,
|
|
||||||
0x6474e552 => Self::Relro,
|
|
||||||
_ => Self::Other(value),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct ProgramHeader {
|
|
||||||
pub segment_type: ProgramHeaderType,
|
|
||||||
pub flags: u32,
|
|
||||||
pub file_offset: u64,
|
|
||||||
pub virtual_address: u64,
|
|
||||||
_physical_address: u64,
|
|
||||||
pub file_size: u64,
|
|
||||||
pub memory_size: u64,
|
|
||||||
pub alignment: u64,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ProgramHeader {
|
|
||||||
pub fn parse(bytes: &[u8], class: ElfClass, endianness: Endianness) -> Result<Self, ElfError> {
|
|
||||||
let mut reader = Reader::new(bytes);
|
|
||||||
reader.set_endianness(endianness);
|
|
||||||
|
|
||||||
let segment_type = ProgramHeaderType::from_u32(reader.read_u32()?);
|
|
||||||
|
|
||||||
let flags = if class == ElfClass::Elf64 {
|
|
||||||
reader.read_u32()?
|
|
||||||
} else {
|
|
||||||
0
|
|
||||||
};
|
|
||||||
|
|
||||||
let file_offset = reader.read_word(class)?;
|
|
||||||
let virtual_address = reader.read_word(class)?;
|
|
||||||
let physical_address = reader.read_word(class)?;
|
|
||||||
let file_size = reader.read_word(class)?;
|
|
||||||
let memory_size = reader.read_word(class)?;
|
|
||||||
|
|
||||||
let flags = if class == ElfClass::Elf32 {
|
|
||||||
reader.read_u32()?
|
|
||||||
} else {
|
|
||||||
flags
|
|
||||||
};
|
|
||||||
|
|
||||||
let alignment = reader.read_word(class)?;
|
|
||||||
|
|
||||||
Ok(Self {
|
|
||||||
segment_type,
|
|
||||||
flags,
|
|
||||||
file_offset,
|
|
||||||
virtual_address,
|
|
||||||
_physical_address: physical_address,
|
|
||||||
file_size,
|
|
||||||
memory_size,
|
|
||||||
alignment,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Elf<'a> {
|
pub struct Elf<'a> {
|
||||||
bytes: &'a [u8],
|
bytes: &'a [u8],
|
||||||
header: ElfHeader,
|
headers: &'a [u8],
|
||||||
|
pub entry: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Segment<'a> {
|
||||||
|
pub data: &'a [u8],
|
||||||
|
pub address: usize,
|
||||||
|
pub memory_size: usize,
|
||||||
|
pub writable: bool,
|
||||||
|
pub executable: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Elf<'a> {
|
impl<'a> Elf<'a> {
|
||||||
pub fn parse(bytes: &'a [u8]) -> Result<Self, ElfError> {
|
pub fn parse(bytes: &'a [u8]) -> Result<Self, ElfError> {
|
||||||
let header = ElfHeader::parse(bytes)?;
|
let header = bytes.get(..64).ok_or(ElfError)?;
|
||||||
|
// Bootstrap images are static ELF64 executables in the native ISA, always LE.
|
||||||
Ok(Self { bytes, header })
|
if &header[..7] != b"\x7fELF\x02\x01\x01"
|
||||||
}
|
|| u16_at(header, 16) != 2
|
||||||
|
|| u16_at(header, 18) != MACHINE
|
||||||
pub fn program_headers(&self) -> Result<ProgramHeaders<'_>, ElfError> {
|
|| u32_at(header, 20) != 1
|
||||||
let offset =
|
|| u16_at(header, 52) != 64
|
||||||
usize::try_from(self.header.program_header_offset).map_err(|_| ElfError::InvalidElf)?;
|
|| u16_at(header, 54) != 56
|
||||||
let entry_size = usize::from(self.header.program_header_entry_size);
|
{
|
||||||
let count = usize::from(self.header.program_header_count);
|
return Err(ElfError);
|
||||||
|
|
||||||
let expected_entry_size = match self.header.class {
|
|
||||||
ElfClass::Elf32 => 32,
|
|
||||||
ElfClass::Elf64 => 56,
|
|
||||||
};
|
|
||||||
|
|
||||||
if entry_size != expected_entry_size {
|
|
||||||
return Err(ElfError::InvalidElf);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let table_size = entry_size.checked_mul(count).ok_or(ElfError::InvalidElf)?;
|
let offset = usize_at(header, 32);
|
||||||
let table_end = offset.checked_add(table_size).ok_or(ElfError::InvalidElf)?;
|
let count = usize::from(u16_at(header, 56));
|
||||||
let bytes = self
|
let end = offset.checked_add(count * 56).ok_or(ElfError)?;
|
||||||
.bytes
|
let headers = bytes.get(offset..end).ok_or(ElfError)?;
|
||||||
.get(offset..table_end)
|
if headers
|
||||||
.ok_or(ElfError::InvalidElf)?;
|
.chunks_exact(56)
|
||||||
|
.any(|h| matches!(u32_at(h, 0), 2 | 3))
|
||||||
|
{
|
||||||
|
// There is no dynamic linker or relocation processing during bootstrap.
|
||||||
|
return Err(ElfError);
|
||||||
|
}
|
||||||
|
|
||||||
Ok(ProgramHeaders {
|
Ok(Self {
|
||||||
bytes,
|
bytes,
|
||||||
class: self.header.class,
|
headers,
|
||||||
endianness: self.header.endianness,
|
entry: usize_at(header, 24),
|
||||||
entry_size,
|
|
||||||
remaining: count,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn bytes(&self) -> &[u8] {
|
pub fn segments(&self) -> impl Iterator<Item = Result<Segment<'a>, ElfError>> + '_ {
|
||||||
self.bytes
|
self.headers
|
||||||
}
|
.chunks_exact(56)
|
||||||
|
.filter(|h| u32_at(h, 0) == 1)
|
||||||
pub fn machine(&self) -> ElfIsa {
|
.map(|h| {
|
||||||
self.header.machine
|
let offset = usize_at(h, 8);
|
||||||
}
|
let address = usize_at(h, 16);
|
||||||
|
let file_size = usize_at(h, 32);
|
||||||
pub fn entry(&self) -> usize {
|
let memory_size = usize_at(h, 40);
|
||||||
self.header.entry as usize
|
let alignment = usize_at(h, 48);
|
||||||
|
if file_size > memory_size
|
||||||
|
|| (alignment > 1
|
||||||
|
&& (!alignment.is_power_of_two()
|
||||||
|
|| address % alignment != offset % alignment))
|
||||||
|
{
|
||||||
|
return Err(ElfError);
|
||||||
|
}
|
||||||
|
let end = offset.checked_add(file_size).ok_or(ElfError)?;
|
||||||
|
let data = self.bytes.get(offset..end).ok_or(ElfError)?;
|
||||||
|
let flags = u32_at(h, 4);
|
||||||
|
Ok(Segment {
|
||||||
|
data,
|
||||||
|
address,
|
||||||
|
memory_size,
|
||||||
|
writable: flags & 2 != 0,
|
||||||
|
executable: flags & 1 != 0,
|
||||||
|
})
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ProgramHeaders<'a> {
|
// Callers only read fixed offsets within already bounds-checked headers.
|
||||||
bytes: &'a [u8],
|
fn u16_at(bytes: &[u8], offset: usize) -> u16 {
|
||||||
class: ElfClass,
|
let mut value = [0; 2];
|
||||||
endianness: Endianness,
|
value.copy_from_slice(&bytes[offset..offset + 2]);
|
||||||
entry_size: usize,
|
u16::from_le_bytes(value)
|
||||||
remaining: usize,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Iterator for ProgramHeaders<'a> {
|
fn u32_at(bytes: &[u8], offset: usize) -> u32 {
|
||||||
type Item = Result<ProgramHeader, ElfError>;
|
let mut value = [0; 4];
|
||||||
|
value.copy_from_slice(&bytes[offset..offset + 4]);
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
u32::from_le_bytes(value)
|
||||||
if self.remaining == 0 {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
let entry = match self.bytes.get(..self.entry_size) {
|
|
||||||
Some(entry) => entry,
|
|
||||||
None => {
|
|
||||||
self.remaining = 0;
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
self.bytes = &self.bytes[self.entry_size..];
|
|
||||||
self.remaining -= 1;
|
|
||||||
|
|
||||||
Some(ProgramHeader::parse(entry, self.class, self.endianness))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
|
||||||
(self.remaining, Some(self.remaining))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ExactSizeIterator for ProgramHeaders<'_> {}
|
fn usize_at(bytes: &[u8], offset: usize) -> usize {
|
||||||
|
let mut value = [0; 8];
|
||||||
struct Reader<'a> {
|
value.copy_from_slice(&bytes[offset..offset + 8]);
|
||||||
bytes: &'a [u8],
|
u64::from_le_bytes(value) as usize
|
||||||
offset: usize,
|
|
||||||
endianness: Endianness,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Reader<'a> {
|
|
||||||
const fn new(bytes: &'a [u8]) -> Self {
|
|
||||||
Self {
|
|
||||||
bytes,
|
|
||||||
offset: 0,
|
|
||||||
endianness: Endianness::Little,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_endianness(&mut self, endianness: Endianness) {
|
|
||||||
self.endianness = endianness;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn read_array<const N: usize>(&mut self) -> Result<[u8; N], ElfError> {
|
|
||||||
let end = self.offset.checked_add(N).ok_or(ElfError::InvalidElf)?;
|
|
||||||
let bytes = self
|
|
||||||
.bytes
|
|
||||||
.get(self.offset..end)
|
|
||||||
.ok_or(ElfError::InvalidElf)?;
|
|
||||||
self.offset = end;
|
|
||||||
|
|
||||||
bytes.try_into().map_err(|_| ElfError::InvalidElf)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn read_u8(&mut self) -> Result<u8, ElfError> {
|
|
||||||
Ok(self.read_array::<1>()?[0])
|
|
||||||
}
|
|
||||||
|
|
||||||
fn read_u16(&mut self) -> Result<u16, ElfError> {
|
|
||||||
let bytes = self.read_array()?;
|
|
||||||
Ok(match self.endianness {
|
|
||||||
Endianness::Little => u16::from_le_bytes(bytes),
|
|
||||||
Endianness::Big => u16::from_be_bytes(bytes),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn read_u32(&mut self) -> Result<u32, ElfError> {
|
|
||||||
let bytes = self.read_array()?;
|
|
||||||
Ok(match self.endianness {
|
|
||||||
Endianness::Little => u32::from_le_bytes(bytes),
|
|
||||||
Endianness::Big => u32::from_be_bytes(bytes),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn read_u64(&mut self) -> Result<u64, ElfError> {
|
|
||||||
let bytes = self.read_array()?;
|
|
||||||
Ok(match self.endianness {
|
|
||||||
Endianness::Little => u64::from_le_bytes(bytes),
|
|
||||||
Endianness::Big => u64::from_be_bytes(bytes),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn read_word(&mut self, class: ElfClass) -> Result<u64, ElfError> {
|
|
||||||
match class {
|
|
||||||
ElfClass::Elf32 => Ok(u64::from(self.read_u32()?)),
|
|
||||||
ElfClass::Elf64 => self.read_u64(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
+9
-28
@@ -14,7 +14,7 @@ mod task;
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
debug::serial,
|
debug::serial,
|
||||||
memory::{AddressSpace, KernelStackPool, MemoryRegionKind},
|
memory::{AddressSpace, MemoryRegionKind, init_frame_allocator, init_kernel_address_space},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct KernelHandoff {
|
pub struct KernelHandoff {
|
||||||
@@ -22,7 +22,6 @@ pub struct KernelHandoff {
|
|||||||
address_space: AddressSpace,
|
address_space: AddressSpace,
|
||||||
direct_map: memory::DirectMap,
|
direct_map: memory::DirectMap,
|
||||||
boot_info: boot::BootInfo,
|
boot_info: boot::BootInfo,
|
||||||
kernel_stack_pool: KernelStackPool,
|
|
||||||
handoff_frame: memory::OwnedFrame,
|
handoff_frame: memory::OwnedFrame,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -51,11 +50,9 @@ pub extern "C" fn _start() -> ! {
|
|||||||
|
|
||||||
println!("Entering kernel main...");
|
println!("Entering kernel main...");
|
||||||
|
|
||||||
let mut kernel_stack_pool = KernelStackPool::new();
|
let kernel_stack =
|
||||||
|
crate::task::scheduler::allocate_kernel_stack(&mut address_space, &mut allocator)
|
||||||
let kernel_stack = kernel_stack_pool
|
.expect("failed to allocate bootstrap stack");
|
||||||
.allocate(&mut address_space, &mut allocator)
|
|
||||||
.expect("failed to allocate bootstrap stack");
|
|
||||||
|
|
||||||
let handoff_frame = allocator
|
let handoff_frame = allocator
|
||||||
.alloc()
|
.alloc()
|
||||||
@@ -70,7 +67,6 @@ pub extern "C" fn _start() -> ! {
|
|||||||
address_space,
|
address_space,
|
||||||
direct_map,
|
direct_map,
|
||||||
boot_info,
|
boot_info,
|
||||||
kernel_stack_pool,
|
|
||||||
handoff_frame,
|
handoff_frame,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -88,21 +84,13 @@ pub extern "C" fn _start() -> ! {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe extern "C" fn kernel_main(handoff: *mut KernelHandoff) -> ! {
|
pub unsafe extern "C" fn kernel_main(handoff: *mut KernelHandoff) -> ! {
|
||||||
let (
|
let (mut allocator, mut address_space, direct_map, boot_info, handoff_frame) = unsafe {
|
||||||
mut allocator,
|
|
||||||
mut address_space,
|
|
||||||
direct_map,
|
|
||||||
boot_info,
|
|
||||||
mut kernel_stack_pool,
|
|
||||||
handoff_frame,
|
|
||||||
) = unsafe {
|
|
||||||
let handoff = handoff.read();
|
let handoff = handoff.read();
|
||||||
(
|
(
|
||||||
handoff.allocator,
|
handoff.allocator,
|
||||||
handoff.address_space,
|
handoff.address_space,
|
||||||
handoff.direct_map,
|
handoff.direct_map,
|
||||||
handoff.boot_info,
|
handoff.boot_info,
|
||||||
handoff.kernel_stack_pool,
|
|
||||||
handoff.handoff_frame,
|
handoff.handoff_frame,
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
@@ -129,27 +117,20 @@ pub unsafe extern "C" fn kernel_main(handoff: *mut KernelHandoff) -> ! {
|
|||||||
|
|
||||||
println!("Initializing interrupt controller...");
|
println!("Initializing interrupt controller...");
|
||||||
|
|
||||||
let interrupt_controller =
|
let _interrupt_controller =
|
||||||
arch::init_interrupt_controller(&madt, &mut allocator, &mut address_space)
|
arch::init_interrupt_controller(&madt, &mut allocator, &mut address_space)
|
||||||
.expect("failed to initialize interrupt controller");
|
.expect("failed to initialize interrupt controller");
|
||||||
|
|
||||||
task::bootstrap::spawn(
|
task::bootstrap::spawn(
|
||||||
"omega3.elf",
|
"omega3.elf",
|
||||||
boot_info.initramfs.data(),
|
&boot_info.initramfs,
|
||||||
&mut address_space,
|
&mut address_space,
|
||||||
&mut allocator,
|
&mut allocator,
|
||||||
direct_map,
|
direct_map,
|
||||||
&mut kernel_stack_pool,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
task::bootstrap::spawn(
|
init_frame_allocator(allocator);
|
||||||
"client.elf",
|
init_kernel_address_space(address_space);
|
||||||
boot_info.initramfs.data(),
|
|
||||||
&mut address_space,
|
|
||||||
&mut allocator,
|
|
||||||
direct_map,
|
|
||||||
&mut kernel_stack_pool,
|
|
||||||
);
|
|
||||||
|
|
||||||
task::scheduler::start();
|
task::scheduler::start();
|
||||||
}
|
}
|
||||||
|
|||||||
+103
-2
@@ -1,3 +1,5 @@
|
|||||||
|
use core::cell::UnsafeCell;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
arch::{PageTable, PageTableCreateError, PageTableMapError, PageTableUnmapError, PagingConfig},
|
arch::{PageTable, PageTableCreateError, PageTableMapError, PageTableUnmapError, PagingConfig},
|
||||||
memory::{
|
memory::{
|
||||||
@@ -6,6 +8,105 @@ use crate::{
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const MAX_ADDRESS_SPACES: usize = 32;
|
||||||
|
struct AddressSpaceTable {
|
||||||
|
entries: [Option<AddressSpace>; MAX_ADDRESS_SPACES],
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AddressSpaceTable {
|
||||||
|
const fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
entries: [const { None }; MAX_ADDRESS_SPACES],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn insert(&mut self, address_space: AddressSpace) -> Option<usize> {
|
||||||
|
for (i, slot) in self.entries.iter_mut().enumerate() {
|
||||||
|
if slot.is_none() {
|
||||||
|
*slot = Some(address_space);
|
||||||
|
return Some(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get(&self, id: usize) -> Option<&AddressSpace> {
|
||||||
|
self.entries.get(id).and_then(Option::as_ref)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_mut(&mut self, id: usize) -> Option<&mut AddressSpace> {
|
||||||
|
self.entries.get_mut(id).and_then(Option::as_mut)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn remove(&mut self, id: usize) -> Option<AddressSpace> {
|
||||||
|
self.entries.get_mut(id).and_then(Option::take)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct GlobalAddressSpaceTable(UnsafeCell<AddressSpaceTable>);
|
||||||
|
|
||||||
|
unsafe impl Sync for GlobalAddressSpaceTable {}
|
||||||
|
|
||||||
|
static ADDRESS_SPACE_TABLE: GlobalAddressSpaceTable =
|
||||||
|
GlobalAddressSpaceTable(UnsafeCell::new(AddressSpaceTable::new()));
|
||||||
|
|
||||||
|
pub fn insert_address_space(address_space: AddressSpace) -> Option<usize> {
|
||||||
|
let table = unsafe { &mut *ADDRESS_SPACE_TABLE.0.get() };
|
||||||
|
|
||||||
|
let id = table.insert(address_space);
|
||||||
|
id
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn remove_address_space(id: usize) -> Option<AddressSpace> {
|
||||||
|
let table = unsafe { &mut *ADDRESS_SPACE_TABLE.0.get() };
|
||||||
|
|
||||||
|
table.remove(id)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn with_address_space<R>(id: usize, f: impl FnOnce(&AddressSpace) -> R) -> Option<R> {
|
||||||
|
let interrupt_state = crate::arch::disable_interrupts_and_save();
|
||||||
|
let table = unsafe { &*ADDRESS_SPACE_TABLE.0.get() };
|
||||||
|
let res = table.get(id).map(f);
|
||||||
|
crate::arch::restore_interrupts(interrupt_state);
|
||||||
|
res
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn with_address_space_mut<R>(id: usize, f: impl FnOnce(&mut AddressSpace) -> R) -> Option<R> {
|
||||||
|
let interrupt_state = crate::arch::disable_interrupts_and_save();
|
||||||
|
let table = unsafe { &mut *ADDRESS_SPACE_TABLE.0.get() };
|
||||||
|
let res = table.get_mut(id).map(f);
|
||||||
|
crate::arch::restore_interrupts(interrupt_state);
|
||||||
|
res
|
||||||
|
}
|
||||||
|
|
||||||
|
struct GlobalKernelAddressSpace(UnsafeCell<Option<AddressSpace>>);
|
||||||
|
|
||||||
|
unsafe impl Sync for GlobalKernelAddressSpace {}
|
||||||
|
|
||||||
|
static KERNEL_ADDRESS_SPACE: GlobalKernelAddressSpace =
|
||||||
|
GlobalKernelAddressSpace(UnsafeCell::new(None));
|
||||||
|
|
||||||
|
pub fn init_kernel_address_space(address_space: AddressSpace) {
|
||||||
|
let interrupt_state = crate::arch::disable_interrupts_and_save();
|
||||||
|
unsafe {
|
||||||
|
*KERNEL_ADDRESS_SPACE.0.get() = Some(address_space);
|
||||||
|
}
|
||||||
|
crate::arch::restore_interrupts(interrupt_state);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn with_kernel_address_space<R>(f: impl FnOnce(&mut AddressSpace) -> R) -> R {
|
||||||
|
let interrupt_state = crate::arch::disable_interrupts_and_save();
|
||||||
|
let space = unsafe {
|
||||||
|
(&mut *KERNEL_ADDRESS_SPACE.0.get())
|
||||||
|
.as_mut()
|
||||||
|
.expect("kernel address space not initialized")
|
||||||
|
};
|
||||||
|
let res = f(space);
|
||||||
|
crate::arch::restore_interrupts(interrupt_state);
|
||||||
|
res
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum MapError {
|
pub enum MapError {
|
||||||
InvalidVirtualAddress,
|
InvalidVirtualAddress,
|
||||||
@@ -82,13 +183,13 @@ impl From<PageTableCreateError> for AddressSpaceCreateError {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq)]
|
#[derive(PartialEq, Eq)]
|
||||||
enum AddressSpaceKind {
|
enum AddressSpaceKind {
|
||||||
Kernel,
|
Kernel,
|
||||||
User,
|
User,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq)]
|
#[derive(PartialEq, Eq)]
|
||||||
pub struct AddressSpace {
|
pub struct AddressSpace {
|
||||||
root: PageTable,
|
root: PageTable,
|
||||||
kind: AddressSpaceKind,
|
kind: AddressSpaceKind,
|
||||||
|
|||||||
+46
-4
@@ -1,3 +1,5 @@
|
|||||||
|
use core::cell::UnsafeCell;
|
||||||
|
|
||||||
use crate::memory::{DirectMap, MemoryRegion, MemoryRegionKind, PhysicalAddr, VirtualAddr};
|
use crate::memory::{DirectMap, MemoryRegion, MemoryRegionKind, PhysicalAddr, VirtualAddr};
|
||||||
|
|
||||||
pub const FRAME_SIZE: usize = 4096;
|
pub const FRAME_SIZE: usize = 4096;
|
||||||
@@ -12,15 +14,57 @@ pub fn align_down_to_frame(addr: usize) -> usize {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[repr(u8)]
|
#[repr(u8)]
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||||
enum FrameState {
|
enum FrameState {
|
||||||
Reserved = 0b00,
|
Reserved = 0b00,
|
||||||
Free = 0b01,
|
Free = 0b01,
|
||||||
Allocated = 0b10,
|
Allocated = 0b10,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct GlobalFrameAllocator(UnsafeCell<Option<FrameAllocator>>);
|
||||||
|
unsafe impl Sync for GlobalFrameAllocator {}
|
||||||
|
|
||||||
|
static FRAME_ALLOCATOR: GlobalFrameAllocator = GlobalFrameAllocator(UnsafeCell::new(None));
|
||||||
|
|
||||||
|
pub fn init_global(allocator: FrameAllocator) {
|
||||||
|
let interrupt_state = crate::arch::disable_interrupts_and_save();
|
||||||
|
unsafe {
|
||||||
|
*FRAME_ALLOCATOR.0.get() = Some(allocator);
|
||||||
|
}
|
||||||
|
crate::arch::restore_interrupts(interrupt_state);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn alloc_frame() -> Option<OwnedFrame> {
|
||||||
|
let interrupt_state = crate::arch::disable_interrupts_and_save();
|
||||||
|
let allocator = unsafe { &mut *FRAME_ALLOCATOR.0.get() };
|
||||||
|
let frame = allocator.as_mut().and_then(|a| a.alloc());
|
||||||
|
crate::arch::restore_interrupts(interrupt_state);
|
||||||
|
frame
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn dealloc_frame(frame: OwnedFrame) {
|
||||||
|
let interrupt_state = crate::arch::disable_interrupts_and_save();
|
||||||
|
let allocator = unsafe { &mut *FRAME_ALLOCATOR.0.get() };
|
||||||
|
if let Some(a) = allocator.as_mut() {
|
||||||
|
unsafe { a.dealloc(frame) };
|
||||||
|
}
|
||||||
|
crate::arch::restore_interrupts(interrupt_state);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(unused)]
|
||||||
|
pub fn with_allocator<R>(f: impl FnOnce(&mut FrameAllocator) -> R) -> R {
|
||||||
|
let interrupt_state = crate::arch::disable_interrupts_and_save();
|
||||||
|
let allocator = unsafe {
|
||||||
|
(&mut *FRAME_ALLOCATOR.0.get())
|
||||||
|
.as_mut()
|
||||||
|
.expect("frame allocator not initialized")
|
||||||
|
};
|
||||||
|
let result = f(allocator);
|
||||||
|
crate::arch::restore_interrupts(interrupt_state);
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
// 64 KiB per GiB
|
// 64 KiB per GiB
|
||||||
#[derive(Debug)]
|
|
||||||
struct Bitmap {
|
struct Bitmap {
|
||||||
start: VirtualAddr,
|
start: VirtualAddr,
|
||||||
frame_count: usize,
|
frame_count: usize,
|
||||||
@@ -70,7 +114,6 @@ pub enum FrameAllocatorInitError {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// very very simple bitmap frame/page allocator
|
// very very simple bitmap frame/page allocator
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct FrameAllocator {
|
pub struct FrameAllocator {
|
||||||
bitmap: Bitmap,
|
bitmap: Bitmap,
|
||||||
next_search: usize,
|
next_search: usize,
|
||||||
@@ -327,7 +370,6 @@ impl FrameAddr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// specifically not Clone or Copy
|
// specifically not Clone or Copy
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct OwnedFrame {
|
pub struct OwnedFrame {
|
||||||
frame: FrameAddr,
|
frame: FrameAddr,
|
||||||
}
|
}
|
||||||
|
|||||||
+14
-9
@@ -6,8 +6,15 @@ mod user;
|
|||||||
use core::ops::Add;
|
use core::ops::Add;
|
||||||
|
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
pub use address_space::{AddressSpace, AddressSpaceCreateError, MapError, UnmapError};
|
pub use address_space::{
|
||||||
pub use frame::{FRAME_SIZE, FrameAddr, FrameAllocator, OwnedFrame};
|
AddressSpace, AddressSpaceCreateError, MapError, UnmapError, init_kernel_address_space,
|
||||||
|
insert_address_space, remove_address_space, with_address_space, with_address_space_mut,
|
||||||
|
with_kernel_address_space,
|
||||||
|
};
|
||||||
|
pub use frame::{
|
||||||
|
FRAME_SIZE, FrameAddr, FrameAllocator, OwnedFrame, alloc_frame, dealloc_frame,
|
||||||
|
init_global as init_frame_allocator, with_allocator,
|
||||||
|
};
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
pub use stack::{KernelStack, KernelStackPool, StackCreateError, UserStack};
|
pub use stack::{KernelStack, KernelStackPool, StackCreateError, UserStack};
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
@@ -31,8 +38,6 @@ impl<const N: usize> BootString<N> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const MAX_MODULE_PATH_LENGTH: usize = 256;
|
|
||||||
|
|
||||||
pub struct InitramfsImage {
|
pub struct InitramfsImage {
|
||||||
pub start: VirtualAddr,
|
pub start: VirtualAddr,
|
||||||
pub length: usize,
|
pub length: usize,
|
||||||
@@ -55,7 +60,7 @@ pub struct KernelMemoryLayout {
|
|||||||
pub segments: [KernelSegment; 3],
|
pub segments: [KernelSegment; 3],
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||||
pub struct PagePermissions {
|
pub struct PagePermissions {
|
||||||
pub writable: bool,
|
pub writable: bool,
|
||||||
pub executable: bool,
|
pub executable: bool,
|
||||||
@@ -117,7 +122,7 @@ impl Add<usize> for VirtualAddr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[repr(u8)]
|
#[repr(u8)]
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||||
pub enum MemoryRegionKind {
|
pub enum MemoryRegionKind {
|
||||||
Usable,
|
Usable,
|
||||||
Reserved,
|
Reserved,
|
||||||
@@ -130,20 +135,20 @@ pub enum MemoryRegionKind {
|
|||||||
MappedReserved,
|
MappedReserved,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy)]
|
||||||
pub enum CachePolicy {
|
pub enum CachePolicy {
|
||||||
Uncacheable,
|
Uncacheable,
|
||||||
WriteBack,
|
WriteBack,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||||
pub struct MemoryRegion {
|
pub struct MemoryRegion {
|
||||||
pub start: PhysicalAddr,
|
pub start: PhysicalAddr,
|
||||||
pub length: usize,
|
pub length: usize,
|
||||||
pub kind: MemoryRegionKind,
|
pub kind: MemoryRegionKind,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub struct DirectMap {
|
pub struct DirectMap {
|
||||||
offset: usize,
|
offset: usize,
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-2
@@ -176,7 +176,6 @@ impl KernelStack {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct UserStack {
|
pub struct UserStack {
|
||||||
mapping: StackMapping,
|
mapping: StackMapping,
|
||||||
}
|
}
|
||||||
@@ -216,7 +215,7 @@ pub struct KernelStackPool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl KernelStackPool {
|
impl KernelStackPool {
|
||||||
pub fn new() -> Self {
|
pub const fn new() -> Self {
|
||||||
Self { free_slots: 0 }
|
Self { free_slots: 0 }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+16
-21
@@ -12,7 +12,6 @@ pub enum AcpiError {
|
|||||||
MultipleIoApicsUnsupported,
|
MultipleIoApicsUnsupported,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct AcpiTables {
|
pub struct AcpiTables {
|
||||||
direct_map: DirectMap,
|
direct_map: DirectMap,
|
||||||
root: RootTable,
|
root: RootTable,
|
||||||
@@ -215,7 +214,6 @@ impl AcpiTables {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
enum RootTable {
|
enum RootTable {
|
||||||
Rsdt(Sdt),
|
Rsdt(Sdt),
|
||||||
Xsdt(Sdt),
|
Xsdt(Sdt),
|
||||||
@@ -251,7 +249,7 @@ impl RootTable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[repr(C, packed)]
|
#[repr(C, packed)]
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy)]
|
||||||
struct Rsdp {
|
struct Rsdp {
|
||||||
signature: [u8; 8],
|
signature: [u8; 8],
|
||||||
checksum: u8,
|
checksum: u8,
|
||||||
@@ -261,7 +259,7 @@ struct Rsdp {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[repr(C, packed)]
|
#[repr(C, packed)]
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy)]
|
||||||
struct Xsdp {
|
struct Xsdp {
|
||||||
rsdp: Rsdp,
|
rsdp: Rsdp,
|
||||||
length: u32,
|
length: u32,
|
||||||
@@ -271,7 +269,7 @@ struct Xsdp {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[repr(C, packed)]
|
#[repr(C, packed)]
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy)]
|
||||||
struct SDTHeader {
|
struct SDTHeader {
|
||||||
signature: [u8; 4],
|
signature: [u8; 4],
|
||||||
length: u32,
|
length: u32,
|
||||||
@@ -284,14 +282,12 @@ struct SDTHeader {
|
|||||||
creator_revision: u32,
|
creator_revision: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct Sdt {
|
pub struct Sdt {
|
||||||
physical_addr: PhysicalAddr,
|
physical_addr: PhysicalAddr,
|
||||||
length: usize,
|
length: usize,
|
||||||
signature: [u8; 4],
|
signature: [u8; 4],
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
pub struct Madt<'a> {
|
pub struct Madt<'a> {
|
||||||
acpi: &'a AcpiTables,
|
acpi: &'a AcpiTables,
|
||||||
@@ -301,7 +297,7 @@ pub struct Madt<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[repr(C, packed)]
|
#[repr(C, packed)]
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy)]
|
||||||
struct MadtBody {
|
struct MadtBody {
|
||||||
local_apic_address: u32,
|
local_apic_address: u32,
|
||||||
flags: u32,
|
flags: u32,
|
||||||
@@ -543,21 +539,20 @@ impl<'a> Iterator for MadtEntries<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[repr(C, packed)]
|
#[repr(C, packed)]
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy)]
|
||||||
pub struct MadtEntryHeader {
|
pub struct MadtEntryHeader {
|
||||||
kind: u8,
|
kind: u8,
|
||||||
length: u8,
|
length: u8,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[repr(C, packed)]
|
#[repr(C, packed)]
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy)]
|
||||||
pub struct LocalApicEntry {
|
pub struct LocalApicEntry {
|
||||||
processor_id: u8,
|
processor_id: u8,
|
||||||
id: u8,
|
id: u8,
|
||||||
flags: u32,
|
flags: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct IoApicInfo {
|
pub struct IoApicInfo {
|
||||||
pub id: u8,
|
pub id: u8,
|
||||||
pub apic_address: PhysicalAddr,
|
pub apic_address: PhysicalAddr,
|
||||||
@@ -565,7 +560,7 @@ pub struct IoApicInfo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[repr(C, packed)]
|
#[repr(C, packed)]
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy)]
|
||||||
pub struct IoApicEntry {
|
pub struct IoApicEntry {
|
||||||
id: u8,
|
id: u8,
|
||||||
reserved: u8,
|
reserved: u8,
|
||||||
@@ -574,7 +569,7 @@ pub struct IoApicEntry {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[repr(C, packed)]
|
#[repr(C, packed)]
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy)]
|
||||||
pub struct InterruptSourceOverride {
|
pub struct InterruptSourceOverride {
|
||||||
bus: u8,
|
bus: u8,
|
||||||
source: u8,
|
source: u8,
|
||||||
@@ -582,19 +577,19 @@ pub struct InterruptSourceOverride {
|
|||||||
flags: u16,
|
flags: u16,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy)]
|
||||||
pub enum InterruptPolarity {
|
pub enum InterruptPolarity {
|
||||||
ActiveHigh,
|
ActiveHigh,
|
||||||
ActiveLow,
|
ActiveLow,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy)]
|
||||||
pub enum TriggerMode {
|
pub enum TriggerMode {
|
||||||
Edge,
|
Edge,
|
||||||
Level,
|
Level,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy)]
|
||||||
pub struct IsaIrqRoute {
|
pub struct IsaIrqRoute {
|
||||||
pub gsi: u32,
|
pub gsi: u32,
|
||||||
pub polarity: InterruptPolarity,
|
pub polarity: InterruptPolarity,
|
||||||
@@ -602,7 +597,7 @@ pub struct IsaIrqRoute {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[repr(C, packed)]
|
#[repr(C, packed)]
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy)]
|
||||||
pub struct IoApicNmiEntry {
|
pub struct IoApicNmiEntry {
|
||||||
nmi_source: u8,
|
nmi_source: u8,
|
||||||
reserved: u8,
|
reserved: u8,
|
||||||
@@ -611,7 +606,7 @@ pub struct IoApicNmiEntry {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[repr(C, packed)]
|
#[repr(C, packed)]
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy)]
|
||||||
pub struct LocalApicNmiEntry {
|
pub struct LocalApicNmiEntry {
|
||||||
processor_id: u8,
|
processor_id: u8,
|
||||||
flags: u16,
|
flags: u16,
|
||||||
@@ -619,14 +614,14 @@ pub struct LocalApicNmiEntry {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[repr(C, packed)]
|
#[repr(C, packed)]
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy)]
|
||||||
pub struct LocalApicAddressOverride {
|
pub struct LocalApicAddressOverride {
|
||||||
reserved: u16,
|
reserved: u16,
|
||||||
local_apic_address: u64,
|
local_apic_address: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[repr(C, packed)]
|
#[repr(C, packed)]
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy)]
|
||||||
pub struct LocalX2ApicEntry {
|
pub struct LocalX2ApicEntry {
|
||||||
reserved: u16,
|
reserved: u16,
|
||||||
local_x2apic_id: u32,
|
local_x2apic_id: u32,
|
||||||
@@ -634,7 +629,7 @@ pub struct LocalX2ApicEntry {
|
|||||||
acpi_processor_uid: u32,
|
acpi_processor_uid: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy)]
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
pub enum MadtEntry {
|
pub enum MadtEntry {
|
||||||
LocalApic(LocalApicEntry),
|
LocalApic(LocalApicEntry),
|
||||||
|
|||||||
+25
-2
@@ -2,7 +2,7 @@ mod table;
|
|||||||
|
|
||||||
use table::*;
|
use table::*;
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||||
#[repr(u64)]
|
#[repr(u64)]
|
||||||
pub enum Status {
|
pub enum Status {
|
||||||
// Status::Success = 0
|
// Status::Success = 0
|
||||||
@@ -11,9 +11,10 @@ pub enum Status {
|
|||||||
BadFileDescriptor = 3, // EBADF
|
BadFileDescriptor = 3, // EBADF
|
||||||
NoSuchTask = 4, // ESRCH
|
NoSuchTask = 4, // ESRCH
|
||||||
OutOfMemory = 5, // ENOMEM
|
OutOfMemory = 5, // ENOMEM
|
||||||
|
BadHandle = 6, // EBADH
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||||
#[repr(u64)]
|
#[repr(u64)]
|
||||||
pub enum SyscallNumber {
|
pub enum SyscallNumber {
|
||||||
Yield = 1,
|
Yield = 1,
|
||||||
@@ -21,6 +22,12 @@ pub enum SyscallNumber {
|
|||||||
Write = 3,
|
Write = 3,
|
||||||
Send = 4,
|
Send = 4,
|
||||||
Recv = 5,
|
Recv = 5,
|
||||||
|
FrameAlloc = 6,
|
||||||
|
FrameDealloc = 7,
|
||||||
|
AsCreate = 8,
|
||||||
|
Map = 9,
|
||||||
|
Unmap = 10,
|
||||||
|
TaskCreate = 11,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryFrom<u64> for SyscallNumber {
|
impl TryFrom<u64> for SyscallNumber {
|
||||||
@@ -32,6 +39,12 @@ impl TryFrom<u64> for SyscallNumber {
|
|||||||
3 => Ok(Self::Write),
|
3 => Ok(Self::Write),
|
||||||
4 => Ok(Self::Send),
|
4 => Ok(Self::Send),
|
||||||
5 => Ok(Self::Recv),
|
5 => Ok(Self::Recv),
|
||||||
|
6 => Ok(Self::FrameAlloc),
|
||||||
|
7 => Ok(Self::FrameDealloc),
|
||||||
|
8 => Ok(Self::AsCreate),
|
||||||
|
9 => Ok(Self::Map),
|
||||||
|
10 => Ok(Self::Unmap),
|
||||||
|
11 => Ok(Self::TaskCreate),
|
||||||
_ => Err(Status::InvalidArgument),
|
_ => Err(Status::InvalidArgument),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -50,6 +63,16 @@ pub fn handle(num: u64, arg0: u64, arg1: u64, arg2: u64, arg3: u64, _arg4: u64,
|
|||||||
SyscallNumber::Recv => {
|
SyscallNumber::Recv => {
|
||||||
sys_recv(arg0 as usize, arg1 as usize, arg2 as usize, arg3 as usize)
|
sys_recv(arg0 as usize, arg1 as usize, arg2 as usize, arg3 as usize)
|
||||||
}
|
}
|
||||||
|
SyscallNumber::FrameAlloc => sys_frame_alloc(arg0 as usize),
|
||||||
|
SyscallNumber::FrameDealloc => sys_frame_dealloc(arg0 as usize),
|
||||||
|
SyscallNumber::AsCreate => sys_as_create(arg0 as usize),
|
||||||
|
SyscallNumber::Map => {
|
||||||
|
sys_map(arg0 as usize, arg1 as usize, arg2 as usize, arg3 as usize)
|
||||||
|
}
|
||||||
|
SyscallNumber::Unmap => sys_unmap(arg0 as usize, arg1 as usize),
|
||||||
|
SyscallNumber::TaskCreate => {
|
||||||
|
sys_task_create(arg0 as usize, arg1 as usize, arg2 as usize, arg3 as usize)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
|||||||
+257
-7
@@ -1,6 +1,10 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
memory::{VirtualAddr, copy_from_user, copy_to_user, copy_val_to_user},
|
memory::{
|
||||||
task::tcb::{BlockReason, MAX_MSG_SIZE, Message},
|
FRAME_SIZE, OwnedFrame, PagePermissions, USER_SPACE_END, VirtualAddr, copy_from_user,
|
||||||
|
copy_to_user, copy_val_to_user,
|
||||||
|
},
|
||||||
|
println,
|
||||||
|
task::tcb::{BlockReason, Handle, KernelObject, MAX_MSG_SIZE, Message, Rights},
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::Status;
|
use super::Status;
|
||||||
@@ -76,19 +80,17 @@ pub fn sys_recv(
|
|||||||
return Err(Status::InvalidArgument);
|
return Err(Status::InvalidArgument);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut interrupt_state = crate::arch::disable_interrupts_and_save();
|
|
||||||
|
|
||||||
let current_task = crate::task::scheduler::get_task_mut(crate::task::scheduler::current())
|
let current_task = crate::task::scheduler::get_task_mut(crate::task::scheduler::current())
|
||||||
.ok_or(Status::NoSuchTask)?;
|
.ok_or(Status::NoSuchTask)?;
|
||||||
|
|
||||||
if current_task.mailbox.len == 0 {
|
if current_task.mailbox.len == 0 {
|
||||||
crate::arch::restore_interrupts(interrupt_state);
|
|
||||||
crate::task::scheduler::block_current(BlockReason::Recv { ep: 0 });
|
crate::task::scheduler::block_current(BlockReason::Recv { ep: 0 });
|
||||||
interrupt_state = crate::arch::disable_interrupts_and_save();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// if we blocked, we will wake up when the mailbox is non-empty
|
// if we blocked, we will wake up when the mailbox is non-empty
|
||||||
|
|
||||||
|
let current_task = crate::task::scheduler::get_task_mut(crate::task::scheduler::current())
|
||||||
|
.ok_or(Status::NoSuchTask)?;
|
||||||
let msg = current_task.mailbox.pop().ok_or(Status::NoSuchTask)?;
|
let msg = current_task.mailbox.pop().ok_or(Status::NoSuchTask)?;
|
||||||
|
|
||||||
copy_to_user(
|
copy_to_user(
|
||||||
@@ -102,7 +104,255 @@ pub fn sys_recv(
|
|||||||
copy_val_to_user(VirtualAddr::new(out_sender), &msg.sender)?;
|
copy_val_to_user(VirtualAddr::new(out_sender), &msg.sender)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
crate::arch::restore_interrupts(interrupt_state);
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sys_frame_alloc(out_handle: usize) -> Result<(), Status> {
|
||||||
|
if out_handle == 0 {
|
||||||
|
return Err(Status::InvalidArgument);
|
||||||
|
}
|
||||||
|
|
||||||
|
let frame = crate::memory::alloc_frame().ok_or(Status::OutOfMemory)?;
|
||||||
|
|
||||||
|
let task_id = crate::task::scheduler::current();
|
||||||
|
let task = match crate::task::scheduler::get_task_mut(task_id) {
|
||||||
|
Some(task) => task,
|
||||||
|
None => {
|
||||||
|
unsafe { crate::memory::dealloc_frame(frame) };
|
||||||
|
return Err(Status::NoSuchTask);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let frame_addr = frame.into_raw();
|
||||||
|
let handle = Handle {
|
||||||
|
object: KernelObject::Frame(frame_addr),
|
||||||
|
rights: Rights::READ | Rights::WRITE | Rights::EXECUTE,
|
||||||
|
};
|
||||||
|
|
||||||
|
let handle_id = match task.handles.push(handle) {
|
||||||
|
Some(id) => id,
|
||||||
|
None => {
|
||||||
|
unsafe { crate::memory::dealloc_frame(OwnedFrame::from_raw(frame_addr)) };
|
||||||
|
return Err(Status::OutOfMemory);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
copy_val_to_user(VirtualAddr::new(out_handle), &handle_id)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sys_frame_dealloc(frame_handle: usize) -> Result<(), Status> {
|
||||||
|
let task = crate::task::scheduler::current();
|
||||||
|
let task = crate::task::scheduler::get_task_mut(task).ok_or(Status::NoSuchTask)?;
|
||||||
|
|
||||||
|
let frame_handle = task.handles.get(frame_handle).ok_or(Status::BadHandle)?;
|
||||||
|
let frame = match frame_handle.object {
|
||||||
|
KernelObject::Frame(frame_addr) => frame_addr,
|
||||||
|
_ => return Err(Status::InvalidArgument),
|
||||||
|
};
|
||||||
|
|
||||||
|
unsafe { crate::memory::dealloc_frame(OwnedFrame::from_raw(frame)) };
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sys_as_create(out_handle: usize) -> Result<(), Status> {
|
||||||
|
if out_handle == 0 {
|
||||||
|
return Err(Status::InvalidArgument);
|
||||||
|
}
|
||||||
|
|
||||||
|
let task_id = crate::task::scheduler::current();
|
||||||
|
let task = crate::task::scheduler::get_task_mut(task_id).ok_or(Status::NoSuchTask)?;
|
||||||
|
|
||||||
|
let new_as = match crate::memory::with_address_space(task.as_id, |caller_as| {
|
||||||
|
crate::memory::with_allocator(|allocator| caller_as.new_user(allocator))
|
||||||
|
}) {
|
||||||
|
Some(Ok(as_space)) => as_space,
|
||||||
|
_ => return Err(Status::OutOfMemory),
|
||||||
|
};
|
||||||
|
|
||||||
|
let as_id = crate::memory::insert_address_space(new_as).ok_or(Status::OutOfMemory)?;
|
||||||
|
|
||||||
|
let handle = Handle {
|
||||||
|
object: KernelObject::AddressSpace(as_id),
|
||||||
|
rights: Rights::READ | Rights::WRITE | Rights::EXECUTE,
|
||||||
|
};
|
||||||
|
|
||||||
|
let handle_id = match task.handles.push(handle) {
|
||||||
|
Some(id) => id,
|
||||||
|
None => {
|
||||||
|
crate::memory::remove_address_space(as_id);
|
||||||
|
return Err(Status::OutOfMemory);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
copy_val_to_user(VirtualAddr::new(out_handle), &handle_id)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sys_map(
|
||||||
|
as_handle: usize,
|
||||||
|
frame_handle: usize,
|
||||||
|
virtual_addr: usize,
|
||||||
|
permissions: usize,
|
||||||
|
) -> Result<(), Status> {
|
||||||
|
if virtual_addr % FRAME_SIZE != 0 {
|
||||||
|
return Err(Status::InvalidArgument);
|
||||||
|
}
|
||||||
|
|
||||||
|
if virtual_addr >= USER_SPACE_END.as_usize() {
|
||||||
|
return Err(Status::InvalidArgument);
|
||||||
|
}
|
||||||
|
|
||||||
|
let task = crate::task::scheduler::current();
|
||||||
|
let task = crate::task::scheduler::get_task_mut(task).ok_or(Status::NoSuchTask)?;
|
||||||
|
|
||||||
|
let as_handle = task.handles.get(as_handle).ok_or(Status::BadHandle)?;
|
||||||
|
let as_id = match as_handle.object {
|
||||||
|
KernelObject::AddressSpace(as_id) => as_id,
|
||||||
|
_ => return Err(Status::InvalidArgument),
|
||||||
|
};
|
||||||
|
|
||||||
|
let frame_handle = task.handles.get(frame_handle).ok_or(Status::BadHandle)?;
|
||||||
|
let frame = match frame_handle.object {
|
||||||
|
KernelObject::Frame(frame_addr) => frame_addr,
|
||||||
|
_ => return Err(Status::InvalidArgument),
|
||||||
|
};
|
||||||
|
|
||||||
|
let virtual_addr = VirtualAddr::new(virtual_addr);
|
||||||
|
let permissions = PagePermissions::new(
|
||||||
|
permissions & (1 << 0) != 0,
|
||||||
|
permissions & (1 << 1) != 0,
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
|
||||||
|
let map_result = crate::memory::with_address_space_mut(as_id, |target_as| {
|
||||||
|
crate::memory::with_allocator(|allocator| {
|
||||||
|
target_as.map(
|
||||||
|
frame.start_address(),
|
||||||
|
virtual_addr,
|
||||||
|
permissions,
|
||||||
|
allocator,
|
||||||
|
crate::memory::CachePolicy::WriteBack,
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.ok_or(Status::BadHandle)?;
|
||||||
|
|
||||||
|
map_result.map_err(|_| Status::OutOfMemory)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sys_unmap(as_handle: usize, virtual_addr: usize) -> Result<(), Status> {
|
||||||
|
if virtual_addr % FRAME_SIZE != 0 {
|
||||||
|
return Err(Status::InvalidArgument);
|
||||||
|
}
|
||||||
|
|
||||||
|
if virtual_addr >= USER_SPACE_END.as_usize() {
|
||||||
|
return Err(Status::InvalidArgument);
|
||||||
|
}
|
||||||
|
|
||||||
|
let task = crate::task::scheduler::current();
|
||||||
|
let task = crate::task::scheduler::get_task_mut(task).ok_or(Status::NoSuchTask)?;
|
||||||
|
|
||||||
|
let as_handle = task.handles.get(as_handle).ok_or(Status::BadHandle)?;
|
||||||
|
let as_id = match as_handle.object {
|
||||||
|
KernelObject::AddressSpace(as_id) => as_id,
|
||||||
|
_ => return Err(Status::InvalidArgument),
|
||||||
|
};
|
||||||
|
|
||||||
|
let virtual_addr = VirtualAddr::new(virtual_addr);
|
||||||
|
|
||||||
|
let map_result = crate::memory::with_address_space_mut(as_id, |target_as| {
|
||||||
|
if target_as.to_physical(virtual_addr).is_none() {
|
||||||
|
return Err(Status::InvalidArgument);
|
||||||
|
}
|
||||||
|
|
||||||
|
crate::memory::with_allocator(|allocator| unsafe {
|
||||||
|
target_as.unmap(virtual_addr, allocator)
|
||||||
|
})
|
||||||
|
.map_err(|_| Status::BadAddress)
|
||||||
|
})
|
||||||
|
.ok_or(Status::BadHandle)?;
|
||||||
|
|
||||||
|
map_result.map_err(|_| Status::OutOfMemory)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sys_task_create(
|
||||||
|
as_handle: usize,
|
||||||
|
entry: usize,
|
||||||
|
user_stack: usize,
|
||||||
|
out_task_handle: usize,
|
||||||
|
) -> Result<(), Status> {
|
||||||
|
if out_task_handle == 0 || entry == 0 || user_stack == 0 {
|
||||||
|
return Err(Status::InvalidArgument);
|
||||||
|
}
|
||||||
|
|
||||||
|
if entry >= 0x0000_8000_0000_0000 || user_stack >= 0x0000_8000_0000_0000 {
|
||||||
|
return Err(Status::BadAddress);
|
||||||
|
}
|
||||||
|
|
||||||
|
let task_id = crate::task::scheduler::current();
|
||||||
|
let task = crate::task::scheduler::get_task_mut(task_id).ok_or(Status::NoSuchTask)?;
|
||||||
|
|
||||||
|
let as_handle = task.handles.get(as_handle).ok_or(Status::BadHandle)?;
|
||||||
|
let as_id = match as_handle.object {
|
||||||
|
KernelObject::AddressSpace(as_id) => as_id,
|
||||||
|
_ => return Err(Status::InvalidArgument),
|
||||||
|
};
|
||||||
|
|
||||||
|
if as_handle.rights.0 & Rights::EXECUTE.0 == 0 {
|
||||||
|
return Err(Status::InvalidArgument);
|
||||||
|
}
|
||||||
|
|
||||||
|
if crate::memory::with_address_space(as_id, |_| ()).is_none() {
|
||||||
|
return Err(Status::BadHandle);
|
||||||
|
}
|
||||||
|
|
||||||
|
let kernel_stack = match crate::memory::with_kernel_address_space(|kernel_as| {
|
||||||
|
crate::memory::with_allocator(|allocator| {
|
||||||
|
crate::task::scheduler::allocate_kernel_stack(kernel_as, allocator)
|
||||||
|
})
|
||||||
|
}) {
|
||||||
|
Ok(stack) => stack,
|
||||||
|
Err(err) => {
|
||||||
|
println!("Failed to allocate kernel stack: {:?}", err);
|
||||||
|
return Err(Status::OutOfMemory);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let new_tcb = crate::task::tcb::Tcb::new_user(
|
||||||
|
0, // assigned by scheduler::add_task
|
||||||
|
as_id,
|
||||||
|
kernel_stack,
|
||||||
|
VirtualAddr::new(entry),
|
||||||
|
VirtualAddr::new(user_stack),
|
||||||
|
);
|
||||||
|
|
||||||
|
let new_task_id = match crate::task::scheduler::add_task(new_tcb) {
|
||||||
|
Ok(id) => id,
|
||||||
|
Err(_) => return Err(Status::OutOfMemory),
|
||||||
|
};
|
||||||
|
|
||||||
|
let handle = Handle {
|
||||||
|
object: KernelObject::Thread(new_task_id),
|
||||||
|
rights: Rights::READ | Rights::WRITE | Rights::EXECUTE,
|
||||||
|
};
|
||||||
|
|
||||||
|
let handle_id = match task.handles.push(handle) {
|
||||||
|
Some(id) => id,
|
||||||
|
None => {
|
||||||
|
crate::task::scheduler::remove_task(new_task_id);
|
||||||
|
return Err(Status::OutOfMemory);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
copy_val_to_user(VirtualAddr::new(out_task_handle), &handle_id)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
+91
-149
@@ -1,80 +1,61 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
format,
|
format,
|
||||||
memory::{
|
memory::{
|
||||||
self, AddressSpace, DirectMap, FRAME_SIZE, FrameAllocator, PagePermissions, UserStack,
|
self, AddressSpace, DirectMap, FRAME_SIZE, FrameAllocator, InitramfsImage, PagePermissions,
|
||||||
VirtualAddr,
|
UserStack, VirtualAddr,
|
||||||
},
|
},
|
||||||
println,
|
|
||||||
task::tcb::Tcb,
|
task::tcb::Tcb,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn spawn(
|
pub fn spawn(
|
||||||
name: &str,
|
name: &str,
|
||||||
initramfs: &[u8],
|
initramfs: &InitramfsImage,
|
||||||
kernel_as: &mut AddressSpace,
|
kernel_as: &mut AddressSpace,
|
||||||
allocator: &mut FrameAllocator,
|
allocator: &mut FrameAllocator,
|
||||||
direct_map: DirectMap,
|
direct_map: DirectMap,
|
||||||
stacks: &mut crate::memory::KernelStackPool,
|
|
||||||
) -> usize {
|
) -> usize {
|
||||||
let bytes = format::cpio::find_file(initramfs, name)
|
let bytes = format::cpio::find_file(initramfs.data(), name)
|
||||||
.unwrap_or_else(|| panic!("{name} missing from initramfs"));
|
.unwrap_or_else(|| panic!("{name} missing from initramfs"));
|
||||||
let kernel_stack = stacks
|
let kernel_stack = crate::task::scheduler::allocate_kernel_stack(kernel_as, allocator)
|
||||||
.allocate(kernel_as, allocator)
|
|
||||||
.expect("kernel stack allocation failed");
|
.expect("kernel stack allocation failed");
|
||||||
|
|
||||||
|
let initramfs_physical_addr = kernel_as
|
||||||
|
.to_physical(initramfs.start)
|
||||||
|
.expect("failed to translate initramfs start address");
|
||||||
|
|
||||||
let mut address_space = kernel_as
|
let mut address_space = kernel_as
|
||||||
.new_user(allocator)
|
.new_user(allocator)
|
||||||
.expect("address space allocation failed");
|
.expect("address space allocation failed");
|
||||||
|
address_space
|
||||||
|
.map_range(
|
||||||
|
initramfs_physical_addr,
|
||||||
|
VirtualAddr::new(0x4000_0000),
|
||||||
|
((initramfs.length) + 0xFFF) & !0xFFF,
|
||||||
|
PagePermissions::new(true, false, true),
|
||||||
|
allocator,
|
||||||
|
memory::CachePolicy::WriteBack,
|
||||||
|
)
|
||||||
|
.expect("failed to map initramfs");
|
||||||
let user_stack =
|
let user_stack =
|
||||||
UserStack::allocate(&mut address_space, allocator).expect("user stack allocation failed");
|
UserStack::allocate(&mut address_space, allocator).expect("user stack allocation failed");
|
||||||
|
|
||||||
let entry = load_elf(bytes, &mut address_space, allocator, direct_map).expect("invalid ELF");
|
let entry = load_elf(bytes, &mut address_space, allocator, direct_map).expect("invalid ELF");
|
||||||
|
|
||||||
let task = Tcb::new_user(0, address_space, kernel_stack, entry, user_stack.top());
|
let as_id =
|
||||||
crate::task::scheduler::add_task(task).expect("scheduler is full")
|
crate::memory::insert_address_space(address_space).expect("address space table is full");
|
||||||
}
|
|
||||||
|
|
||||||
pub fn root(
|
let task = Tcb::new_user(0, as_id, kernel_stack, entry, user_stack.top());
|
||||||
initramfs: &[u8],
|
crate::task::scheduler::add_task(task).expect("scheduler is full")
|
||||||
kernel_as: &mut AddressSpace,
|
|
||||||
allocator: &mut FrameAllocator,
|
|
||||||
direct_map: DirectMap,
|
|
||||||
stacks: &mut crate::memory::KernelStackPool,
|
|
||||||
) {
|
|
||||||
spawn(
|
|
||||||
"omega3.elf",
|
|
||||||
initramfs,
|
|
||||||
kernel_as,
|
|
||||||
allocator,
|
|
||||||
direct_map,
|
|
||||||
stacks,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
enum ElfLoadError {
|
enum ElfLoadError {
|
||||||
AddressTranslationFailed,
|
AddressTranslationFailed,
|
||||||
FailedToMapSegment,
|
FailedToMapSegment,
|
||||||
AddressOverflow,
|
|
||||||
InvalidStack,
|
|
||||||
OutOfMemory,
|
OutOfMemory,
|
||||||
InvalidElf,
|
InvalidElf,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(target_arch = "x86_64")]
|
|
||||||
fn is_loadable(elf: &format::elf::Elf) -> bool {
|
|
||||||
// on x86_64, we only support ELFs that are either 32 bit x86 or 64 bit x86
|
|
||||||
matches!(
|
|
||||||
elf.machine(),
|
|
||||||
format::elf::ElfIsa::X86 | format::elf::ElfIsa::Amd64
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(not(target_arch = "x86_64"))]
|
|
||||||
fn is_loadable(elf: &format::elf::Elf) -> bool {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
|
|
||||||
fn load_elf(
|
fn load_elf(
|
||||||
bytes: &[u8],
|
bytes: &[u8],
|
||||||
user_address_space: &mut AddressSpace,
|
user_address_space: &mut AddressSpace,
|
||||||
@@ -82,113 +63,74 @@ fn load_elf(
|
|||||||
direct_map: DirectMap,
|
direct_map: DirectMap,
|
||||||
) -> Result<VirtualAddr, ElfLoadError> {
|
) -> Result<VirtualAddr, ElfLoadError> {
|
||||||
let program = format::elf::Elf::parse(bytes).map_err(|_| ElfLoadError::InvalidElf)?;
|
let program = format::elf::Elf::parse(bytes).map_err(|_| ElfLoadError::InvalidElf)?;
|
||||||
if !is_loadable(&program) {
|
let mut executable_entry = false;
|
||||||
|
|
||||||
|
for segment in program.segments() {
|
||||||
|
let segment = segment.map_err(|_| ElfLoadError::InvalidElf)?;
|
||||||
|
let end = segment
|
||||||
|
.address
|
||||||
|
.checked_add(segment.memory_size)
|
||||||
|
.filter(|&end| end <= memory::USER_SPACE_END.as_usize())
|
||||||
|
.ok_or(ElfLoadError::InvalidElf)?;
|
||||||
|
if segment.memory_size == 0 {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
executable_entry |= segment.executable && (segment.address..end).contains(&program.entry);
|
||||||
|
|
||||||
|
let page_start = segment.address & !(FRAME_SIZE - 1);
|
||||||
|
let file_end = segment.address + segment.data.len();
|
||||||
|
let permissions = PagePermissions::new(segment.writable, segment.executable, true);
|
||||||
|
|
||||||
|
// Overlapping segment pages are rejected by map(), including stack/archive collisions.
|
||||||
|
for page in (page_start..end).step_by(FRAME_SIZE) {
|
||||||
|
let frame = allocator.alloc_nozero().ok_or(ElfLoadError::OutOfMemory)?;
|
||||||
|
let physical = frame.frame_address().start_address();
|
||||||
|
let Some(destination) = direct_map.translate(physical) else {
|
||||||
|
unsafe { allocator.dealloc(frame) };
|
||||||
|
return Err(ElfLoadError::AddressTranslationFailed);
|
||||||
|
};
|
||||||
|
|
||||||
|
let copy_start = page.max(segment.address).min(page + FRAME_SIZE);
|
||||||
|
let copy_end = (page + FRAME_SIZE).min(file_end).max(copy_start);
|
||||||
|
let prefix = copy_start - page;
|
||||||
|
let copied = copy_end - copy_start;
|
||||||
|
unsafe {
|
||||||
|
let destination = destination.as_mut_ptr::<u8>();
|
||||||
|
// Initialize padding and BSS, but don't zero bytes we're about to overwrite.
|
||||||
|
core::ptr::write_bytes(destination, 0, prefix);
|
||||||
|
if copied != 0 {
|
||||||
|
core::ptr::copy_nonoverlapping(
|
||||||
|
segment.data.as_ptr().add(copy_start - segment.address),
|
||||||
|
destination.add(prefix),
|
||||||
|
copied,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
core::ptr::write_bytes(
|
||||||
|
destination.add(prefix + copied),
|
||||||
|
0,
|
||||||
|
FRAME_SIZE - prefix - copied,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if user_address_space
|
||||||
|
.map(
|
||||||
|
physical,
|
||||||
|
VirtualAddr::new(page),
|
||||||
|
permissions,
|
||||||
|
allocator,
|
||||||
|
memory::CachePolicy::WriteBack,
|
||||||
|
)
|
||||||
|
.is_err()
|
||||||
|
{
|
||||||
|
unsafe { allocator.dealloc(frame) };
|
||||||
|
return Err(ElfLoadError::FailedToMapSegment);
|
||||||
|
}
|
||||||
|
let _ = frame.into_raw();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !executable_entry {
|
||||||
return Err(ElfLoadError::InvalidElf);
|
return Err(ElfLoadError::InvalidElf);
|
||||||
}
|
}
|
||||||
|
Ok(VirtualAddr::new(program.entry))
|
||||||
for header in program
|
|
||||||
.program_headers()
|
|
||||||
.map_err(|_| ElfLoadError::InvalidElf)?
|
|
||||||
{
|
|
||||||
println!("Processing program header: {:?}", header);
|
|
||||||
let header = header.map_err(|_| ElfLoadError::InvalidElf)?;
|
|
||||||
|
|
||||||
if header.file_size > header.memory_size {
|
|
||||||
return Err(ElfLoadError::InvalidElf);
|
|
||||||
}
|
|
||||||
|
|
||||||
match header.segment_type {
|
|
||||||
format::elf::ProgramHeaderType::Load => {
|
|
||||||
// TODO: give a fuck about alignment
|
|
||||||
// TODO: handle program segments that overlap
|
|
||||||
let segment_start = header.virtual_address as usize;
|
|
||||||
if (program.entry() >= segment_start
|
|
||||||
&& program.entry() < segment_start + header.memory_size as usize)
|
|
||||||
&& header.flags & 0x01 == 0
|
|
||||||
{
|
|
||||||
// entry is within NX segment
|
|
||||||
return Err(ElfLoadError::InvalidElf);
|
|
||||||
}
|
|
||||||
|
|
||||||
let page_start = segment_start & !(FRAME_SIZE - 1);
|
|
||||||
let page_offset = segment_start - page_start;
|
|
||||||
|
|
||||||
let mapped_length = page_offset
|
|
||||||
.checked_add(header.memory_size as usize)
|
|
||||||
.ok_or(ElfLoadError::AddressOverflow)?
|
|
||||||
.div_ceil(FRAME_SIZE)
|
|
||||||
* FRAME_SIZE;
|
|
||||||
|
|
||||||
let frame_count = mapped_length / FRAME_SIZE;
|
|
||||||
|
|
||||||
let executable = header.flags & 0x01 != 0;
|
|
||||||
let writable = header.flags & 0x02 != 0;
|
|
||||||
// TODO: support only-executable segments
|
|
||||||
// let readable = header.flags & 0x04 != 0;
|
|
||||||
|
|
||||||
for i in 0..frame_count {
|
|
||||||
let frame = allocator.alloc().ok_or(ElfLoadError::OutOfMemory)?;
|
|
||||||
|
|
||||||
println!(
|
|
||||||
"Mapping code frame: {:X?} to {:X?}",
|
|
||||||
frame,
|
|
||||||
page_start + i * FRAME_SIZE
|
|
||||||
);
|
|
||||||
|
|
||||||
if user_address_space
|
|
||||||
.map(
|
|
||||||
frame.frame_address().start_address(),
|
|
||||||
VirtualAddr::new(page_start + i * FRAME_SIZE),
|
|
||||||
PagePermissions::new(writable, executable, true),
|
|
||||||
allocator,
|
|
||||||
memory::CachePolicy::WriteBack,
|
|
||||||
)
|
|
||||||
.is_err()
|
|
||||||
{
|
|
||||||
unsafe { allocator.dealloc(frame) };
|
|
||||||
return Err(ElfLoadError::FailedToMapSegment);
|
|
||||||
}
|
|
||||||
|
|
||||||
let _ = frame.into_raw();
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut copied = 0;
|
|
||||||
|
|
||||||
while copied < header.file_size as usize {
|
|
||||||
let destination = VirtualAddr::new(segment_start + copied);
|
|
||||||
let physical = user_address_space
|
|
||||||
.to_physical(destination)
|
|
||||||
.ok_or(ElfLoadError::AddressTranslationFailed)?;
|
|
||||||
let direct_mapped = direct_map
|
|
||||||
.translate(physical)
|
|
||||||
.ok_or(ElfLoadError::AddressTranslationFailed)?;
|
|
||||||
|
|
||||||
let page_remaining = FRAME_SIZE - destination.as_usize() % FRAME_SIZE;
|
|
||||||
let copy_length = page_remaining.min(header.file_size as usize - copied);
|
|
||||||
|
|
||||||
unsafe {
|
|
||||||
core::ptr::copy_nonoverlapping(
|
|
||||||
program
|
|
||||||
.bytes()
|
|
||||||
.as_ptr()
|
|
||||||
.add(header.file_offset as usize + copied),
|
|
||||||
direct_mapped.as_mut_ptr(),
|
|
||||||
copy_length,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
copied += copy_length;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
format::elf::ProgramHeaderType::GnuStack => {
|
|
||||||
// if the stack is NOT R/W NX, we refuse to map it
|
|
||||||
if header.flags != 6 {
|
|
||||||
return Err(ElfLoadError::InvalidStack);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(VirtualAddr::new(program.entry()))
|
|
||||||
}
|
}
|
||||||
|
|||||||
+70
-11
@@ -2,9 +2,11 @@ use core::cell::UnsafeCell;
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
arch::ThreadContext,
|
arch::ThreadContext,
|
||||||
memory::{AddressSpace, VirtualAddr},
|
memory::{
|
||||||
|
AddressSpace, FrameAllocator, KernelStack, KernelStackPool, StackCreateError, VirtualAddr,
|
||||||
|
},
|
||||||
println,
|
println,
|
||||||
task::tcb::{BlockReason, ExitReason, Tcb, ThreadState},
|
task::tcb::{BlockReason, ExitReason, Handle, KernelObject, Rights, Tcb, ThreadState},
|
||||||
};
|
};
|
||||||
|
|
||||||
const MAX_TASKS: usize = 32;
|
const MAX_TASKS: usize = 32;
|
||||||
@@ -15,6 +17,7 @@ struct Scheduler {
|
|||||||
current: Option<TaskId>,
|
current: Option<TaskId>,
|
||||||
tasks: [Option<Tcb>; MAX_TASKS],
|
tasks: [Option<Tcb>; MAX_TASKS],
|
||||||
ready: ReadyQueue,
|
ready: ReadyQueue,
|
||||||
|
stacks: KernelStackPool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Scheduler {
|
impl Scheduler {
|
||||||
@@ -23,6 +26,7 @@ impl Scheduler {
|
|||||||
current: None,
|
current: None,
|
||||||
tasks: [const { None }; MAX_TASKS],
|
tasks: [const { None }; MAX_TASKS],
|
||||||
ready: ReadyQueue::new(),
|
ready: ReadyQueue::new(),
|
||||||
|
stacks: KernelStackPool::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -31,19 +35,19 @@ impl Scheduler {
|
|||||||
|
|
||||||
let current = self.tasks[current_id].as_mut().unwrap();
|
let current = self.tasks[current_id].as_mut().unwrap();
|
||||||
let prev_ctx = &mut current.context as *mut ThreadContext;
|
let prev_ctx = &mut current.context as *mut ThreadContext;
|
||||||
let prev_addr_space = ¤t.address_space as *const AddressSpace;
|
let prev_as_id = current.as_id;
|
||||||
|
|
||||||
let next = self.tasks[next_id].as_ref().unwrap();
|
let next = self.tasks[next_id].as_ref().unwrap();
|
||||||
let next_ctx = &next.context as *const ThreadContext;
|
let next_ctx = &next.context as *const ThreadContext;
|
||||||
let next_addr_space = &next.address_space as *const AddressSpace;
|
let next_as_id = next.as_id;
|
||||||
let next_kernel_stack = next.kernel_stack.top();
|
let next_kernel_stack = next.kernel_stack.top();
|
||||||
|
|
||||||
Switch {
|
Switch {
|
||||||
previous_context: prev_ctx,
|
previous_context: prev_ctx,
|
||||||
next_context: next_ctx,
|
next_context: next_ctx,
|
||||||
next_address_space: next_addr_space,
|
next_as_id,
|
||||||
next_kernel_stack,
|
next_kernel_stack,
|
||||||
activate_address_space: unsafe { *next_addr_space != *prev_addr_space },
|
activate_address_space: next_as_id != prev_as_id,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -51,7 +55,7 @@ impl Scheduler {
|
|||||||
struct Switch {
|
struct Switch {
|
||||||
previous_context: *mut ThreadContext,
|
previous_context: *mut ThreadContext,
|
||||||
next_context: *const ThreadContext,
|
next_context: *const ThreadContext,
|
||||||
next_address_space: *const AddressSpace,
|
next_as_id: usize,
|
||||||
next_kernel_stack: VirtualAddr,
|
next_kernel_stack: VirtualAddr,
|
||||||
activate_address_space: bool,
|
activate_address_space: bool,
|
||||||
}
|
}
|
||||||
@@ -59,9 +63,9 @@ struct Switch {
|
|||||||
impl Switch {
|
impl Switch {
|
||||||
unsafe fn perform(self) {
|
unsafe fn perform(self) {
|
||||||
if self.activate_address_space {
|
if self.activate_address_space {
|
||||||
unsafe {
|
crate::memory::with_address_space(self.next_as_id, |as_ref| unsafe {
|
||||||
(&*self.next_address_space).activate();
|
as_ref.activate();
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
crate::arch::set_kernel_stack(self.next_kernel_stack);
|
crate::arch::set_kernel_stack(self.next_kernel_stack);
|
||||||
@@ -110,6 +114,23 @@ impl ReadyQueue {
|
|||||||
|
|
||||||
Some(task)
|
Some(task)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn remove(&mut self, task: TaskId) -> bool {
|
||||||
|
for i in 0..self.len {
|
||||||
|
let idx = (self.head + i) % MAX_TASKS;
|
||||||
|
if self.entries[idx] == task {
|
||||||
|
for j in i..(self.len - 1) {
|
||||||
|
let from = (self.head + j + 1) % MAX_TASKS;
|
||||||
|
let to = (self.head + j) % MAX_TASKS;
|
||||||
|
self.entries[to] = self.entries[from];
|
||||||
|
}
|
||||||
|
self.len -= 1;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct GlobalScheduler(UnsafeCell<Scheduler>);
|
struct GlobalScheduler(UnsafeCell<Scheduler>);
|
||||||
@@ -127,6 +148,12 @@ pub fn add_task(mut task: Tcb) -> Result<TaskId, Tcb> {
|
|||||||
match scheduler.tasks.iter().position(Option::is_none) {
|
match scheduler.tasks.iter().position(Option::is_none) {
|
||||||
Some(id) => {
|
Some(id) => {
|
||||||
task.id = id;
|
task.id = id;
|
||||||
|
|
||||||
|
task.handles.push(Handle {
|
||||||
|
object: KernelObject::Thread(id),
|
||||||
|
rights: Rights::READ | Rights::WRITE | Rights::EXECUTE,
|
||||||
|
});
|
||||||
|
|
||||||
task.state = ThreadState::Ready;
|
task.state = ThreadState::Ready;
|
||||||
scheduler.tasks[id] = Some(task);
|
scheduler.tasks[id] = Some(task);
|
||||||
assert!(scheduler.ready.push_back(id));
|
assert!(scheduler.ready.push_back(id));
|
||||||
@@ -159,7 +186,7 @@ pub fn start() -> ! {
|
|||||||
Switch {
|
Switch {
|
||||||
previous_context: &mut bootstrap_context,
|
previous_context: &mut bootstrap_context,
|
||||||
next_context: &next.context,
|
next_context: &next.context,
|
||||||
next_address_space: &next.address_space,
|
next_as_id: next.as_id,
|
||||||
next_kernel_stack: next.kernel_stack.top(),
|
next_kernel_stack: next.kernel_stack.top(),
|
||||||
activate_address_space: true,
|
activate_address_space: true,
|
||||||
}
|
}
|
||||||
@@ -172,6 +199,38 @@ pub fn start() -> ! {
|
|||||||
panic!("scheduler returned to bootstrap context");
|
panic!("scheduler returned to bootstrap context");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn allocate_kernel_stack(
|
||||||
|
address_space: &mut AddressSpace,
|
||||||
|
allocator: &mut FrameAllocator,
|
||||||
|
) -> Result<KernelStack, StackCreateError> {
|
||||||
|
let interrupt_state = crate::arch::disable_interrupts_and_save();
|
||||||
|
let scheduler = unsafe { &mut *SCHEDULER.0.get() };
|
||||||
|
let result = scheduler.stacks.allocate(address_space, allocator);
|
||||||
|
crate::arch::restore_interrupts(interrupt_state);
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn remove_task(id: TaskId) -> Option<Tcb> {
|
||||||
|
let interrupt_state = crate::arch::disable_interrupts_and_save();
|
||||||
|
|
||||||
|
let result = {
|
||||||
|
let scheduler = unsafe { &mut *SCHEDULER.0.get() };
|
||||||
|
|
||||||
|
if scheduler.current == Some(id) {
|
||||||
|
None
|
||||||
|
} else if let Some(task) = scheduler.tasks.get_mut(id).and_then(Option::take) {
|
||||||
|
scheduler.ready.remove(id);
|
||||||
|
scheduler.stacks.free(&task.kernel_stack);
|
||||||
|
Some(task)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
crate::arch::restore_interrupts(interrupt_state);
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get_task(id: TaskId) -> Option<&'static Tcb> {
|
pub fn get_task(id: TaskId) -> Option<&'static Tcb> {
|
||||||
let scheduler = unsafe { &mut *SCHEDULER.0.get() };
|
let scheduler = unsafe { &mut *SCHEDULER.0.get() };
|
||||||
scheduler.tasks.get(id).and_then(Option::as_ref)
|
scheduler.tasks.get(id).and_then(Option::as_ref)
|
||||||
|
|||||||
+87
-7
@@ -1,6 +1,8 @@
|
|||||||
|
use core::ops::BitOr;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
arch::ThreadContext,
|
arch::ThreadContext,
|
||||||
memory::{AddressSpace, KernelStack, VirtualAddr},
|
memory::{FrameAddr, KernelStack, VirtualAddr},
|
||||||
};
|
};
|
||||||
|
|
||||||
// Thread Control Block
|
// Thread Control Block
|
||||||
@@ -29,14 +31,13 @@ pub enum ThreadState {
|
|||||||
pub const MAX_MSG_SIZE: usize = 128;
|
pub const MAX_MSG_SIZE: usize = 128;
|
||||||
pub const MAILBOX_CAPACITY: usize = 4;
|
pub const MAILBOX_CAPACITY: usize = 4;
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy)]
|
||||||
pub struct Message {
|
pub struct Message {
|
||||||
pub sender: usize,
|
pub sender: usize,
|
||||||
pub length: usize,
|
pub length: usize,
|
||||||
pub data: [u8; MAX_MSG_SIZE],
|
pub data: [u8; MAX_MSG_SIZE],
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct Mailbox {
|
pub struct Mailbox {
|
||||||
pub messages: [Option<Message>; MAILBOX_CAPACITY],
|
pub messages: [Option<Message>; MAILBOX_CAPACITY],
|
||||||
pub head: usize,
|
pub head: usize,
|
||||||
@@ -75,33 +76,112 @@ impl Mailbox {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
const MAX_HANDLES: usize = 32;
|
||||||
|
|
||||||
|
pub enum KernelObject {
|
||||||
|
AddressSpace(usize),
|
||||||
|
Frame(FrameAddr),
|
||||||
|
Thread(usize),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Handle {
|
||||||
|
pub object: KernelObject,
|
||||||
|
pub rights: Rights,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
pub struct Rights(pub u32);
|
||||||
|
|
||||||
|
impl Rights {
|
||||||
|
pub const READ: Self = Self(1 << 0);
|
||||||
|
pub const WRITE: Self = Self(1 << 1);
|
||||||
|
pub const EXECUTE: Self = Self(1 << 2);
|
||||||
|
pub const MAP: Self = Self(1 << 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BitOr for Rights {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn bitor(self, rhs: Self) -> Self::Output {
|
||||||
|
Self(self.0 | rhs.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct HandleTable {
|
||||||
|
handles: [Option<Handle>; MAX_HANDLES],
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HandleTable {
|
||||||
|
pub const fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
handles: [const { None }; MAX_HANDLES],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn push(&mut self, handle: Handle) -> Option<usize> {
|
||||||
|
for (i, slot) in self.handles.iter_mut().enumerate() {
|
||||||
|
if slot.is_none() {
|
||||||
|
*slot = Some(handle);
|
||||||
|
return Some(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get(&self, id: usize) -> Option<&Handle> {
|
||||||
|
self.handles.get(id).and_then(Option::as_ref)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_mut(&mut self, id: usize) -> Option<&mut Handle> {
|
||||||
|
self.handles.get_mut(id).and_then(Option::as_mut)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct Tcb {
|
pub struct Tcb {
|
||||||
pub id: usize,
|
pub id: usize,
|
||||||
|
pub as_id: usize,
|
||||||
pub state: ThreadState,
|
pub state: ThreadState,
|
||||||
pub kernel_stack: KernelStack,
|
pub kernel_stack: KernelStack,
|
||||||
pub context: ThreadContext,
|
pub context: ThreadContext,
|
||||||
pub address_space: AddressSpace,
|
|
||||||
pub mailbox: Mailbox,
|
pub mailbox: Mailbox,
|
||||||
|
pub handles: HandleTable,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl core::fmt::Debug for Tcb {
|
||||||
|
fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||||
|
formatter
|
||||||
|
.debug_struct("Tcb")
|
||||||
|
.field("id", &self.id)
|
||||||
|
.field("as_id", &self.as_id)
|
||||||
|
.field("state", &self.state)
|
||||||
|
.finish_non_exhaustive()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Tcb {
|
impl Tcb {
|
||||||
pub fn new_user(
|
pub fn new_user(
|
||||||
id: usize,
|
id: usize,
|
||||||
address_space: AddressSpace,
|
as_id: usize,
|
||||||
kernel_stack: KernelStack,
|
kernel_stack: KernelStack,
|
||||||
entry: VirtualAddr,
|
entry: VirtualAddr,
|
||||||
user_stack: VirtualAddr,
|
user_stack: VirtualAddr,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let context = ThreadContext::new(entry, user_stack, kernel_stack.top());
|
let context = ThreadContext::new(entry, user_stack, kernel_stack.top());
|
||||||
|
let mut handles = HandleTable::new();
|
||||||
|
handles.push(Handle {
|
||||||
|
object: KernelObject::AddressSpace(as_id),
|
||||||
|
rights: Rights::READ | Rights::WRITE | Rights::EXECUTE,
|
||||||
|
});
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
id,
|
id,
|
||||||
|
as_id,
|
||||||
state: ThreadState::Ready,
|
state: ThreadState::Ready,
|
||||||
kernel_stack,
|
kernel_stack,
|
||||||
context,
|
context,
|
||||||
address_space,
|
|
||||||
mailbox: Mailbox::new(),
|
mailbox: Mailbox::new(),
|
||||||
|
handles,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,15 +7,18 @@ use dusk_sys::{println, sys_exit, sys_recv, sys_send};
|
|||||||
pub extern "C" fn _start() -> ! {
|
pub extern "C" fn _start() -> ! {
|
||||||
let msg = "Hello from client!";
|
let msg = "Hello from client!";
|
||||||
println!("[client] Sent: {}", msg);
|
println!("[client] Sent: {}", msg);
|
||||||
sys_send(0, msg.as_ptr() as usize, msg.len()).unwrap();
|
// TODO: we assume the echo server is task 1 (spawned by omega3)
|
||||||
|
sys_send(1, msg.as_ptr() as usize, msg.len()).unwrap();
|
||||||
|
|
||||||
let out = [0u8; 128];
|
let out = [0u8; 128];
|
||||||
let out_ptr = out.as_ptr() as usize;
|
let out_ptr = out.as_ptr() as usize;
|
||||||
let max_len = out.len();
|
let max_len = out.len();
|
||||||
let (actual_len, sender) = sys_recv(out_ptr, max_len).unwrap();
|
let (actual_len, _) = sys_recv(out_ptr, max_len).unwrap();
|
||||||
println!(
|
println!(
|
||||||
"[client] Received: {}",
|
"[client] Received: {}",
|
||||||
core::str::from_utf8(&out[..actual_len]).unwrap()
|
core::str::from_utf8(&out[..actual_len]).unwrap()
|
||||||
);
|
);
|
||||||
|
|
||||||
sys_exit(0);
|
sys_exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,6 +12,14 @@ pub enum Status {
|
|||||||
OutOfMemory = 5,
|
OutOfMemory = 5,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Opaque handle type
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||||
|
pub struct Handle(usize);
|
||||||
|
|
||||||
|
// our own address space and thread handle are always given to us
|
||||||
|
pub const SELF_AS: Handle = Handle(0);
|
||||||
|
pub const SELF_THREAD: Handle = Handle(1);
|
||||||
|
|
||||||
impl From<usize> for Status {
|
impl From<usize> for Status {
|
||||||
fn from(value: usize) -> Self {
|
fn from(value: usize) -> Self {
|
||||||
match value {
|
match value {
|
||||||
@@ -25,6 +33,21 @@ impl From<usize> for Status {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[repr(u64)]
|
||||||
|
pub enum SyscallNumber {
|
||||||
|
Yield = 1,
|
||||||
|
Exit = 2,
|
||||||
|
Write = 3,
|
||||||
|
Send = 4,
|
||||||
|
Recv = 5,
|
||||||
|
FrameAlloc = 6,
|
||||||
|
FrameDealloc = 7,
|
||||||
|
AsCreate = 8,
|
||||||
|
Map = 9,
|
||||||
|
Unmap = 10,
|
||||||
|
TaskCreate = 11,
|
||||||
|
}
|
||||||
|
|
||||||
pub fn sys_yield() {
|
pub fn sys_yield() {
|
||||||
unsafe {
|
unsafe {
|
||||||
asm!(
|
asm!(
|
||||||
@@ -46,7 +69,7 @@ fn debug_write(buf: &str) -> Result<(), Status> {
|
|||||||
in("rsi") buf.as_ptr(),
|
in("rsi") buf.as_ptr(),
|
||||||
in("rdx") buf.len(),
|
in("rdx") buf.len(),
|
||||||
in("r10") 0,
|
in("r10") 0,
|
||||||
inlateout("rax") 3usize => status,
|
inlateout("rax") SyscallNumber::Write as usize => status,
|
||||||
lateout("rcx") _,
|
lateout("rcx") _,
|
||||||
lateout("r11") _
|
lateout("r11") _
|
||||||
);
|
);
|
||||||
@@ -96,7 +119,7 @@ pub fn sys_exit(exit_code: usize) -> ! {
|
|||||||
asm!(
|
asm!(
|
||||||
"syscall",
|
"syscall",
|
||||||
in("rdi") exit_code,
|
in("rdi") exit_code,
|
||||||
in("rax") 2usize,
|
in("rax") SyscallNumber::Exit as usize,
|
||||||
options(noreturn)
|
options(noreturn)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -111,7 +134,7 @@ pub fn sys_send(dest_task_id: usize, msg_ptr: usize, len: usize) -> Result<(), S
|
|||||||
in("rdi") dest_task_id,
|
in("rdi") dest_task_id,
|
||||||
in("rsi") msg_ptr,
|
in("rsi") msg_ptr,
|
||||||
in("rdx") len,
|
in("rdx") len,
|
||||||
inlateout("rax") 4usize => status,
|
inlateout("rax") SyscallNumber::Send as usize => status,
|
||||||
lateout("rcx") _,
|
lateout("rcx") _,
|
||||||
lateout("r11") _,
|
lateout("r11") _,
|
||||||
);
|
);
|
||||||
@@ -137,7 +160,7 @@ pub fn sys_recv(buf_ptr: usize, max_len: usize) -> Result<(usize, usize), Status
|
|||||||
in("rsi") max_len,
|
in("rsi") max_len,
|
||||||
in("rdx") &raw mut actual_len as usize,
|
in("rdx") &raw mut actual_len as usize,
|
||||||
in("r10") &raw mut sender as usize,
|
in("r10") &raw mut sender as usize,
|
||||||
inlateout("rax") 5usize => status,
|
inlateout("rax") SyscallNumber::Recv as usize => status,
|
||||||
lateout("rcx") _,
|
lateout("rcx") _,
|
||||||
lateout("r11") _,
|
lateout("r11") _,
|
||||||
);
|
);
|
||||||
@@ -149,3 +172,143 @@ pub fn sys_recv(buf_ptr: usize, max_len: usize) -> Result<(usize, usize), Status
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn sys_frame_alloc() -> Result<Handle, Status> {
|
||||||
|
let mut handle: usize = 0;
|
||||||
|
unsafe {
|
||||||
|
let status: usize;
|
||||||
|
|
||||||
|
asm!(
|
||||||
|
"syscall",
|
||||||
|
in("rdi") &raw mut handle as usize,
|
||||||
|
inlateout("rax") SyscallNumber::FrameAlloc as usize => status,
|
||||||
|
lateout("rcx") _,
|
||||||
|
lateout("r11") _,
|
||||||
|
);
|
||||||
|
|
||||||
|
if status != 0 {
|
||||||
|
Err(status.into())
|
||||||
|
} else {
|
||||||
|
Ok(Handle(handle))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sys_frame_dealloc(frame_handle: Handle) -> Result<(), Status> {
|
||||||
|
unsafe {
|
||||||
|
let status: usize;
|
||||||
|
|
||||||
|
asm!(
|
||||||
|
"syscall",
|
||||||
|
in("rdi") frame_handle.0,
|
||||||
|
inlateout("rax") SyscallNumber::FrameDealloc as usize => status,
|
||||||
|
lateout("rcx") _,
|
||||||
|
lateout("r11") _,
|
||||||
|
);
|
||||||
|
|
||||||
|
if status != 0 {
|
||||||
|
Err(status.into())
|
||||||
|
} else {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sys_as_create() -> Result<Handle, Status> {
|
||||||
|
let mut handle: usize = 0;
|
||||||
|
unsafe {
|
||||||
|
let status: usize;
|
||||||
|
|
||||||
|
asm!(
|
||||||
|
"syscall",
|
||||||
|
in("rdi") &raw mut handle as usize,
|
||||||
|
inlateout("rax") SyscallNumber::AsCreate as usize => status,
|
||||||
|
lateout("rcx") _,
|
||||||
|
lateout("r11") _,
|
||||||
|
);
|
||||||
|
|
||||||
|
if status != 0 {
|
||||||
|
Err(status.into())
|
||||||
|
} else {
|
||||||
|
Ok(Handle(handle))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sys_map(
|
||||||
|
as_handle: Handle,
|
||||||
|
frame_handle: Handle,
|
||||||
|
virtual_addr: usize,
|
||||||
|
permissions: usize,
|
||||||
|
) -> Result<(), Status> {
|
||||||
|
unsafe {
|
||||||
|
let status: usize;
|
||||||
|
|
||||||
|
asm!(
|
||||||
|
"syscall",
|
||||||
|
in("rdi") as_handle.0,
|
||||||
|
in("rsi") frame_handle.0,
|
||||||
|
in("rdx") virtual_addr,
|
||||||
|
in("r10") permissions,
|
||||||
|
inlateout("rax") SyscallNumber::Map as usize => status,
|
||||||
|
lateout("rcx") _,
|
||||||
|
lateout("r11") _,
|
||||||
|
);
|
||||||
|
|
||||||
|
if status != 0 {
|
||||||
|
Err(status.into())
|
||||||
|
} else {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sys_unmap(as_handle: Handle, virtual_addr: usize) -> Result<(), Status> {
|
||||||
|
unsafe {
|
||||||
|
let status: usize;
|
||||||
|
|
||||||
|
asm!(
|
||||||
|
"syscall",
|
||||||
|
in("rdi") as_handle.0,
|
||||||
|
in("rsi") virtual_addr,
|
||||||
|
inlateout("rax") SyscallNumber::Unmap as usize => status,
|
||||||
|
lateout("rcx") _,
|
||||||
|
lateout("r11") _,
|
||||||
|
);
|
||||||
|
|
||||||
|
if status != 0 {
|
||||||
|
Err(status.into())
|
||||||
|
} else {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sys_task_create(
|
||||||
|
as_handle: Handle,
|
||||||
|
entry: usize,
|
||||||
|
user_stack: usize,
|
||||||
|
) -> Result<Handle, Status> {
|
||||||
|
let mut handle: usize = 0;
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
let status: usize;
|
||||||
|
|
||||||
|
asm!(
|
||||||
|
"syscall",
|
||||||
|
in("rdi") as_handle.0,
|
||||||
|
in("rsi") entry,
|
||||||
|
in("rdx") user_stack,
|
||||||
|
in("r10") &raw mut handle as usize,
|
||||||
|
inlateout("rax") SyscallNumber::TaskCreate as usize => status,
|
||||||
|
lateout("rcx") _,
|
||||||
|
lateout("r11") _,
|
||||||
|
);
|
||||||
|
|
||||||
|
if status != 0 {
|
||||||
|
Err(status.into())
|
||||||
|
} else {
|
||||||
|
Ok(Handle(handle))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
[package]
|
||||||
|
name = "echo"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2024"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
dusk-sys = { path = "../dusk-sys" }
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "echo"
|
||||||
|
test = false
|
||||||
|
bench = false
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
#![no_std]
|
||||||
|
#![no_main]
|
||||||
|
|
||||||
|
use dusk_sys::{println, sys_exit, sys_recv, sys_send};
|
||||||
|
|
||||||
|
#[unsafe(no_mangle)]
|
||||||
|
pub extern "C" fn _start() -> ! {
|
||||||
|
let out = [0u8; 128];
|
||||||
|
loop {
|
||||||
|
let (actual_len, sender) = sys_recv(out.as_ptr() as usize, out.len()).unwrap();
|
||||||
|
println!(
|
||||||
|
"[echo] Received: {}",
|
||||||
|
core::str::from_utf8(&out[..actual_len]).unwrap()
|
||||||
|
);
|
||||||
|
sys_send(sender, out.as_ptr() as usize, actual_len).unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[panic_handler]
|
||||||
|
fn panic(info: &core::panic::PanicInfo) -> ! {
|
||||||
|
println!("{info}");
|
||||||
|
sys_exit(1);
|
||||||
|
}
|
||||||
@@ -0,0 +1,73 @@
|
|||||||
|
// CPIO newc archive parser
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
struct Header {
|
||||||
|
pub c_magic: [u8; 6],
|
||||||
|
pub c_ino: [u8; 8],
|
||||||
|
pub c_mode: [u8; 8],
|
||||||
|
pub c_uid: [u8; 8],
|
||||||
|
pub c_gid: [u8; 8],
|
||||||
|
pub c_nlink: [u8; 8],
|
||||||
|
pub c_mtime: [u8; 8],
|
||||||
|
pub c_filesize: [u8; 8],
|
||||||
|
pub c_devmajor: [u8; 8],
|
||||||
|
pub c_devminor: [u8; 8],
|
||||||
|
pub c_rdevmajor: [u8; 8],
|
||||||
|
pub c_rdevminor: [u8; 8],
|
||||||
|
pub c_namesize: [u8; 8],
|
||||||
|
pub c_check: [u8; 8],
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Header {
|
||||||
|
pub fn from_bytes(bytes: &[u8]) -> Option<Self> {
|
||||||
|
if bytes.len() < core::mem::size_of::<Header>() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
let header: Header = unsafe { core::ptr::read(bytes.as_ptr() as *const Header) };
|
||||||
|
|
||||||
|
if header.c_magic != *b"070701" {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
Some(header)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn find_file<'a>(archive: *const u8, target: &str) -> Option<&'a [u8]> {
|
||||||
|
let mut offset = 0;
|
||||||
|
|
||||||
|
loop {
|
||||||
|
let header = Header::from_bytes(&unsafe {
|
||||||
|
core::slice::from_raw_parts(archive.add(offset), core::mem::size_of::<Header>())
|
||||||
|
})?;
|
||||||
|
let header_start = offset;
|
||||||
|
offset += core::mem::size_of::<Header>();
|
||||||
|
|
||||||
|
let file_len =
|
||||||
|
usize::from_str_radix(core::str::from_utf8(&header.c_filesize).ok()?, 16).ok()?;
|
||||||
|
let name_len =
|
||||||
|
usize::from_str_radix(core::str::from_utf8(&header.c_namesize).ok()?, 16).ok()?;
|
||||||
|
|
||||||
|
let name_bytes = &unsafe { core::slice::from_raw_parts(archive.add(offset), name_len) };
|
||||||
|
let name = core::str::from_utf8(name_bytes)
|
||||||
|
.ok()?
|
||||||
|
.trim_end_matches('\0');
|
||||||
|
|
||||||
|
if name == "TRAILER!!!" {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
let data_start = header_start + ((core::mem::size_of::<Header>() + name_len + 3) & !3);
|
||||||
|
|
||||||
|
if name == target {
|
||||||
|
return Some(&unsafe {
|
||||||
|
core::slice::from_raw_parts(archive.add(data_start), file_len)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
offset = data_start + ((file_len + 3) & !3);
|
||||||
|
}
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
||||||
@@ -0,0 +1,425 @@
|
|||||||
|
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||||
|
pub enum ElfIsa {
|
||||||
|
None,
|
||||||
|
Sparc,
|
||||||
|
X86,
|
||||||
|
Mips,
|
||||||
|
Ppc,
|
||||||
|
Arm,
|
||||||
|
SuperH,
|
||||||
|
Ia64,
|
||||||
|
Amd64,
|
||||||
|
AArch64,
|
||||||
|
Riscv,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ElfIsa {
|
||||||
|
fn from_u16(value: u16) -> Result<Self, ElfError> {
|
||||||
|
match value {
|
||||||
|
0x00 => Ok(Self::None),
|
||||||
|
0x02 => Ok(Self::Sparc),
|
||||||
|
0x03 => Ok(Self::X86),
|
||||||
|
0x08 => Ok(Self::Mips),
|
||||||
|
0x14 => Ok(Self::Ppc),
|
||||||
|
0x28 => Ok(Self::Arm),
|
||||||
|
0x2A => Ok(Self::SuperH),
|
||||||
|
0x32 => Ok(Self::Ia64),
|
||||||
|
0x3E => Ok(Self::Amd64),
|
||||||
|
0xB7 => Ok(Self::AArch64),
|
||||||
|
0xF3 => Ok(Self::Riscv),
|
||||||
|
_ => Err(ElfError::InvalidElf),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||||
|
pub enum ElfClass {
|
||||||
|
Elf32,
|
||||||
|
Elf64,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ElfClass {
|
||||||
|
fn from_u8(value: u8) -> Result<Self, ElfError> {
|
||||||
|
match value {
|
||||||
|
1 => Ok(Self::Elf32),
|
||||||
|
2 => Ok(Self::Elf64),
|
||||||
|
_ => Err(ElfError::InvalidElf),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const fn header_size(self) -> u16 {
|
||||||
|
match self {
|
||||||
|
Self::Elf32 => 52,
|
||||||
|
Self::Elf64 => 64,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||||
|
pub enum Endianness {
|
||||||
|
Little,
|
||||||
|
Big,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Endianness {
|
||||||
|
fn from_u8(value: u8) -> Result<Self, ElfError> {
|
||||||
|
match value {
|
||||||
|
1 => Ok(Self::Little),
|
||||||
|
2 => Ok(Self::Big),
|
||||||
|
_ => Err(ElfError::InvalidElf),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(u16)]
|
||||||
|
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||||
|
pub enum ElfType {
|
||||||
|
Relocatable = 1,
|
||||||
|
Executable = 2,
|
||||||
|
SharedObject = 3,
|
||||||
|
Core = 4,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ElfType {
|
||||||
|
fn from_u16(value: u16) -> Result<Self, ElfError> {
|
||||||
|
match value {
|
||||||
|
1 => Ok(Self::Relocatable),
|
||||||
|
2 => Ok(Self::Executable),
|
||||||
|
3 => Ok(Self::SharedObject),
|
||||||
|
4 => Ok(Self::Core),
|
||||||
|
_ => Err(ElfError::InvalidElf),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
#[allow(unused)]
|
||||||
|
pub struct ElfHeader {
|
||||||
|
magic: [u8; 4],
|
||||||
|
pub class: ElfClass,
|
||||||
|
endianness: Endianness,
|
||||||
|
version: u8,
|
||||||
|
os_abi: u8,
|
||||||
|
_reserved: [u8; 8],
|
||||||
|
pub object_type: ElfType,
|
||||||
|
pub machine: ElfIsa,
|
||||||
|
version_1: u32,
|
||||||
|
entry: u64, // 2115136
|
||||||
|
program_header_offset: u64, // 64
|
||||||
|
section_header_offset: u64, // 2759752
|
||||||
|
flags: u32, // 0
|
||||||
|
header_size: u16, // 64
|
||||||
|
program_header_entry_size: u16, // 56
|
||||||
|
program_header_count: u16, // 6
|
||||||
|
section_header_entry_size: u16, // 64
|
||||||
|
section_header_count: u16, // 17
|
||||||
|
section_name_index: u16, // 15
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum ElfError {
|
||||||
|
InvalidElf,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ElfHeader {
|
||||||
|
pub fn parse(bytes: &[u8]) -> Result<Self, ElfError> {
|
||||||
|
let mut reader = Reader::new(bytes);
|
||||||
|
|
||||||
|
let magic = reader.read_array()?;
|
||||||
|
if magic != *b"\x7fELF" {
|
||||||
|
return Err(ElfError::InvalidElf);
|
||||||
|
}
|
||||||
|
|
||||||
|
let class = ElfClass::from_u8(reader.read_u8()?)?;
|
||||||
|
let endianness = Endianness::from_u8(reader.read_u8()?)?;
|
||||||
|
reader.set_endianness(endianness);
|
||||||
|
|
||||||
|
let version = reader.read_u8()?;
|
||||||
|
let os_abi = reader.read_u8()?;
|
||||||
|
let reserved = reader.read_array()?;
|
||||||
|
let object_type = ElfType::from_u16(reader.read_u16()?)?;
|
||||||
|
let machine = ElfIsa::from_u16(reader.read_u16()?)?;
|
||||||
|
let version_1 = reader.read_u32()?;
|
||||||
|
let entry = reader.read_word(class)?;
|
||||||
|
let program_header_offset = reader.read_word(class)?;
|
||||||
|
let section_header_offset = reader.read_word(class)?;
|
||||||
|
let flags = reader.read_u32()?;
|
||||||
|
let header_size = reader.read_u16()?;
|
||||||
|
let program_header_entry_size = reader.read_u16()?;
|
||||||
|
let program_header_count = reader.read_u16()?;
|
||||||
|
let section_header_entry_size = reader.read_u16()?;
|
||||||
|
let section_header_count = reader.read_u16()?;
|
||||||
|
let section_name_index = reader.read_u16()?;
|
||||||
|
|
||||||
|
if header_size != class.header_size() {
|
||||||
|
return Err(ElfError::InvalidElf);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(Self {
|
||||||
|
magic,
|
||||||
|
class,
|
||||||
|
endianness,
|
||||||
|
version,
|
||||||
|
os_abi,
|
||||||
|
_reserved: reserved,
|
||||||
|
object_type,
|
||||||
|
machine,
|
||||||
|
version_1,
|
||||||
|
entry,
|
||||||
|
program_header_offset,
|
||||||
|
section_header_offset,
|
||||||
|
flags,
|
||||||
|
header_size,
|
||||||
|
program_header_entry_size,
|
||||||
|
program_header_count,
|
||||||
|
section_header_entry_size,
|
||||||
|
section_header_count,
|
||||||
|
section_name_index,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(u32)]
|
||||||
|
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||||
|
pub enum ProgramHeaderType {
|
||||||
|
Null = 0,
|
||||||
|
Load = 1,
|
||||||
|
Dynamic = 2,
|
||||||
|
Interpreter = 3,
|
||||||
|
Note = 4,
|
||||||
|
Shlib = 5,
|
||||||
|
Phdr = 6,
|
||||||
|
GnuStack = 0x6474e551,
|
||||||
|
Relro = 0x6474e552,
|
||||||
|
Other(u32),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ProgramHeaderType {
|
||||||
|
fn from_u32(value: u32) -> Self {
|
||||||
|
match value {
|
||||||
|
0 => Self::Null,
|
||||||
|
1 => Self::Load,
|
||||||
|
2 => Self::Dynamic,
|
||||||
|
3 => Self::Interpreter,
|
||||||
|
4 => Self::Note,
|
||||||
|
5 => Self::Shlib,
|
||||||
|
6 => Self::Phdr,
|
||||||
|
0x6474e551 => Self::GnuStack,
|
||||||
|
0x6474e552 => Self::Relro,
|
||||||
|
_ => Self::Other(value),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
#[allow(unused)]
|
||||||
|
pub struct ProgramHeader {
|
||||||
|
pub segment_type: ProgramHeaderType,
|
||||||
|
pub flags: u32,
|
||||||
|
pub file_offset: u64,
|
||||||
|
pub virtual_address: u64,
|
||||||
|
_physical_address: u64,
|
||||||
|
pub file_size: u64,
|
||||||
|
pub memory_size: u64,
|
||||||
|
pub alignment: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ProgramHeader {
|
||||||
|
pub fn parse(bytes: &[u8], class: ElfClass, endianness: Endianness) -> Result<Self, ElfError> {
|
||||||
|
let mut reader = Reader::new(bytes);
|
||||||
|
reader.set_endianness(endianness);
|
||||||
|
|
||||||
|
let segment_type = ProgramHeaderType::from_u32(reader.read_u32()?);
|
||||||
|
|
||||||
|
let flags = if class == ElfClass::Elf64 {
|
||||||
|
reader.read_u32()?
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
};
|
||||||
|
|
||||||
|
let file_offset = reader.read_word(class)?;
|
||||||
|
let virtual_address = reader.read_word(class)?;
|
||||||
|
let physical_address = reader.read_word(class)?;
|
||||||
|
let file_size = reader.read_word(class)?;
|
||||||
|
let memory_size = reader.read_word(class)?;
|
||||||
|
|
||||||
|
let flags = if class == ElfClass::Elf32 {
|
||||||
|
reader.read_u32()?
|
||||||
|
} else {
|
||||||
|
flags
|
||||||
|
};
|
||||||
|
|
||||||
|
let alignment = reader.read_word(class)?;
|
||||||
|
|
||||||
|
Ok(Self {
|
||||||
|
segment_type,
|
||||||
|
flags,
|
||||||
|
file_offset,
|
||||||
|
virtual_address,
|
||||||
|
_physical_address: physical_address,
|
||||||
|
file_size,
|
||||||
|
memory_size,
|
||||||
|
alignment,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Elf<'a> {
|
||||||
|
bytes: &'a [u8],
|
||||||
|
header: ElfHeader,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Elf<'a> {
|
||||||
|
pub fn parse(bytes: &'a [u8]) -> Result<Self, ElfError> {
|
||||||
|
let header = ElfHeader::parse(bytes)?;
|
||||||
|
|
||||||
|
Ok(Self { bytes, header })
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn program_headers(&self) -> Result<ProgramHeaders<'_>, ElfError> {
|
||||||
|
let offset =
|
||||||
|
usize::try_from(self.header.program_header_offset).map_err(|_| ElfError::InvalidElf)?;
|
||||||
|
let entry_size = usize::from(self.header.program_header_entry_size);
|
||||||
|
let count = usize::from(self.header.program_header_count);
|
||||||
|
|
||||||
|
let expected_entry_size = match self.header.class {
|
||||||
|
ElfClass::Elf32 => 32,
|
||||||
|
ElfClass::Elf64 => 56,
|
||||||
|
};
|
||||||
|
|
||||||
|
if entry_size != expected_entry_size {
|
||||||
|
return Err(ElfError::InvalidElf);
|
||||||
|
}
|
||||||
|
|
||||||
|
let table_size = entry_size.checked_mul(count).ok_or(ElfError::InvalidElf)?;
|
||||||
|
let table_end = offset.checked_add(table_size).ok_or(ElfError::InvalidElf)?;
|
||||||
|
let bytes = self
|
||||||
|
.bytes
|
||||||
|
.get(offset..table_end)
|
||||||
|
.ok_or(ElfError::InvalidElf)?;
|
||||||
|
|
||||||
|
Ok(ProgramHeaders {
|
||||||
|
bytes,
|
||||||
|
class: self.header.class,
|
||||||
|
endianness: self.header.endianness,
|
||||||
|
entry_size,
|
||||||
|
remaining: count,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn bytes(&self) -> &[u8] {
|
||||||
|
self.bytes
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(unused)]
|
||||||
|
pub fn machine(&self) -> ElfIsa {
|
||||||
|
self.header.machine
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn entry(&self) -> usize {
|
||||||
|
self.header.entry as usize
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct ProgramHeaders<'a> {
|
||||||
|
bytes: &'a [u8],
|
||||||
|
class: ElfClass,
|
||||||
|
endianness: Endianness,
|
||||||
|
entry_size: usize,
|
||||||
|
remaining: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Iterator for ProgramHeaders<'a> {
|
||||||
|
type Item = Result<ProgramHeader, ElfError>;
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
if self.remaining == 0 {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
let entry = match self.bytes.get(..self.entry_size) {
|
||||||
|
Some(entry) => entry,
|
||||||
|
None => {
|
||||||
|
self.remaining = 0;
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
self.bytes = &self.bytes[self.entry_size..];
|
||||||
|
self.remaining -= 1;
|
||||||
|
|
||||||
|
Some(ProgramHeader::parse(entry, self.class, self.endianness))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||||
|
(self.remaining, Some(self.remaining))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ExactSizeIterator for ProgramHeaders<'_> {}
|
||||||
|
|
||||||
|
struct Reader<'a> {
|
||||||
|
bytes: &'a [u8],
|
||||||
|
offset: usize,
|
||||||
|
endianness: Endianness,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Reader<'a> {
|
||||||
|
const fn new(bytes: &'a [u8]) -> Self {
|
||||||
|
Self {
|
||||||
|
bytes,
|
||||||
|
offset: 0,
|
||||||
|
endianness: Endianness::Little,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_endianness(&mut self, endianness: Endianness) {
|
||||||
|
self.endianness = endianness;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read_array<const N: usize>(&mut self) -> Result<[u8; N], ElfError> {
|
||||||
|
let end = self.offset.checked_add(N).ok_or(ElfError::InvalidElf)?;
|
||||||
|
let bytes = self
|
||||||
|
.bytes
|
||||||
|
.get(self.offset..end)
|
||||||
|
.ok_or(ElfError::InvalidElf)?;
|
||||||
|
self.offset = end;
|
||||||
|
|
||||||
|
bytes.try_into().map_err(|_| ElfError::InvalidElf)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read_u8(&mut self) -> Result<u8, ElfError> {
|
||||||
|
Ok(self.read_array::<1>()?[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read_u16(&mut self) -> Result<u16, ElfError> {
|
||||||
|
let bytes = self.read_array()?;
|
||||||
|
Ok(match self.endianness {
|
||||||
|
Endianness::Little => u16::from_le_bytes(bytes),
|
||||||
|
Endianness::Big => u16::from_be_bytes(bytes),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read_u32(&mut self) -> Result<u32, ElfError> {
|
||||||
|
let bytes = self.read_array()?;
|
||||||
|
Ok(match self.endianness {
|
||||||
|
Endianness::Little => u32::from_le_bytes(bytes),
|
||||||
|
Endianness::Big => u32::from_be_bytes(bytes),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read_u64(&mut self) -> Result<u64, ElfError> {
|
||||||
|
let bytes = self.read_array()?;
|
||||||
|
Ok(match self.endianness {
|
||||||
|
Endianness::Little => u64::from_le_bytes(bytes),
|
||||||
|
Endianness::Big => u64::from_be_bytes(bytes),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read_word(&mut self, class: ElfClass) -> Result<u64, ElfError> {
|
||||||
|
match class {
|
||||||
|
ElfClass::Elf32 => Ok(u64::from(self.read_u32()?)),
|
||||||
|
ElfClass::Elf64 => self.read_u64(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,7 +1,19 @@
|
|||||||
#![no_std]
|
#![no_std]
|
||||||
#![no_main]
|
#![no_main]
|
||||||
|
|
||||||
use dusk_sys::{println, sys_exit, sys_recv, sys_send};
|
mod cpio;
|
||||||
|
mod elf;
|
||||||
|
|
||||||
|
use dusk_sys::{
|
||||||
|
Handle, SELF_AS, println, sys_as_create, sys_exit, sys_frame_alloc, sys_map, sys_task_create,
|
||||||
|
sys_unmap, sys_yield,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Mapped into the root task's address space by the kernel.
|
||||||
|
static INITRAMFS_START: usize = 0x4000_0000;
|
||||||
|
const SCRATCH_PAGE: usize = 0x8000_0000;
|
||||||
|
const STACK_TOP: usize = 0x0000_7FFF_FFFF_F000;
|
||||||
|
const STACK_PAGES: usize = 4;
|
||||||
|
|
||||||
#[unsafe(no_mangle)]
|
#[unsafe(no_mangle)]
|
||||||
pub extern "C" fn _start() -> ! {
|
pub extern "C" fn _start() -> ! {
|
||||||
@@ -14,21 +26,81 @@ pub extern "C" fn _start() -> ! {
|
|||||||
println!(r#" d88888 88888b "Y88888P" "#);
|
println!(r#" d88888 88888b "Y88888P" "#);
|
||||||
println!(r#"----- Omega3 Dusk Root Server"#);
|
println!(r#"----- Omega3 Dusk Root Server"#);
|
||||||
|
|
||||||
let buf = [0u8; 128];
|
let echo_bytes = cpio::find_file(INITRAMFS_START as *const u8, "echo.elf").unwrap();
|
||||||
let buf_ptr = buf.as_ptr() as usize;
|
let echo_elf = elf::Elf::parse(echo_bytes).unwrap();
|
||||||
let max_len = buf.len();
|
let echo_as = sys_as_create().unwrap();
|
||||||
loop {
|
let echo_entry = load_elf(&echo_elf, echo_as);
|
||||||
let (actual_len, sender) = sys_recv(buf_ptr, max_len).unwrap();
|
map_stack(echo_as, STACK_TOP, STACK_PAGES);
|
||||||
println!(
|
let _ = sys_task_create(echo_as, echo_entry, STACK_TOP).unwrap();
|
||||||
"[server] Received: {}",
|
|
||||||
core::str::from_utf8(&buf[..actual_len]).unwrap()
|
let client_bytes = cpio::find_file(INITRAMFS_START as *const u8, "client.elf").unwrap();
|
||||||
);
|
let client_elf = elf::Elf::parse(client_bytes).unwrap();
|
||||||
sys_send(sender, buf_ptr, actual_len).unwrap();
|
let client_as = sys_as_create().unwrap();
|
||||||
}
|
let client_entry = load_elf(&client_elf, client_as);
|
||||||
|
map_stack(client_as, STACK_TOP, STACK_PAGES);
|
||||||
|
let _ = sys_task_create(client_as, client_entry, STACK_TOP).unwrap();
|
||||||
|
|
||||||
sys_exit(0);
|
sys_exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn load_elf(elf: &elf::Elf, target_as: Handle) -> usize {
|
||||||
|
for header in elf.program_headers().unwrap() {
|
||||||
|
let header = header.unwrap();
|
||||||
|
if header.segment_type != elf::ProgramHeaderType::Load || header.memory_size == 0 {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut perms = 0;
|
||||||
|
if header.flags & 2 != 0 {
|
||||||
|
perms |= 1 << 0;
|
||||||
|
}
|
||||||
|
if header.flags & 1 != 0 {
|
||||||
|
perms |= 1 << 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
let segment_start = header.virtual_address as usize;
|
||||||
|
let segment_end = segment_start + header.memory_size as usize;
|
||||||
|
let file_end = segment_start + header.file_size as usize;
|
||||||
|
let page_start = segment_start & !0xFFF;
|
||||||
|
|
||||||
|
for page in (page_start..segment_end).step_by(0x1000) {
|
||||||
|
let frame = sys_frame_alloc().unwrap();
|
||||||
|
|
||||||
|
sys_map(SELF_AS, frame, SCRATCH_PAGE, 0b01).unwrap();
|
||||||
|
unsafe {
|
||||||
|
core::ptr::write_bytes(SCRATCH_PAGE as *mut u8, 0, 0x1000);
|
||||||
|
|
||||||
|
let copy_start = page.max(segment_start).min(page + 0x1000);
|
||||||
|
let copy_end = (page + 0x1000).min(file_end).max(copy_start);
|
||||||
|
if copy_end > copy_start {
|
||||||
|
let page_offset = copy_start - page;
|
||||||
|
let file_offset = header.file_offset as usize + (copy_start - segment_start);
|
||||||
|
let len = copy_end - copy_start;
|
||||||
|
|
||||||
|
core::ptr::copy_nonoverlapping(
|
||||||
|
elf.bytes().as_ptr().add(file_offset),
|
||||||
|
(SCRATCH_PAGE as *mut u8).add(page_offset),
|
||||||
|
len,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sys_unmap(SELF_AS, SCRATCH_PAGE).unwrap();
|
||||||
|
|
||||||
|
sys_map(target_as, frame, page, perms).unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
elf.entry()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn map_stack(target_as: Handle, stack_top: usize, pages: usize) {
|
||||||
|
for i in 1..=pages {
|
||||||
|
let frame = sys_frame_alloc().unwrap();
|
||||||
|
let page_addr = stack_top - i * 0x1000;
|
||||||
|
sys_map(target_as, frame, page_addr, 0b01).unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[panic_handler]
|
#[panic_handler]
|
||||||
fn panic(info: &core::panic::PanicInfo) -> ! {
|
fn panic(info: &core::panic::PanicInfo) -> ! {
|
||||||
println!("{info}");
|
println!("{info}");
|
||||||
|
|||||||
Reference in New Issue
Block a user