Make x86_64 work (pre-syscalls)
This commit is contained in:
parent
c255c3fa08
commit
d14ca5ecdb
21
Makefile
21
Makefile
@ -32,8 +32,6 @@ ifeq ($(ARCH),x86_64)
|
||||
MACH=none
|
||||
QEMU_OPTS+=-cdrom $(O)/image.iso \
|
||||
-M q35 \
|
||||
-cpu host \
|
||||
-enable-kvm \
|
||||
-m 512 \
|
||||
-serial mon:stdio \
|
||||
-net none
|
||||
@ -72,16 +70,10 @@ endif
|
||||
|
||||
.PHONY: address error etc kernel src
|
||||
|
||||
all: kernel
|
||||
all: image
|
||||
|
||||
kernel:
|
||||
cd kernel && cargo build $(CARGO_BUILD_OPTS)
|
||||
ifeq ($(ARCH),x86_64)
|
||||
mkdir -p $(O)/image/boot/grub
|
||||
cp etc/x86_64-none.grub $(O)/image/boot/grub/grub.cfg
|
||||
cp $(O)/kernel $(O)/image/boot/kernel
|
||||
grub-mkrescue -o $(O)/image.iso $(O)/image
|
||||
endif
|
||||
ifeq ($(ARCH),aarch64)
|
||||
$(LLVM_BASE)/llvm-strip -o $(O)/kernel.strip $(O)/kernel
|
||||
$(LLVM_BASE)/llvm-size $(O)/kernel.strip
|
||||
@ -100,6 +92,16 @@ ifeq ($(MACH),orangepi3)
|
||||
$(O)/uImage
|
||||
endif
|
||||
|
||||
image: kernel initrd
|
||||
ifeq ($(ARCH),x86_64)
|
||||
mkdir -p $(O)/image/boot/grub
|
||||
cp etc/x86_64-none.grub $(O)/image/boot/grub/grub.cfg
|
||||
cp $(O)/kernel $(O)/image/boot/kernel
|
||||
cp $(O)/initrd.img $(O)/image/boot/initrd.img
|
||||
|
||||
grub-mkrescue -o $(O)/image.iso $(O)/image
|
||||
endif
|
||||
|
||||
initrd:
|
||||
cd user && cargo build \
|
||||
--target=../etc/$(ARCH)-osdev5.json \
|
||||
@ -112,7 +114,6 @@ initrd:
|
||||
touch $(O)/rootfs/sys/.do_not_remove
|
||||
cp target/$(ARCH)-osdev5/$(PROFILE)/init $(O)/rootfs/init
|
||||
cp target/$(ARCH)-osdev5/$(PROFILE)/shell $(O)/rootfs/bin
|
||||
cp target/$(ARCH)-osdev5/$(PROFILE)/fuzzy $(O)/rootfs/bin
|
||||
cp target/$(ARCH)-osdev5/$(PROFILE)/ls $(O)/rootfs/bin
|
||||
cp target/$(ARCH)-osdev5/$(PROFILE)/cat $(O)/rootfs/bin
|
||||
cp target/$(ARCH)-osdev5/$(PROFILE)/hexd $(O)/rootfs/bin
|
||||
|
@ -1,3 +1,4 @@
|
||||
menuentry "OS" {
|
||||
multiboot2 /boot/kernel
|
||||
module2 /boot/initrd.img
|
||||
}
|
||||
|
21
etc/x86_64-osdev5.json
Normal file
21
etc/x86_64-osdev5.json
Normal file
@ -0,0 +1,21 @@
|
||||
{
|
||||
"arch": "x86_64",
|
||||
"cpu": "x86-64",
|
||||
"data-layout": "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128",
|
||||
|
||||
"disable-redzone": true,
|
||||
"executables": true,
|
||||
"panic-strategy": "abort",
|
||||
|
||||
"linker": "rust-lld",
|
||||
"linker-flavor": "ld.lld",
|
||||
|
||||
"llvm-target": "x86_64-unknown-linux-gnu",
|
||||
"max-atomic-width": 64,
|
||||
"target-pointer-width": "64",
|
||||
|
||||
"os": "none",
|
||||
"pre-link-args": {
|
||||
"ld.lld": [ "-Tetc/aarch64-osdev5.ld" ]
|
||||
}
|
||||
}
|
@ -34,6 +34,9 @@ _entry:
|
||||
|
||||
.code64
|
||||
_entry_upper:
|
||||
movabsq $1f, %rax
|
||||
jmp *%rax
|
||||
1:
|
||||
lea bsp_stack_top(%rip), %rax
|
||||
mov %rax, %rsp
|
||||
|
||||
|
@ -6,10 +6,13 @@ use crate::mem::{
|
||||
};
|
||||
use crate::debug;
|
||||
use crate::fs::{devfs, sysfs};
|
||||
use crate::config::{ConfigKey, CONFIG};
|
||||
use crate::dev::{pseudo, Device, display::FramebufferInfo};
|
||||
use core::mem::MaybeUninit;
|
||||
use crate::font;
|
||||
use multiboot2::{BootInformation, MemoryArea};
|
||||
use core::arch::{global_asm, asm};
|
||||
use crate::proc;
|
||||
|
||||
static mut RESERVED_REGION_MB2: MaybeUninit<ReservedRegion> = MaybeUninit::uninit();
|
||||
|
||||
@ -72,6 +75,14 @@ extern "C" fn __x86_64_bsp_main(mb_checksum: u32, mb_info_ptr: u32) -> ! {
|
||||
heap::init(heap_base_virt, 16 * 1024 * 1024);
|
||||
}
|
||||
|
||||
let initrd_info = mb_info.module_tags().next().unwrap();
|
||||
{
|
||||
let mut cfg = CONFIG.lock();
|
||||
|
||||
cfg.set_usize(ConfigKey::InitrdBase, initrd_info.start_address() as usize);
|
||||
cfg.set_usize(ConfigKey::InitrdSize, initrd_info.module_size() as usize);
|
||||
}
|
||||
|
||||
// Setup hardware
|
||||
unsafe {
|
||||
x86_64::INTC.enable().ok();
|
||||
@ -95,10 +106,8 @@ extern "C" fn __x86_64_bsp_main(mb_checksum: u32, mb_info_ptr: u32) -> ! {
|
||||
devfs::add_named_char_device(&pseudo::ZERO, "zero").unwrap();
|
||||
devfs::add_named_char_device(&pseudo::RANDOM, "random").unwrap();
|
||||
|
||||
loop {
|
||||
unsafe {
|
||||
asm!("sti; hlt");
|
||||
}
|
||||
unsafe {
|
||||
proc::enter();
|
||||
}
|
||||
}
|
||||
|
||||
|
76
kernel/src/arch/x86_64/context.S
Normal file
76
kernel/src/arch/x86_64/context.S
Normal file
@ -0,0 +1,76 @@
|
||||
.section .text
|
||||
.global __x86_64_ctx_switch
|
||||
.global __x86_64_ctx_switch_to
|
||||
.global __x86_64_ctx_enter_kernel
|
||||
.global __x86_64_ctx_enter_from_fork
|
||||
|
||||
__x86_64_ctx_enter_user:
|
||||
pop %rcx
|
||||
pop %rdi
|
||||
pop %rdi
|
||||
pop %rdx
|
||||
|
||||
push $0x10
|
||||
push %rcx
|
||||
|
||||
push $0 // $0x200
|
||||
|
||||
push $0x08
|
||||
push %rdx
|
||||
|
||||
iretq
|
||||
|
||||
__x86_64_ctx_enter_kernel:
|
||||
pop %rdi
|
||||
pop %rdx
|
||||
mov %rsp, %rcx
|
||||
|
||||
push $0x10
|
||||
push %rcx
|
||||
|
||||
push $0x200
|
||||
|
||||
push $0x08
|
||||
push %rdx
|
||||
|
||||
iretq
|
||||
|
||||
__x86_64_ctx_enter_from_fork:
|
||||
jmp .
|
||||
|
||||
__x86_64_ctx_switch:
|
||||
// %rsi -- src ctx ptr
|
||||
// %rdi -- dst ctx ptr
|
||||
|
||||
push %r15
|
||||
push %r14
|
||||
push %r13
|
||||
push %r12
|
||||
push %rbx
|
||||
push %rbp
|
||||
|
||||
mov %cr3, %rax
|
||||
push %rax
|
||||
// TODO save gs_base
|
||||
push %rax
|
||||
|
||||
mov %rsp, (%rsi)
|
||||
__x86_64_ctx_switch_to:
|
||||
mov (%rdi), %rsp
|
||||
|
||||
pop %rbp
|
||||
pop %rbx
|
||||
pop %r12
|
||||
pop %r13
|
||||
pop %r14
|
||||
pop %r15
|
||||
|
||||
pop %rax
|
||||
test %rax, %rax
|
||||
jz 1f
|
||||
mov %rax, %cr3
|
||||
1:
|
||||
pop %rax
|
||||
// TODO set gs_base = rax
|
||||
|
||||
ret
|
150
kernel/src/arch/x86_64/context.rs
Normal file
150
kernel/src/arch/x86_64/context.rs
Normal file
@ -0,0 +1,150 @@
|
||||
use crate::mem::{
|
||||
self,
|
||||
phys::{self, PageUsage},
|
||||
};
|
||||
use core::mem::size_of;
|
||||
use core::arch::global_asm;
|
||||
|
||||
struct Stack {
|
||||
bp: usize,
|
||||
sp: usize,
|
||||
}
|
||||
|
||||
/// Structure representing thread context
|
||||
#[repr(C)]
|
||||
pub struct Context {
|
||||
/// Thread's kernel stack pointer
|
||||
pub k_sp: usize, // 0x00
|
||||
|
||||
stack_base: usize,
|
||||
stack_page_count: usize,
|
||||
}
|
||||
|
||||
impl Context {
|
||||
/// Constructs a new kernel-space thread context
|
||||
pub fn kernel(entry: usize, arg: usize) -> Self {
|
||||
let mut stack = Stack::new(8);
|
||||
|
||||
stack.push(entry);
|
||||
stack.push(arg);
|
||||
|
||||
stack.setup_common(__x86_64_ctx_enter_kernel as usize, 0);
|
||||
|
||||
Self {
|
||||
k_sp: stack.sp,
|
||||
|
||||
stack_base: stack.bp,
|
||||
stack_page_count: 8,
|
||||
}
|
||||
}
|
||||
|
||||
/// Constructs a new user-space thread context
|
||||
pub fn user(entry: usize, arg: usize, cr3: usize, ustack: usize) -> Self {
|
||||
let cr3 = cr3 & 0xFFFFFFFF;
|
||||
let mut stack = Stack::new(8);
|
||||
|
||||
stack.push(entry);
|
||||
stack.push(arg);
|
||||
stack.push(0);
|
||||
stack.push(ustack);
|
||||
|
||||
stack.setup_common(__x86_64_ctx_enter_user as usize, cr3);
|
||||
|
||||
Self {
|
||||
k_sp: stack.sp,
|
||||
|
||||
stack_base: stack.bp,
|
||||
stack_page_count: 8,
|
||||
}
|
||||
}
|
||||
|
||||
/// Constructs an uninitialized thread context
|
||||
pub fn empty() -> Self {
|
||||
let stack = Stack::new(8);
|
||||
Self {
|
||||
k_sp: stack.sp,
|
||||
stack_base: stack.bp,
|
||||
stack_page_count: 8
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets up a context for signal entry
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// Unsafe: may clobber an already active context
|
||||
pub unsafe fn setup_signal_entry(&mut self, entry: usize, arg: usize, cr3: usize, ustack: usize) {
|
||||
todo!()
|
||||
}
|
||||
|
||||
/// Performs initial thread entry
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// Unsafe: does not check if any context has already been activated
|
||||
/// before, so must only be called once.
|
||||
pub unsafe extern "C" fn enter(&mut self) -> ! {
|
||||
__x86_64_ctx_switch_to(self);
|
||||
panic!("This code should not run");
|
||||
}
|
||||
|
||||
/// Performs context switch from `self` to `to`.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// Unsafe: does not check if `self` is actually an active context.
|
||||
pub unsafe extern "C" fn switch(&mut self, to: &mut Context) {
|
||||
__x86_64_ctx_switch(to, self);
|
||||
}
|
||||
}
|
||||
|
||||
impl Stack {
|
||||
pub fn new(page_count: usize) -> Stack {
|
||||
let phys = phys::alloc_contiguous_pages(PageUsage::Kernel, page_count).unwrap();
|
||||
let bp = mem::virtualize(phys);
|
||||
Stack {
|
||||
bp,
|
||||
sp: bp + page_count * mem::PAGE_SIZE,
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn from_base_size(bp: usize, page_count: usize) -> Stack {
|
||||
Stack {
|
||||
bp,
|
||||
sp: bp + page_count * mem::PAGE_SIZE
|
||||
}
|
||||
}
|
||||
|
||||
pub fn setup_common(&mut self, entry: usize, cr3: usize) {
|
||||
self.push(entry); // return address
|
||||
self.push(0); // gs_base
|
||||
self.push(cr3);
|
||||
self.push(0); // r15
|
||||
self.push(0); // r14
|
||||
self.push(0); // r13
|
||||
self.push(0); // r12
|
||||
self.push(0); // rbx
|
||||
self.push(0); // rbp
|
||||
}
|
||||
|
||||
pub fn push(&mut self, value: usize) {
|
||||
if self.bp == self.sp {
|
||||
panic!("Stack overflow");
|
||||
}
|
||||
|
||||
self.sp -= size_of::<usize>();
|
||||
unsafe {
|
||||
*(self.sp as *mut usize) = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
fn __x86_64_ctx_enter_from_fork();
|
||||
fn __x86_64_ctx_enter_kernel();
|
||||
fn __x86_64_ctx_enter_user();
|
||||
fn __x86_64_ctx_switch(dst: *mut Context, src: *mut Context);
|
||||
fn __x86_64_ctx_switch_to(dst: *mut Context);
|
||||
}
|
||||
|
||||
global_asm!(include_str!("context.S"), options(att_syntax));
|
@ -1,6 +1,7 @@
|
||||
use crate::arch::x86_64;
|
||||
use crate::debug::Level;
|
||||
use crate::dev::irq::{IrqContext, IntController};
|
||||
use crate::dev::irq::{IntController, IrqContext};
|
||||
use core::arch::{asm, global_asm};
|
||||
|
||||
#[derive(Debug)]
|
||||
struct ExceptionFrame {
|
||||
@ -49,7 +50,12 @@ fn pfault_access_type(code: u64) -> &'static str {
|
||||
|
||||
fn pfault_dump(level: Level, frame: &ExceptionFrame, cr2: u64) {
|
||||
println!(level, "\x1B[41;1mPage fault:");
|
||||
println!(level, " Illegal {} at {:#018x}\x1B[0m", pfault_access_type(frame.err_code), cr2);
|
||||
println!(
|
||||
level,
|
||||
" Illegal {} at {:#018x}\x1B[0m",
|
||||
pfault_access_type(frame.err_code),
|
||||
cr2
|
||||
);
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
|
@ -1,4 +1,5 @@
|
||||
use core::mem::size_of_val;
|
||||
use core::arch::asm;
|
||||
|
||||
#[repr(packed)]
|
||||
struct Entry {
|
||||
|
@ -1,3 +1,4 @@
|
||||
use core::arch::{asm, global_asm};
|
||||
use core::mem::size_of_val;
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
@ -9,13 +10,13 @@ pub struct Entry {
|
||||
flags: u8,
|
||||
base_hi: u16,
|
||||
base_ex: u32,
|
||||
__res1: u32
|
||||
__res1: u32,
|
||||
}
|
||||
|
||||
#[repr(packed)]
|
||||
struct Pointer {
|
||||
limit: u16,
|
||||
offset: usize
|
||||
offset: usize,
|
||||
}
|
||||
|
||||
pub const SIZE: usize = 256;
|
||||
@ -32,7 +33,7 @@ impl Entry {
|
||||
selector,
|
||||
flags,
|
||||
__res0: 0,
|
||||
__res1: 0
|
||||
__res1: 0,
|
||||
}
|
||||
}
|
||||
|
||||
@ -44,7 +45,7 @@ impl Entry {
|
||||
selector: 0,
|
||||
flags: 0,
|
||||
__res0: 0,
|
||||
__res1: 0
|
||||
__res1: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -64,7 +65,7 @@ pub unsafe fn init<F: FnOnce(&mut [Entry; SIZE]) -> ()>(f: F) {
|
||||
|
||||
let idtr = Pointer {
|
||||
limit: size_of_val(&IDT) as u16 - 1,
|
||||
offset: &IDT as *const _ as usize
|
||||
offset: &IDT as *const _ as usize,
|
||||
};
|
||||
asm!("lidt ({})", in(reg) &idtr, options(att_syntax));
|
||||
}
|
||||
|
@ -8,6 +8,7 @@ use crate::dev::{
|
||||
};
|
||||
use crate::sync::IrqSafeSpinLock;
|
||||
use libsys::error::Errno;
|
||||
use core::arch::global_asm;
|
||||
|
||||
const ICW1_INIT: u8 = 0x10;
|
||||
const ICW1_ICW4: u8 = 0x01;
|
||||
|
@ -1,4 +1,5 @@
|
||||
use core::marker::PhantomData;
|
||||
use core::arch::asm;
|
||||
|
||||
pub struct PortIo<T> {
|
||||
port: u16,
|
||||
|
@ -31,19 +31,51 @@ __x86_64_irq_\no:
|
||||
|
||||
__x86_64_irq_0:
|
||||
cli
|
||||
push %rax
|
||||
push %rdx
|
||||
|
||||
mov $'T', %al
|
||||
push %rax
|
||||
push %rcx
|
||||
push %rdx
|
||||
push %rbx
|
||||
push %rbp
|
||||
push %rsi
|
||||
push %rdi
|
||||
|
||||
push %r8
|
||||
push %r9
|
||||
push %r10
|
||||
push %r11
|
||||
push %r12
|
||||
push %r13
|
||||
push %r14
|
||||
push %r15
|
||||
|
||||
mov $0x3F8, %dx
|
||||
mov $'T', %al
|
||||
outb %al, %dx
|
||||
|
||||
mov $0x20, %al
|
||||
mov $0x20, %dx
|
||||
outb %al, %dx
|
||||
|
||||
call sched_yield
|
||||
|
||||
pop %r15
|
||||
pop %r14
|
||||
pop %r13
|
||||
pop %r12
|
||||
pop %r11
|
||||
pop %r10
|
||||
pop %r9
|
||||
pop %r8
|
||||
|
||||
pop %rdi
|
||||
pop %rsi
|
||||
pop %rbp
|
||||
pop %rbx
|
||||
pop %rdx
|
||||
pop %rcx
|
||||
pop %rax
|
||||
|
||||
iretq
|
||||
|
||||
irq_entry 1
|
||||
|
@ -1,4 +1,5 @@
|
||||
use crate::dev::{serial::SerialDevice, display::StaticFramebuffer, irq::IntController};
|
||||
use core::arch::asm;
|
||||
|
||||
mod uart;
|
||||
use uart::Uart;
|
||||
@ -10,6 +11,7 @@ pub(self) use io::PortIo;
|
||||
|
||||
pub mod boot;
|
||||
pub mod table;
|
||||
pub mod context;
|
||||
pub(self) mod gdt;
|
||||
pub(self) mod idt;
|
||||
pub(self) mod exception;
|
||||
|
@ -1,6 +1,11 @@
|
||||
use crate::mem::virt::AddressSpace;
|
||||
use crate::mem::{
|
||||
self,
|
||||
virt::{AddressSpace, table::{MapAttributes, Entry as AbstractEntry}},
|
||||
phys::{self, PageUsage}
|
||||
};
|
||||
use core::ops::{Index, IndexMut};
|
||||
use libsys::error::Errno;
|
||||
use core::arch::asm;
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
#[repr(transparent)]
|
||||
@ -22,6 +27,17 @@ pub struct FixedTableGroup {
|
||||
#[repr(transparent)]
|
||||
pub struct Space(Table);
|
||||
|
||||
bitflags! {
|
||||
/// Attributes attached to each translation [Entry]
|
||||
pub struct RawAttributes: u64 {
|
||||
const PRESENT = 1 << 0;
|
||||
const WRITE = 1 << 1;
|
||||
const USER = 1 << 2;
|
||||
const BLOCK = 1 << 7;
|
||||
const GLOBAL = 1 << 8;
|
||||
}
|
||||
}
|
||||
|
||||
// Upper mappings
|
||||
#[no_mangle]
|
||||
static mut KERNEL_FIXED: FixedTableGroup = FixedTableGroup {
|
||||
@ -30,6 +46,42 @@ static mut KERNEL_FIXED: FixedTableGroup = FixedTableGroup {
|
||||
pd: [Table::empty(); 16]
|
||||
};
|
||||
|
||||
impl TryFrom<MapAttributes> for RawAttributes {
|
||||
type Error = Errno;
|
||||
|
||||
fn try_from(i: MapAttributes) -> Result<Self, Errno> {
|
||||
let mut res = RawAttributes::empty();
|
||||
|
||||
if i.contains(MapAttributes::USER_READ) {
|
||||
res |= RawAttributes::USER;
|
||||
}
|
||||
if i.contains(MapAttributes::USER_WRITE) || i.contains(MapAttributes::KERNEL_WRITE) {
|
||||
res |= RawAttributes::WRITE;
|
||||
}
|
||||
|
||||
Ok(res)
|
||||
}
|
||||
}
|
||||
|
||||
impl AbstractEntry for Entry {
|
||||
fn from_parts(phys: usize, attrs: MapAttributes) -> Self {
|
||||
let attrs = RawAttributes::try_from(attrs).unwrap();
|
||||
Self((phys as u64) | attrs.bits() | 1)
|
||||
}
|
||||
|
||||
fn is_present(self) -> bool {
|
||||
self.0 & (1 << 0) != 0
|
||||
}
|
||||
|
||||
fn is_table(self) -> bool {
|
||||
self.0 & (1 << 7) == 0
|
||||
}
|
||||
|
||||
fn target(self) -> usize {
|
||||
(self.0 & !0xFFF) as usize
|
||||
}
|
||||
}
|
||||
|
||||
impl Entry {
|
||||
const fn invalid() -> Self {
|
||||
Self(0)
|
||||
@ -42,6 +94,42 @@ impl Table {
|
||||
entries: [Entry::invalid(); 512]
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns next-level translation table reference for `index`, if one is present.
|
||||
/// If `index` represents a `Block`-type mapping, will return an error.
|
||||
/// If `index` does not map to any translation table, will try to allocate, init and
|
||||
/// map a new one, returning it after doing so.
|
||||
pub fn next_level_table_or_alloc(&mut self, index: usize) -> Result<&'static mut Table, Errno> {
|
||||
let entry = self[index];
|
||||
if entry.is_present() {
|
||||
if !entry.is_table() {
|
||||
return Err(Errno::InvalidArgument);
|
||||
}
|
||||
|
||||
Ok(unsafe { &mut *(mem::virtualize(entry.target()) as *mut _) })
|
||||
} else {
|
||||
let phys = phys::alloc_page(PageUsage::Paging)?;
|
||||
let res = unsafe { &mut *(mem::virtualize(phys) as *mut Self) };
|
||||
self[index] = Entry::from_parts(phys, MapAttributes::USER_WRITE | MapAttributes::USER_READ | MapAttributes::NOT_GLOBAL);
|
||||
res.entries.fill(Entry::invalid());
|
||||
Ok(res)
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns next-level translation table reference for `index`, if one is present.
|
||||
/// Same as [next_level_table_or_alloc], but returns `None` if no table is mapped.
|
||||
pub fn next_level_table(&mut self, index: usize) -> Option<&'static mut Table> {
|
||||
let entry = self[index];
|
||||
if entry.is_present() {
|
||||
if !entry.is_table() {
|
||||
panic!("Entry is not a table: idx={}", index);
|
||||
}
|
||||
|
||||
Some(unsafe { &mut *(mem::virtualize(entry.target()) as *mut _) })
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Space {
|
||||
@ -53,17 +141,70 @@ impl Space {
|
||||
impl AddressSpace for Space {
|
||||
type Entry = Entry;
|
||||
|
||||
fn read_last_level_entry(&self, virt: usize) -> Result<Entry, Errno> {
|
||||
fn alloc_empty() -> Result<&'static mut Self, Errno> {
|
||||
let pdpt_phys = unsafe {
|
||||
&KERNEL_FIXED.pdpt as *const _ as usize - mem::KERNEL_OFFSET
|
||||
};
|
||||
let page = phys::alloc_page(PageUsage::Paging)?;
|
||||
let res = unsafe { &mut *(mem::virtualize(page) as *mut Self) };
|
||||
res.0.entries[..511].fill(Entry::invalid());
|
||||
res.0.entries[511] = Entry::from_parts(pdpt_phys, MapAttributes::SHARE_OUTER | MapAttributes::KERNEL_EXEC | MapAttributes::KERNEL_WRITE | MapAttributes::NOT_GLOBAL);
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
fn release(space: &mut Self) {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn address_phys(&mut self) -> usize {
|
||||
todo!();
|
||||
}
|
||||
|
||||
fn read_last_level_entry(&mut self, virt: usize) -> Result<Entry, Errno> {
|
||||
let l0i = virt >> 39;
|
||||
let l1i = (virt >> 30) & 0x1FF;
|
||||
let l2i = (virt >> 21) & 0x1FF;
|
||||
let l3i = (virt >> 12) & 0x1FF;
|
||||
|
||||
let l0_table = self.0.next_level_table(l0i).ok_or(Errno::DoesNotExist)?;
|
||||
let l1_table = l0_table.next_level_table(l1i).ok_or(Errno::DoesNotExist)?;
|
||||
let l2_table = l1_table.next_level_table(l2i).ok_or(Errno::DoesNotExist)?;
|
||||
|
||||
let entry = l2_table[l3i];
|
||||
if entry.is_present() {
|
||||
Ok(entry)
|
||||
} else {
|
||||
Err(Errno::DoesNotExist)
|
||||
}
|
||||
}
|
||||
|
||||
fn write_last_level_entry(
|
||||
&mut self,
|
||||
virt: usize,
|
||||
entry: Entry,
|
||||
map_intermediate: bool,
|
||||
) -> Result<(), Errno> {
|
||||
todo!();
|
||||
let l0i = virt >> 39;
|
||||
let l1i = (virt >> 30) & 0x1FF;
|
||||
let l2i = (virt >> 21) & 0x1FF;
|
||||
let l3i = (virt >> 12) & 0x1FF;
|
||||
|
||||
let l0_table = self.0.next_level_table_or_alloc(l0i)?;
|
||||
let l1_table = l0_table.next_level_table_or_alloc(l1i)?;
|
||||
let l2_table = l1_table.next_level_table_or_alloc(l2i)?;
|
||||
|
||||
if l2_table[l3i].is_present() {
|
||||
warnln!("Entry already exists for address: virt={:#x}, prev={:#x}, new={:#x}", virt, l2_table[l3i].target(), entry.target());
|
||||
Err(Errno::AlreadyExists)
|
||||
} else {
|
||||
l2_table[l3i] = entry;
|
||||
unsafe {
|
||||
core::arch::asm!("invlpg ({})", in(reg) virt, options(att_syntax));
|
||||
}
|
||||
#[cfg(feature = "verbose")]
|
||||
debugln!("{:#p} Map {:#x} -> {:#x}", self, virt, entry.target());
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -36,26 +36,26 @@ pub extern "C" fn init_fn(_arg: usize) -> ! {
|
||||
|
||||
proc.io.lock().set_ioctx(ioctx);
|
||||
|
||||
// Open stdin/stdout/stderr
|
||||
{
|
||||
let devfs_root = devfs::root();
|
||||
let tty_node = if console.is_empty() {
|
||||
devfs_root.lookup("ttyS0")
|
||||
} else {
|
||||
devfs_root.lookup(console)
|
||||
}
|
||||
.expect("Failed to open stdout for init process");
|
||||
// // Open stdin/stdout/stderr
|
||||
// {
|
||||
// let devfs_root = devfs::root();
|
||||
// let tty_node = if console.is_empty() {
|
||||
// devfs_root.lookup("ttyS0")
|
||||
// } else {
|
||||
// devfs_root.lookup(console)
|
||||
// }
|
||||
// .expect("Failed to open stdout for init process");
|
||||
|
||||
let mut io = proc.io.lock();
|
||||
let stdin = tty_node.open(OpenFlags::O_RDONLY).unwrap();
|
||||
let stdout = tty_node.open(OpenFlags::O_WRONLY).unwrap();
|
||||
let stderr = stdout.clone();
|
||||
// let mut io = proc.io.lock();
|
||||
// let stdin = tty_node.open(OpenFlags::O_RDONLY).unwrap();
|
||||
// let stdout = tty_node.open(OpenFlags::O_WRONLY).unwrap();
|
||||
// let stderr = stdout.clone();
|
||||
|
||||
io.set_file(FileDescriptor::STDIN, stdin).unwrap();
|
||||
io.set_file(FileDescriptor::STDOUT, stdout).unwrap();
|
||||
io.set_file(FileDescriptor::STDERR, stderr).unwrap();
|
||||
io.set_ctty(tty_node);
|
||||
}
|
||||
// io.set_file(FileDescriptor::STDIN, stdin).unwrap();
|
||||
// io.set_file(FileDescriptor::STDOUT, stdout).unwrap();
|
||||
// io.set_file(FileDescriptor::STDERR, stderr).unwrap();
|
||||
// io.set_ctty(tty_node);
|
||||
// }
|
||||
|
||||
drop(cfg);
|
||||
|
||||
|
@ -36,9 +36,9 @@ pub mod config;
|
||||
pub mod dev;
|
||||
pub mod fs;
|
||||
pub mod font;
|
||||
// pub mod init;
|
||||
pub mod init;
|
||||
pub mod mem;
|
||||
// pub mod proc;
|
||||
pub mod proc;
|
||||
pub mod sync;
|
||||
// pub mod syscall;
|
||||
pub mod util;
|
||||
|
@ -11,14 +11,49 @@ use crate::arch::platform::table;
|
||||
|
||||
pub use table::{Space, Table};
|
||||
|
||||
pub trait AddressSpace {
|
||||
type Entry;
|
||||
bitflags! {
|
||||
/// Attributes attached to each translation [Entry]
|
||||
pub struct MapAttributes: u64 {
|
||||
const USER_READ = 1 << 1;
|
||||
const USER_WRITE = 1 << 2;
|
||||
const USER_EXEC = 1 << 3;
|
||||
const KERNEL_WRITE = 1 << 4;
|
||||
const KERNEL_EXEC = 1 << 5;
|
||||
|
||||
fn read_last_level_entry(&self, virt: usize) -> Result<Self::Entry, Errno>;
|
||||
const SHARE_OUTER = 1 << 6;
|
||||
const SHARE_INNER = 2 << 6;
|
||||
|
||||
const NOT_GLOBAL = 1 << 8;
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Entry: Clone + Copy {
|
||||
fn from_parts(phys: usize, attrs: MapAttributes) -> Self;
|
||||
fn target(self) -> usize;
|
||||
fn is_present(self) -> bool;
|
||||
fn is_table(self) -> bool;
|
||||
}
|
||||
|
||||
pub trait AddressSpace {
|
||||
type Entry: Entry;
|
||||
|
||||
fn alloc_empty() -> Result<&'static mut Self, Errno>;
|
||||
fn release(space: &mut Self);
|
||||
fn address_phys(&mut self) -> usize;
|
||||
fn read_last_level_entry(&mut self, virt: usize) -> Result<Self::Entry, Errno>;
|
||||
fn write_last_level_entry(
|
||||
&mut self,
|
||||
virt: usize,
|
||||
entry: Self::Entry,
|
||||
map_intermediate: bool,
|
||||
) -> Result<(), Errno>;
|
||||
|
||||
fn map(&mut self, virt: usize, phys: usize, attrs: MapAttributes) -> Result<(), Errno> {
|
||||
let entry = Entry::from_parts(phys, attrs);
|
||||
self.write_last_level_entry(virt, entry, true).map(|_| ())
|
||||
}
|
||||
|
||||
fn translate(&mut self, virt: usize) -> Result<usize, Errno> {
|
||||
self.read_last_level_entry(virt).map(Entry::target)
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,7 @@
|
||||
use crate::mem::{
|
||||
self,
|
||||
phys::{self, PageUsage},
|
||||
virt::{MapAttributes, Space},
|
||||
virt::{Space, table::{AddressSpace, MapAttributes}},
|
||||
};
|
||||
use core::mem::{size_of, MaybeUninit};
|
||||
use libsys::{
|
||||
@ -66,10 +66,10 @@ struct Phdr<E: Elf> {
|
||||
}
|
||||
|
||||
fn map_flags(elf_flags: usize) -> MapAttributes {
|
||||
let mut dst_flags = MapAttributes::NOT_GLOBAL | MapAttributes::SH_OUTER;
|
||||
let mut dst_flags = MapAttributes::SHARE_OUTER | MapAttributes::NOT_GLOBAL;
|
||||
|
||||
if elf_flags & (1 << 0) /* PF_X */ == 0 {
|
||||
dst_flags |= MapAttributes::UXN | MapAttributes::PXN;
|
||||
if elf_flags & (1 << 0) /* PF_X */ != 0 {
|
||||
dst_flags |= MapAttributes::USER_EXEC | MapAttributes::KERNEL_EXEC;
|
||||
}
|
||||
|
||||
match (elf_flags & (3 << 1)) >> 1 {
|
||||
@ -78,9 +78,9 @@ fn map_flags(elf_flags: usize) -> MapAttributes {
|
||||
// Write-only: not sure if such mapping should exist at all
|
||||
1 => todo!(),
|
||||
// Read-only
|
||||
2 => dst_flags |= MapAttributes::AP_BOTH_READONLY,
|
||||
2 => dst_flags |= MapAttributes::USER_READ,
|
||||
// Read+Write
|
||||
3 => dst_flags |= MapAttributes::AP_BOTH_READWRITE,
|
||||
3 => dst_flags |= MapAttributes::USER_READ | MapAttributes::USER_WRITE | MapAttributes::KERNEL_WRITE,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
|
@ -27,6 +27,11 @@ pub fn switch() {
|
||||
SCHED.switch(false);
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
extern "C" fn sched_yield() {
|
||||
SCHED.switch(false);
|
||||
}
|
||||
|
||||
pub(self) static PROCESSES: IrqSafeSpinLock<BTreeMap<Pid, ProcessRef>> =
|
||||
IrqSafeSpinLock::new(BTreeMap::new());
|
||||
|
||||
|
@ -1,14 +1,14 @@
|
||||
//! Process data and control
|
||||
use crate::arch::aarch64::exception::ExceptionFrame;
|
||||
// use crate::arch::aarch64::exception::ExceptionFrame;
|
||||
use crate::mem::{
|
||||
self,
|
||||
phys::{self, PageUsage},
|
||||
virt::{MapAttributes, Space},
|
||||
virt::{table::{MapAttributes, AddressSpace}, Space},
|
||||
};
|
||||
use crate::proc::{
|
||||
wait::Wait, Context, ProcessIo, Thread, ThreadRef, ThreadState, PROCESSES, SCHED, Tid,
|
||||
};
|
||||
use crate::sync::{IrqSafeSpinLock};
|
||||
use crate::sync::{IrqSafeSpinLock, IrqSafeSpinLockGuard};
|
||||
use alloc::{rc::Rc, vec::Vec};
|
||||
use core::sync::atomic::{AtomicU32, Ordering};
|
||||
use libsys::{
|
||||
@ -18,6 +18,7 @@ use libsys::{
|
||||
signal::Signal,
|
||||
ProgramArgs,
|
||||
};
|
||||
use core::arch::asm;
|
||||
|
||||
/// Wrapper type for a process struct reference
|
||||
pub type ProcessRef = Rc<Process>;
|
||||
@ -155,191 +156,197 @@ impl Process {
|
||||
None
|
||||
}
|
||||
|
||||
/// Handles all pending signals (when returning from aborted syscall)
|
||||
pub fn handle_pending_signals(&self) {
|
||||
let mut lock = self.inner.lock();
|
||||
let ttbr0 = lock.space.as_mut().unwrap().address_phys() | ((lock.id.asid() as usize) << 48);
|
||||
let main_thread = Thread::get(lock.threads[0]).unwrap();
|
||||
drop(lock);
|
||||
|
||||
loop {
|
||||
let state = self.signal_state.load(Ordering::Acquire);
|
||||
if let Some(signal) = Self::find1(state).map(|e| Signal::try_from(e as u32).unwrap()) {
|
||||
self.signal_state.fetch_and(!(1 << (signal as u32)), Ordering::Release);
|
||||
main_thread.clone().enter_signal(signal, ttbr0);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
fn space_phys(lock: &mut IrqSafeSpinLockGuard<ProcessInner>) -> usize {
|
||||
lock.space.as_mut().unwrap().address_phys() | ((lock.id.asid() as usize) << 48)
|
||||
}
|
||||
|
||||
/// Sets a pending signal for a process
|
||||
pub fn set_signal(&self, signal: Signal) {
|
||||
let mut lock = self.inner.lock();
|
||||
let ttbr0 = lock.space.as_mut().unwrap().address_phys() | ((lock.id.asid() as usize) << 48);
|
||||
let main_thread = Thread::get(lock.threads[0]).unwrap();
|
||||
drop(lock);
|
||||
// /// Handles all pending signals (when returning from aborted syscall)
|
||||
// pub fn handle_pending_signals(&self) {
|
||||
// let mut lock = self.inner.lock();
|
||||
// let table = Self::space_phys(&lock);
|
||||
// let main_thread = Thread::get(lock.threads[0]).unwrap();
|
||||
// drop(lock);
|
||||
|
||||
// TODO check that `signal` is not a fault signal
|
||||
// it is illegal to call this function with
|
||||
// fault signals
|
||||
// loop {
|
||||
// let state = self.signal_state.load(Ordering::Acquire);
|
||||
// if let Some(signal) = Self::find1(state).map(|e| Signal::try_from(e as u32).unwrap()) {
|
||||
// self.signal_state.fetch_and(!(1 << (signal as u32)), Ordering::Release);
|
||||
// main_thread.clone().enter_signal(signal, table);
|
||||
// } else {
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
match main_thread.state() {
|
||||
ThreadState::Running => {
|
||||
main_thread.enter_signal(signal, ttbr0);
|
||||
}
|
||||
ThreadState::Waiting => {
|
||||
self.signal_state.fetch_or(1 << (signal as u32), Ordering::Release);
|
||||
main_thread.interrupt_wait(true);
|
||||
}
|
||||
ThreadState::Ready => {
|
||||
main_thread.clone().setup_signal(signal, ttbr0);
|
||||
main_thread.interrupt_wait(false);
|
||||
}
|
||||
ThreadState::Finished => {
|
||||
// TODO report error back
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
}
|
||||
// /// Sets a pending signal for a process
|
||||
// pub fn set_signal(&self, signal: Signal) {
|
||||
// let mut lock = self.inner.lock();
|
||||
// let table = Self::space_phys(&lock);
|
||||
// let main_thread = Thread::get(lock.threads[0]).unwrap();
|
||||
// drop(lock);
|
||||
|
||||
/// Immediately delivers a signal to requested thread
|
||||
pub fn enter_fault_signal(&self, thread: ThreadRef, signal: Signal) {
|
||||
let mut lock = self.inner.lock();
|
||||
let ttbr0 = lock.space.as_mut().unwrap().address_phys() | ((lock.id.asid() as usize) << 48);
|
||||
drop(lock);
|
||||
thread.enter_signal(signal, ttbr0);
|
||||
}
|
||||
// // TODO check that `signal` is not a fault signal
|
||||
// // it is illegal to call this function with
|
||||
// // fault signals
|
||||
|
||||
/// Crates a new thread in the process
|
||||
pub fn new_user_thread(&self, entry: usize, stack: usize, arg: usize) -> Result<Tid, Errno> {
|
||||
let mut lock = self.inner.lock();
|
||||
// match main_thread.state() {
|
||||
// ThreadState::Running => {
|
||||
// main_thread.enter_signal(signal, table);
|
||||
// }
|
||||
// ThreadState::Waiting => {
|
||||
// self.signal_state.fetch_or(1 << (signal as u32), Ordering::Release);
|
||||
// main_thread.interrupt_wait(true);
|
||||
// }
|
||||
// ThreadState::Ready => {
|
||||
// main_thread.clone().setup_signal(signal, table);
|
||||
// main_thread.interrupt_wait(false);
|
||||
// }
|
||||
// ThreadState::Finished => {
|
||||
// // TODO report error back
|
||||
// todo!()
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
let space_phys = lock.space.as_mut().unwrap().address_phys();
|
||||
let ttbr0 = space_phys | ((lock.id.asid() as usize) << 48);
|
||||
// /// Immediately delivers a signal to requested thread
|
||||
// pub fn enter_fault_signal(&self, thread: ThreadRef, signal: Signal) {
|
||||
// let mut lock = self.inner.lock();
|
||||
// let table = Self::space_phys(&lock);
|
||||
// drop(lock);
|
||||
// thread.enter_signal(signal, table);
|
||||
// }
|
||||
|
||||
let thread = Thread::new_user(lock.id, entry, stack, arg, ttbr0)?;
|
||||
let tid = thread.id();
|
||||
lock.threads.push(tid);
|
||||
SCHED.enqueue(tid);
|
||||
// /// Crates a new thread in the process
|
||||
// pub fn new_user_thread(&self, entry: usize, stack: usize, arg: usize) -> Result<Tid, Errno> {
|
||||
// let mut lock = self.inner.lock();
|
||||
|
||||
Ok(tid)
|
||||
}
|
||||
// let table = Self::space_phys(&lock);
|
||||
// let thread = Thread::new_user(lock.id, entry, stack, arg, table)?;
|
||||
// let tid = thread.id();
|
||||
// lock.threads.push(tid);
|
||||
// SCHED.enqueue(tid);
|
||||
|
||||
/// Creates a "fork" of the process, cloning its address space and
|
||||
/// resources
|
||||
pub fn fork(&self, frame: &mut ExceptionFrame) -> Result<Pid, Errno> {
|
||||
let src_io = self.io.lock();
|
||||
let mut src_inner = self.inner.lock();
|
||||
// Ok(tid)
|
||||
// }
|
||||
|
||||
let dst_id = new_user_pid();
|
||||
let dst_space = src_inner.space.as_mut().unwrap().fork()?;
|
||||
let dst_space_phys = (dst_space as *mut _ as usize) - mem::KERNEL_OFFSET;
|
||||
let dst_ttbr0 = dst_space_phys | ((dst_id.asid() as usize) << 48);
|
||||
// /// Creates a "fork" of the process, cloning its address space and
|
||||
// /// resources
|
||||
// pub fn fork(&self, frame: &mut ExceptionFrame) -> Result<Pid, Errno> {
|
||||
// let src_io = self.io.lock();
|
||||
// let mut src_inner = self.inner.lock();
|
||||
|
||||
let mut threads = Vec::new();
|
||||
let tid = Thread::fork(Some(dst_id), frame, dst_ttbr0)?.id();
|
||||
threads.push(tid);
|
||||
// let dst_id = new_user_pid();
|
||||
// let dst_space = src_inner.space.as_mut().unwrap().fork()?;
|
||||
|
||||
let dst = Rc::new(Self {
|
||||
exit_wait: Wait::new("process_exit"),
|
||||
io: IrqSafeSpinLock::new(src_io.fork()?),
|
||||
signal_state: AtomicU32::new(0),
|
||||
inner: IrqSafeSpinLock::new(ProcessInner {
|
||||
threads,
|
||||
exit: None,
|
||||
space: Some(dst_space),
|
||||
state: ProcessState::Active,
|
||||
id: dst_id,
|
||||
pgid: src_inner.pgid,
|
||||
ppid: Some(src_inner.id),
|
||||
sid: src_inner.sid,
|
||||
}),
|
||||
});
|
||||
// let dst_space_phys = (dst_space as *mut _ as usize) - mem::KERNEL_OFFSET;
|
||||
// let dst_ttbr0 = dst_space_phys | ((dst_id.asid() as usize) << 48);
|
||||
|
||||
debugln!("Process {:?} forked into {:?}", src_inner.id, dst_id);
|
||||
assert!(PROCESSES.lock().insert(dst_id, dst).is_none());
|
||||
// let mut threads = Vec::new();
|
||||
// let tid = Thread::fork(Some(dst_id), frame, dst_ttbr0)?.id();
|
||||
// threads.push(tid);
|
||||
|
||||
SCHED.enqueue(tid);
|
||||
// let dst = Rc::new(Self {
|
||||
// exit_wait: Wait::new("process_exit"),
|
||||
// io: IrqSafeSpinLock::new(src_io.fork()?),
|
||||
// signal_state: AtomicU32::new(0),
|
||||
// inner: IrqSafeSpinLock::new(ProcessInner {
|
||||
// threads,
|
||||
// exit: None,
|
||||
// space: Some(dst_space),
|
||||
// state: ProcessState::Active,
|
||||
// id: dst_id,
|
||||
// pgid: src_inner.pgid,
|
||||
// ppid: Some(src_inner.id),
|
||||
// sid: src_inner.sid,
|
||||
// }),
|
||||
// });
|
||||
|
||||
Ok(dst_id)
|
||||
}
|
||||
// debugln!("Process {:?} forked into {:?}", src_inner.id, dst_id);
|
||||
// assert!(PROCESSES.lock().insert(dst_id, dst).is_none());
|
||||
|
||||
// SCHED.enqueue(tid);
|
||||
|
||||
// Ok(dst_id)
|
||||
// }
|
||||
|
||||
/// Terminates a process.
|
||||
pub fn exit(self: ProcessRef, status: ExitCode) {
|
||||
let thread = Thread::current();
|
||||
let mut lock = self.inner.lock();
|
||||
let is_running = thread.owner_id().map(|e| e == lock.id).unwrap_or(false);
|
||||
todo!()
|
||||
// let thread = Thread::current();
|
||||
// let mut lock = self.inner.lock();
|
||||
// let is_running = thread.owner_id().map(|e| e == lock.id).unwrap_or(false);
|
||||
|
||||
infoln!("Process {:?} is exiting: {:?}", lock.id, status);
|
||||
assert!(lock.exit.is_none());
|
||||
lock.exit = Some(status);
|
||||
lock.state = ProcessState::Finished;
|
||||
// infoln!("Process {:?} is exiting: {:?}", lock.id, status);
|
||||
// assert!(lock.exit.is_none());
|
||||
// lock.exit = Some(status);
|
||||
// lock.state = ProcessState::Finished;
|
||||
|
||||
for &tid in lock.threads.iter() {
|
||||
let thread = Thread::get(tid).unwrap();
|
||||
if thread.state() == ThreadState::Waiting {
|
||||
todo!()
|
||||
}
|
||||
thread.terminate(status);
|
||||
SCHED.dequeue(tid);
|
||||
}
|
||||
// for &tid in lock.threads.iter() {
|
||||
// let thread = Thread::get(tid).unwrap();
|
||||
// if thread.state() == ThreadState::Waiting {
|
||||
// todo!()
|
||||
// }
|
||||
// thread.terminate(status);
|
||||
// SCHED.dequeue(tid);
|
||||
// }
|
||||
|
||||
if let Some(space) = lock.space.take() {
|
||||
unsafe {
|
||||
Space::release(space);
|
||||
Process::invalidate_asid((lock.id.asid() as usize) << 48);
|
||||
}
|
||||
}
|
||||
// if let Some(space) = lock.space.take() {
|
||||
// unsafe {
|
||||
// Space::release(space);
|
||||
// Process::invalidate_asid((lock.id.asid() as usize) << 48);
|
||||
// }
|
||||
// }
|
||||
|
||||
// TODO when exiting from signal handler interrupting an IO operation
|
||||
// deadlock is achieved
|
||||
self.io.lock().handle_exit();
|
||||
// // TODO when exiting from signal handler interrupting an IO operation
|
||||
// // deadlock is achieved
|
||||
// self.io.lock().handle_exit();
|
||||
|
||||
drop(lock);
|
||||
// drop(lock);
|
||||
|
||||
self.exit_wait.wakeup_all();
|
||||
// self.exit_wait.wakeup_all();
|
||||
|
||||
if is_running {
|
||||
SCHED.switch(true);
|
||||
panic!("This code should never run");
|
||||
}
|
||||
// if is_running {
|
||||
// SCHED.switch(true);
|
||||
// panic!("This code should never run");
|
||||
// }
|
||||
}
|
||||
|
||||
/// Terminates a thread of the process. If the thread is the only
|
||||
/// one remaining, process itself is exited (see [Process::exit])
|
||||
pub fn exit_thread(thread: ThreadRef, status: ExitCode) {
|
||||
let switch = {
|
||||
let switch = thread.state() == ThreadState::Running;
|
||||
let process = thread.owner().unwrap();
|
||||
let mut lock = process.inner.lock();
|
||||
let tid = thread.id();
|
||||
todo!()
|
||||
|
||||
if lock.threads.len() == 1 {
|
||||
// TODO call Process::exit instead?
|
||||
drop(lock);
|
||||
process.exit(status);
|
||||
return;
|
||||
}
|
||||
// let switch = {
|
||||
// let switch = thread.state() == ThreadState::Running;
|
||||
// let process = thread.owner().unwrap();
|
||||
// let mut lock = process.inner.lock();
|
||||
// let tid = thread.id();
|
||||
|
||||
lock.threads.retain(|&e| e != tid);
|
||||
// if lock.threads.len() == 1 {
|
||||
// // TODO call Process::exit instead?
|
||||
// drop(lock);
|
||||
// process.exit(status);
|
||||
// return;
|
||||
// }
|
||||
|
||||
thread.terminate(status);
|
||||
SCHED.dequeue(tid);
|
||||
debugln!("Thread {:?} terminated", tid);
|
||||
// lock.threads.retain(|&e| e != tid);
|
||||
|
||||
switch
|
||||
};
|
||||
// thread.terminate(status);
|
||||
// SCHED.dequeue(tid);
|
||||
// debugln!("Thread {:?} terminated", tid);
|
||||
|
||||
if switch {
|
||||
// TODO retain thread ID in process "finished" list and
|
||||
// drop it when process finishes
|
||||
SCHED.switch(true);
|
||||
panic!("This code should not run");
|
||||
} else {
|
||||
// Can drop this thread: it's not running
|
||||
todo!();
|
||||
}
|
||||
// switch
|
||||
// };
|
||||
|
||||
// if switch {
|
||||
// // TODO retain thread ID in process "finished" list and
|
||||
// // drop it when process finishes
|
||||
// SCHED.switch(true);
|
||||
// panic!("This code should not run");
|
||||
// } else {
|
||||
// // Can drop this thread: it's not running
|
||||
// todo!();
|
||||
// }
|
||||
}
|
||||
|
||||
fn collect(&self) -> Option<ExitCode> {
|
||||
@ -381,11 +388,9 @@ impl Process {
|
||||
phys
|
||||
} else {
|
||||
let page = phys::alloc_page(PageUsage::UserPrivate)?;
|
||||
let flags = MapAttributes::SH_OUTER
|
||||
let flags = MapAttributes::SHARE_OUTER
|
||||
| MapAttributes::NOT_GLOBAL
|
||||
| MapAttributes::UXN
|
||||
| MapAttributes::PXN
|
||||
| MapAttributes::AP_BOTH_READONLY;
|
||||
| MapAttributes::USER_READ;
|
||||
space.map(page_virt, page, flags)?;
|
||||
page
|
||||
};
|
||||
@ -405,11 +410,9 @@ impl Process {
|
||||
phys
|
||||
} else {
|
||||
let page = phys::alloc_page(PageUsage::UserPrivate)?;
|
||||
let flags = MapAttributes::SH_OUTER
|
||||
let flags = MapAttributes::SHARE_OUTER
|
||||
| MapAttributes::NOT_GLOBAL
|
||||
| MapAttributes::UXN
|
||||
| MapAttributes::PXN
|
||||
| MapAttributes::AP_BOTH_READONLY;
|
||||
| MapAttributes::USER_READ;
|
||||
space.map(page_virt, page, flags)?;
|
||||
page
|
||||
};
|
||||
@ -464,16 +467,16 @@ impl Process {
|
||||
(self.id().asid() as usize) << 48
|
||||
}
|
||||
|
||||
pub fn invalidate_tlb(&self) {
|
||||
Process::invalidate_asid(self.asid());
|
||||
}
|
||||
// pub fn invalidate_tlb(&self) {
|
||||
// Process::invalidate_asid(self.asid());
|
||||
// }
|
||||
|
||||
#[inline]
|
||||
pub fn invalidate_asid(asid: usize) {
|
||||
unsafe {
|
||||
asm!("tlbi aside1, {}", in(reg) asid);
|
||||
}
|
||||
}
|
||||
// #[inline]
|
||||
// pub fn invalidate_asid(asid: usize) {
|
||||
// unsafe {
|
||||
// asm!("tlbi aside1, {}", in(reg) asid);
|
||||
// }
|
||||
// }
|
||||
|
||||
/// Loads a new program into current process address space
|
||||
pub fn execve<F: FnOnce(&mut Space) -> Result<usize, Errno>>(
|
||||
@ -482,7 +485,8 @@ impl Process {
|
||||
) -> Result<(), Errno> {
|
||||
unsafe {
|
||||
// Run with interrupts disabled
|
||||
asm!("msr daifset, #2");
|
||||
// asm!("msr daifset, #2");
|
||||
asm!("cli");
|
||||
}
|
||||
|
||||
let proc = Process::current();
|
||||
@ -519,11 +523,11 @@ impl Process {
|
||||
let ustack_virt_bottom = Self::USTACK_VIRT_TOP - Self::USTACK_PAGES * mem::PAGE_SIZE;
|
||||
for i in 0..Self::USTACK_PAGES {
|
||||
let page = phys::alloc_page(PageUsage::UserPrivate).unwrap();
|
||||
let flags = MapAttributes::SH_OUTER
|
||||
let flags = MapAttributes::SHARE_OUTER
|
||||
| MapAttributes::NOT_GLOBAL
|
||||
| MapAttributes::UXN
|
||||
| MapAttributes::PXN
|
||||
| MapAttributes::AP_BOTH_READWRITE;
|
||||
| MapAttributes::USER_WRITE
|
||||
| MapAttributes::USER_READ
|
||||
| MapAttributes::KERNEL_WRITE;
|
||||
new_space
|
||||
.map(ustack_virt_bottom + i * mem::PAGE_SIZE, page, flags)
|
||||
.unwrap();
|
||||
@ -539,7 +543,7 @@ impl Process {
|
||||
// TODO drop old context
|
||||
let ctx = thread.ctx.get();
|
||||
let asid = (process_lock.id.asid() as usize) << 48;
|
||||
Process::invalidate_asid(asid);
|
||||
// Process::invalidate_asid(asid);
|
||||
|
||||
ctx.write(Context::user(
|
||||
entry,
|
||||
|
@ -4,6 +4,7 @@ use crate::sync::IrqSafeSpinLock;
|
||||
use crate::util::InitOnce;
|
||||
use libsys::proc::Tid;
|
||||
use alloc::{collections::VecDeque, rc::Rc};
|
||||
use core::arch::asm;
|
||||
|
||||
struct SchedulerInner {
|
||||
queue: VecDeque<Tid>,
|
||||
@ -69,7 +70,8 @@ impl Scheduler {
|
||||
THREADS.lock().get(&id).unwrap().clone()
|
||||
};
|
||||
|
||||
asm!("msr daifset, #2");
|
||||
asm!("cli");
|
||||
// asm!("msr daifset, #2");
|
||||
Thread::enter(thread)
|
||||
}
|
||||
|
||||
@ -121,7 +123,8 @@ impl Scheduler {
|
||||
|
||||
if !Rc::ptr_eq(&from, &to) {
|
||||
unsafe {
|
||||
asm!("msr daifset, #2");
|
||||
asm!("cli");
|
||||
// asm!("msr daifset, #2");
|
||||
Thread::switch(from, to, discard);
|
||||
}
|
||||
}
|
||||
@ -150,7 +153,7 @@ pub fn is_ready() -> bool {
|
||||
#[inline(never)]
|
||||
extern "C" fn idle_fn(_a: usize) -> ! {
|
||||
loop {
|
||||
cortex_a::asm::wfi();
|
||||
// cortex_a::asm::wfi();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
//! Facilities for controlling threads - smallest units of
|
||||
//! execution in the operating system
|
||||
use crate::arch::aarch64::exception::ExceptionFrame;
|
||||
// use crate::arch::aarch64::exception::ExceptionFrame;
|
||||
use crate::proc::{
|
||||
wait::{Wait, WaitStatus},
|
||||
Process, ProcessRef, SCHED, THREADS,
|
||||
@ -143,34 +143,34 @@ impl Thread {
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
/// Creates a fork thread cloning `frame` context
|
||||
pub fn fork(
|
||||
owner: Option<Pid>,
|
||||
frame: &ExceptionFrame,
|
||||
ttbr0: usize,
|
||||
) -> Result<ThreadRef, Errno> {
|
||||
let id = new_tid();
|
||||
// /// Creates a fork thread cloning `frame` context
|
||||
// pub fn fork(
|
||||
// owner: Option<Pid>,
|
||||
// frame: &ExceptionFrame,
|
||||
// ttbr0: usize,
|
||||
// ) -> Result<ThreadRef, Errno> {
|
||||
// let id = new_tid();
|
||||
|
||||
let res = Rc::new(Self {
|
||||
ctx: UnsafeCell::new(Context::fork(frame, ttbr0)),
|
||||
signal_ctx: UnsafeCell::new(Context::empty()),
|
||||
signal_pending: AtomicU32::new(0),
|
||||
exit_wait: Wait::new("thread_exit"),
|
||||
exit_status: InitOnce::new(),
|
||||
inner: IrqSafeSpinLock::new(ThreadInner {
|
||||
signal_entry: 0,
|
||||
signal_stack: 0,
|
||||
id,
|
||||
owner,
|
||||
pending_wait: None,
|
||||
wait_status: WaitStatus::Done,
|
||||
state: State::Ready,
|
||||
}),
|
||||
});
|
||||
debugln!("Forked new user thread: {:?}", id);
|
||||
assert!(THREADS.lock().insert(id, res.clone()).is_none());
|
||||
Ok(res)
|
||||
}
|
||||
// let res = Rc::new(Self {
|
||||
// ctx: UnsafeCell::new(Context::fork(frame, ttbr0)),
|
||||
// signal_ctx: UnsafeCell::new(Context::empty()),
|
||||
// signal_pending: AtomicU32::new(0),
|
||||
// exit_wait: Wait::new("thread_exit"),
|
||||
// exit_status: InitOnce::new(),
|
||||
// inner: IrqSafeSpinLock::new(ThreadInner {
|
||||
// signal_entry: 0,
|
||||
// signal_stack: 0,
|
||||
// id,
|
||||
// owner,
|
||||
// pending_wait: None,
|
||||
// wait_status: WaitStatus::Done,
|
||||
// state: State::Ready,
|
||||
// }),
|
||||
// });
|
||||
// debugln!("Forked new user thread: {:?}", id);
|
||||
// assert!(THREADS.lock().insert(id, res.clone()).is_none());
|
||||
// Ok(res)
|
||||
// }
|
||||
|
||||
/// Returns the thread ID
|
||||
#[inline]
|
||||
|
@ -39,35 +39,37 @@ pub static WAIT_SELECT: Wait = Wait::new("select");
|
||||
|
||||
/// Checks for any timed out wait channels and interrupts them
|
||||
pub fn tick() {
|
||||
let time = machine::local_timer().timestamp().unwrap();
|
||||
let mut list = TICK_LIST.lock();
|
||||
let mut cursor = list.cursor_front_mut();
|
||||
todo!();
|
||||
// let time = machine::local_timer().timestamp().unwrap();
|
||||
// let mut list = TICK_LIST.lock();
|
||||
// let mut cursor = list.cursor_front_mut();
|
||||
|
||||
while let Some(item) = cursor.current() {
|
||||
if time > item.deadline {
|
||||
let tid = item.tid;
|
||||
cursor.remove_current();
|
||||
SCHED.enqueue(tid);
|
||||
} else {
|
||||
cursor.move_next();
|
||||
}
|
||||
}
|
||||
// while let Some(item) = cursor.current() {
|
||||
// if time > item.deadline {
|
||||
// let tid = item.tid;
|
||||
// cursor.remove_current();
|
||||
// SCHED.enqueue(tid);
|
||||
// } else {
|
||||
// cursor.move_next();
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
/// Suspends current process for given duration
|
||||
pub fn sleep(timeout: Duration, remaining: &mut Duration) -> Result<(), Errno> {
|
||||
// Dummy wait descriptor which will never receive notifications
|
||||
static SLEEP_NOTIFY: Wait = Wait::new("sleep");
|
||||
let deadline = machine::local_timer().timestamp()? + timeout;
|
||||
match SLEEP_NOTIFY.wait(Some(deadline)) {
|
||||
Err(Errno::Interrupt) => {
|
||||
*remaining = deadline - machine::local_timer().timestamp()?;
|
||||
Err(Errno::Interrupt)
|
||||
}
|
||||
Err(Errno::TimedOut) => Ok(()),
|
||||
Ok(_) => panic!("Impossible result"),
|
||||
res => res,
|
||||
}
|
||||
todo!()
|
||||
// // Dummy wait descriptor which will never receive notifications
|
||||
// static SLEEP_NOTIFY: Wait = Wait::new("sleep");
|
||||
// let deadline = machine::local_timer().timestamp()? + timeout;
|
||||
// match SLEEP_NOTIFY.wait(Some(deadline)) {
|
||||
// Err(Errno::Interrupt) => {
|
||||
// *remaining = deadline - machine::local_timer().timestamp()?;
|
||||
// Err(Errno::Interrupt)
|
||||
// }
|
||||
// Err(Errno::TimedOut) => Ok(()),
|
||||
// Ok(_) => panic!("Impossible result"),
|
||||
// res => res,
|
||||
// }
|
||||
}
|
||||
|
||||
/// Suspends current process until some file descriptor
|
||||
@ -78,49 +80,51 @@ pub fn select(
|
||||
mut wfds: Option<&mut FdSet>,
|
||||
timeout: Option<Duration>,
|
||||
) -> Result<usize, Errno> {
|
||||
if wfds.is_none() && rfds.is_none() {
|
||||
todo!();
|
||||
}
|
||||
let read = rfds.as_deref().map(FdSet::clone);
|
||||
let write = wfds.as_deref().map(FdSet::clone);
|
||||
if let Some(rfds) = &mut rfds {
|
||||
rfds.reset();
|
||||
}
|
||||
if let Some(wfds) = &mut wfds {
|
||||
wfds.reset();
|
||||
}
|
||||
todo!();
|
||||
|
||||
let deadline = timeout.map(|v| v + machine::local_timer().timestamp().unwrap());
|
||||
let proc = thread.owner().unwrap();
|
||||
let mut io = proc.io.lock();
|
||||
// if wfds.is_none() && rfds.is_none() {
|
||||
// todo!();
|
||||
// }
|
||||
// let read = rfds.as_deref().map(FdSet::clone);
|
||||
// let write = wfds.as_deref().map(FdSet::clone);
|
||||
// if let Some(rfds) = &mut rfds {
|
||||
// rfds.reset();
|
||||
// }
|
||||
// if let Some(wfds) = &mut wfds {
|
||||
// wfds.reset();
|
||||
// }
|
||||
|
||||
loop {
|
||||
if let Some(read) = &read {
|
||||
for fd in read.iter() {
|
||||
let file = io.file(fd)?;
|
||||
if file.borrow().is_ready(false)? {
|
||||
rfds.as_mut().unwrap().set(fd);
|
||||
return Ok(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
if let Some(write) = &write {
|
||||
for fd in write.iter() {
|
||||
let file = io.file(fd)?;
|
||||
if file.borrow().is_ready(true)? {
|
||||
wfds.as_mut().unwrap().set(fd);
|
||||
return Ok(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
// let deadline = timeout.map(|v| v + machine::local_timer().timestamp().unwrap());
|
||||
// let proc = thread.owner().unwrap();
|
||||
// let mut io = proc.io.lock();
|
||||
|
||||
// Suspend
|
||||
match WAIT_SELECT.wait(deadline) {
|
||||
Err(Errno::TimedOut) => return Ok(0),
|
||||
Err(e) => return Err(e),
|
||||
Ok(_) => {}
|
||||
}
|
||||
}
|
||||
// loop {
|
||||
// if let Some(read) = &read {
|
||||
// for fd in read.iter() {
|
||||
// let file = io.file(fd)?;
|
||||
// if file.borrow().is_ready(false)? {
|
||||
// rfds.as_mut().unwrap().set(fd);
|
||||
// return Ok(1);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// if let Some(write) = &write {
|
||||
// for fd in write.iter() {
|
||||
// let file = io.file(fd)?;
|
||||
// if file.borrow().is_ready(true)? {
|
||||
// wfds.as_mut().unwrap().set(fd);
|
||||
// return Ok(1);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// // Suspend
|
||||
// match WAIT_SELECT.wait(deadline) {
|
||||
// Err(Errno::TimedOut) => return Ok(0),
|
||||
// Err(e) => return Err(e),
|
||||
// Ok(_) => {}
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
impl Wait {
|
||||
@ -134,61 +138,65 @@ impl Wait {
|
||||
|
||||
/// Interrupt wait pending on the channel
|
||||
pub fn abort(&self, tid: Tid, enqueue: bool) {
|
||||
let mut queue = self.queue.lock();
|
||||
let mut tick_lock = TICK_LIST.lock();
|
||||
let mut cursor = tick_lock.cursor_front_mut();
|
||||
while let Some(item) = cursor.current() {
|
||||
if tid == item.tid {
|
||||
cursor.remove_current();
|
||||
break;
|
||||
} else {
|
||||
cursor.move_next();
|
||||
}
|
||||
}
|
||||
todo!();
|
||||
|
||||
let mut cursor = queue.cursor_front_mut();
|
||||
while let Some(item) = cursor.current() {
|
||||
if tid == *item {
|
||||
cursor.remove_current();
|
||||
let thread = Thread::get(tid).unwrap();
|
||||
thread.set_wait_status(WaitStatus::Interrupted);
|
||||
if enqueue {
|
||||
SCHED.enqueue(tid);
|
||||
}
|
||||
break;
|
||||
} else {
|
||||
cursor.move_next();
|
||||
}
|
||||
}
|
||||
// let mut queue = self.queue.lock();
|
||||
// let mut tick_lock = TICK_LIST.lock();
|
||||
// let mut cursor = tick_lock.cursor_front_mut();
|
||||
// while let Some(item) = cursor.current() {
|
||||
// if tid == item.tid {
|
||||
// cursor.remove_current();
|
||||
// break;
|
||||
// } else {
|
||||
// cursor.move_next();
|
||||
// }
|
||||
// }
|
||||
|
||||
// let mut cursor = queue.cursor_front_mut();
|
||||
// while let Some(item) = cursor.current() {
|
||||
// if tid == *item {
|
||||
// cursor.remove_current();
|
||||
// let thread = Thread::get(tid).unwrap();
|
||||
// thread.set_wait_status(WaitStatus::Interrupted);
|
||||
// if enqueue {
|
||||
// SCHED.enqueue(tid);
|
||||
// }
|
||||
// break;
|
||||
// } else {
|
||||
// cursor.move_next();
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
fn wakeup_some(&self, mut limit: usize) -> usize {
|
||||
// No IRQs will arrive now == safe to manipulate tick list
|
||||
let mut queue = self.queue.lock();
|
||||
let mut count = 0;
|
||||
while limit != 0 && !queue.is_empty() {
|
||||
let tid = queue.pop_front();
|
||||
if let Some(tid) = tid {
|
||||
let mut tick_lock = TICK_LIST.lock();
|
||||
let mut cursor = tick_lock.cursor_front_mut();
|
||||
while let Some(item) = cursor.current() {
|
||||
if tid == item.tid {
|
||||
cursor.remove_current();
|
||||
break;
|
||||
} else {
|
||||
cursor.move_next();
|
||||
}
|
||||
}
|
||||
drop(tick_lock);
|
||||
todo!();
|
||||
|
||||
Thread::get(tid).unwrap().set_wait_status(WaitStatus::Done);
|
||||
SCHED.enqueue(tid);
|
||||
}
|
||||
// // No IRQs will arrive now == safe to manipulate tick list
|
||||
// let mut queue = self.queue.lock();
|
||||
// let mut count = 0;
|
||||
// while limit != 0 && !queue.is_empty() {
|
||||
// let tid = queue.pop_front();
|
||||
// if let Some(tid) = tid {
|
||||
// let mut tick_lock = TICK_LIST.lock();
|
||||
// let mut cursor = tick_lock.cursor_front_mut();
|
||||
// while let Some(item) = cursor.current() {
|
||||
// if tid == item.tid {
|
||||
// cursor.remove_current();
|
||||
// break;
|
||||
// } else {
|
||||
// cursor.move_next();
|
||||
// }
|
||||
// }
|
||||
// drop(tick_lock);
|
||||
|
||||
limit -= 1;
|
||||
count += 1;
|
||||
}
|
||||
count
|
||||
// Thread::get(tid).unwrap().set_wait_status(WaitStatus::Done);
|
||||
// SCHED.enqueue(tid);
|
||||
// }
|
||||
|
||||
// limit -= 1;
|
||||
// count += 1;
|
||||
// }
|
||||
// count
|
||||
}
|
||||
|
||||
/// Notifies all processes waiting for this event
|
||||
@ -204,51 +212,53 @@ impl Wait {
|
||||
/// Suspends current process until event is signalled or
|
||||
/// (optional) deadline is reached
|
||||
pub fn wait(&self, deadline: Option<Duration>) -> Result<(), Errno> {
|
||||
let thread = Thread::current();
|
||||
//let deadline = timeout.map(|t| machine::local_timer().timestamp().unwrap() + t);
|
||||
let mut queue_lock = self.queue.lock();
|
||||
todo!();
|
||||
|
||||
queue_lock.push_back(thread.id());
|
||||
thread.setup_wait(self);
|
||||
// let thread = Thread::current();
|
||||
// //let deadline = timeout.map(|t| machine::local_timer().timestamp().unwrap() + t);
|
||||
// let mut queue_lock = self.queue.lock();
|
||||
|
||||
if let Some(deadline) = deadline {
|
||||
TICK_LIST.lock().push_back(Timeout {
|
||||
tid: thread.id(),
|
||||
deadline,
|
||||
});
|
||||
}
|
||||
// queue_lock.push_back(thread.id());
|
||||
// thread.setup_wait(self);
|
||||
|
||||
loop {
|
||||
match thread.wait_status() {
|
||||
WaitStatus::Pending => {}
|
||||
WaitStatus::Done => {
|
||||
return Ok(());
|
||||
}
|
||||
WaitStatus::Interrupted => {
|
||||
return Err(Errno::Interrupt);
|
||||
}
|
||||
};
|
||||
// if let Some(deadline) = deadline {
|
||||
// TICK_LIST.lock().push_back(Timeout {
|
||||
// tid: thread.id(),
|
||||
// deadline,
|
||||
// });
|
||||
// }
|
||||
|
||||
drop(queue_lock);
|
||||
thread.enter_wait();
|
||||
queue_lock = self.queue.lock();
|
||||
// loop {
|
||||
// match thread.wait_status() {
|
||||
// WaitStatus::Pending => {}
|
||||
// WaitStatus::Done => {
|
||||
// return Ok(());
|
||||
// }
|
||||
// WaitStatus::Interrupted => {
|
||||
// return Err(Errno::Interrupt);
|
||||
// }
|
||||
// };
|
||||
|
||||
if let Some(deadline) = deadline {
|
||||
if machine::local_timer().timestamp()? > deadline {
|
||||
let mut cursor = queue_lock.cursor_front_mut();
|
||||
// drop(queue_lock);
|
||||
// thread.enter_wait();
|
||||
// queue_lock = self.queue.lock();
|
||||
|
||||
while let Some(&mut item) = cursor.current() {
|
||||
if thread.id() == item {
|
||||
cursor.remove_current();
|
||||
break;
|
||||
} else {
|
||||
cursor.move_next();
|
||||
}
|
||||
}
|
||||
// if let Some(deadline) = deadline {
|
||||
// if machine::local_timer().timestamp()? > deadline {
|
||||
// let mut cursor = queue_lock.cursor_front_mut();
|
||||
|
||||
return Err(Errno::TimedOut);
|
||||
}
|
||||
}
|
||||
}
|
||||
// while let Some(&mut item) = cursor.current() {
|
||||
// if thread.id() == item {
|
||||
// cursor.remove_current();
|
||||
// break;
|
||||
// } else {
|
||||
// cursor.move_next();
|
||||
// }
|
||||
// }
|
||||
|
||||
// return Err(Errno::TimedOut);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
@ -11,50 +11,61 @@ use crate::{
|
||||
},
|
||||
};
|
||||
use core::time::Duration;
|
||||
use core::arch::asm;
|
||||
|
||||
// TODO document the syscall ABI
|
||||
|
||||
// TODO move this to libusr
|
||||
macro_rules! syscall {
|
||||
($num:expr) => {{
|
||||
let mut res: usize;
|
||||
asm!("svc #0", out("x0") res, in("x8") $num.repr(), options(nostack));
|
||||
res
|
||||
// let mut res: usize;
|
||||
// asm!("svc #0", out("x0") res, in("x8") $num.repr(), options(nostack));
|
||||
// res
|
||||
loop {}
|
||||
0
|
||||
}};
|
||||
($num:expr, $a0:expr) => {{
|
||||
let mut res: usize = $a0;
|
||||
asm!("svc #0",
|
||||
inout("x0") res,
|
||||
in("x8") $num.repr(), options(nostack));
|
||||
res
|
||||
// let mut res: usize = $a0;
|
||||
// asm!("svc #0",
|
||||
// inout("x0") res,
|
||||
// in("x8") $num.repr(), options(nostack));
|
||||
// res
|
||||
loop {}
|
||||
0
|
||||
}};
|
||||
($num:expr, $a0:expr, $a1:expr) => {{
|
||||
let mut res: usize = $a0;
|
||||
asm!("svc #0",
|
||||
inout("x0") res, in("x1") $a1,
|
||||
in("x8") $num.repr(), options(nostack));
|
||||
res
|
||||
// let mut res: usize = $a0;
|
||||
// asm!("svc #0",
|
||||
// inout("x0") res, in("x1") $a1,
|
||||
// in("x8") $num.repr(), options(nostack));
|
||||
// res
|
||||
loop {}
|
||||
0
|
||||
}};
|
||||
($num:expr, $a0:expr, $a1:expr, $a2:expr) => {{
|
||||
let mut res: usize = $a0;
|
||||
asm!("svc #0",
|
||||
inout("x0") res, in("x1") $a1, in("x2") $a2,
|
||||
in("x8") $num.repr(), options(nostack));
|
||||
asm!("syscall",
|
||||
inout("rax") res, in("rdi") $a1, in("rsi") $a2,
|
||||
in("rdx") $num.repr(), options(nostack));
|
||||
res
|
||||
}};
|
||||
($num:expr, $a0:expr, $a1:expr, $a2:expr, $a3:expr) => {{
|
||||
let mut res: usize = $a0;
|
||||
asm!("svc #0",
|
||||
inout("x0") res, in("x1") $a1, in("x2") $a2,
|
||||
in("x3") $a3, in("x8") $num.repr(), options(nostack));
|
||||
res
|
||||
// let mut res: usize = $a0;
|
||||
// asm!("svc #0",
|
||||
// inout("x0") res, in("x1") $a1, in("x2") $a2,
|
||||
// in("x3") $a3, in("x8") $num.repr(), options(nostack));
|
||||
// res
|
||||
loop {}
|
||||
0
|
||||
}};
|
||||
($num:expr, $a0:expr, $a1:expr, $a2:expr, $a3:expr, $a4:expr) => {{
|
||||
let mut res: usize = $a0;
|
||||
asm!("svc #0",
|
||||
inout("x0") res, in("x1") $a1, in("x2") $a2,
|
||||
in("x3") $a3, in("x4") $a4, in("x8") $num.repr(), options(nostack));
|
||||
res
|
||||
// let mut res: usize = $a0;
|
||||
// asm!("svc #0",
|
||||
// inout("x0") res, in("x1") $a1, in("x2") $a2,
|
||||
// in("x3") $a3, in("x4") $a4, in("x8") $num.repr(), options(nostack));
|
||||
// res
|
||||
loop {}
|
||||
0
|
||||
}};
|
||||
}
|
||||
|
||||
|
@ -26,11 +26,14 @@ extern "C" fn _start(arg: &'static ProgramArgs) -> ! {
|
||||
fn main() -> i32;
|
||||
}
|
||||
|
||||
unsafe {
|
||||
allocator::init();
|
||||
thread::init_main();
|
||||
env::setup_env(arg);
|
||||
}
|
||||
trace!(TraceLevel::Debug, "Test!");
|
||||
loop {}
|
||||
|
||||
// unsafe {
|
||||
// allocator::init();
|
||||
// thread::init_main();
|
||||
// env::setup_env(arg);
|
||||
// }
|
||||
|
||||
let res = unsafe { main() };
|
||||
sys::sys_exit(ExitCode::from(res));
|
||||
|
@ -60,16 +60,16 @@ impl<T> JoinHandle<T> {
|
||||
}
|
||||
|
||||
unsafe fn init_common(signal_stack_pointer: *mut u8) {
|
||||
let tid = u32::from(sys_ex_gettid()) as u64;
|
||||
asm!("msr tpidr_el0, {:x}", in(reg) tid);
|
||||
// let tid = u32::from(sys_ex_gettid()) as u64;
|
||||
// asm!("msr tpidr_el0, {:x}", in(reg) tid);
|
||||
|
||||
// thread::current() should be valid at this point
|
||||
|
||||
sys_ex_signal(
|
||||
signal::signal_handler as usize,
|
||||
signal_stack_pointer as usize,
|
||||
)
|
||||
.unwrap();
|
||||
// sys_ex_signal(
|
||||
// signal::signal_handler as usize,
|
||||
// signal_stack_pointer as usize,
|
||||
// )
|
||||
// .unwrap();
|
||||
}
|
||||
|
||||
pub(crate) unsafe fn init_main() {
|
||||
@ -82,11 +82,12 @@ pub(crate) unsafe fn init_main() {
|
||||
}
|
||||
|
||||
pub fn current() -> Thread {
|
||||
let mut id: u64;
|
||||
unsafe {
|
||||
asm!("mrs {:x}, tpidr_el0", out(reg) id);
|
||||
}
|
||||
Thread { id: Tid::from(id as u32) }
|
||||
todo!()
|
||||
// let mut id: u64;
|
||||
// unsafe {
|
||||
// asm!("mrs {:x}, tpidr_el0", out(reg) id);
|
||||
// }
|
||||
// Thread { id: Tid::from(id as u32) }
|
||||
}
|
||||
|
||||
pub fn spawn<F, T>(f: F) -> JoinHandle<T>
|
||||
|
@ -13,9 +13,9 @@ path = "src/init/main.rs"
|
||||
name = "shell"
|
||||
path = "src/bin/shell.rs"
|
||||
|
||||
[[bin]]
|
||||
name = "fuzzy"
|
||||
path = "src/bin/fuzzy.rs"
|
||||
# [[bin]]
|
||||
# name = "fuzzy"
|
||||
# path = "src/bin/fuzzy.rs"
|
||||
|
||||
[[bin]]
|
||||
name = "ls"
|
||||
|
@ -1,139 +1,141 @@
|
||||
#![feature(asm)]
|
||||
// #![feature(asm)]
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
#![allow(unused_macros)]
|
||||
#![allow(dead_code)]
|
||||
|
||||
//
|
||||
// #![allow(unused_macros)]
|
||||
// #![allow(dead_code)]
|
||||
//
|
||||
#[macro_use]
|
||||
extern crate libusr;
|
||||
|
||||
use libusr::sys::{abi::SystemCall, stat::Stat};
|
||||
|
||||
static mut STATE: u64 = 0;
|
||||
|
||||
macro_rules! syscall {
|
||||
($num:expr) => {{
|
||||
let mut res: usize;
|
||||
asm!("svc #0", out("x0") res, in("x8") $num, options(nostack));
|
||||
res
|
||||
}};
|
||||
($num:expr, $a0:expr) => {{
|
||||
let mut res: usize = $a0;
|
||||
asm!("svc #0",
|
||||
inout("x0") res,
|
||||
in("x8") $num, options(nostack));
|
||||
res
|
||||
}};
|
||||
($num:expr, $a0:expr, $a1:expr) => {{
|
||||
let mut res: usize = $a0;
|
||||
asm!("svc #0",
|
||||
inout("x0") res, in("x1") $a1,
|
||||
in("x8") $num, options(nostack));
|
||||
res
|
||||
}};
|
||||
($num:expr, $a0:expr, $a1:expr, $a2:expr) => {{
|
||||
let mut res: usize = $a0;
|
||||
asm!("svc #0",
|
||||
inout("x0") res, in("x1") $a1, in("x2") $a2,
|
||||
in("x8") $num, options(nostack));
|
||||
res
|
||||
}};
|
||||
($num:expr, $a0:expr, $a1:expr, $a2:expr, $a3:expr) => {{
|
||||
let mut res: usize = $a0;
|
||||
asm!("svc #0",
|
||||
inout("x0") res, in("x1") $a1, in("x2") $a2,
|
||||
in("x3") $a3, in("x8") $num, options(nostack));
|
||||
res
|
||||
}};
|
||||
($num:expr, $a0:expr, $a1:expr, $a2:expr, $a3:expr, $a4:expr) => {{
|
||||
let mut res: usize = $a0;
|
||||
asm!("svc #0",
|
||||
inout("x0") res, in("x1") $a1, in("x2") $a2,
|
||||
in("x3") $a3, in("x4") $a4, in("x8") $num, options(nostack));
|
||||
res
|
||||
}};
|
||||
}
|
||||
|
||||
/// Integer/size argument
|
||||
macro_rules! argn {
|
||||
($a:expr) => {
|
||||
$a as usize
|
||||
};
|
||||
}
|
||||
/// Pointer/base argument
|
||||
macro_rules! argp {
|
||||
($a:expr) => {
|
||||
$a as usize
|
||||
};
|
||||
}
|
||||
|
||||
fn random_set_seed(seed: u64) {
|
||||
unsafe { STATE = seed; }
|
||||
}
|
||||
|
||||
fn random_u64() -> u64 {
|
||||
let mut x = unsafe { STATE };
|
||||
x ^= x << 13;
|
||||
x ^= x >> 7;
|
||||
x ^= x << 17;
|
||||
unsafe {
|
||||
STATE = x;
|
||||
}
|
||||
x
|
||||
}
|
||||
|
||||
fn random_ascii_char() -> u8 {
|
||||
((random_u64() % (0x7F - 0x20)) as u8) + 0x20
|
||||
}
|
||||
|
||||
fn random_str_range(buf: &mut [u8], min: usize, max: usize) -> &str {
|
||||
let max = core::cmp::min(buf.len(), max);
|
||||
assert!(max > min);
|
||||
let len = ((random_u64() as usize) % (max - min)) + min;
|
||||
for c in buf[..len].iter_mut() {
|
||||
*c = random_ascii_char();
|
||||
}
|
||||
core::str::from_utf8(&buf[..len]).unwrap()
|
||||
}
|
||||
|
||||
fn random_str(buf: &mut [u8]) -> &str {
|
||||
random_str_range(buf, 0, buf.len())
|
||||
}
|
||||
|
||||
fn random_bytes(buf: &mut [u8]) {
|
||||
for byte in buf.iter_mut() {
|
||||
*byte = (random_u64() & 0xFF) as u8;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// use libusr::sys::{abi::SystemCall, stat::Stat};
|
||||
//
|
||||
// static mut STATE: u64 = 0;
|
||||
//
|
||||
// macro_rules! syscall {
|
||||
// ($num:expr) => {{
|
||||
// let mut res: usize;
|
||||
// asm!("svc #0", out("x0") res, in("x8") $num, options(nostack));
|
||||
// res
|
||||
// }};
|
||||
// ($num:expr, $a0:expr) => {{
|
||||
// let mut res: usize = $a0;
|
||||
// asm!("svc #0",
|
||||
// inout("x0") res,
|
||||
// in("x8") $num, options(nostack));
|
||||
// res
|
||||
// }};
|
||||
// ($num:expr, $a0:expr, $a1:expr) => {{
|
||||
// let mut res: usize = $a0;
|
||||
// asm!("svc #0",
|
||||
// inout("x0") res, in("x1") $a1,
|
||||
// in("x8") $num, options(nostack));
|
||||
// res
|
||||
// }};
|
||||
// ($num:expr, $a0:expr, $a1:expr, $a2:expr) => {{
|
||||
// let mut res: usize = $a0;
|
||||
// asm!("svc #0",
|
||||
// inout("x0") res, in("x1") $a1, in("x2") $a2,
|
||||
// in("x8") $num, options(nostack));
|
||||
// res
|
||||
// }};
|
||||
// ($num:expr, $a0:expr, $a1:expr, $a2:expr, $a3:expr) => {{
|
||||
// let mut res: usize = $a0;
|
||||
// asm!("svc #0",
|
||||
// inout("x0") res, in("x1") $a1, in("x2") $a2,
|
||||
// in("x3") $a3, in("x8") $num, options(nostack));
|
||||
// res
|
||||
// }};
|
||||
// ($num:expr, $a0:expr, $a1:expr, $a2:expr, $a3:expr, $a4:expr) => {{
|
||||
// let mut res: usize = $a0;
|
||||
// asm!("svc #0",
|
||||
// inout("x0") res, in("x1") $a1, in("x2") $a2,
|
||||
// in("x3") $a3, in("x4") $a4, in("x8") $num, options(nostack));
|
||||
// res
|
||||
// }};
|
||||
// }
|
||||
//
|
||||
// /// Integer/size argument
|
||||
// macro_rules! argn {
|
||||
// ($a:expr) => {
|
||||
// $a as usize
|
||||
// };
|
||||
// }
|
||||
// /// Pointer/base argument
|
||||
// macro_rules! argp {
|
||||
// ($a:expr) => {
|
||||
// $a as usize
|
||||
// };
|
||||
// }
|
||||
//
|
||||
// fn random_set_seed(seed: u64) {
|
||||
// unsafe { STATE = seed; }
|
||||
// }
|
||||
//
|
||||
// fn random_u64() -> u64 {
|
||||
// let mut x = unsafe { STATE };
|
||||
// x ^= x << 13;
|
||||
// x ^= x >> 7;
|
||||
// x ^= x << 17;
|
||||
// unsafe {
|
||||
// STATE = x;
|
||||
// }
|
||||
// x
|
||||
// }
|
||||
//
|
||||
// fn random_ascii_char() -> u8 {
|
||||
// ((random_u64() % (0x7F - 0x20)) as u8) + 0x20
|
||||
// }
|
||||
//
|
||||
// fn random_str_range(buf: &mut [u8], min: usize, max: usize) -> &str {
|
||||
// let max = core::cmp::min(buf.len(), max);
|
||||
// assert!(max > min);
|
||||
// let len = ((random_u64() as usize) % (max - min)) + min;
|
||||
// for c in buf[..len].iter_mut() {
|
||||
// *c = random_ascii_char();
|
||||
// }
|
||||
// core::str::from_utf8(&buf[..len]).unwrap()
|
||||
// }
|
||||
//
|
||||
// fn random_str(buf: &mut [u8]) -> &str {
|
||||
// random_str_range(buf, 0, buf.len())
|
||||
// }
|
||||
//
|
||||
// fn random_bytes(buf: &mut [u8]) {
|
||||
// for byte in buf.iter_mut() {
|
||||
// *byte = (random_u64() & 0xFF) as u8;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
#[no_mangle]
|
||||
fn main() -> i32 {
|
||||
let seed = libusr::sys::sys_ex_getcputime().unwrap().as_nanos() as u64 / 13;
|
||||
println!("Using seed: {:#x}", seed);
|
||||
random_set_seed(seed);
|
||||
|
||||
let mut buf = [0; 256];
|
||||
|
||||
// Test sys_ex_getcputime()
|
||||
let mut prev_time = libusr::sys::sys_ex_getcputime().unwrap().as_nanos();
|
||||
for _ in 0..1000 {
|
||||
let t = libusr::sys::sys_ex_getcputime().unwrap().as_nanos();
|
||||
assert!(t >= prev_time);
|
||||
prev_time = t;
|
||||
}
|
||||
|
||||
// Test non-utf8 input fed into syscalls expecting strings
|
||||
// let old_signal = signal::set_handler(Signal::InvalidSystemCall, SignalHandler::Ignore);
|
||||
for _ in 0..10000 {
|
||||
random_bytes(&mut buf);
|
||||
let mut stat = Stat::default();
|
||||
|
||||
unsafe {
|
||||
syscall!(SystemCall::FileStatus.repr(), (-2i32) as usize, buf.as_mut_ptr() as usize, buf.len(), (&mut stat) as *mut _ as usize);
|
||||
}
|
||||
}
|
||||
// signal::set_handler(Signal::InvalidSystemCall, old_signal);
|
||||
|
||||
0
|
||||
loop {}
|
||||
}
|
||||
// let seed = libusr::sys::sys_ex_getcputime().unwrap().as_nanos() as u64 / 13;
|
||||
// println!("Using seed: {:#x}", seed);
|
||||
// random_set_seed(seed);
|
||||
//
|
||||
// let mut buf = [0; 256];
|
||||
//
|
||||
// // Test sys_ex_getcputime()
|
||||
// let mut prev_time = libusr::sys::sys_ex_getcputime().unwrap().as_nanos();
|
||||
// for _ in 0..1000 {
|
||||
// let t = libusr::sys::sys_ex_getcputime().unwrap().as_nanos();
|
||||
// assert!(t >= prev_time);
|
||||
// prev_time = t;
|
||||
// }
|
||||
//
|
||||
// // Test non-utf8 input fed into syscalls expecting strings
|
||||
// // let old_signal = signal::set_handler(Signal::InvalidSystemCall, SignalHandler::Ignore);
|
||||
// for _ in 0..10000 {
|
||||
// random_bytes(&mut buf);
|
||||
// let mut stat = Stat::default();
|
||||
//
|
||||
// unsafe {
|
||||
// syscall!(SystemCall::FileStatus.repr(), (-2i32) as usize, buf.as_mut_ptr() as usize, buf.len(), (&mut stat) as *mut _ as usize);
|
||||
// }
|
||||
// }
|
||||
// // signal::set_handler(Signal::InvalidSystemCall, old_signal);
|
||||
//
|
||||
// 0
|
||||
// }
|
||||
|
@ -9,6 +9,8 @@ use libusr::sys::{stat::MountOptions, sys_execve, sys_fork, sys_mount, sys_waitp
|
||||
|
||||
#[no_mangle]
|
||||
fn main() -> i32 {
|
||||
loop {}
|
||||
|
||||
sys_mount(
|
||||
"/dev",
|
||||
&MountOptions {
|
||||
@ -32,9 +34,6 @@ fn main() -> i32 {
|
||||
println!("Process {:?} exited with status {}", pid, status);
|
||||
|
||||
loop {
|
||||
unsafe {
|
||||
asm!("nop");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
sys_execve("/sbin/login", &["/sbin/login", "/dev/ttyS0"]).unwrap();
|
||||
|
Loading…
x
Reference in New Issue
Block a user