Add `i8042.exist` to override ACPI flags

This commit is contained in:
Ruihan Li 2025-12-02 23:42:40 +08:00 committed by Tate, Hongliang Tian
parent 04a2290812
commit 13afca6441
12 changed files with 99 additions and 24 deletions

12
Cargo.lock generated
View File

@ -165,6 +165,16 @@ dependencies = [
"spin",
]
[[package]]
name = "aster-cmdline"
version = "0.1.0"
dependencies = [
"component",
"log",
"ostd",
"spin",
]
[[package]]
name = "aster-console"
version = "0.1.0"
@ -192,6 +202,7 @@ dependencies = [
name = "aster-i8042"
version = "0.1.0"
dependencies = [
"aster-cmdline",
"aster-input",
"bitflags 2.9.1",
"component",
@ -263,6 +274,7 @@ dependencies = [
"align_ext",
"aster-bigtcp",
"aster-block",
"aster-cmdline",
"aster-console",
"aster-framebuffer",
"aster-i8042",

View File

@ -14,6 +14,7 @@ members = [
"ostd/libs/ostd-test",
"kernel",
"kernel/comps/block",
"kernel/comps/cmdline",
"kernel/comps/console",
"kernel/comps/framebuffer",
"kernel/comps/input",

View File

@ -14,6 +14,7 @@ mlsdisk = { name = "aster-mlsdisk" }
systree = { name = "aster-systree" }
i8042 = { name = "aster-i8042" }
pci = { name = "aster-pci" }
cmdline = { name = "aster-cmdline" }
[whitelist]
[whitelist.nix.main]

View File

@ -224,6 +224,7 @@ OSDK_CRATES := \
ostd/libs/linux-bzimage/setup \
kernel \
kernel/comps/block \
kernel/comps/cmdline \
kernel/comps/console \
kernel/comps/framebuffer \
kernel/comps/input \

View File

@ -10,6 +10,7 @@ align_ext = { path = "../ostd/libs/align_ext" }
aster-input = { path = "comps/input" }
aster-block = { path = "comps/block" }
aster-network = { path = "comps/network" }
aster-cmdline = { path = "comps/cmdline" }
aster-console = { path = "comps/console" }
aster-framebuffer = { path = "comps/framebuffer" }
aster-softirq = { path = "comps/softirq" }

View File

@ -0,0 +1,15 @@
[package]
name = "aster-cmdline"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
component = { path = "../../libs/comp-sys/component" }
ostd = { path = "../../../ostd" }
log = "0.4"
spin = "0.9.4"
[lints]
workspace = true

View File

@ -1,7 +1,5 @@
// SPDX-License-Identifier: MPL-2.0
#![expect(unused_variables)]
//! The module to parse kernel command-line arguments.
//!
//! The format of the Asterinas command line string conforms
@ -9,6 +7,10 @@
//!
//! <https://www.kernel.org/doc/html/v6.4/admin-guide/kernel-parameters.html>
//!
#![no_std]
#![deny(unsafe_code)]
extern crate alloc;
use alloc::{
collections::BTreeMap,
@ -18,7 +20,7 @@ use alloc::{
vec::Vec,
};
use ostd::boot::boot_info;
use component::{init_component, ComponentInitError};
use spin::Once;
#[derive(PartialEq, Debug)]
@ -47,13 +49,6 @@ pub struct KCmdlineArg {
// Define get APIs.
impl KCmdlineArg {
/// Gets the singleton instance of `KCmdlineArg`.
pub fn singleton() -> &'static KCmdlineArg {
static INSTANCE: Once<KCmdlineArg> = Once::new();
INSTANCE.call_once(|| KCmdlineArg::from(boot_info().kernel_cmdline.as_str()))
}
/// Gets the path of the init process.
pub fn get_initproc_path(&self) -> Option<&str> {
self.initproc.path.as_deref()
@ -75,7 +70,6 @@ impl KCmdlineArg {
}
/// Gets the argument vector of a kernel module.
#[expect(dead_code)]
pub fn get_module_args(&self, module: &str) -> Option<&Vec<ModuleArg>> {
self.module_args.get(module)
}
@ -177,7 +171,7 @@ impl From<&str> for KCmdlineArg {
// The option has a value.
match option {
"init" => {
if let Some(v) = &result.initproc.path {
if result.initproc.path.is_some() {
panic!("[KCmdline] Init process specified twice");
}
result.initproc.path = Some(value.to_string());
@ -205,3 +199,13 @@ impl From<&str> for KCmdlineArg {
result
}
}
/// The [`KCmdlineArg`] singleton.
pub static KCMDLINE: Once<KCmdlineArg> = Once::new();
#[init_component]
fn init() -> Result<(), ComponentInitError> {
KCMDLINE.call_once(|| KCmdlineArg::from(ostd::boot::boot_info().kernel_cmdline.as_str()));
Ok(())
}

View File

@ -12,6 +12,7 @@ bitflags = "2.5"
log = "0.4"
spin = "0.9.4"
aster-input = { path = "../input" }
aster-cmdline = { path = "../cmdline" }
[lints]
workspace = true

View File

@ -5,6 +5,7 @@
//! Reference: <https://wiki.osdev.org/I8042_PS/2_Controller>
//!
use aster_cmdline::{ModuleArg, KCMDLINE};
use bitflags::bitflags;
use ostd::{
arch::{device::io_port::ReadWriteAccess, kernel::ACPI_INFO},
@ -129,15 +130,32 @@ impl I8042Controller {
const DATA_PORT_ADDR: u16 = 0x60;
const STATUS_OR_COMMAND_PORT_ADDR: u16 = 0x64;
if ACPI_INFO
.get()
.unwrap()
.boot_flags
.is_some_and(|flags| !flags.motherboard_implements_8042())
{
if !Self::is_present_acpi() {
// The PS/2 controller does not exist. See:
// <https://uefi.org/specs/ACPI/6.5/05_ACPI_Software_Programming_Model.html#ia-pc-boot-architecture-flags>.
return Err(I8042ControllerError::NotPresent);
//
// However, it may actually be present and enumerable from other sources, such as PnP
// devices. See:
// <https://elixir.bootlin.com/linux/v6.18/source/drivers/input/serio/i8042-acpipnpio.h#L1578>.
//
// Currently, we lack the necessary support, so we allow the user to manually override
// the ACPI flag by appending "i8042.exist" to the kernel command line.
//
// TODO: Add support for enumerating PnP devices and remove the command line option.
if !Self::is_present_cmdline() {
log::info!(
"ACPI says i8042 controller is absent; \
if it is incorrect, append 'i8042.exist' in cmdline to override it"
);
return Err(I8042ControllerError::NotPresent);
} else {
log::info!(
"ACPI says i8042 controller is absent; \
however, it is overridden by 'i8042.exist' in cmdline"
);
}
} else {
log::info!("ACPI says i8042 controller is present");
}
let controller = Self {
@ -147,6 +165,26 @@ impl I8042Controller {
Ok(controller)
}
fn is_present_acpi() -> bool {
ACPI_INFO
.get()
.unwrap()
.boot_flags
.is_some_and(|flags| !flags.motherboard_implements_8042())
}
/// Checks if the kernel command line contains the "i8042.exist" option.
fn is_present_cmdline() -> bool {
!KCMDLINE
.get()
.unwrap()
.get_module_args("i8042")
.is_some_and(|args| {
args.iter()
.any(|arg| matches!(arg, ModuleArg::Arg(s) if s.as_bytes() == b"exist"))
})
}
fn read_configuration(&mut self) -> Result<Configuration, I8042ControllerError> {
self.wait_and_send_command(Command::ReadConfiguration)?;
self.wait_and_recv_data()

View File

@ -6,6 +6,7 @@
//!
//! Reference: <https://www.kernel.org/doc/html/latest/admin-guide/devices.html>
use aster_cmdline::KCMDLINE;
use device_id::{DeviceId, MajorId, MinorId};
use spin::Once;
@ -22,7 +23,6 @@ use crate::{
device::{Device, DeviceType},
inode_handle::FileIo,
},
kcmdline::KCmdlineArg,
prelude::*,
process::{JobControl, Terminal},
};
@ -104,7 +104,9 @@ impl SystemConsole {
INSTANCE.call_once(|| {
// TODO: Support specifying multiple TTY devices, e.g., "console=hvc0 console=tty0".
let console_name = KCmdlineArg::singleton()
let console_name = KCMDLINE
.get()
.unwrap()
.get_console_names()
.first()
.map(String::as_str)

View File

@ -2,6 +2,7 @@
//! Kernel initialization.
use aster_cmdline::KCMDLINE;
use component::InitStage;
use ostd::{
arch::qemu::{exit_qemu, QemuExitCode},
@ -12,7 +13,6 @@ use spin::once::Once;
use crate::{
fs::{fs_resolver::FsResolver, path::MountNamespace},
kcmdline::KCmdlineArg,
prelude::*,
process::{spawn_init_process, Process},
sched::SchedPolicy,
@ -144,7 +144,7 @@ fn first_kthread() {
print_banner();
INIT_PROCESS.call_once(|| {
let karg = KCmdlineArg::singleton();
let karg = KCMDLINE.get().unwrap();
spawn_init_process(
karg.get_initproc_path().unwrap(),
karg.get_initproc_argv().to_vec(),

View File

@ -46,7 +46,6 @@ mod events;
mod fs;
mod init;
mod ipc;
mod kcmdline;
mod net;
mod prelude;
mod process;