Hardcode global scheme IDs.

This commit is contained in:
4lDO2
2023-09-06 11:04:46 +02:00
parent 679c26c03b
commit 10e86ea89d
8 changed files with 72 additions and 111 deletions
+1
View File
@@ -49,6 +49,7 @@
#![feature(naked_functions)]
#![feature(offset_of)]
#![feature(sync_unsafe_cell)]
#![feature(variant_count)]
#![no_std]
#![no_main]
+7 -20
View File
@@ -9,7 +9,6 @@ use spin::{Mutex, Once, RwLock};
use crate::acpi::{RXSDT_ENUM, RxsdtEnum};
use crate::event;
use crate::scheme::SchemeId;
use crate::sync::WaitCondition;
use crate::syscall::data::Stat;
@@ -23,7 +22,7 @@ use crate::syscall::flag::{
use crate::syscall::error::{Error, Result};
use crate::syscall::usercopy::{UserSliceRo, UserSliceWo};
use super::{KernelScheme, CallerCtx, OpenResult};
use super::{GlobalSchemes, KernelScheme, CallerCtx, OpenResult};
/// A scheme used to access the RSDT or XSDT, which is needed for e.g. `acpid` to function.
pub struct AcpiScheme;
@@ -50,21 +49,15 @@ const TOPLEVEL_CONTENTS: &[u8] = b"rxsdt\nkstop\n";
static KSTOP_WAITCOND: WaitCondition = WaitCondition::new();
static KSTOP_FLAG: Mutex<bool> = Mutex::new(false);
static SCHEME_ID: Once<SchemeId> = Once::new();
pub fn register_kstop() -> bool {
*KSTOP_FLAG.lock() = true;
let mut waiters_awoken = KSTOP_WAITCOND.notify();
if let Some(&acpi_scheme) = SCHEME_ID.get() {
let handles = HANDLES.read();
let handles = HANDLES.read();
for (&fd, _) in handles.iter().filter(|(_, handle)| handle.kind == HandleKind::ShutdownPipe) {
event::trigger(acpi_scheme, fd, EVENT_READ);
waiters_awoken += 1;
}
} else {
log::error!("Calling register_kstop before kernel ACPI scheme was initialized");
for (&fd, _) in handles.iter().filter(|(_, handle)| handle.kind == HandleKind::ShutdownPipe) {
event::trigger(GlobalSchemes::Acpi.scheme_id(), fd, EVENT_READ);
waiters_awoken += 1;
}
if waiters_awoken == 0 {
@@ -78,13 +71,12 @@ pub fn register_kstop() -> bool {
}
impl AcpiScheme {
pub fn init(id: SchemeId) {
pub fn init() {
// NOTE: This __must__ be called from the main kernel context, while initializing all
// schemes. If it is called by any other context, then all ACPI data will probably not even
// be mapped.
let mut data_init = false;
let mut id_init = false;
DATA.call_once(|| {
data_init = true;
@@ -100,13 +92,8 @@ impl AcpiScheme {
Box::from(table)
});
SCHEME_ID.call_once(|| {
id_init = true;
id
});
if !data_init || !id_init {
if !data_init {
log::error!("AcpiScheme::init called multiple times");
}
}
+3 -16
View File
@@ -1,15 +1,12 @@
use core::sync::atomic::{AtomicUsize, Ordering};
use spin::{Once, RwLock};
use spin::RwLock;
use crate::arch::debug::Writer;
use crate::event;
use crate::scheme::*;
use crate::sync::WaitQueue;
use crate::syscall::flag::{EventFlags, EVENT_READ, F_GETFL, F_SETFL, O_ACCMODE, O_NONBLOCK};
use crate::syscall::usercopy::UserSliceRo;
use crate::syscall::usercopy::UserSliceWo;
static SCHEME_ID: Once<SchemeId> = Once::new();
use crate::syscall::usercopy::{UserSliceRo, UserSliceWo};
static NEXT_ID: AtomicUsize = AtomicUsize::new(0);
@@ -30,23 +27,13 @@ pub fn debug_input(data: u8) {
// Notify readers of input updates
pub fn debug_notify() {
let Some(scheme_id) = SCHEME_ID.get().copied() else {
return;
};
for (id, _handle) in HANDLES.read().iter() {
event::trigger(scheme_id, *id, EVENT_READ);
event::trigger(GlobalSchemes::Debug.scheme_id(), *id, EVENT_READ);
}
}
pub struct DebugScheme;
impl DebugScheme {
pub fn init(scheme_id: SchemeId) {
SCHEME_ID.call_once(|| scheme_id);
}
}
impl KernelScheme for DebugScheme {
fn kopen(&self, path: &str, flags: usize, ctx: CallerCtx) -> Result<OpenResult> {
if ctx.uid != 0 {
-4
View File
@@ -55,10 +55,6 @@ impl Handle {
}
impl MemoryScheme {
pub fn new() -> Self {
MemoryScheme
}
pub fn fmap_anonymous(addr_space: &Arc<RwLock<AddrSpace>>, map: &Map) -> Result<usize> {
let span = PageSpan::validate_nonempty(VirtualAddress::new(map.address), map.size).ok_or(Error::new(EINVAL))?;
let page_count = NonZeroUsize::new(span.count).ok_or(Error::new(EINVAL))?;
+53 -39
View File
@@ -111,9 +111,8 @@ pub struct SchemeList {
map: BTreeMap<SchemeId, KernelSchemes>,
names: BTreeMap<SchemeNamespace, BTreeMap<Box<str>, SchemeId>>,
next_ns: usize,
next_id: usize
next_id: usize,
}
impl SchemeList {
/// Create a new scheme list.
pub fn new() -> Self {
@@ -122,8 +121,9 @@ impl SchemeList {
names: BTreeMap::new(),
// Scheme namespaces always start at 1. 0 is a reserved namespace, the null namespace
next_ns: 1,
next_id: 1
next_id: 1 + core::mem::variant_count::<GlobalSchemes>(),
};
list.new_null();
list.new_root();
list
@@ -136,12 +136,9 @@ impl SchemeList {
//TODO: Only memory: is in the null namespace right now. It should be removed when
//anonymous mmap's are implemented
self.insert(ns, "memory", |_| KernelSchemes::Memory).unwrap();
self.insert_global(ns, "memory", GlobalSchemes::Memory).unwrap();
self.insert(ns, "thisproc", |_| KernelSchemes::Proc(Arc::new(ProcScheme::restricted()))).unwrap();
self.insert(ns, "pipe", |scheme_id| {
PipeScheme::init(scheme_id);
KernelSchemes::Pipe
}).unwrap();
self.insert_global(ns, "pipe", GlobalSchemes::Pipe).unwrap();
}
/// Initialize a new namespace
@@ -151,13 +148,10 @@ impl SchemeList {
self.names.insert(ns, BTreeMap::new());
self.insert(ns, "", |scheme_id| KernelSchemes::Root(Arc::new(RootScheme::new(ns, scheme_id)))).unwrap();
self.insert(ns, "event", |_| KernelSchemes::Event).unwrap();
self.insert_global(ns, "event", GlobalSchemes::Event).unwrap();
self.insert(ns, "itimer", |_| KernelSchemes::ITimer(Arc::new(ITimerScheme::new()))).unwrap();
self.insert(ns, "memory", |_| KernelSchemes::Memory).unwrap();
self.insert(ns, "pipe", |scheme_id| {
PipeScheme::init(scheme_id);
KernelSchemes::Pipe
}).unwrap();
self.insert_global(ns, "memory", GlobalSchemes::Memory).unwrap();
self.insert_global(ns, "pipe", GlobalSchemes::Pipe).unwrap();
self.insert(ns, "sys", |_| KernelSchemes::Sys(Arc::new(SysScheme::new()))).unwrap();
self.insert(ns, "time", |scheme_id| KernelSchemes::Time(Arc::new(TimeScheme::new(scheme_id)))).unwrap();
@@ -170,28 +164,19 @@ impl SchemeList {
let ns = self.new_ns();
// These schemes should only be available on the root
#[cfg(all(feature = "acpi", any(target_arch = "x86", target_arch = "x86_64")))]
self.insert(ns, "kernel.acpi", |scheme_id| {
AcpiScheme::init(scheme_id);
KernelSchemes::Acpi
}).unwrap();
#[cfg(all(any(target_arch = "aarch64")))]
{
self.insert(ns, "kernel.dtb", |scheme_id| Arc::new(DtbScheme::new(scheme_id))).unwrap();
}
self.insert(ns, "debug", |scheme_id| {
DebugScheme::init(scheme_id);
KernelSchemes::Debug
}).unwrap();
#[cfg(all(feature = "acpi", any(target_arch = "x86", target_arch = "x86_64")))]
{
self.insert_global(ns, "kernel.acpi", GlobalSchemes::Acpi).unwrap();
}
self.insert_global(ns, "debug", GlobalSchemes::Debug).unwrap();
self.insert(ns, "irq", |scheme_id| KernelSchemes::Irq(Arc::new(IrqScheme::new(scheme_id)))).unwrap();
self.insert(ns, "proc", |scheme_id| KernelSchemes::Proc(Arc::new(ProcScheme::new(scheme_id)))).unwrap();
self.insert(ns, "thisproc", |_| KernelSchemes::Proc(Arc::new(ProcScheme::restricted()))).unwrap();
self.insert(ns, "serio", |scheme_id| {
SerioScheme::init(scheme_id);
KernelSchemes::Serio
}).unwrap();
self.insert_global(ns, "serio", GlobalSchemes::Serio).unwrap();
}
pub fn make_ns(&mut self, from: SchemeNamespace, names: impl IntoIterator<Item = Box<str>>) -> Result<SchemeNamespace> {
@@ -236,6 +221,16 @@ impl SchemeList {
None
}
pub fn insert_global(&mut self, ns: SchemeNamespace, name: &str, global: GlobalSchemes) -> Result<()> {
let prev = self.names.get_mut(&ns).ok_or(Error::new(ENODEV))?.insert(name.into(), global.scheme_id());
if prev.is_some() {
return Err(Error::new(EEXIST));
}
Ok(())
}
/// Create a new scheme.
pub fn insert(&mut self, ns: SchemeNamespace, name: &str, scheme_fn: impl FnOnce(SchemeId) -> KernelSchemes) -> Result<SchemeId> {
self.insert_and_pass(ns, name, |id| (scheme_fn(id), ())).map(|(id, ())| id)
@@ -422,18 +417,23 @@ pub fn calc_seek_offset(cur_pos: usize, rel_pos: isize, whence: usize, len: usiz
#[derive(Clone)]
pub enum KernelSchemes {
Debug,
Event,
Irq(Arc<IrqScheme>),
ITimer(Arc<ITimerScheme>),
Memory,
Pipe,
Proc(Arc<ProcScheme>),
Root(Arc<RootScheme>),
Serio,
Sys(Arc<SysScheme>),
Time(Arc<TimeScheme>),
User(UserScheme),
Global(GlobalSchemes),
}
#[repr(u8)]
#[derive(Clone, Copy)]
pub enum GlobalSchemes {
Debug = 1,
Event,
Memory,
Pipe,
Serio,
#[cfg(all(feature = "acpi", any(target_arch = "x86", target_arch = "x86_64")))]
Acpi,
@@ -444,21 +444,35 @@ impl core::ops::Deref for KernelSchemes {
fn deref(&self) -> &Self::Target {
match self {
Self::Debug => &DebugScheme,
Self::Event => &EventScheme,
Self::Irq(scheme) => &**scheme,
Self::ITimer(scheme) => &**scheme,
Self::Memory => &MemoryScheme,
Self::Pipe => &PipeScheme,
Self::Proc(scheme) => &**scheme,
Self::Root(scheme) => &**scheme,
Self::Serio => &SerioScheme,
Self::Sys(scheme) => &**scheme,
Self::Time(scheme) => &**scheme,
Self::User(scheme) => scheme,
Self::Global(global) => &**global,
}
}
}
impl core::ops::Deref for GlobalSchemes {
type Target = dyn KernelScheme;
fn deref(&self) -> &Self::Target {
match self {
Self::Debug => &DebugScheme,
Self::Event => &EventScheme,
Self::Memory => &MemoryScheme,
Self::Pipe => &PipeScheme,
Self::Serio => &SerioScheme,
#[cfg(all(feature = "acpi", any(target_arch = "x86", target_arch = "x86_64")))]
Self::Acpi => &AcpiScheme,
}
}
}
impl GlobalSchemes {
pub fn scheme_id(self) -> SchemeId {
SchemeId::new(self as usize)
}
}
+5 -17
View File
@@ -3,30 +3,24 @@ use core::sync::atomic::{AtomicUsize, Ordering, AtomicBool};
use alloc::sync::Arc;
use alloc::collections::{BTreeMap, VecDeque};
use spin::{Mutex, Once, RwLock};
use spin::{Mutex, RwLock};
use crate::event;
use crate::scheme::SchemeId;
use crate::sync::WaitCondition;
use crate::syscall::error::{Error, Result, EAGAIN, EBADF, EINTR, EINVAL, ENOENT, EPIPE, ESPIPE};
use crate::syscall::flag::{EventFlags, EVENT_READ, EVENT_WRITE, F_GETFL, F_SETFL, O_ACCMODE, O_NONBLOCK, MODE_FIFO};
use crate::syscall::data::Stat;
use crate::syscall::usercopy::{UserSliceWo, UserSliceRo};
use super::{KernelScheme, OpenResult, CallerCtx};
use super::{KernelScheme, OpenResult, CallerCtx, GlobalSchemes};
// TODO: Preallocate a number of scheme IDs, since there can only be *one* root namespace, and
// therefore only *one* pipe scheme.
static SCHEME_ID: Once<SchemeId> = Once::new();
static PIPE_NEXT_ID: AtomicUsize = AtomicUsize::new(1);
// TODO: SLOB?
static PIPES: RwLock<BTreeMap<usize, Arc<Pipe>>> = RwLock::new(BTreeMap::new());
pub fn pipe_scheme_id() -> SchemeId {
*SCHEME_ID.get().expect("pipe scheme must be initialized")
}
const MAX_QUEUE_SIZE: usize = 65536;
// In almost all places where Rust (and LLVM) uses pointers, they are limited to nonnegative isize,
@@ -56,12 +50,6 @@ pub fn pipe(flags: usize) -> Result<(usize, usize)> {
pub struct PipeScheme;
impl PipeScheme {
pub fn init(scheme_id: SchemeId) {
SCHEME_ID.call_once(|| scheme_id);
}
}
impl KernelScheme for PipeScheme {
fn fcntl(&self, id: usize, cmd: usize, arg: usize) -> Result<usize> {
let (is_writer_not_reader, key) = from_raw_id(id);
@@ -110,7 +98,7 @@ impl KernelScheme for PipeScheme {
let (is_write_not_read, key) = from_raw_id(id);
let pipe = Arc::clone(PIPES.read().get(&key).ok_or(Error::new(EBADF))?);
let scheme_id = pipe_scheme_id();
let scheme_id = GlobalSchemes::Pipe.scheme_id();
let can_remove = if is_write_not_read {
event::trigger(scheme_id, key, EVENT_READ);
@@ -193,7 +181,7 @@ impl KernelScheme for PipeScheme {
let _ = vec.drain(..bytes_read);
if bytes_read > 0 {
event::trigger(pipe_scheme_id(), key | WRITE_NOT_READ_BIT, EVENT_WRITE);
event::trigger(GlobalSchemes::Pipe.scheme_id(), key | WRITE_NOT_READ_BIT, EVENT_WRITE);
pipe.write_condition.notify();
return Ok(bytes_read);
@@ -242,7 +230,7 @@ impl KernelScheme for PipeScheme {
}
if bytes_written > 0 {
event::trigger(pipe_scheme_id(), key, EVENT_READ);
event::trigger(GlobalSchemes::Pipe.scheme_id(), key, EVENT_READ);
pipe.read_condition.notify();
return Ok(bytes_written);
+2 -14
View File
@@ -3,7 +3,7 @@
use core::str;
use core::sync::atomic::{AtomicUsize, Ordering};
use spin::{Once, RwLock};
use spin::RwLock;
use crate::event;
use crate::scheme::*;
@@ -11,8 +11,6 @@ use crate::sync::WaitQueue;
use crate::syscall::flag::{EventFlags, EVENT_READ, F_GETFL, F_SETFL, O_ACCMODE, O_NONBLOCK};
use crate::syscall::usercopy::UserSliceWo;
static SCHEME_ID: Once<SchemeId> = Once::new();
static NEXT_ID: AtomicUsize = AtomicUsize::new(0);
/// Input queue
@@ -30,23 +28,13 @@ static HANDLES: RwLock<BTreeMap<usize, Handle>> = RwLock::new(BTreeMap::new());
pub fn serio_input(index: usize, data: u8) {
INPUT[index].send(data);
let Some(scheme_id) = SCHEME_ID.get().copied() else {
return;
};
for (id, _handle) in HANDLES.read().iter() {
event::trigger(scheme_id, *id, EVENT_READ);
event::trigger(GlobalSchemes::Serio.scheme_id(), *id, EVENT_READ);
}
}
pub struct SerioScheme;
impl SerioScheme {
pub fn init(scheme_id: SchemeId) {
SCHEME_ID.call_once(|| scheme_id);
}
}
impl KernelScheme for SerioScheme {
fn kopen(&self, path: &str, flags: usize, ctx: CallerCtx) -> Result<OpenResult> {
if ctx.uid != 0 {
+1 -1
View File
@@ -214,7 +214,7 @@ pub fn sendfd(socket: FileHandle, fd: FileHandle, flags_raw: usize, arg: u64) ->
let (scheme, number) = match current.get_file(socket).ok_or(Error::new(EBADF))?.description.read() {
ref desc => (desc.scheme, desc.number),
};
let scheme = Arc::clone(scheme::schemes().get(scheme).ok_or(Error::new(ENODEV))?);
let scheme = scheme::schemes().get(scheme).ok_or(Error::new(ENODEV))?.clone();
(scheme, number, current.remove_file(fd).ok_or(Error::new(EBADF))?.description)
};