Files
RedBear-OS/src/startup/mod.rs
T
Red Bear OS 4f2a0436eb kernel: re-sync ACPI subsystem with upstream master
Phase A of the ACPI fork-sync plan (local/docs/ACPI-FORK-SYNC-STRATEGY-2026-06-30.md).

Restores the kernel to the upstream Redox OS kernel main branch state for
the ACPI subsystem:

- Cargo.toml: switch redox_syscall from 0.7.4 (two versions behind) to a
  git ref of gitlab.redox-os.org/redox-os/syscall.git, matching the
  upstream master dependency. The crates.io 0.8.1 release predates the
  AcpiVerb enum that MR #613 / MR #275 introduced, so a crates.io pin
  is insufficient.

- src/acpi/rsdp.rs: full rewrite to match upstream f49c7d99 (RSDP
  validation + NonNull + fail-softly):
    * signature check "RSD PTR "
    * 20-byte base checksum
    * full-length checksum for revision >= 2
    * NonNull<u8> instead of *const u8
  Fixes gap #1 from the 2026-06-30 ACPI assessment: the kernel was
  accepting any pointer from the bootloader without validation.

- src/startup/mod.rs: acpi_rsdp() returns Option<NonNull<u8>> to match
  the new Rsdp::get_rsdp signature.

- src/acpi/mod.rs: init() takes Option<NonNull<u8>>.

- src/scheme/acpi.rs: full rewrite to upstream MR #613 (Simplify acpi
  scheme). Drops the /scheme/kernel.acpi/ filesystem surface in favor
  of a single Fd::open + call() interface with AcpiVerb verbs:
    * AcpiVerb::ReadRxsdt - returns the raw RXSDT bytes
    * AcpiVerb::CheckShutdown - returns whether shutdown is pending
  Uses HandleBits bitflags, atomic EXISTS_KSTOP_HANDLE, Mutex<L4> from
  crate::sync::ordered. Replaces /scheme/kernel.acpi/rxsdt and
  /scheme/kernel.acpi/kstop files.

- src/scheme/mod.rs: KernelScheme::kcall signature updated to take
  fds: &[usize] instead of id: usize (matches upstream). kfpath now
  has a default body returning EOPNOTSUPP (matches upstream).

- src/scheme/memory.rs, proc.rs, user.rs: kcall impls updated to
  match new trait signature, using fds.first() to extract the single
  handle for backward compat.

- src/scheme/proc.rs: kcall dispatch adds _ => Err(EINVAL) catch-all
  for the new ProcSchemeVerb variants (RegsInt, RegsFloat, RegsEnv,
  SchedAffinity, Start) that the gitlab syscall crate adds. These
  verbs are not yet implemented in the proc scheme; the catch-all
  returns EINVAL cleanly instead of failing to compile.

- src/syscall/fs.rs: SYS_CALL dispatcher now passes &[number] to
  scheme.kcall() to match the new trait signature.

- Makefile: removed -Z json-target-spec flag (promoted to stable in
  nightly 2026-04-01; the flag is unknown in our pinned toolchain).

Verified by `make` in local/sources/kernel/ with PATH including the
prefix cross-toolchain: kernel builds and links successfully.
2026-06-30 04:09:05 +03:00

240 lines
6.8 KiB
Rust

use core::{
hint, slice,
sync::atomic::{AtomicBool, Ordering},
};
use core::ptr::NonNull;
use crate::{
arch::interrupt,
context,
context::switch::SwitchResult,
memory::{PhysicalAddress, RmmA, RmmArch},
profiling, scheme,
sync::CleanLockToken,
};
pub mod memory;
#[repr(C, packed(8))]
pub(crate) struct KernelArgs {
kernel_base: u64,
kernel_size: u64,
stack_base: u64,
stack_size: u64,
env_base: u64,
env_size: u64,
/// The base pointer to the saved RSDP or device tree blob.
///
/// On x86 this field can be NULL, and if so, the system has not booted
/// with UEFI or in some other way retrieved the RSDPs. The kernel or a
/// userspace driver will thus try searching the BIOS memory instead. On
/// UEFI systems, searching is not guaranteed to actually work though.
/// On other architectures this field must always contain a pointer to
/// either an RSDP or device tree blob.
pub(crate) hwdesc_base: u64,
pub(crate) hwdesc_size: u64,
areas_base: u64,
areas_size: u64,
/// The physical base 64-bit pointer to the contiguous bootstrap/initfs.
bootstrap_base: u64,
/// Size of contiguous bootstrap/initfs physical region, not necessarily page aligned.
bootstrap_size: u64,
}
impl KernelArgs {
pub(crate) fn print(&self) {
debug!(
"Kernel: {:X}:{:X}",
{ self.kernel_base },
self.kernel_base + self.kernel_size
);
debug!(
"Env: {:X}:{:X}",
{ self.env_base },
self.env_base + self.env_size
);
debug!(
"HWDESC: {:X}:{:X}",
{ self.hwdesc_base },
self.hwdesc_base + self.hwdesc_size
);
debug!(
"Areas: {:X}:{:X}",
{ self.areas_base },
self.areas_base + self.areas_size
);
debug!(
"Bootstrap: {:X}:{:X}",
{ self.bootstrap_base },
self.bootstrap_base + self.bootstrap_size
);
}
pub(crate) fn bootstrap(&self) -> Bootstrap {
Bootstrap {
base: crate::memory::Frame::containing(crate::memory::PhysicalAddress::new(
self.bootstrap_base as usize,
)),
page_count: (self.bootstrap_size as usize) / crate::memory::PAGE_SIZE,
env: self.env(),
}
}
pub(crate) fn env(&self) -> &'static [u8] {
unsafe {
slice::from_raw_parts(
RmmA::phys_to_virt(PhysicalAddress::new(self.env_base as usize)).data()
as *const u8,
self.env_size as usize,
)
}
}
pub(crate) fn acpi_rsdp(&self) -> Option<NonNull<u8>> {
if self.hwdesc_base != 0 {
let data = unsafe {
slice::from_raw_parts(
RmmA::phys_to_virt(PhysicalAddress::new(self.hwdesc_base as usize)).data()
as *const u8,
self.hwdesc_size as usize,
)
};
if data.starts_with(b"RSD PTR ") {
Some(NonNull::new(data.as_ptr() as *mut u8).unwrap())
} else {
None
}
} else {
None
}
}
pub(crate) fn dtb(&self) -> Option<fdt::Fdt<'static>> {
if self.hwdesc_base != 0 {
let data = unsafe {
slice::from_raw_parts(
RmmA::phys_to_virt(PhysicalAddress::new(self.hwdesc_base as usize)).data()
as *const u8,
self.hwdesc_size as usize,
)
};
fdt::Fdt::new(data).ok()
} else {
None
}
}
}
pub(crate) fn init_env() -> &'static [u8] {
BOOTSTRAP.get().expect("BOOTSTRAP was not set").env
}
extern "C" fn userspace_init() {
let mut token = unsafe { CleanLockToken::new() };
let bootstrap = BOOTSTRAP.get().expect("BOOTSTRAP was not set");
unsafe { crate::syscall::process::usermode_bootstrap(bootstrap, &mut token) }
}
pub(crate) struct Bootstrap {
pub(crate) base: crate::memory::Frame,
pub(crate) page_count: usize,
env: &'static [u8],
}
static BOOTSTRAP: spin::Once<Bootstrap> = spin::Once::new();
pub(crate) static AP_READY: AtomicBool = AtomicBool::new(false);
static BSP_READY: AtomicBool = AtomicBool::new(false);
/// This is the kernel entry point for the primary CPU. The arch crate is responsible for calling this
pub(crate) fn kmain(bootstrap: Bootstrap) -> ! {
let mut token = unsafe { CleanLockToken::new() };
BSP_READY.store(true, Ordering::SeqCst);
//Initialize the first context, stored in kernel/src/context/mod.rs
context::init(&mut token);
//Initialize global schemes, such as `acpi:`.
scheme::init_globals();
debug!("BSP: {} CPUs", crate::cpu_count());
debug!("Env: {:?}", ::core::str::from_utf8(bootstrap.env));
BOOTSTRAP.call_once(|| bootstrap);
profiling::ready_for_profiling();
let owner = None; // kmain not owned by any fd
match context::spawn(true, owner, userspace_init, &mut token) {
Ok(context_lock) => {
let mut context = context_lock.write(token.token());
context.status = context::Status::Runnable;
context.name.clear();
context.name.push_str("[bootstrap]");
// TODO: Remove these from kernel
context.euid = 0;
context.egid = 0;
}
Err(err) => {
panic!("failed to spawn userspace_init: {:?}", err);
}
}
run_userspace(&mut token)
}
/// This is the main kernel entry point for secondary CPUs
#[allow(unreachable_code, unused_variables, dead_code)]
pub(crate) fn kmain_ap(cpu_id: crate::cpu_set::LogicalCpuId) -> ! {
let mut token = unsafe { CleanLockToken::new() };
AP_READY.store(true, Ordering::SeqCst);
while !BSP_READY.load(Ordering::SeqCst) {
hint::spin_loop();
}
profiling::maybe_run_profiling_helper_forever(cpu_id);
if !cfg!(feature = "multi_core") {
debug!("AP {}: Disabled", cpu_id);
loop {
unsafe {
interrupt::disable();
interrupt::halt();
}
}
}
context::init(&mut token);
debug!("AP {}", cpu_id);
profiling::ready_for_profiling();
run_userspace(&mut token);
}
fn run_userspace(token: &mut CleanLockToken) -> ! {
loop {
unsafe {
interrupt::disable();
match context::switch(token) {
SwitchResult::Switched => {
interrupt::enable_and_nop();
}
SwitchResult::AllContextsIdle => {
// Enable interrupts, then halt CPU (to save power) until the next interrupt is actually fired.
interrupt::enable_and_halt();
}
}
}
}
}