mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-28 03:43:23 +00:00
Implement OSDK functionalities and opt-in OSDK for asterinas
This commit is contained in:
committed by
Tate, Hongliang Tian
parent
bc9bce9dea
commit
f97d0f1260
@ -7,6 +7,7 @@ edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
align_ext = { path = "../libs/align_ext" }
|
||||
aster-main = { path = "../libs/aster-main" }
|
||||
bit_field = "0.10.1"
|
||||
bitflags = "1.3"
|
||||
bitvec = { version = "1.0", default-features = false, features = ["alloc"] }
|
||||
|
@ -1,74 +0,0 @@
|
||||
ENTRY(__multiboot_boot)
|
||||
OUTPUT_ARCH(i386:x86-64)
|
||||
OUTPUT_FORMAT(elf64-x86-64)
|
||||
|
||||
KERNEL_LMA = 0x8000000;
|
||||
LINUX_32_ENTRY = 0x8001000;
|
||||
KERNEL_VMA = 0xffffffff80000000;
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
. = KERNEL_LMA;
|
||||
|
||||
__kernel_start = .;
|
||||
|
||||
.multiboot_header : { KEEP(*(.multiboot_header)) }
|
||||
.multiboot2_header : { KEEP(*(.multiboot2_header)) }
|
||||
|
||||
. = LINUX_32_ENTRY;
|
||||
|
||||
.boot : { KEEP(*(.boot)) }
|
||||
|
||||
. += KERNEL_VMA;
|
||||
|
||||
.text : AT(ADDR(.text) - KERNEL_VMA) {
|
||||
*(.text .text.*)
|
||||
PROVIDE(__etext = .);
|
||||
}
|
||||
.rodata : AT(ADDR(.rodata) - KERNEL_VMA) { *(.rodata .rodata.*) }
|
||||
|
||||
.eh_frame_hdr : AT(ADDR(.eh_frame_hdr) - KERNEL_VMA) {
|
||||
KEEP(*(.eh_frame_hdr .eh_frame_hdr.*))
|
||||
}
|
||||
. = ALIGN(8);
|
||||
.eh_frame : AT(ADDR(.eh_frame) - KERNEL_VMA) {
|
||||
PROVIDE(__eh_frame = .);
|
||||
KEEP(*(.eh_frame .eh_frame.*))
|
||||
}
|
||||
|
||||
.gcc_except_table : AT(ADDR(.gcc_except_table) - KERNEL_VMA) { *(.gcc_except_table .gcc_except_table.*) }
|
||||
|
||||
.data.rel.ro : AT(ADDR(.data.rel.ro) - KERNEL_VMA) { *(.data.rel.ro .data.rel.ro.*) }
|
||||
.dynamic : AT(ADDR(.dynamic) - KERNEL_VMA) { *(.dynamic) }
|
||||
|
||||
.init_array : AT(ADDR(.init_array) - KERNEL_VMA) {
|
||||
__sinit_array = .;
|
||||
KEEP(*(SORT(.init_array .init_array.*)))
|
||||
__einit_array = .;
|
||||
}
|
||||
|
||||
.got : AT(ADDR(.got) - KERNEL_VMA) { *(.got .got.*) }
|
||||
.got.plt : AT(ADDR(.got.plt) - KERNEL_VMA) { *(.got.plt .got.plt.*) }
|
||||
|
||||
. = DATA_SEGMENT_RELRO_END(0, .);
|
||||
|
||||
.data : AT(ADDR(.data) - KERNEL_VMA) { *(.data .data.*) }
|
||||
.bss : AT(ADDR(.bss) - KERNEL_VMA) {
|
||||
__bss = .;
|
||||
*(.bss .bss.*) *(COMMON)
|
||||
__bss_end = .;
|
||||
}
|
||||
|
||||
.ktest_array : AT(ADDR(.ktest_array) - KERNEL_VMA) {
|
||||
__ktest_array = .;
|
||||
KEEP(*(SORT(.ktest_array)))
|
||||
__ktest_array_end = .;
|
||||
}
|
||||
|
||||
.tdata : AT(ADDR(.tdata) - KERNEL_VMA) { *(.tdata .tdata.*) }
|
||||
.tbss : AT(ADDR(.tbss) - KERNEL_VMA) { *(.tbss .tbss.*) }
|
||||
|
||||
. = DATA_SEGMENT_END(.);
|
||||
|
||||
__kernel_end = . - KERNEL_VMA;
|
||||
}
|
@ -91,11 +91,6 @@ impl From<&str> for KCmdlineArg {
|
||||
// The main parse loop. The processing steps are arranged (not very strictly)
|
||||
// by the analysis over the Backus–Naur form syntax tree.
|
||||
for arg in split_arg(cmdline) {
|
||||
// FIXME: The -kernel option in QEMU seems to add this string to the command line, which we skip for now.
|
||||
if arg.starts_with("target/x86_64-custom/") {
|
||||
warn!("Found kcmdline: {:?}, skipped for now.", arg);
|
||||
continue;
|
||||
}
|
||||
// Cmdline => KernelArg "--" InitArg
|
||||
// KernelArg => Arg "\s+" KernelArg | %empty
|
||||
// InitArg => Arg "\s+" InitArg | %empty
|
||||
@ -116,7 +111,8 @@ impl From<&str> for KCmdlineArg {
|
||||
1 => (arg_pattern[0], None),
|
||||
2 => (arg_pattern[0], Some(arg_pattern[1])),
|
||||
_ => {
|
||||
panic!("Unable to parse argument {}", arg);
|
||||
warn!("Unable to parse kernel argument {}, skip for now", arg);
|
||||
continue;
|
||||
}
|
||||
};
|
||||
// Entry => Module "." ModuleOptionName | KernelOptionName
|
||||
@ -125,7 +121,11 @@ impl From<&str> for KCmdlineArg {
|
||||
1 => (None, entry_pattern[0]),
|
||||
2 => (Some(entry_pattern[0]), entry_pattern[1]),
|
||||
_ => {
|
||||
panic!("Unable to parse entry {} in argument {}", entry, arg);
|
||||
warn!(
|
||||
"Unable to parse entry {} in argument {}, skip for now",
|
||||
entry, arg
|
||||
);
|
||||
continue;
|
||||
}
|
||||
};
|
||||
if let Some(modname) = node {
|
||||
|
@ -113,48 +113,38 @@ pub fn call_aster_main() -> ! {
|
||||
// The entry point of kernel code, which should be defined by the package that
|
||||
// uses aster-frame.
|
||||
extern "Rust" {
|
||||
fn aster_main() -> !;
|
||||
fn __aster_main() -> !;
|
||||
}
|
||||
aster_main();
|
||||
__aster_main();
|
||||
}
|
||||
#[cfg(ktest)]
|
||||
{
|
||||
use alloc::{boxed::Box, string::ToString};
|
||||
use core::any::Any;
|
||||
|
||||
use crate::arch::qemu::{exit_qemu, QemuExitCode};
|
||||
unsafe {
|
||||
crate::init();
|
||||
let fn_catch_unwind = &(unwinding::panic::catch_unwind::<(), fn()>
|
||||
as fn(fn()) -> Result<(), Box<(dyn Any + Send + 'static)>>);
|
||||
// Parse the whitelist from the kernel command line.
|
||||
let mut paths = None;
|
||||
let args = kernel_cmdline().get_module_args("ktest");
|
||||
if let Some(args) = args {
|
||||
for options in args {
|
||||
match options {
|
||||
kcmdline::ModuleArg::KeyVal(key, val) => {
|
||||
if key.to_str().unwrap() == "whitelist" && val.to_str().unwrap() != "" {
|
||||
let paths_str = val.to_str().unwrap();
|
||||
paths = Some(
|
||||
paths_str
|
||||
.split(',')
|
||||
.map(|s| s.to_string())
|
||||
.collect::<Vec<_>>(),
|
||||
);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
use ktest::runner::{run_ktests, KtestResult};
|
||||
match run_ktests(
|
||||
&crate::console::print,
|
||||
fn_catch_unwind,
|
||||
paths.map(|v| v.into_iter()),
|
||||
) {
|
||||
KtestResult::Ok => exit_qemu(QemuExitCode::Success),
|
||||
KtestResult::Failed => exit_qemu(QemuExitCode::Failed),
|
||||
// The whitelists that will be generated by OSDK runner as static consts.
|
||||
extern "Rust" {
|
||||
static KTEST_TEST_WHITELIST: Option<&'static [&'static str]>;
|
||||
static KTEST_CRATE_WHITELIST: Option<&'static [&'static str]>;
|
||||
}
|
||||
run_ktests(KTEST_TEST_WHITELIST, KTEST_CRATE_WHITELIST);
|
||||
}
|
||||
}
|
||||
|
||||
fn run_ktests(test_whitelist: Option<&[&str]>, crate_whitelist: Option<&[&str]>) -> ! {
|
||||
use crate::arch::qemu::{exit_qemu, QemuExitCode};
|
||||
use alloc::{boxed::Box, string::ToString};
|
||||
use core::any::Any;
|
||||
|
||||
let fn_catch_unwind = &(unwinding::panic::catch_unwind::<(), fn()>
|
||||
as fn(fn()) -> Result<(), Box<(dyn Any + Send + 'static)>>);
|
||||
|
||||
use ktest::runner::{run_ktests, KtestResult};
|
||||
match run_ktests(
|
||||
&crate::console::print,
|
||||
fn_catch_unwind,
|
||||
test_whitelist.map(|s| s.iter().map(|s| s.to_string())),
|
||||
crate_whitelist,
|
||||
) {
|
||||
KtestResult::Ok => exit_qemu(QemuExitCode::Success),
|
||||
KtestResult::Failed => exit_qemu(QemuExitCode::Failed),
|
||||
};
|
||||
}
|
||||
|
@ -19,6 +19,7 @@
|
||||
#![no_std]
|
||||
|
||||
extern crate alloc;
|
||||
#[cfg(ktest)]
|
||||
#[macro_use]
|
||||
extern crate ktest;
|
||||
#[macro_use]
|
||||
@ -83,7 +84,7 @@ fn invoke_ffi_init_funcs() {
|
||||
}
|
||||
|
||||
/// Simple unit tests for the ktest framework.
|
||||
#[if_cfg_ktest]
|
||||
#[cfg(ktest)]
|
||||
mod test {
|
||||
#[ktest]
|
||||
fn trivial_assertion() {
|
||||
|
@ -23,12 +23,12 @@ use unwinding::{
|
||||
panic::begin_panic,
|
||||
};
|
||||
|
||||
fn abort() -> ! {
|
||||
exit_qemu(QemuExitCode::Failed);
|
||||
}
|
||||
|
||||
#[panic_handler]
|
||||
fn panic_handler(info: &core::panic::PanicInfo) -> ! {
|
||||
/// The panic handler must be defined in the binary crate or in the crate that the binary
|
||||
/// crate explicity declares by `extern crate`. We cannot let the base crate depend on the
|
||||
/// framework due to prismatic dependencies. That's why we export this symbol and state the
|
||||
/// panic handler in the binary crate.
|
||||
#[export_name = "__aster_panic_handler"]
|
||||
pub fn panic_handler(info: &core::panic::PanicInfo) -> ! {
|
||||
let throw_info = ktest::PanicInfo {
|
||||
message: info.message().unwrap().to_string(),
|
||||
file: info.location().unwrap().file().to_string(),
|
||||
@ -46,6 +46,10 @@ fn panic_handler(info: &core::panic::PanicInfo) -> ! {
|
||||
abort();
|
||||
}
|
||||
|
||||
fn abort() -> ! {
|
||||
exit_qemu(QemuExitCode::Failed);
|
||||
}
|
||||
|
||||
fn print_stack_trace() {
|
||||
struct CallbackData {
|
||||
counter: usize,
|
||||
|
@ -8,3 +8,7 @@ pub(crate) use alloc::{boxed::Box, sync::Arc, vec::Vec};
|
||||
pub(crate) use core::any::Any;
|
||||
|
||||
pub use crate::vm::{Paddr, Vaddr};
|
||||
|
||||
pub use crate::early_print as print;
|
||||
pub use crate::early_println as println;
|
||||
pub use aster_main::aster_main;
|
||||
|
@ -288,7 +288,7 @@ impl fmt::Debug for AtomicBits {
|
||||
}
|
||||
}
|
||||
|
||||
#[if_cfg_ktest]
|
||||
#[cfg(ktest)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
|
@ -162,7 +162,7 @@ impl HasPaddr for DmaCoherent {
|
||||
}
|
||||
}
|
||||
|
||||
#[if_cfg_ktest]
|
||||
#[cfg(ktest)]
|
||||
mod test {
|
||||
use alloc::vec;
|
||||
|
||||
|
@ -195,7 +195,7 @@ impl HasPaddr for DmaStream {
|
||||
}
|
||||
}
|
||||
|
||||
#[if_cfg_ktest]
|
||||
#[cfg(ktest)]
|
||||
mod test {
|
||||
use alloc::vec;
|
||||
|
||||
|
14
framework/libs/aster-main/Cargo.toml
Normal file
14
framework/libs/aster-main/Cargo.toml
Normal file
@ -0,0 +1,14 @@
|
||||
[package]
|
||||
name = "aster-main"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[lib]
|
||||
proc-macro = true
|
||||
|
||||
[dependencies]
|
||||
proc-macro2 = "1.0.78"
|
||||
quote = "1.0.35"
|
||||
syn = { version = "2.0.48", features = ["full"] }
|
22
framework/libs/aster-main/src/lib.rs
Normal file
22
framework/libs/aster-main/src/lib.rs
Normal file
@ -0,0 +1,22 @@
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
use proc_macro::TokenStream;
|
||||
use quote::quote;
|
||||
use syn::{parse_macro_input, ItemFn};
|
||||
|
||||
#[proc_macro_attribute]
|
||||
pub fn aster_main(_attr: TokenStream, item: TokenStream) -> TokenStream {
|
||||
let main_fn = parse_macro_input!(item as ItemFn);
|
||||
let main_fn_name = &main_fn.sig.ident;
|
||||
|
||||
quote!(
|
||||
#[no_mangle]
|
||||
pub fn __aster_main() -> ! {
|
||||
aster_frame::init();
|
||||
#main_fn_name();
|
||||
}
|
||||
|
||||
#main_fn
|
||||
)
|
||||
.into()
|
||||
}
|
@ -7,24 +7,7 @@ extern crate proc_macro2;
|
||||
use proc_macro::TokenStream;
|
||||
use quote::quote;
|
||||
use rand::{distributions::Alphanumeric, Rng};
|
||||
use syn::{parse_macro_input, Expr, Ident, ItemFn, ItemMod};
|
||||
|
||||
/// The conditional compilation attribute macro to control the compilation of test
|
||||
/// modules.
|
||||
#[proc_macro_attribute]
|
||||
pub fn if_cfg_ktest(_attr: TokenStream, item: TokenStream) -> TokenStream {
|
||||
// Assuming that the item is a module declearation, otherwise panics.
|
||||
let input = parse_macro_input!(item as ItemMod);
|
||||
|
||||
let crate_name = std::env::var("CARGO_PKG_NAME").unwrap();
|
||||
|
||||
let output = quote! {
|
||||
#[cfg(all(ktest, any(ktest = "all", ktest = #crate_name)))]
|
||||
#input
|
||||
};
|
||||
|
||||
TokenStream::from(output)
|
||||
}
|
||||
use syn::{parse_macro_input, Expr, Ident, ItemFn};
|
||||
|
||||
/// The test attribute macro to mark a test function.
|
||||
#[proc_macro_attribute]
|
||||
|
@ -21,8 +21,8 @@
|
||||
//! module, e.g.:
|
||||
//!
|
||||
//! ```rust
|
||||
//! use ktest::{ktest, if_cfg_ktest};
|
||||
//! #[if_cfg_ktest]
|
||||
//! use ktest::ktest;
|
||||
//! #[cfg(ktest)]
|
||||
//! mod test {
|
||||
//! #[ktest]
|
||||
//! fn trivial_assertion() {
|
||||
@ -97,7 +97,7 @@ extern crate alloc;
|
||||
use alloc::{boxed::Box, string::String};
|
||||
use core::result::Result;
|
||||
|
||||
pub use ktest_proc_macro::{if_cfg_ktest, ktest};
|
||||
pub use ktest_proc_macro::ktest;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct PanicInfo {
|
||||
|
@ -3,7 +3,7 @@
|
||||
//! Test runner enabling control over the tests.
|
||||
//!
|
||||
|
||||
use alloc::{string::String, vec::Vec};
|
||||
use alloc::{string::String, vec::Vec, collections::BTreeSet};
|
||||
use core::format_args;
|
||||
|
||||
use owo_colors::OwoColorize;
|
||||
@ -35,7 +35,8 @@ pub enum KtestResult {
|
||||
pub fn run_ktests<PrintFn, PathsIter>(
|
||||
print: &PrintFn,
|
||||
catch_unwind: &CatchUnwindImpl,
|
||||
whitelist: Option<PathsIter>,
|
||||
test_whitelist: Option<PathsIter>,
|
||||
crate_whitelist: Option<&[&str]>,
|
||||
) -> KtestResult
|
||||
where
|
||||
PrintFn: Fn(core::fmt::Arguments),
|
||||
@ -48,7 +49,7 @@ where
|
||||
}
|
||||
|
||||
let whitelist_trie =
|
||||
whitelist.map(|paths| SuffixTrie::from_paths(paths.map(|p| KtestPath::from(&p))));
|
||||
test_whitelist.map(|paths| SuffixTrie::from_paths(paths.map(|p| KtestPath::from(&p))));
|
||||
|
||||
let tree = KtestTree::from_iter(KtestIter::new());
|
||||
print!(
|
||||
@ -56,7 +57,15 @@ where
|
||||
tree.nr_tot_tests(),
|
||||
tree.nr_tot_crates()
|
||||
);
|
||||
let crate_set =
|
||||
crate_whitelist.map(|crates| crates.iter().copied().collect::<BTreeSet<&str>>());
|
||||
for crate_ in tree.iter() {
|
||||
if let Some(crate_set) = &crate_set {
|
||||
if !crate_set.contains(crate_.name()) {
|
||||
print!("\n[ktest runner] skipping crate \"{}\".\n", crate_.name());
|
||||
continue;
|
||||
}
|
||||
}
|
||||
match run_crate_ktests(crate_, print, catch_unwind, &whitelist_trie) {
|
||||
KtestResult::Ok => {}
|
||||
KtestResult::Failed => return KtestResult::Failed,
|
||||
|
@ -39,26 +39,16 @@ pub enum BzImageType {
|
||||
/// - `target_image_path`: The path to the target bzImage.
|
||||
/// - `image_type`: The type of the bzImage that we are building.
|
||||
/// - `kernel_path`: The path to the kernel ELF.
|
||||
/// - `setup_src`: The path to the setup crate.
|
||||
/// - `setup_tmp_out_dir`: The path to the temporary output directory for the setup binary.
|
||||
pub fn make_bzimage(
|
||||
target_image_path: &Path,
|
||||
image_type: BzImageType,
|
||||
kernel_path: &Path,
|
||||
setup_src: &Path,
|
||||
setup_tmp_out_dir: &Path,
|
||||
) {
|
||||
pub fn make_bzimage(target_image_path: &Path, image_type: BzImageType, kernel_path: &Path) {
|
||||
let setup = match image_type {
|
||||
BzImageType::Legacy32 => {
|
||||
let arch = setup_src
|
||||
.join("x86_64-i386_pm-none.json")
|
||||
let arch = PathBuf::from("../../setup/x86_64-i386_pm-none.json")
|
||||
.canonicalize()
|
||||
.unwrap();
|
||||
build_setup_with_arch(setup_src, setup_tmp_out_dir, &SetupBuildArch::Other(arch))
|
||||
}
|
||||
BzImageType::Efi64 => {
|
||||
build_setup_with_arch(setup_src, setup_tmp_out_dir, &SetupBuildArch::X86_64)
|
||||
build_setup_with_arch(&SetupBuildArch::Other(arch))
|
||||
}
|
||||
BzImageType::Efi64 => build_setup_with_arch(&SetupBuildArch::X86_64),
|
||||
};
|
||||
|
||||
let mut setup_elf = Vec::new();
|
||||
@ -186,33 +176,24 @@ fn fill_legacy_header_fields(
|
||||
/// Build the setup binary.
|
||||
///
|
||||
/// It will return the path to the built setup binary.
|
||||
fn build_setup_with_arch(source_dir: &Path, tmp_out_dir: &Path, arch: &SetupBuildArch) -> PathBuf {
|
||||
if !tmp_out_dir.exists() {
|
||||
std::fs::create_dir_all(&tmp_out_dir).unwrap();
|
||||
}
|
||||
let tmp_out_dir = std::fs::canonicalize(tmp_out_dir).unwrap();
|
||||
|
||||
fn build_setup_with_arch(arch: &SetupBuildArch) -> PathBuf {
|
||||
// Relocations are fewer in release mode. That's why the release mode is more stable than
|
||||
// the debug mode.
|
||||
let profile = "release";
|
||||
|
||||
let cargo = std::env::var("CARGO").unwrap();
|
||||
let mut cmd = std::process::Command::new(cargo);
|
||||
cmd.current_dir(source_dir);
|
||||
let mut cmd = std::process::Command::new("cargo");
|
||||
cmd.current_dir("../../setup");
|
||||
cmd.arg("build");
|
||||
if profile == "release" {
|
||||
cmd.arg("--release");
|
||||
}
|
||||
cmd.arg("--package").arg("linux-bzimage-setup");
|
||||
cmd.arg("--bin").arg("linux-bzimage-setup");
|
||||
cmd.arg("--target").arg(match arch {
|
||||
SetupBuildArch::X86_64 => "x86_64-unknown-none",
|
||||
SetupBuildArch::Other(path) => path.to_str().unwrap(),
|
||||
});
|
||||
cmd.arg("-Zbuild-std=core,alloc,compiler_builtins");
|
||||
cmd.arg("-Zbuild-std-features=compiler-builtins-mem");
|
||||
// Specify the build target directory to avoid cargo running
|
||||
// into a deadlock reading the workspace files.
|
||||
cmd.arg("--target-dir").arg(tmp_out_dir.as_os_str());
|
||||
cmd.env_remove("RUSTFLAGS");
|
||||
cmd.env_remove("CARGO_ENCODED_RUSTFLAGS");
|
||||
|
||||
@ -231,7 +212,7 @@ fn build_setup_with_arch(source_dir: &Path, tmp_out_dir: &Path, arch: &SetupBuil
|
||||
SetupBuildArch::Other(path) => path.file_stem().unwrap().to_str().unwrap(),
|
||||
};
|
||||
|
||||
let setup_artifact = tmp_out_dir
|
||||
let setup_artifact = PathBuf::from("../../setup/target")
|
||||
.join(arch_name)
|
||||
.join(profile)
|
||||
.join("linux-bzimage-setup");
|
||||
|
2
framework/libs/linux-bzimage/setup/.gitignore
vendored
Normal file
2
framework/libs/linux-bzimage/setup/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
# The Rust build cache for the setup crate is placed here.
|
||||
target/
|
@ -3,6 +3,10 @@ name = "linux-bzimage-setup"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[[bin]]
|
||||
name = "linux-bzimage-setup"
|
||||
path = "src/main.rs"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
|
Reference in New Issue
Block a user