kernel: LG Gram SMBIOS scan + MWAIT idle + warning cleanup

Round 7 LG Gram 16Z90TP-G.AL89C compatibility work.

BLOCKING ERRORS FIXED (smbios.rs):
- Wrap map_physical_range() calls in unsafe {} blocks at lines 83, 180
  (unsafe-op-in-unsafe-fn is denied in edition 2024)
- Fix lifetime: bytes is &'static [u8] since mapped SMBIOS memory persists
  for kernel lifetime; propagate &'static through dmi_string, decode_type_1,
  decode_type_2 signatures

E0133 WARNINGS FIXED (interrupt/mod.rs):
- Wrap mwait_loop inline asm! in unsafe {} block
- Wrap enable_and_halt() + mwait_loop() calls in idle_loop in unsafe {} blocks

UNNECESSARY-UNSAFE WARNINGS FIXED:
- cpuid.rs: remove unsafe {} wrapper around now-safe __cpuid_count intrinsic
- tsc.rs: remove unsafe {} wrapper around now-safe rdtsc intrinsic

GENERAL WARNING CLEANUP (~40 warnings across 19 files):
- Remove unused imports: rmm/lib.rs, acpi/mod.rs, rsdt.rs, rxsdt.rs,
  slit.rs, srat/, xsdt.rs, context/mod.rs, memory/mod.rs, numa.rs,
  scheme/user.rs, syscall/fs.rs
- Prefix unused variables with _
- Remove unnecessary mut
- Remove unnecessary unsafe {} blocks: stop.rs, srat/mod.rs, memory/mod.rs

Verified: repo cook kernel --force-rebuild succeeds with zero errors and
zero warnings.

LG Gram 16Z90TP-G.AL89C: SMBIOS scan now reads vendor/model/panel
orientation table for quirks-driven panel orientation detection.
This commit is contained in:
2026-07-27 00:49:24 +09:00
parent bb4a97ec63
commit bd656d7f2c
21 changed files with 77 additions and 90 deletions
-1
View File
@@ -1,7 +1,6 @@
#![no_std]
#![allow(clippy::new_without_default)]
use core::ops::Add;
pub use crate::{allocator::*, arch::*, page::*};
+3 -3
View File
@@ -3,7 +3,7 @@
use core::ptr::NonNull;
use alloc::{boxed::Box, string::String, vec::Vec};
use alloc::{string::String, vec::Vec};
use hashbrown::HashMap;
use rmm::{BumpAllocator, FrameAllocator, PageMapper};
@@ -11,7 +11,7 @@ use spin::{Once, RwLock};
use crate::{
acpi::rxsdt::RxsdtIter,
memory::{KernelMapper, PageFlags, PhysicalAddress, RmmA, RmmArch},
memory::{PageFlags, PhysicalAddress, RmmA, RmmArch},
};
use self::{hpet::Hpet, madt::Madt, rsdp::Rsdp, rsdt::Rsdt, rxsdt::Rxsdt, sdt::Sdt, xsdt::Xsdt};
@@ -171,7 +171,7 @@ pub unsafe fn init_before_mem(
/// Parse the ACPI tables to gather CPU, interrupt, and timer information. The code performs allocations, so
/// it must be called only after the allocator is set up.
pub unsafe fn init_after_mem(already_supplied_rsdp: Option<NonNull<u8>>) {
pub unsafe fn init_after_mem(_already_supplied_rsdp: Option<NonNull<u8>>) {
if let Some(rxsdt) = RXSDT_ENUM.get() {
unsafe {
{
-2
View File
@@ -1,6 +1,4 @@
use alloc::boxed::Box;
use core::convert::TryFrom;
use rmm::PhysicalAddress;
use crate::acpi::{rxsdt::RxsdtIter, RxsdtEnum};
-1
View File
@@ -1,4 +1,3 @@
use alloc::boxed::Box;
use rmm::PhysicalAddress;
use crate::acpi::{sdt::Sdt, RxsdtEnum};
+4 -10
View File
@@ -1,12 +1,6 @@
use crate::{
acpi::{rxsdt::Rxsdt, sdt::Sdt, RXSDT_ENUM},
find_one_sdt,
memory::{round_up_pages, PAGE_SIZE},
numa::{self},
};
use core::{ops::Add, slice};
use hashbrown::HashMap;
use rmm::{Arch, BumpAllocator, FrameAllocator, FrameCount};
use crate::acpi::{rxsdt::Rxsdt, sdt::Sdt, RXSDT_ENUM};
use core::slice;
use rmm::{Arch, BumpAllocator};
use spin::once::Once;
#[derive(Debug)]
@@ -24,7 +18,7 @@ impl Slit {
address: (sdt.data_address() + 8) as *const u8,
}
}
pub fn init<A: Arch>(&self, allocator: &mut BumpAllocator<A>) -> &'static mut [u8] {
pub fn init<A: Arch>(&self, _allocator: &mut BumpAllocator<A>) -> &'static mut [u8] {
unsafe { slice::from_raw_parts_mut(self.address as *mut u8, (self.no * self.no) as usize) }
}
}
+24 -11
View File
@@ -80,11 +80,16 @@ fn scan() -> Option<SmbiosInfo> {
{
use crate::memory::KernelMapper;
let mut mapper = KernelMapper::lock_rw();
super::map_physical_range(
PhysicalAddress::new(SMBIOS_ANCHOR_START),
SMBIOS_ANCHOR_LEN,
&mut mapper,
);
// SAFETY: mapping the read-only SMBIOS anchor scan window (0xF0000,
// 64 KiB) into the kernel's linear map. The region is firmware-owned
// read-only memory; the mapping persists for kernel lifetime.
unsafe {
super::map_physical_range(
PhysicalAddress::new(SMBIOS_ANCHOR_START),
SMBIOS_ANCHOR_LEN,
&mut mapper,
);
}
}
let anchor_virt = RmmA::phys_to_virt(PhysicalAddress::new(SMBIOS_ANCHOR_START)).data();
@@ -177,12 +182,20 @@ fn walk_table(table_addr: usize, total_len: usize, num_structs: u16) -> Option<S
{
use crate::memory::KernelMapper;
let mut mapper = KernelMapper::lock_rw();
super::map_physical_range(PhysicalAddress::new(table_addr), total_len, &mut mapper);
// SAFETY: mapping the SMBIOS structure table at `table_addr` for
// `total_len` bytes into the kernel's linear map. The region is
// firmware-owned read-only memory; the mapping persists for kernel
// lifetime, which is why string slices extracted from it are `&'static`.
unsafe {
super::map_physical_range(PhysicalAddress::new(table_addr), total_len, &mut mapper);
}
}
let virt = RmmA::phys_to_virt(PhysicalAddress::new(table_addr)).data();
// SAFETY: `total_len` bytes at `table_addr` were just mapped.
let bytes: &[u8] = unsafe { core::slice::from_raw_parts(virt as *const u8, total_len) };
// SAFETY: `total_len` bytes at `table_addr` were just mapped into the
// kernel's linear map. The mapping is read-only and persists for kernel
// lifetime, so the slice is `&'static`.
let bytes: &'static [u8] = unsafe { core::slice::from_raw_parts(virt as *const u8, total_len) };
let mut info = SmbiosInfo::default();
let mut offset = 0usize;
@@ -245,7 +258,7 @@ fn checksum_ok(buf: &[u8]) -> bool {
/// Returns a `'static` slice into the mapped SMBIOS table. Index 0 means
/// "not present". Strings containing only spaces are treated as absent
/// (matches Linux semantics).
fn dmi_string(strings: &[u8], index: u8) -> Option<&'static str> {
fn dmi_string(strings: &'static [u8], index: u8) -> Option<&'static str> {
if index == 0 {
return None;
}
@@ -276,7 +289,7 @@ fn dmi_string(strings: &[u8], index: u8) -> Option<&'static str> {
/// Decode SMBIOS Type 1 (System Information) — DMTF DSP0134 §7.2.
/// Offset 4 = manufacturer string index, offset 5 = product name string index.
fn decode_type_1(formatted: &[u8], strings: &[u8], info: &mut SmbiosInfo) {
fn decode_type_1(formatted: &'static [u8], strings: &'static [u8], info: &mut SmbiosInfo) {
if formatted.len() < 6 {
return;
}
@@ -290,7 +303,7 @@ fn decode_type_1(formatted: &[u8], strings: &[u8], info: &mut SmbiosInfo) {
/// Decode SMBIOS Type 2 (Baseboard Information) — DMTF DSP0134 §7.3.
/// Offset 4 = manufacturer string index, offset 5 = product string index.
fn decode_type_2(formatted: &[u8], strings: &[u8], info: &mut SmbiosInfo) {
fn decode_type_2(formatted: &'static [u8], strings: &'static [u8], info: &mut SmbiosInfo) {
if formatted.len() < 6 {
return;
}
+3 -4
View File
@@ -2,14 +2,13 @@
use core::slice;
use hashbrown::HashMap;
use rmm::{Arch, BumpAllocator, FrameAllocator};
use spin::once::Once;
use crate::{
acpi::{find_sdt, get_sdt_signature, rxsdt::Rxsdt, sdt::Sdt, srat, RXSDT_ENUM},
acpi::{rxsdt::Rxsdt, sdt::Sdt, RXSDT_ENUM},
cpu_set::MAX_CPU_COUNT,
find_one_sdt, memory,
memory,
numa::{self, NumaMemory},
};
@@ -38,7 +37,7 @@ pub fn init<A: Arch>(
.expect("Failed to allocate memory for storing NUMA info");
let dom_node_map_ptr =
unsafe { crate::memory::RmmA::phys_to_virt(dom_node_map).data() as *mut u32 };
crate::memory::RmmA::phys_to_virt(dom_node_map).data() as *mut u32;
// Occupies 512 bytes (1/8th of a page)
let dom_node_map: &'static mut [u32] =
-6
View File
@@ -1,12 +1,6 @@
use core::{iter, slice};
use hashbrown::HashMap;
use rmm::{Arch, BumpAllocator, FrameAllocator, PhysicalAddress};
use crate::{
acpi::srat::{to_usize, Srat, SratEntry},
cpu_set,
memory::{self, PAGE_SIZE},
numa::{self, assign_memory_id, NumaMemory},
};
-2
View File
@@ -1,6 +1,4 @@
use alloc::boxed::Box;
use core::convert::TryFrom;
use rmm::PhysicalAddress;
use crate::acpi::{rxsdt::RxsdtIter, RxsdtEnum};
+1 -1
View File
@@ -6,7 +6,7 @@ pub fn cpuid() -> CpuId {
#[cfg(target_arch = "x86")]
let result = unsafe { core::arch::x86::__cpuid_count(a, c) };
#[cfg(target_arch = "x86_64")]
let result = unsafe { core::arch::x86_64::__cpuid_count(a, c) };
let result = core::arch::x86_64::__cpuid_count(a, c);
CpuIdResult {
eax: result.eax,
ebx: result.ebx,
+2 -2
View File
@@ -99,7 +99,7 @@ pub fn get_kvm_support() -> &'static Option<KvmSupport> {
static KVM_SUPPORT: Once<Option<KvmSupport>> = Once::new();
KVM_SUPPORT.call_once(|| {
let res = unsafe { __cpuid(0x4000_0000) };
let res = __cpuid(0x4000_0000);
if [res.ebx, res.ecx, res.edx].map(u32::to_le_bytes) != [*b"KVMK", *b"VMKV", *b"M\0\0\0"] {
return None;
}
@@ -107,7 +107,7 @@ pub fn get_kvm_support() -> &'static Option<KvmSupport> {
if max_leaf < 0x4000_0001 {
return None;
}
let res = unsafe { __cpuid(0x4000_0001) };
let res = __cpuid(0x4000_0001);
let supp_feats = KvmFeatureBits::from_bits_retain(res.eax);
+16 -17
View File
@@ -52,7 +52,7 @@ pub unsafe fn halt() {
pub fn cpuid_max_mwait_substate() -> u16 {
use raw_cpuid::CpuId;
use raw_cpuid::CpuIdResult;
let cpuid = CpuId::with_cpuid_fn(|a, c| {
let cpuid = CpuId::with_cpuid_fn(|_a, _c| {
// raw_cpuid's expected closure signature: closure takes
// (leaf, subleaf) and returns CpuIdResult. When the cache
// is populated (which it is by the time we run), this
@@ -99,12 +99,18 @@ pub fn cpuid_max_mwait_substate() -> u16 {
#[inline(always)]
pub unsafe fn mwait_loop(eax_hint: u32, ecx_hint: u32) {
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
core::arch::asm!(
"sti; monitor; mwait",
in("eax") eax_hint,
in("ecx") ecx_hint,
options(nomem, nostack, preserves_flags),
);
// SAFETY: `sti; monitor; mwait` is an atomic "enable interrupts +
// monitor+wait" sequence. The caller guarantees MWAIT is supported
// (checked via cpuid_max_mwait_substate). ecx=0 means "break on any
// interrupt". nomem/nostack/preserves_flags match the ABI contract.
unsafe {
core::arch::asm!(
"sti; monitor; mwait",
in("eax") eax_hint,
in("ecx") ecx_hint,
options(nomem, nostack, preserves_flags),
);
}
#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
let _ = (eax_hint, ecx_hint);
@@ -138,18 +144,11 @@ pub unsafe fn mwait_loop(eax_hint: u32, ecx_hint: u32) {
pub unsafe fn idle_loop() {
let max_substate = cpuid_max_mwait_substate();
if max_substate == 0 {
// No MWAIT support. Land in C1 via hlt. This matches the
// pre-MWAIT behavior of `enable_and_halt` and is safe on
// every x86 CPU since the original Pentium.
enable_and_halt();
unsafe { enable_and_halt() };
} else {
// MWAIT supported. Enter the deepest substate, break on any
// interrupt (ecx=0). Prefer the LPIT entry_trigger hint (set by
// acpid via AcpiVerb::SetLpiHint); fall back to CPUID leaf-5 max
// substate when no LPIT hint is available.
let eax_hint: u32 = crate::scheme::acpi::lpi_mwait_hint()
.unwrap_or(0x20 | (max_substate as u32));
enable_and_halt(); // interrupts must be enabled first
mwait_loop(eax_hint, 0);
unsafe { enable_and_halt() };
unsafe { mwait_loop(eax_hint, 0) };
}
}
+1 -1
View File
@@ -109,7 +109,7 @@ unsafe extern "C" fn start(args_ptr: *const KernelArgs, stack_end: usize) -> ! {
let mut bump_allocator =
crate::startup::memory::init(&args, Some(0x100000), Some(0x40000000));
#[cfg(target_arch = "x86_64")]
let mut bump_allocator = crate::startup::memory::init(&args, Some(0x100000), None);
let bump_allocator = crate::startup::memory::init(&args, Some(0x100000), None);
// Initialize paging
paging::init();
+2 -4
View File
@@ -146,10 +146,8 @@ pub unsafe fn kstop(token: &mut CleanLockToken) -> ! {
/// Hardware-agnostic: works on any platform with Modern Standby
/// firmware (Dell, HP, Lenovo, LG Gram, etc.).
pub unsafe fn enter_s2idle() {
unsafe {
info!("Phase I: kstop s2idle request");
crate::scheme::acpi::s2idle_request_set();
}
info!("Phase I: kstop s2idle request");
crate::scheme::acpi::s2idle_request_set();
}
/// Signal s2idle exit.
+1 -2
View File
@@ -11,7 +11,6 @@ use core::{cmp::Reverse, num::NonZeroUsize, ops::Deref};
use crate::{
context::{
memory::AddrSpaceWrapper,
switch::{BASE_SLICE_TICKS, NANOS_PER_TICK, SCALE, SCHED_PRIO_TO_WEIGHT, TICK_INTERVAL},
},
cpu_set::LogicalCpuSet,
ipi::{ipi, IpiKind, IpiTarget},
@@ -294,7 +293,7 @@ pub fn spawn(
let context_lock = Arc::new(ContextLock::new(context));
let context_ref = ContextRef(Arc::clone(&context_lock));
let run_ref = WeakContextRef(Arc::downgrade(&context_ref.0));
let _run_ref = WeakContextRef(Arc::downgrade(&context_ref.0));
contexts_mut(token.downgrade()).insert(context_ref);
Ok(context_lock)
+1 -1
View File
@@ -78,7 +78,7 @@ pub fn excp_handler(excp: syscall::Exception) {
let context = current.write(token.token());
let Some(eh) = context.sig.as_ref().and_then(|s| s.excp_handler) else {
let Some(_eh) = context.sig.as_ref().and_then(|s| s.excp_handler) else {
// TODO: Let procmgr print this?
info!(
"UNHANDLED EXCEPTION, CPU {}, PID {}, NAME {}, CONTEXT {current:p}",
+7 -7
View File
@@ -6,7 +6,7 @@ use core::{
num::NonZeroUsize,
ops::AddAssign,
slice,
sync::atomic::{AtomicU8, AtomicUsize, Ordering},
sync::atomic::{AtomicUsize, Ordering},
};
pub use kernel_mapper::KernelMapper;
@@ -612,7 +612,7 @@ fn init_sections(mut allocator: &mut BumpAllocator<RmmA>) {
i: &mut usize, // out parameter
force: bool|
-> Option<MemoryArea> {
let mut iter = free_areas_iter().peekable();
let _iter = free_areas_iter().peekable();
while let Some(mut memory_map_area) = iter.next() {
if !{
@@ -734,7 +734,7 @@ fn init_sections(mut allocator: &mut BumpAllocator<RmmA>) {
let mut sections_fill_result = Some(region);
let mut force = false;
while let Some(mut region) = sections_fill_result {
while let Some(region) = sections_fill_result {
sections_fill_result = sections_fill(Some(region), &mut i, force);
force = true;
}
@@ -764,7 +764,7 @@ fn init_sections(mut allocator: &mut BumpAllocator<RmmA>) {
}
}
let mut append_page = |page: Frame,
let append_page = |page: Frame,
info: &'static PageInfo,
order,
first_pages: &mut [Option<(Frame, &'static PageInfo)>; 11],
@@ -805,7 +805,7 @@ fn init_sections(mut allocator: &mut BumpAllocator<RmmA>) {
};
}
let mut free_list_fill = |region: Option<MemoryArea>,
let free_list_fill = |region: Option<MemoryArea>,
allocator: &mut BumpAllocator<RmmA>|
-> [Option<(Frame, &'static PageInfo)>; ORDER_COUNT as usize] {
let mut first_pages: [Option<(Frame, &'static PageInfo)>; ORDER_COUNT as usize] =
@@ -921,7 +921,7 @@ fn init_sections(mut allocator: &mut BumpAllocator<RmmA>) {
.div_ceil(PAGE_SIZE),
))
.expect("Failed to allocate free list page");
let va = unsafe { RmmA::phys_to_virt(free_list_page).data() as *mut Mutex<FreeList> };
let va = RmmA::phys_to_virt(free_list_page).data() as *mut Mutex<FreeList>;
free_lists = unsafe { slice::from_raw_parts_mut(va, numa::number_of_memory_regions()) };
for (i, region) in regions.enumerate() {
let free_list = FreeList {
@@ -939,7 +939,7 @@ fn init_sections(mut allocator: &mut BumpAllocator<RmmA>) {
size_of::<Mutex<FreeList>>().div_ceil(PAGE_SIZE),
))
.expect("Failed to allocate free list page");
let va = unsafe { RmmA::phys_to_virt(free_list_page).data() as *mut Mutex<FreeList> };
let va = RmmA::phys_to_virt(free_list_page).data() as *mut Mutex<FreeList>;
free_lists = unsafe { slice::from_raw_parts_mut(va, 1) };
let free_list = FreeList {
for_orders: free_list_fill(None, &mut allocator)
+6 -8
View File
@@ -2,11 +2,9 @@ use core::ops::Add;
use crate::{
acpi,
cpu_set::LogicalCpuId,
sync::{CleanLockToken, Mutex, L0},
sync::CleanLockToken,
};
use alloc::{sync::Arc, vec::Vec};
use hashbrown::HashMap;
use alloc::vec::Vec;
use rmm::{Arch, BumpAllocator, MemoryArea, PhysicalAddress};
use spin::once::Once;
use syscall::{Error, Result, ENODATA, EOPNOTSUPP};
@@ -75,7 +73,7 @@ pub fn cpu_belongs_to_which_node(cpu_id: usize) -> Option<u32> {
/// A helper function that prints information about NUMA - available nodes, cpus and memory blocks in them
/// their starts and lengths
pub fn dump_info() {
if let Some(map) = DOMAIN_NODE_MAP.get()
if let Some(_map) = DOMAIN_NODE_MAP.get()
&& let Some(cpus) = NUMA_CPUS.get()
&& let Some(memories) = NUMA_MEMORY.get()
{
@@ -186,7 +184,7 @@ pub fn nearest_preceding_memory_region(addr: usize, overlap: bool) -> Option<&'s
.max_by_key(|e| e.start)
}
pub fn get_numa_info(token: &mut CleanLockToken) -> Result<Vec<u8>> {
pub fn get_numa_info(_token: &mut CleanLockToken) -> Result<Vec<u8>> {
let cpu_info = NUMA_CPUS
.get()
.ok_or(Error::new(EOPNOTSUPP))?
@@ -214,7 +212,7 @@ pub fn get_numa_info(token: &mut CleanLockToken) -> Result<Vec<u8>> {
Ok(numa_info)
}
pub fn get_numa_distance_info(token: &mut CleanLockToken) -> Result<Vec<u8>> {
pub fn get_numa_distance_info(_token: &mut CleanLockToken) -> Result<Vec<u8>> {
Ok(DISTANCES
.get()
.ok_or(Error::new(ENODATA))?
@@ -223,7 +221,7 @@ pub fn get_numa_distance_info(token: &mut CleanLockToken) -> Result<Vec<u8>> {
.collect())
}
pub fn get_numa_dom_info(token: &mut CleanLockToken) -> Result<Vec<u8>> {
pub fn get_numa_dom_info(_token: &mut CleanLockToken) -> Result<Vec<u8>> {
Ok(DOMAIN_NODE_MAP
.get()
.ok_or(Error::new(EOPNOTSUPP))?
+4 -4
View File
@@ -556,7 +556,7 @@ impl ProcScheme {
let resolved = format!("proc/{}/{}", pid, rest);
let mut parts = resolved.split('/');
let _ = parts.next(); // "proc"
let pid = parts.next().and_then(|p| p.parse::<usize>().ok()).unwrap_or(pid);
let _pid = parts.next().and_then(|p| p.parse::<usize>().ok()).unwrap_or(pid);
if let Some(kind) = Self::proc_open(&resolved) {
let handle = Handle {
context: context::current(),
@@ -912,17 +912,17 @@ impl KernelScheme for ProcScheme {
&self,
id: usize,
descs: Vec<Arc<context::file::LockedFileDescription>>,
flags: CallFlags,
_flags: CallFlags,
_arg: u64,
metadata: &[u64],
token: &mut CleanLockToken,
) -> Result<usize> {
let context = {
let mut handles = HANDLES.read(token.token());
let (handles, mut token) = handles.token_split();
let (handles, token) = handles.token_split();
let handle = handles.get(&id).unwrap();
let Handle { context, kind } = handle;
let Handle { context, kind: _ } = handle;
if let ContextHandle::Filetable { .. } | ContextHandle::NewFiletable { .. } =
&handle.kind
+1 -2
View File
@@ -23,11 +23,10 @@ use crate::{
PageSpan, DANGLING,
},
unblock_context, wakeup_context, BorrowedHtBuf, ContextLock, PreemptGuard, PreemptGuardL1,
Status, WeakContextRef,
Status,
},
event,
memory::{Frame, Page, VirtualAddress, PAGE_SIZE},
percpu::PercpuBlock,
scheme::SchemeId,
sync::{CleanLockToken, LockToken, Mutex, RwLock, WaitQueue, L1},
syscall::{
+1 -1
View File
@@ -2,7 +2,7 @@
use core::num::NonZeroUsize;
use alloc::{string::{String, ToString}, sync::Arc, vec::Vec};
use alloc::{string::String, sync::Arc, vec::Vec};
use redox_path::RedoxPath;
use crate::{