Make x86_64 work (pre-syscalls)

This commit is contained in:
Mark Poliakov 2022-01-12 13:47:29 +02:00
parent c255c3fa08
commit d14ca5ecdb
30 changed files with 1114 additions and 595 deletions

View File

@ -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

View File

@ -1,3 +1,4 @@
menuentry "OS" {
multiboot2 /boot/kernel
module2 /boot/initrd.img
}

21
etc/x86_64-osdev5.json Normal file
View 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" ]
}
}

View File

@ -34,6 +34,9 @@ _entry:
.code64
_entry_upper:
movabsq $1f, %rax
jmp *%rax
1:
lea bsp_stack_top(%rip), %rax
mov %rax, %rsp

View File

@ -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();
}
}

View 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

View 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));

View File

@ -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]

View File

@ -1,4 +1,5 @@
use core::mem::size_of_val;
use core::arch::asm;
#[repr(packed)]
struct Entry {

View File

@ -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));
}

View File

@ -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;

View File

@ -1,4 +1,5 @@
use core::marker::PhantomData;
use core::arch::asm;
pub struct PortIo<T> {
port: u16,

View File

@ -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

View File

@ -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;

View File

@ -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(())
}
}
}

View File

@ -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);

View File

@ -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;

View File

@ -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)
}
}

View File

@ -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!(),
};

View File

@ -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());

View File

@ -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,

View File

@ -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();
}
}

View File

@ -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]

View File

@ -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);
// }
// }
// }
}
}

View File

@ -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
}};
}

View File

@ -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));

View File

@ -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>

View File

@ -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"

View File

@ -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
// }

View File

@ -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();