mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-25 10:23:23 +00:00
Fix multiple issues in the initproc path
This commit is contained in:
committed by
Tate, Hongliang Tian
parent
4a33020b4f
commit
acfbc7efdc
2
.github/workflows/syscall_test.yml
vendored
2
.github/workflows/syscall_test.yml
vendored
@ -18,4 +18,4 @@ jobs:
|
|||||||
|
|
||||||
- name: Syscall Test
|
- name: Syscall Test
|
||||||
id: syscall_test
|
id: syscall_test
|
||||||
run: make syscall_test ENABLE_KVM=false
|
run: make run AUTO_SYSCALL_TEST=1 ENABLE_KVM=0
|
||||||
|
@ -13,14 +13,13 @@ use std::{
|
|||||||
process::Command,
|
process::Command,
|
||||||
};
|
};
|
||||||
|
|
||||||
use clap::{Parser, builder::Str};
|
use clap::{builder::Str, Parser};
|
||||||
|
|
||||||
/// The CLI of this runner.
|
/// The CLI of this runner.
|
||||||
#[derive(Parser, Debug)]
|
#[derive(Parser, Debug)]
|
||||||
#[command(author, version, about, long_about = None)]
|
#[command(author, version, about, long_about = None)]
|
||||||
struct Args {
|
struct Args {
|
||||||
// Positional arguments.
|
// Positional arguments.
|
||||||
|
|
||||||
/// The Jinux binary path.
|
/// The Jinux binary path.
|
||||||
path: PathBuf,
|
path: PathBuf,
|
||||||
|
|
||||||
@ -29,7 +28,6 @@ struct Args {
|
|||||||
kcmdline: String,
|
kcmdline: String,
|
||||||
|
|
||||||
// Optional arguments.
|
// Optional arguments.
|
||||||
|
|
||||||
/// Enable KVM when running QEMU.
|
/// Enable KVM when running QEMU.
|
||||||
#[arg(long, default_value_t = false)]
|
#[arg(long, default_value_t = false)]
|
||||||
enable_kvm: bool,
|
enable_kvm: bool,
|
||||||
|
@ -5,5 +5,5 @@
|
|||||||
//! on its way.
|
//! on its way.
|
||||||
//!
|
//!
|
||||||
|
|
||||||
pub mod multiboot2;
|
mod multiboot2;
|
||||||
pub use self::multiboot2::init_boot_args;
|
pub use self::multiboot2::init_boot_args;
|
||||||
|
@ -13,12 +13,9 @@ use alloc::{
|
|||||||
vec,
|
vec,
|
||||||
vec::Vec,
|
vec::Vec,
|
||||||
};
|
};
|
||||||
use log::debug;
|
|
||||||
|
|
||||||
#[derive(PartialEq, Debug)]
|
#[derive(PartialEq, Debug)]
|
||||||
struct InitprocArg {
|
struct InitprocArgs {
|
||||||
// Since environment arguments can precede the init path argument, we
|
|
||||||
// have no choice but to wrap the path in `Option` and check it later.
|
|
||||||
path: Option<String>,
|
path: Option<String>,
|
||||||
argv: Vec<CString>,
|
argv: Vec<CString>,
|
||||||
envp: Vec<CString>,
|
envp: Vec<CString>,
|
||||||
@ -27,7 +24,7 @@ struct InitprocArg {
|
|||||||
/// The struct to store the parsed kernel command-line arguments.
|
/// The struct to store the parsed kernel command-line arguments.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct KCmdlineArg {
|
pub struct KCmdlineArg {
|
||||||
initproc: Option<InitprocArg>,
|
initproc: InitprocArgs,
|
||||||
module_args: BTreeMap<String, Vec<CString>>,
|
module_args: BTreeMap<String, Vec<CString>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -35,18 +32,15 @@ pub struct KCmdlineArg {
|
|||||||
impl KCmdlineArg {
|
impl KCmdlineArg {
|
||||||
/// Get the path of the initprocess.
|
/// Get the path of the initprocess.
|
||||||
pub fn get_initproc_path(&self) -> Option<&str> {
|
pub fn get_initproc_path(&self) -> Option<&str> {
|
||||||
self.initproc
|
self.initproc.path.as_ref().map(|s| s.as_str())
|
||||||
.as_ref()
|
|
||||||
.and_then(|i| i.path.as_ref())
|
|
||||||
.map(|s| s.as_str())
|
|
||||||
}
|
}
|
||||||
/// Get the argument vector(argv) of the initprocess.
|
/// Get the argument vector(argv) of the initprocess.
|
||||||
pub fn get_initproc_argv(&self) -> Option<&Vec<CString>> {
|
pub fn get_initproc_argv(&self) -> &Vec<CString> {
|
||||||
self.initproc.as_ref().map(|i| &i.argv)
|
&self.initproc.argv
|
||||||
}
|
}
|
||||||
/// Get the environment vector(envp) of the initprocess.
|
/// Get the environment vector(envp) of the initprocess.
|
||||||
pub fn get_initproc_envp(&self) -> Option<&Vec<CString>> {
|
pub fn get_initproc_envp(&self) -> &Vec<CString> {
|
||||||
self.initproc.as_ref().map(|i| &i.argv)
|
&self.initproc.envp
|
||||||
}
|
}
|
||||||
/// Get the argument vector of a kernel module.
|
/// Get the argument vector of a kernel module.
|
||||||
pub fn get_module_args(&self, module: &str) -> Option<&Vec<CString>> {
|
pub fn get_module_args(&self, module: &str) -> Option<&Vec<CString>> {
|
||||||
@ -72,8 +66,12 @@ fn split_arg(input: &str) -> impl Iterator<Item = &str> {
|
|||||||
impl From<&str> for KCmdlineArg {
|
impl From<&str> for KCmdlineArg {
|
||||||
fn from(cmdline: &str) -> Self {
|
fn from(cmdline: &str) -> Self {
|
||||||
// What we construct.
|
// What we construct.
|
||||||
let mut result = KCmdlineArg {
|
let mut result: KCmdlineArg = KCmdlineArg {
|
||||||
initproc: None,
|
initproc: InitprocArgs {
|
||||||
|
path: None,
|
||||||
|
argv: Vec::new(),
|
||||||
|
envp: Vec::new(),
|
||||||
|
},
|
||||||
module_args: BTreeMap::new(),
|
module_args: BTreeMap::new(),
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -87,11 +85,10 @@ impl From<&str> for KCmdlineArg {
|
|||||||
// KernelArg => Arg "\s+" KernelArg | %empty
|
// KernelArg => Arg "\s+" KernelArg | %empty
|
||||||
// InitArg => Arg "\s+" InitArg | %empty
|
// InitArg => Arg "\s+" InitArg | %empty
|
||||||
if kcmdline_end {
|
if kcmdline_end {
|
||||||
if let Some(&mut ref mut i) = result.initproc.as_mut() {
|
if result.initproc.path == None {
|
||||||
i.argv.push(CString::new(arg).unwrap());
|
|
||||||
} else {
|
|
||||||
panic!("Initproc arguments provided but no initproc path specified!");
|
panic!("Initproc arguments provided but no initproc path specified!");
|
||||||
}
|
}
|
||||||
|
result.initproc.argv.push(CString::new(arg).unwrap());
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if arg == "--" {
|
if arg == "--" {
|
||||||
@ -134,32 +131,16 @@ impl From<&str> for KCmdlineArg {
|
|||||||
// The option has a value.
|
// The option has a value.
|
||||||
match option {
|
match option {
|
||||||
"init" => {
|
"init" => {
|
||||||
if let Some(&mut ref mut i) = result.initproc.as_mut() {
|
if let Some(v) = &result.initproc.path {
|
||||||
if let Some(v) = &i.path {
|
panic!("Initproc assigned twice in the command line!");
|
||||||
panic!("Initproc assigned twice in the command line!");
|
|
||||||
}
|
|
||||||
i.path = Some(value.to_string());
|
|
||||||
} else {
|
|
||||||
result.initproc = Some(InitprocArg {
|
|
||||||
path: Some(value.to_string()),
|
|
||||||
argv: Vec::new(),
|
|
||||||
envp: Vec::new(),
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
result.initproc.path = Some(value.to_string());
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
// If the option is not recognized, it is passed to the initproc.
|
// If the option is not recognized, it is passed to the initproc.
|
||||||
// Pattern 'option=value' is treated as the init environment.
|
// Pattern 'option=value' is treated as the init environment.
|
||||||
let envp_entry = CString::new(option.to_string() + "=" + value).unwrap();
|
let envp_entry = CString::new(option.to_string() + "=" + value).unwrap();
|
||||||
if let Some(&mut ref mut i) = result.initproc.as_mut() {
|
result.initproc.envp.push(envp_entry);
|
||||||
i.envp.push(envp_entry);
|
|
||||||
} else {
|
|
||||||
result.initproc = Some(InitprocArg {
|
|
||||||
path: None,
|
|
||||||
argv: Vec::new(),
|
|
||||||
envp: vec![envp_entry],
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -169,28 +150,12 @@ impl From<&str> for KCmdlineArg {
|
|||||||
// If the option is not recognized, it is passed to the initproc.
|
// If the option is not recognized, it is passed to the initproc.
|
||||||
// Pattern 'option' without value is treated as the init argument.
|
// Pattern 'option' without value is treated as the init argument.
|
||||||
let argv_entry = CString::new(option.to_string()).unwrap();
|
let argv_entry = CString::new(option.to_string()).unwrap();
|
||||||
if let Some(&mut ref mut i) = result.initproc.as_mut() {
|
result.initproc.argv.push(argv_entry);
|
||||||
i.argv.push(argv_entry);
|
|
||||||
} else {
|
|
||||||
result.initproc = Some(InitprocArg {
|
|
||||||
path: None,
|
|
||||||
argv: vec![argv_entry],
|
|
||||||
envp: Vec::new(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
debug!("{:?}", result);
|
|
||||||
|
|
||||||
if let Some(&ref i) = result.initproc.as_ref() {
|
|
||||||
if i.path == None {
|
|
||||||
panic!("Initproc arguments provided but no initproc! Maybe have bad option.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,8 +2,6 @@
|
|||||||
//! from the bootloader to the rest of the framework.
|
//! from the bootloader to the rest of the framework.
|
||||||
//!
|
//!
|
||||||
|
|
||||||
use crate::arch::boot::init_boot_args;
|
|
||||||
|
|
||||||
pub mod kcmdline;
|
pub mod kcmdline;
|
||||||
use kcmdline::KCmdlineArg;
|
use kcmdline::KCmdlineArg;
|
||||||
|
|
||||||
@ -13,6 +11,8 @@ use self::memory_region::MemoryRegion;
|
|||||||
use alloc::{string::String, vec::Vec};
|
use alloc::{string::String, vec::Vec};
|
||||||
use spin::Once;
|
use spin::Once;
|
||||||
|
|
||||||
|
/// ACPI information from the bootloader.
|
||||||
|
///
|
||||||
/// The boot crate can choose either providing the raw RSDP physical address or
|
/// The boot crate can choose either providing the raw RSDP physical address or
|
||||||
/// providing the RSDT/XSDT physical address after parsing RSDP.
|
/// providing the RSDT/XSDT physical address after parsing RSDP.
|
||||||
/// This is because bootloaders differ in such behaviors.
|
/// This is because bootloaders differ in such behaviors.
|
||||||
@ -36,40 +36,39 @@ pub struct BootloaderFramebufferArg {
|
|||||||
pub bpp: usize,
|
pub bpp: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use a macro to simplify coding.
|
|
||||||
macro_rules! define_global_static_boot_arguments {
|
macro_rules! define_global_static_boot_arguments {
|
||||||
( $( $lower:ident, $upper:ident, $typ:ty; )* ) => {
|
( $( $lower:ident, $upper:ident, $typ:ty; )* ) => {
|
||||||
// Define statics and corresponding public get APIs.
|
// Define statics and corresponding public getter APIs.
|
||||||
$(
|
$(
|
||||||
static $upper: Once<$typ> = Once::new();
|
static $upper: Once<$typ> = Once::new();
|
||||||
/// Macro generated public get API.
|
/// Macro generated public getter API.
|
||||||
pub fn $lower() -> &'static $typ {
|
pub fn $lower() -> &'static $typ {
|
||||||
$upper.get().unwrap()
|
$upper.get().unwrap()
|
||||||
}
|
}
|
||||||
)*
|
)*
|
||||||
|
|
||||||
// Produce a init function call. The init function must
|
// Produce a init function call. The init function must
|
||||||
// be defined in the `arch::boot` module conforming to this
|
// be defined in the `arch::boot` module conforming to this
|
||||||
// definition.
|
// definition.
|
||||||
fn arch_init_boot_args() {
|
fn arch_init_boot_args() {
|
||||||
init_boot_args( $( &$upper, )* );
|
crate::arch::boot::init_boot_args( $( &$upper, )* );
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Define a series of static variable definitions and its APIs. The names in
|
// Define a series of static variables and their getter APIs.
|
||||||
// each line are:
|
|
||||||
// 1. The lowercase name of the variable, also the name of the get API;
|
|
||||||
// 2. the uppercase name of the variable;
|
|
||||||
// 3. the type of the variable.
|
|
||||||
define_global_static_boot_arguments!(
|
define_global_static_boot_arguments!(
|
||||||
bootloader_name, BOOTLOADER_NAME, String;
|
// Getter Names | Static Variables | Variable Types
|
||||||
kernel_cmdline, KERNEL_CMDLINE, KCmdlineArg;
|
bootloader_name, BOOTLOADER_NAME, String;
|
||||||
initramfs, INITRAMFS, &'static [u8];
|
kernel_cmdline, KERNEL_CMDLINE, KCmdlineArg;
|
||||||
acpi_arg, ACPI_ARG, BootloaderAcpiArg;
|
initramfs, INITRAMFS, &'static [u8];
|
||||||
framebuffer_arg, FRAMEBUFFER_ARG, BootloaderFramebufferArg;
|
acpi_arg, ACPI_ARG, BootloaderAcpiArg;
|
||||||
memory_regions, MEMORY_REGIONS, Vec<MemoryRegion>;
|
framebuffer_arg, FRAMEBUFFER_ARG, BootloaderFramebufferArg;
|
||||||
|
memory_regions, MEMORY_REGIONS, Vec<MemoryRegion>;
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/// The initialization method of the boot module.
|
||||||
|
///
|
||||||
/// After initializing the boot module, the get functions could be called.
|
/// After initializing the boot module, the get functions could be called.
|
||||||
/// The initialization must be done after the heap is set and before physical
|
/// The initialization must be done after the heap is set and before physical
|
||||||
/// mappings are cancelled.
|
/// mappings are cancelled.
|
||||||
|
@ -81,25 +81,25 @@ fn init_thread() {
|
|||||||
|
|
||||||
let initproc = Process::spawn_user_process(
|
let initproc = Process::spawn_user_process(
|
||||||
karg.get_initproc_path().unwrap(),
|
karg.get_initproc_path().unwrap(),
|
||||||
karg.get_initproc_argv().unwrap().to_vec(),
|
karg.get_initproc_argv().to_vec(),
|
||||||
karg.get_initproc_envp().unwrap().to_vec(),
|
karg.get_initproc_envp().to_vec(),
|
||||||
)
|
)
|
||||||
.expect("Run init process failed.");
|
.expect("Run init process failed.");
|
||||||
|
|
||||||
loop {
|
// Wait till initproc become zombie.
|
||||||
// If initproc becomes zombie, then exit qemu.
|
while *initproc.status().lock() != ProcessStatus::Zombie {
|
||||||
if *initproc.status().lock() == ProcessStatus::Zombie {
|
|
||||||
let exit_code = if initproc.exit_code().load(Ordering::Relaxed) == 0 {
|
|
||||||
QemuExitCode::Success
|
|
||||||
} else {
|
|
||||||
QemuExitCode::Failed
|
|
||||||
};
|
|
||||||
exit_qemu(exit_code);
|
|
||||||
}
|
|
||||||
// We don't have preemptive scheduler now.
|
// We don't have preemptive scheduler now.
|
||||||
// The long running init thread should yield its own execution to allow other tasks to go on.
|
// The long running init thread should yield its own execution to allow other tasks to go on.
|
||||||
Thread::yield_now();
|
Thread::yield_now();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: exit via qemu isa debug device should not be the only way.
|
||||||
|
let exit_code = if initproc.exit_code().load(Ordering::Relaxed) == 0 {
|
||||||
|
QemuExitCode::Success
|
||||||
|
} else {
|
||||||
|
QemuExitCode::Failed
|
||||||
|
};
|
||||||
|
exit_qemu(exit_code);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// first process never return
|
/// first process never return
|
||||||
|
Reference in New Issue
Block a user