mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-09 13:26:48 +00:00
Add EFI stub
This commit is contained in:
parent
acf4a057d9
commit
32e62080ce
73
Cargo.lock
generated
73
Cargo.lock
generated
@ -956,6 +956,10 @@ dependencies = [
|
||||
"rle-decode-fast",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "linux_boot_params"
|
||||
version = "0.1.0"
|
||||
|
||||
[[package]]
|
||||
name = "lock_api"
|
||||
version = "0.4.10"
|
||||
@ -968,9 +972,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.19"
|
||||
version = "0.4.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4"
|
||||
checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f"
|
||||
|
||||
[[package]]
|
||||
name = "lru"
|
||||
@ -1028,7 +1032,7 @@ dependencies = [
|
||||
"derive_more",
|
||||
"log",
|
||||
"ptr_meta",
|
||||
"uefi-raw",
|
||||
"uefi-raw 0.3.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1496,6 +1500,41 @@ dependencies = [
|
||||
"x86",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ucs2"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bad643914094137d475641b6bab89462505316ec2ce70907ad20102d28a79ab8"
|
||||
dependencies = [
|
||||
"bit_field",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "uefi"
|
||||
version = "0.26.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "07ead9f748a4646479b850add36b527113a80e80a7e0f44d7b0334291850dcc5"
|
||||
dependencies = [
|
||||
"bitflags 2.3.3",
|
||||
"log",
|
||||
"ptr_meta",
|
||||
"ucs2",
|
||||
"uefi-macros",
|
||||
"uefi-raw 0.5.0",
|
||||
"uguid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "uefi-macros"
|
||||
version = "0.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "26a7b1c2c808c3db854a54d5215e3f7e7aaf5dcfbce095598cba6af29895695d"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.29",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "uefi-raw"
|
||||
version = "0.3.0"
|
||||
@ -1508,10 +1547,32 @@ dependencies = [
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "uguid"
|
||||
version = "2.0.1"
|
||||
name = "uefi-raw"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "16dfbd255defbd727b3a30e8950695d2e6d045841ee250ff0f1f7ced17917f8d"
|
||||
checksum = "864ac69eadd877bfb34e7814be1928122ed0057d9f975169a56ee496aa7bdfd7"
|
||||
dependencies = [
|
||||
"bitflags 2.3.3",
|
||||
"ptr_meta",
|
||||
"uguid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "uefi-services"
|
||||
version = "0.23.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a79fcb420624743c895bad0f9480fbc2f64e7c8d8611fb1ada6bdd799942feb4"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"log",
|
||||
"uefi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "uguid"
|
||||
version = "2.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1ef516f0806c5f61da6aa95125d0eb2d91cc95b2df426c06bde8be657282aee5"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
|
1
Makefile
1
Makefile
@ -86,6 +86,7 @@ USERMODE_TESTABLE := \
|
||||
runner \
|
||||
framework/libs/align_ext \
|
||||
framework/libs/boot-trojan/builder \
|
||||
framework/libs/boot-trojan/linux-boot-params \
|
||||
framework/libs/ktest \
|
||||
framework/libs/ktest-proc-macro \
|
||||
services/libs/cpio-decoder \
|
||||
|
@ -10,6 +10,7 @@ align_ext = { path = "../libs/align_ext" }
|
||||
bit_field = "0.10.1"
|
||||
bitflags = "1.3"
|
||||
bitvec = { version = "1.0", default-features = false, features = ["alloc"] }
|
||||
linux_boot_params = { path = "../libs/boot-trojan/linux-boot-params" }
|
||||
buddy_system_allocator = "0.9.0"
|
||||
cfg-if = "1.0"
|
||||
gimli = { version = "0.28", default-features = false, features = ["read-core"] }
|
||||
|
@ -1,291 +0,0 @@
|
||||
//! The Linux Boot Protocol boot_params module.
|
||||
//!
|
||||
//! The bootloader will deliver the address of the `BootParams` struct
|
||||
//! as the argument of the kernel entrypoint. So we must define a Linux
|
||||
//! ABI compatible struct in Rust, despite that most of the fields are
|
||||
//! currently not needed by Asterinas.
|
||||
//!
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
#[repr(C, packed)]
|
||||
pub(super) struct ScreenInfo {
|
||||
pub(super) orig_x: u8, /* 0x00 */
|
||||
pub(super) orig_y: u8, /* 0x01 */
|
||||
pub(super) ext_mem_k: u16, /* 0x02 */
|
||||
pub(super) orig_video_page: u16, /* 0x04 */
|
||||
pub(super) orig_video_mode: u8, /* 0x06 */
|
||||
pub(super) orig_video_cols: u8, /* 0x07 */
|
||||
pub(super) flags: u8, /* 0x08 */
|
||||
pub(super) unused2: u8, /* 0x09 */
|
||||
pub(super) orig_video_ega_bx: u16, /* 0x0a */
|
||||
pub(super) unused3: u16, /* 0x0c */
|
||||
pub(super) orig_video_lines: u8, /* 0x0e */
|
||||
pub(super) orig_video_is_vga: u8, /* 0x0f */
|
||||
pub(super) orig_video_points: u16, /* 0x10 */
|
||||
|
||||
/* VESA graphic mode -- linear frame buffer */
|
||||
pub(super) lfb_width: u16, /* 0x12 */
|
||||
pub(super) lfb_height: u16, /* 0x14 */
|
||||
pub(super) lfb_depth: u16, /* 0x16 */
|
||||
pub(super) lfb_base: u32, /* 0x18 */
|
||||
pub(super) lfb_size: u32, /* 0x1c */
|
||||
pub(super) cl_magic: u16,
|
||||
pub(super) cl_offset: u16, /* 0x20 */
|
||||
pub(super) lfb_linelength: u16, /* 0x24 */
|
||||
pub(super) red_size: u8, /* 0x26 */
|
||||
pub(super) red_pos: u8, /* 0x27 */
|
||||
pub(super) green_size: u8, /* 0x28 */
|
||||
pub(super) green_pos: u8, /* 0x29 */
|
||||
pub(super) blue_size: u8, /* 0x2a */
|
||||
pub(super) blue_pos: u8, /* 0x2b */
|
||||
pub(super) rsvd_size: u8, /* 0x2c */
|
||||
pub(super) rsvd_pos: u8, /* 0x2d */
|
||||
pub(super) vesapm_seg: u16, /* 0x2e */
|
||||
pub(super) vesapm_off: u16, /* 0x30 */
|
||||
pub(super) pages: u16, /* 0x32 */
|
||||
pub(super) vesa_attributes: u16, /* 0x34 */
|
||||
pub(super) capabilities: u32, /* 0x36 */
|
||||
pub(super) ext_lfb_base: u32, /* 0x3a */
|
||||
pub(super) _reserved: [u8; 2], /* 0x3e */
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
#[repr(C, packed)]
|
||||
pub(super) struct ApmBiosInfo {
|
||||
pub(super) version: u16,
|
||||
pub(super) cseg: u16,
|
||||
pub(super) offset: u32,
|
||||
pub(super) cseg_16: u16,
|
||||
pub(super) dseg: u16,
|
||||
pub(super) flags: u16,
|
||||
pub(super) cseg_len: u16,
|
||||
pub(super) cseg_16_len: u16,
|
||||
pub(super) dseg_len: u16,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
#[repr(C, packed)]
|
||||
pub(super) struct IstInfo {
|
||||
pub(super) signature: u32,
|
||||
pub(super) command: u32,
|
||||
pub(super) event: u32,
|
||||
pub(super) perf_level: u32,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
#[repr(C, packed)]
|
||||
pub(super) struct SysDescTable {
|
||||
pub(super) length: u16,
|
||||
pub(super) table: [u8; 14],
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
#[repr(C, packed)]
|
||||
pub(super) struct OlpcOfwHeader {
|
||||
pub(super) ofw_magic: u32, /* OFW signature */
|
||||
pub(super) ofw_version: u32,
|
||||
pub(super) cif_handler: u32, /* callback into OFW */
|
||||
pub(super) irq_desc_table: u32,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
#[repr(C)]
|
||||
pub(super) struct EdidInfo {
|
||||
pub(super) dummy: [u8; 128],
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
#[repr(C)]
|
||||
pub(super) struct EfiInfo {
|
||||
pub(super) efi_loader_signature: u32,
|
||||
pub(super) efi_systab: u32,
|
||||
pub(super) efi_memdesc_size: u32,
|
||||
pub(super) efi_memdesc_version: u32,
|
||||
pub(super) efi_memmap: u32,
|
||||
pub(super) efi_memmap_size: u32,
|
||||
pub(super) efi_systab_hi: u32,
|
||||
pub(super) efi_memmap_hi: u32,
|
||||
}
|
||||
|
||||
/// Magic stored in SetupHeader.header.
|
||||
pub(super) const LINUX_BOOT_HEADER_MAGIC: u32 = 0x53726448;
|
||||
|
||||
/// Linux Boot Protocol Header.
|
||||
///
|
||||
/// Originally defined in the linux source tree:
|
||||
/// `linux/arch/x86/include/uapi/asm/bootparam.h`
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
#[repr(C, packed)]
|
||||
pub(super) struct SetupHeader {
|
||||
pub(super) setup_sects: u8,
|
||||
pub(super) root_flags: u16,
|
||||
pub(super) syssize: u32,
|
||||
pub(super) ram_size: u16,
|
||||
pub(super) vid_mode: u16,
|
||||
pub(super) root_dev: u16,
|
||||
pub(super) boot_flag: u16,
|
||||
pub(super) jump: u16,
|
||||
pub(super) header: u32,
|
||||
pub(super) version: u16,
|
||||
pub(super) realmode_swtch: u32,
|
||||
pub(super) start_sys_seg: u16,
|
||||
pub(super) kernel_version: u16,
|
||||
pub(super) type_of_loader: u8,
|
||||
pub(super) loadflags: u8,
|
||||
pub(super) setup_move_size: u16,
|
||||
pub(super) code32_start: u32,
|
||||
pub(super) ramdisk_image: u32,
|
||||
pub(super) ramdisk_size: u32,
|
||||
pub(super) bootsect_kludge: u32,
|
||||
pub(super) heap_end_ptr: u16,
|
||||
pub(super) ext_loader_ver: u8,
|
||||
pub(super) ext_loader_type: u8,
|
||||
pub(super) cmd_line_ptr: u32,
|
||||
pub(super) initrd_addr_max: u32,
|
||||
pub(super) kernel_alignment: u32,
|
||||
pub(super) relocatable_kernel: u8,
|
||||
pub(super) min_alignment: u8,
|
||||
pub(super) xloadflags: u16,
|
||||
pub(super) cmdline_size: u32,
|
||||
pub(super) hardware_subarch: u32,
|
||||
pub(super) hardware_subarch_data: u64,
|
||||
pub(super) payload_offset: u32,
|
||||
pub(super) payload_length: u32,
|
||||
pub(super) setup_data: u64,
|
||||
pub(super) pref_address: u64,
|
||||
pub(super) init_size: u32,
|
||||
pub(super) handover_offset: u32,
|
||||
pub(super) kernel_info_offset: u32,
|
||||
}
|
||||
|
||||
/// The E820 types known to the kernel.
|
||||
///
|
||||
/// Originally defined in the linux source tree:
|
||||
/// `linux/arch/x86/include/asm/e820/types.h`
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
#[repr(u32)]
|
||||
pub(super) enum E820Type {
|
||||
Ram = 1,
|
||||
Reserved = 2,
|
||||
Acpi = 3,
|
||||
Nvs = 4,
|
||||
Unusable = 5,
|
||||
Pmem = 7,
|
||||
/*
|
||||
* This is a non-standardized way to represent ADR or
|
||||
* NVDIMM regions that persist over a reboot.
|
||||
*
|
||||
* The kernel will ignore their special capabilities
|
||||
* unless the CONFIG_X86_PMEM_LEGACY=y option is set.
|
||||
*
|
||||
* ( Note that older platforms also used 6 for the same
|
||||
* type of memory, but newer versions switched to 12 as
|
||||
* 6 was assigned differently. Some time they will learn... )
|
||||
*/
|
||||
Pram = 12,
|
||||
/*
|
||||
* Special-purpose memory is indicated to the system via the
|
||||
* EFI_MEMORY_SP attribute. Define an e820 translation of this
|
||||
* memory type for the purpose of reserving this range and
|
||||
* marking it with the IORES_DESC_SOFT_RESERVED designation.
|
||||
*/
|
||||
SoftReserved = 0xefffffff,
|
||||
/*
|
||||
* Reserved RAM used by the kernel itself if
|
||||
* CONFIG_INTEL_TXT=y is enabled, memory of this type
|
||||
* will be included in the S3 integrity calculation
|
||||
* and so should not include any memory that the BIOS
|
||||
* might alter over the S3 transition:
|
||||
*/
|
||||
ReservedKern = 128,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
#[repr(C, packed)]
|
||||
pub(super) struct BootE820Entry {
|
||||
pub(super) addr: u64,
|
||||
pub(super) size: u64,
|
||||
pub(super) typ: E820Type,
|
||||
}
|
||||
|
||||
const E820_MAX_ENTRIES_ZEROPAGE: usize = 128;
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
#[repr(C, packed)]
|
||||
pub(super) struct EddDeviceParams {
|
||||
// TODO: We currently have no plans to support the edd device,
|
||||
// and we need unnamed fields (Rust RFC 2102) to implement this
|
||||
// FFI neatly. So we put a dummy implementation here conforming
|
||||
// to the BootParams struct ABI.
|
||||
pub(super) _dummy: [u8; (0xeec - 0xd00) / 6 - 8],
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
#[repr(C, packed)]
|
||||
pub(super) struct EddInfo {
|
||||
pub(super) device: u8,
|
||||
pub(super) version: u8,
|
||||
pub(super) interface_support: u16,
|
||||
pub(super) legacy_max_cylinder: u16,
|
||||
pub(super) legacy_max_head: u8,
|
||||
pub(super) legacy_sectors_per_track: u8,
|
||||
pub(super) params: EddDeviceParams,
|
||||
}
|
||||
|
||||
const EDD_MBR_SIG_MAX: usize = 16;
|
||||
const EDDMAXNR: usize = 6;
|
||||
|
||||
/// Linux 32/64-bit Boot Protocol parameter struct.
|
||||
///
|
||||
/// Originally defined in the linux source tree:
|
||||
/// `linux/arch/x86/include/uapi/asm/bootparam.h`
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
#[repr(C, packed)]
|
||||
pub(super) struct BootParams {
|
||||
pub(super) screen_info: ScreenInfo, /* 0x000 */
|
||||
pub(super) apm_bios_info: ApmBiosInfo, /* 0x040 */
|
||||
pub(super) _pad2: [u8; 4], /* 0x054 */
|
||||
pub(super) tboot_addr: u64, /* 0x058 */
|
||||
pub(super) ist_info: IstInfo, /* 0x060 */
|
||||
pub(super) acpi_rsdp_addr: u64, /* 0x070 */
|
||||
pub(super) _pad3: [u8; 8], /* 0x078 */
|
||||
pub(super) hd0_info: [u8; 16], /* obsolete! 0x080 */
|
||||
pub(super) hd1_info: [u8; 16], /* obsolete! 0x090 */
|
||||
pub(super) sys_desc_table: SysDescTable, /* obsolete! 0x0a0 */
|
||||
pub(super) olpc_ofw_header: OlpcOfwHeader, /* 0x0b0 */
|
||||
pub(super) ext_ramdisk_image: u32, /* 0x0c0 */
|
||||
pub(super) ext_ramdisk_size: u32, /* 0x0c4 */
|
||||
pub(super) ext_cmd_line_ptr: u32, /* 0x0c8 */
|
||||
pub(super) _pad4: [u8; 112], /* 0x0cc */
|
||||
pub(super) cc_blob_address: u32, /* 0x13c */
|
||||
pub(super) edid_info: EdidInfo, /* 0x140 */
|
||||
pub(super) efi_info: EfiInfo, /* 0x1c0 */
|
||||
pub(super) alt_mem_k: u32, /* 0x1e0 */
|
||||
pub(super) scratch: u32, /* Scratch field! 0x1e4 */
|
||||
pub(super) e820_entries: u8, /* 0x1e8 */
|
||||
pub(super) eddbuf_entries: u8, /* 0x1e9 */
|
||||
pub(super) edd_mbr_sig_buf_entries: u8, /* 0x1ea */
|
||||
pub(super) kbd_status: u8, /* 0x1eb */
|
||||
pub(super) secure_boot: u8, /* 0x1ec */
|
||||
pub(super) _pad5: [u8; 2], /* 0x1ed */
|
||||
/*
|
||||
* The sentinel is set to a nonzero value (0xff) in header.S.
|
||||
*
|
||||
* A bootloader is supposed to only take setup_header and put
|
||||
* it into a clean boot_params buffer. If it turns out that
|
||||
* it is clumsy or too generous with the buffer, it most
|
||||
* probably will pick up the sentinel variable too. The fact
|
||||
* that this variable then is still 0xff will let kernel
|
||||
* know that some variables in boot_params are invalid and
|
||||
* kernel should zero out certain portions of boot_params.
|
||||
*/
|
||||
pub(super) sentinel: u8, /* 0x1ef */
|
||||
pub(super) _pad6: [u8; 1], /* 0x1f0 */
|
||||
pub(super) hdr: SetupHeader, /* setup header 0x1f1 */
|
||||
pub(super) _pad7: [u8; 0x290 - 0x1f1 - core::mem::size_of::<SetupHeader>()],
|
||||
pub(super) edd_mbr_sig_buffer: [u32; EDD_MBR_SIG_MAX], /* 0x290 */
|
||||
pub(super) e820_table: [BootE820Entry; E820_MAX_ENTRIES_ZEROPAGE], /* 0x2d0 */
|
||||
pub(super) _pad8: [u8; 48], /* 0xcd0 */
|
||||
pub(super) eddbuf: [EddInfo; EDDMAXNR], /* 0xd00 */
|
||||
pub(super) _pad9: [u8; 276], /* 0xeec */
|
||||
}
|
@ -1,8 +1,8 @@
|
||||
//! The Linux 64-bit Boot Protocol supporting module.
|
||||
//!
|
||||
|
||||
mod boot_params;
|
||||
use boot_params::E820Type;
|
||||
extern crate linux_boot_params;
|
||||
use linux_boot_params::{BootParams, E820Type, LINUX_BOOT_HEADER_MAGIC};
|
||||
|
||||
use crate::boot::{
|
||||
kcmdline::KCmdlineArg,
|
||||
@ -16,7 +16,7 @@ use core::ffi::CStr;
|
||||
|
||||
use spin::Once;
|
||||
|
||||
static BOOT_PARAMS: Once<boot_params::BootParams> = Once::new();
|
||||
static BOOT_PARAMS: Once<BootParams> = Once::new();
|
||||
|
||||
fn init_bootloader_name(bootloader_name: &'static Once<String>) {
|
||||
let hdr = &BOOT_PARAMS.get().unwrap().hdr;
|
||||
@ -140,9 +140,9 @@ fn init_memory_regions(memory_regions: &'static Once<Vec<MemoryRegion>>) {
|
||||
|
||||
/// The entry point of Rust code called by the Linux 64-bit boot compatible bootloader.
|
||||
#[no_mangle]
|
||||
unsafe extern "sysv64" fn __linux64_boot(params_ptr: *const boot_params::BootParams) -> ! {
|
||||
unsafe extern "sysv64" fn __linux64_boot(params_ptr: *const BootParams) -> ! {
|
||||
let params = *params_ptr;
|
||||
assert_eq!({ params.hdr.header }, boot_params::LINUX_BOOT_HEADER_MAGIC);
|
||||
assert_eq!({ params.hdr.header }, LINUX_BOOT_HEADER_MAGIC);
|
||||
BOOT_PARAMS.call_once(|| params);
|
||||
crate::boot::register_boot_init_callbacks(
|
||||
init_bootloader_name,
|
||||
|
@ -2,7 +2,6 @@ mod mapping;
|
||||
mod pe_header;
|
||||
|
||||
use std::{
|
||||
ffi::OsStr,
|
||||
fs::File,
|
||||
io::{Read, Write},
|
||||
path::{Path, PathBuf},
|
||||
@ -85,12 +84,15 @@ fn fill_legacy_header_fields(
|
||||
|
||||
pub fn make_bzimage(path: &Path, kernel_path: &Path, trojan_src: &Path, trojan_out: &Path) {
|
||||
#[cfg(feature = "trojan64")]
|
||||
let trojan = build_trojan_with_arch(trojan_src, trojan_out, "x86_64-unknown-none".as_ref());
|
||||
let trojan = build_trojan_with_arch(trojan_src, trojan_out, &TrojanBuildArch::X86_64);
|
||||
|
||||
#[cfg(not(feature = "trojan64"))]
|
||||
let trojan = {
|
||||
let arch = trojan_src.join("x86_64-i386_pm-none.json");
|
||||
build_trojan_with_arch(trojan_src, trojan_out, arch.as_os_str())
|
||||
let arch = trojan_src
|
||||
.join("x86_64-i386_pm-none.json")
|
||||
.canonicalize()
|
||||
.unwrap();
|
||||
build_trojan_with_arch(trojan_src, trojan_out, &TrojanBuildArch::Other(arch))
|
||||
};
|
||||
|
||||
let mut trojan_elf = Vec::new();
|
||||
@ -140,14 +142,32 @@ pub fn make_bzimage(path: &Path, kernel_path: &Path, trojan_src: &Path, trojan_o
|
||||
}
|
||||
}
|
||||
|
||||
fn build_trojan_with_arch(source_dir: &Path, out_dir: &Path, arch: &OsStr) -> PathBuf {
|
||||
// We need a custom target file for i386 but not for x86_64.
|
||||
// The compiler may warn us the X86_64 enum variant is not constructed
|
||||
// when we are building for i386, but we can ignore it.
|
||||
#[allow(dead_code)]
|
||||
enum TrojanBuildArch {
|
||||
X86_64,
|
||||
Other(PathBuf),
|
||||
}
|
||||
|
||||
fn build_trojan_with_arch(source_dir: &Path, out_dir: &Path, arch: &TrojanBuildArch) -> PathBuf {
|
||||
if !out_dir.exists() {
|
||||
std::fs::create_dir_all(&out_dir).unwrap();
|
||||
}
|
||||
let out_dir = std::fs::canonicalize(out_dir).unwrap();
|
||||
|
||||
let cargo = std::env::var("CARGO").unwrap();
|
||||
let mut cmd = std::process::Command::new(cargo);
|
||||
cmd.current_dir(source_dir);
|
||||
cmd.arg("build");
|
||||
// Relocations are fewer in release mode, saving header real-estate.
|
||||
cmd.arg("--release");
|
||||
cmd.arg("--package").arg("aster-boot-trojan");
|
||||
cmd.arg("--manifest-path")
|
||||
.arg(source_dir.join("Cargo.toml").as_os_str());
|
||||
cmd.arg("--target").arg(arch);
|
||||
cmd.arg("--target").arg(match arch {
|
||||
TrojanBuildArch::X86_64 => "x86_64-unknown-none",
|
||||
TrojanBuildArch::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
|
||||
@ -155,6 +175,7 @@ fn build_trojan_with_arch(source_dir: &Path, out_dir: &Path, arch: &OsStr) -> Pa
|
||||
cmd.arg("--target-dir").arg(out_dir.as_os_str());
|
||||
cmd.env_remove("RUSTFLAGS");
|
||||
cmd.env_remove("CARGO_ENCODED_RUSTFLAGS");
|
||||
|
||||
let mut child = cmd.spawn().unwrap();
|
||||
let status = child.wait().unwrap();
|
||||
if !status.success() {
|
||||
@ -164,12 +185,15 @@ fn build_trojan_with_arch(source_dir: &Path, out_dir: &Path, arch: &OsStr) -> Pa
|
||||
);
|
||||
}
|
||||
|
||||
// If the arch is a builtin target rather than json, the path operation works as well.
|
||||
let arch_name = Path::new(arch).file_stem().unwrap().to_str().unwrap();
|
||||
// Return the path to the trojan binary.
|
||||
let arch_name = match arch {
|
||||
TrojanBuildArch::X86_64 => "x86_64-unknown-none",
|
||||
TrojanBuildArch::Other(path) => path.file_stem().unwrap().to_str().unwrap(),
|
||||
};
|
||||
|
||||
let trojan_artifact = out_dir
|
||||
.join(arch_name)
|
||||
.join("debug")
|
||||
.join("release")
|
||||
.join("aster-boot-trojan");
|
||||
|
||||
trojan_artifact.to_owned()
|
||||
|
@ -1,7 +1,11 @@
|
||||
//! In the trojan, VA - SETUP32_LMA == FileOffset - LEGACY_SETUP_SEC_SIZE.
|
||||
//! And the addresses are specified in the ELF file.
|
||||
|
||||
use std::{cmp::PartialOrd, convert::From, ops::Sub};
|
||||
use std::{
|
||||
cmp::PartialOrd,
|
||||
convert::From,
|
||||
ops::{Add, Sub},
|
||||
};
|
||||
|
||||
// We chose the legacy setup sections to be 7 so that the setup header
|
||||
// is page-aligned and the legacy setup section size would be 0x1000.
|
||||
@ -40,6 +44,16 @@ impl Sub for TrojanVA {
|
||||
}
|
||||
}
|
||||
|
||||
impl Add<usize> for TrojanVA {
|
||||
type Output = Self;
|
||||
|
||||
fn add(self, rhs: usize) -> Self::Output {
|
||||
Self {
|
||||
addr: self.addr + rhs,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<usize> for TrojanFileOffset {
|
||||
fn from(offset: usize) -> Self {
|
||||
Self { offset }
|
||||
@ -60,6 +74,16 @@ impl Sub for TrojanFileOffset {
|
||||
}
|
||||
}
|
||||
|
||||
impl Add<usize> for TrojanFileOffset {
|
||||
type Output = Self;
|
||||
|
||||
fn add(self, rhs: usize) -> Self::Output {
|
||||
Self {
|
||||
offset: self.offset + rhs,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<TrojanVA> for TrojanFileOffset {
|
||||
fn from(va: TrojanVA) -> Self {
|
||||
Self {
|
||||
|
@ -104,6 +104,42 @@ struct Pe32PlusOptHdr {
|
||||
data_dirs: u32, // number of data dir entries
|
||||
}
|
||||
|
||||
#[derive(Zeroable, Pod, Serialize, Clone, Copy)]
|
||||
#[repr(C, packed)]
|
||||
struct Pe32PlusOptDataDirEnt {
|
||||
/// The RVA is the address of the table relative to the base address of the image when the table is loaded.
|
||||
rva: u32,
|
||||
size: u32,
|
||||
}
|
||||
|
||||
impl Pe32PlusOptDataDirEnt {
|
||||
fn none() -> Self {
|
||||
Self { rva: 0, size: 0 }
|
||||
}
|
||||
}
|
||||
|
||||
/// The data directories in the PE32+ optional header.
|
||||
///
|
||||
/// The `data_dirs` number field in the PE32+ optional header is just an illusion that you can choose to have a
|
||||
/// subset of the data directories. The actual number of data directories is fixed to 16 and you can only ignore
|
||||
/// data directories at the end of the list. We ignore data directories after the 8th as what Linux do.
|
||||
#[derive(Zeroable, Pod, Serialize, Clone, Copy)]
|
||||
#[repr(C, packed)]
|
||||
struct Pe32PlusOptDataDirs {
|
||||
export_table: Pe32PlusOptDataDirEnt,
|
||||
import_table: Pe32PlusOptDataDirEnt,
|
||||
resource_table: Pe32PlusOptDataDirEnt,
|
||||
exception_table: Pe32PlusOptDataDirEnt,
|
||||
certificate_table: Pe32PlusOptDataDirEnt,
|
||||
base_relocation_table: Pe32PlusOptDataDirEnt,
|
||||
}
|
||||
|
||||
impl Pe32PlusOptDataDirs {
|
||||
fn num_dirs() -> usize {
|
||||
size_of::<Self>() / size_of::<Pe32PlusOptDataDirEnt>()
|
||||
}
|
||||
}
|
||||
|
||||
// The `flags` field choices in the PE section header.
|
||||
// Excluding the alignment flags, which is not bitflags.
|
||||
bitflags::bitflags! {
|
||||
@ -163,51 +199,50 @@ struct PeSectionHdr {
|
||||
}
|
||||
|
||||
struct TrojanSectionAddrInfo {
|
||||
pub setup: Range<TrojanVA>,
|
||||
pub text: Range<TrojanVA>,
|
||||
pub data: Range<TrojanVA>,
|
||||
pub bss: Range<TrojanVA>,
|
||||
/// All the readonly but loaded sections.
|
||||
pub rodata: Range<TrojanVA>,
|
||||
}
|
||||
|
||||
impl TrojanSectionAddrInfo {
|
||||
fn from(elf: &xmas_elf::ElfFile) -> Self {
|
||||
let mut setup_start = None;
|
||||
let mut setup_end = None;
|
||||
let mut text_start = None;
|
||||
let mut text_end = None;
|
||||
for section in elf.section_iter() {
|
||||
match elf.get_shstr(section.name()) {
|
||||
Ok(s) => {
|
||||
if s == ".setup" {
|
||||
setup_start = Some(section.address() as usize);
|
||||
setup_end = Some(section.address() as usize + section.size() as usize);
|
||||
} else if s == ".text" {
|
||||
text_start = Some(section.address() as usize);
|
||||
text_end = Some(section.address() as usize + section.size() as usize);
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
panic!("Error: {:#?}", e);
|
||||
let mut data_start = None;
|
||||
let mut data_end = None;
|
||||
let mut bss_start = None;
|
||||
let mut bss_end = None;
|
||||
let mut rodata_start = None;
|
||||
let mut rodata_end = None;
|
||||
for program in elf.program_iter() {
|
||||
if program.get_type().unwrap() == xmas_elf::program::Type::Load {
|
||||
let offset = TrojanVA::from(program.virtual_addr() as usize);
|
||||
let length = program.mem_size() as usize;
|
||||
if program.flags().is_execute() {
|
||||
text_start = Some(offset);
|
||||
text_end = Some(offset + length);
|
||||
} else if program.flags().is_write() {
|
||||
data_start = Some(offset);
|
||||
data_end = Some(offset + program.file_size() as usize);
|
||||
bss_start = Some(offset + program.file_size() as usize);
|
||||
bss_end = Some(offset + length);
|
||||
} else if program.flags().is_read() {
|
||||
rodata_start = Some(offset);
|
||||
rodata_end = Some(offset + length);
|
||||
}
|
||||
}
|
||||
}
|
||||
assert!(
|
||||
matches!(setup_start, Some(SETUP32_LMA)),
|
||||
"setup_start: {:#x?}",
|
||||
setup_start
|
||||
);
|
||||
|
||||
Self {
|
||||
setup: TrojanVA::from(setup_start.unwrap())..TrojanVA::from(setup_end.unwrap()),
|
||||
text: TrojanVA::from(text_start.unwrap())..TrojanVA::from(text_end.unwrap()),
|
||||
data: TrojanVA::from(data_start.unwrap())..TrojanVA::from(data_end.unwrap()),
|
||||
bss: TrojanVA::from(bss_start.unwrap())..TrojanVA::from(bss_end.unwrap()),
|
||||
rodata: TrojanVA::from(rodata_start.unwrap())..TrojanVA::from(rodata_end.unwrap()),
|
||||
}
|
||||
}
|
||||
|
||||
fn setup_virt_size(&self) -> usize {
|
||||
self.setup.end - self.setup.start
|
||||
}
|
||||
|
||||
fn setup_file_size(&self) -> usize {
|
||||
TrojanFileOffset::from(self.setup.end) - TrojanFileOffset::from(self.setup.start)
|
||||
}
|
||||
|
||||
fn text_virt_size(&self) -> usize {
|
||||
self.text.end - self.text.start
|
||||
}
|
||||
@ -215,6 +250,26 @@ impl TrojanSectionAddrInfo {
|
||||
fn text_file_size(&self) -> usize {
|
||||
TrojanFileOffset::from(self.text.end) - TrojanFileOffset::from(self.text.start)
|
||||
}
|
||||
|
||||
fn data_virt_size(&self) -> usize {
|
||||
self.data.end - self.data.start
|
||||
}
|
||||
|
||||
fn data_file_size(&self) -> usize {
|
||||
TrojanFileOffset::from(self.data.end) - TrojanFileOffset::from(self.data.start)
|
||||
}
|
||||
|
||||
fn bss_virt_size(&self) -> usize {
|
||||
self.bss.end - self.bss.start
|
||||
}
|
||||
|
||||
fn rodata_virt_size(&self) -> usize {
|
||||
self.rodata.end - self.rodata.start
|
||||
}
|
||||
|
||||
fn rodata_file_size(&self) -> usize {
|
||||
TrojanFileOffset::from(self.rodata.end) - TrojanFileOffset::from(self.rodata.start)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct TrojanPeCoffHeaderBuf {
|
||||
@ -226,11 +281,16 @@ pub(crate) fn make_pe_coff_header(setup_elf: &[u8], image_size: usize) -> Trojan
|
||||
let elf = xmas_elf::ElfFile::new(setup_elf).unwrap();
|
||||
let mut bin = Vec::<u8>::new();
|
||||
|
||||
// The EFI application loader requires a relocation section.
|
||||
let relocs = vec![];
|
||||
// The place where we put the stub, must be after the legacy header and before 0x1000.
|
||||
let reloc_offset = TrojanFileOffset::from(0x500);
|
||||
|
||||
// PE header
|
||||
let pe_hdr = PeHdr {
|
||||
let mut pe_hdr = PeHdr {
|
||||
magic: PE_MAGIC,
|
||||
machine: PeMachineType::Amd64 as u16,
|
||||
sections: 3, // please set this field according to the number of sections added in the pe header
|
||||
sections: 0, // this field will be modified later
|
||||
timestamp: 0,
|
||||
symbol_table: 0,
|
||||
symbols: 1, // I don't know why, Linux header.S says it's 1
|
||||
@ -271,33 +331,27 @@ pub(crate) fn make_pe_coff_header(setup_elf: &[u8], image_size: usize) -> Trojan
|
||||
heap_size_req: 0,
|
||||
heap_size: 0,
|
||||
loader_flags: 0,
|
||||
data_dirs: 0,
|
||||
data_dirs: Pe32PlusOptDataDirs::num_dirs() as u32,
|
||||
};
|
||||
|
||||
let pe_opt_hdr_data_dirs = Pe32PlusOptDataDirs {
|
||||
export_table: Pe32PlusOptDataDirEnt::none(),
|
||||
import_table: Pe32PlusOptDataDirEnt::none(),
|
||||
resource_table: Pe32PlusOptDataDirEnt::none(),
|
||||
exception_table: Pe32PlusOptDataDirEnt::none(),
|
||||
certificate_table: Pe32PlusOptDataDirEnt::none(),
|
||||
base_relocation_table: Pe32PlusOptDataDirEnt {
|
||||
rva: usize::from(reloc_offset) as u32,
|
||||
size: relocs.len() as u32,
|
||||
},
|
||||
};
|
||||
|
||||
let addr_info = TrojanSectionAddrInfo::from(&elf);
|
||||
|
||||
// PE section headers
|
||||
let pe_setup_hdr = PeSectionHdr {
|
||||
name: [b'.', b's', b'e', b't', b'u', b'p', 0, 0],
|
||||
virtual_size: addr_info.setup_virt_size() as u32,
|
||||
virtual_address: usize::from(addr_info.setup.start) as u32,
|
||||
raw_data_size: addr_info.setup_file_size() as u32,
|
||||
data_addr: usize::from(TrojanFileOffset::from(addr_info.setup.start)) as u32,
|
||||
relocs: 0,
|
||||
line_numbers: 0,
|
||||
num_relocs: 0,
|
||||
num_lin_numbers: 0,
|
||||
flags: (PeSectionHdrFlags::CNT_CODE
|
||||
| PeSectionHdrFlags::MEM_READ
|
||||
| PeSectionHdrFlags::MEM_EXECUTE
|
||||
| PeSectionHdrFlags::MEM_DISCARDABLE)
|
||||
.bits
|
||||
| PeSectionHdrFlagsAlign::_16Bytes as u32,
|
||||
};
|
||||
// The EFI application loader requires a relocation section
|
||||
let reloc_offset = TrojanFileOffset::from(0x500); // must be after the legacy header and before 0x1000
|
||||
let relocs = vec![];
|
||||
let pe_reloc_hdr = PeSectionHdr {
|
||||
let mut sec_hdrs = Vec::<PeSectionHdr>::new();
|
||||
// .reloc
|
||||
sec_hdrs.push(PeSectionHdr {
|
||||
name: [b'.', b'r', b'e', b'l', b'o', b'c', 0, 0],
|
||||
virtual_size: relocs.len() as u32,
|
||||
virtual_address: usize::from(TrojanVA::from(reloc_offset)) as u32,
|
||||
@ -312,8 +366,9 @@ pub(crate) fn make_pe_coff_header(setup_elf: &[u8], image_size: usize) -> Trojan
|
||||
| PeSectionHdrFlags::MEM_DISCARDABLE)
|
||||
.bits
|
||||
| PeSectionHdrFlagsAlign::_1Bytes as u32,
|
||||
};
|
||||
let pe_text_hdr = PeSectionHdr {
|
||||
});
|
||||
// .text
|
||||
sec_hdrs.push(PeSectionHdr {
|
||||
name: [b'.', b't', b'e', b'x', b't', 0, 0, 0],
|
||||
virtual_size: addr_info.text_virt_size() as u32,
|
||||
virtual_address: usize::from(addr_info.text.start) as u32,
|
||||
@ -328,7 +383,55 @@ pub(crate) fn make_pe_coff_header(setup_elf: &[u8], image_size: usize) -> Trojan
|
||||
| PeSectionHdrFlags::MEM_EXECUTE)
|
||||
.bits
|
||||
| PeSectionHdrFlagsAlign::_16Bytes as u32,
|
||||
};
|
||||
});
|
||||
// .data
|
||||
sec_hdrs.push(PeSectionHdr {
|
||||
name: [b'.', b'd', b'a', b't', b'a', 0, 0, 0],
|
||||
virtual_size: addr_info.data_virt_size() as u32,
|
||||
virtual_address: usize::from(addr_info.data.start) as u32,
|
||||
raw_data_size: addr_info.data_file_size() as u32,
|
||||
data_addr: usize::from(TrojanFileOffset::from(addr_info.data.start)) as u32,
|
||||
relocs: 0,
|
||||
line_numbers: 0,
|
||||
num_relocs: 0,
|
||||
num_lin_numbers: 0,
|
||||
flags: (PeSectionHdrFlags::CNT_INITIALIZED_DATA
|
||||
| PeSectionHdrFlags::MEM_READ
|
||||
| PeSectionHdrFlags::MEM_WRITE)
|
||||
.bits
|
||||
| PeSectionHdrFlagsAlign::_16Bytes as u32,
|
||||
});
|
||||
// .bss
|
||||
sec_hdrs.push(PeSectionHdr {
|
||||
name: [b'.', b'b', b's', b's', 0, 0, 0, 0],
|
||||
virtual_size: addr_info.bss_virt_size() as u32,
|
||||
virtual_address: usize::from(addr_info.bss.start) as u32,
|
||||
raw_data_size: 0,
|
||||
data_addr: 0,
|
||||
relocs: 0,
|
||||
line_numbers: 0,
|
||||
num_relocs: 0,
|
||||
num_lin_numbers: 0,
|
||||
flags: (PeSectionHdrFlags::CNT_UNINITIALIZED_DATA
|
||||
| PeSectionHdrFlags::MEM_READ
|
||||
| PeSectionHdrFlags::MEM_WRITE)
|
||||
.bits
|
||||
| PeSectionHdrFlagsAlign::_16Bytes as u32,
|
||||
});
|
||||
// .rodata
|
||||
sec_hdrs.push(PeSectionHdr {
|
||||
name: [b'.', b'r', b'o', b'd', b'a', b't', b'a', 0],
|
||||
virtual_size: addr_info.rodata_virt_size() as u32,
|
||||
virtual_address: usize::from(addr_info.rodata.start) as u32,
|
||||
raw_data_size: addr_info.rodata_file_size() as u32,
|
||||
data_addr: usize::from(TrojanFileOffset::from(addr_info.rodata.start)) as u32,
|
||||
relocs: 0,
|
||||
line_numbers: 0,
|
||||
num_relocs: 0,
|
||||
num_lin_numbers: 0,
|
||||
flags: (PeSectionHdrFlags::CNT_INITIALIZED_DATA | PeSectionHdrFlags::MEM_READ).bits
|
||||
| PeSectionHdrFlagsAlign::_16Bytes as u32,
|
||||
});
|
||||
|
||||
// Write the MS-DOS header
|
||||
bin.extend_from_slice(&MZ_MAGIC.to_le_bytes());
|
||||
@ -338,13 +441,15 @@ pub(crate) fn make_pe_coff_header(setup_elf: &[u8], image_size: usize) -> Trojan
|
||||
bin.extend_from_slice(&(0x3cu32 + size_of::<u32>() as u32).to_le_bytes());
|
||||
|
||||
// Write the PE header
|
||||
pe_hdr.sections = sec_hdrs.len() as u16;
|
||||
bin.extend_from_slice(bytemuck::bytes_of(&pe_hdr));
|
||||
// Write the PE32+ optional header
|
||||
bin.extend_from_slice(bytemuck::bytes_of(&pe_opt_hdr));
|
||||
bin.extend_from_slice(bytemuck::bytes_of(&pe_opt_hdr_data_dirs));
|
||||
// Write the PE section headers
|
||||
bin.extend_from_slice(bytemuck::bytes_of(&pe_setup_hdr));
|
||||
bin.extend_from_slice(bytemuck::bytes_of(&pe_reloc_hdr));
|
||||
bin.extend_from_slice(bytemuck::bytes_of(&pe_text_hdr));
|
||||
for sec_hdr in sec_hdrs {
|
||||
bin.extend_from_slice(bytemuck::bytes_of(&sec_hdr));
|
||||
}
|
||||
|
||||
TrojanPeCoffHeaderBuf {
|
||||
header_at_zero: bin,
|
||||
|
8
framework/libs/boot-trojan/linux-boot-params/Cargo.toml
Normal file
8
framework/libs/boot-trojan/linux-boot-params/Cargo.toml
Normal file
@ -0,0 +1,8 @@
|
||||
[package]
|
||||
name = "linux_boot_params"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
293
framework/libs/boot-trojan/linux-boot-params/src/lib.rs
Normal file
293
framework/libs/boot-trojan/linux-boot-params/src/lib.rs
Normal file
@ -0,0 +1,293 @@
|
||||
//! The Linux Boot Protocol boot_params definition.
|
||||
//!
|
||||
//! The bootloader will deliver the address of the `BootParams` struct
|
||||
//! as the argument of the kernel entrypoint. So we must define a Linux
|
||||
//! ABI compatible struct in Rust, despite that most of the fields are
|
||||
//! currently not needed by Asterinas.
|
||||
//!
|
||||
|
||||
#![cfg_attr(not(test), no_std)]
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
#[repr(C, packed)]
|
||||
pub struct ScreenInfo {
|
||||
pub orig_x: u8, /* 0x00 */
|
||||
pub orig_y: u8, /* 0x01 */
|
||||
pub ext_mem_k: u16, /* 0x02 */
|
||||
pub orig_video_page: u16, /* 0x04 */
|
||||
pub orig_video_mode: u8, /* 0x06 */
|
||||
pub orig_video_cols: u8, /* 0x07 */
|
||||
pub flags: u8, /* 0x08 */
|
||||
pub unused2: u8, /* 0x09 */
|
||||
pub orig_video_ega_bx: u16, /* 0x0a */
|
||||
pub unused3: u16, /* 0x0c */
|
||||
pub orig_video_lines: u8, /* 0x0e */
|
||||
pub orig_video_is_vga: u8, /* 0x0f */
|
||||
pub orig_video_points: u16, /* 0x10 */
|
||||
|
||||
/* VESA graphic mode -- linear frame buffer */
|
||||
pub lfb_width: u16, /* 0x12 */
|
||||
pub lfb_height: u16, /* 0x14 */
|
||||
pub lfb_depth: u16, /* 0x16 */
|
||||
pub lfb_base: u32, /* 0x18 */
|
||||
pub lfb_size: u32, /* 0x1c */
|
||||
pub cl_magic: u16,
|
||||
pub cl_offset: u16, /* 0x20 */
|
||||
pub lfb_linelength: u16, /* 0x24 */
|
||||
pub red_size: u8, /* 0x26 */
|
||||
pub red_pos: u8, /* 0x27 */
|
||||
pub green_size: u8, /* 0x28 */
|
||||
pub green_pos: u8, /* 0x29 */
|
||||
pub blue_size: u8, /* 0x2a */
|
||||
pub blue_pos: u8, /* 0x2b */
|
||||
pub rsvd_size: u8, /* 0x2c */
|
||||
pub rsvd_pos: u8, /* 0x2d */
|
||||
pub vesapm_seg: u16, /* 0x2e */
|
||||
pub vesapm_off: u16, /* 0x30 */
|
||||
pub pages: u16, /* 0x32 */
|
||||
pub vesa_attributes: u16, /* 0x34 */
|
||||
pub capabilities: u32, /* 0x36 */
|
||||
pub ext_lfb_base: u32, /* 0x3a */
|
||||
pub _reserved: [u8; 2], /* 0x3e */
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
#[repr(C, packed)]
|
||||
pub struct ApmBiosInfo {
|
||||
pub version: u16,
|
||||
pub cseg: u16,
|
||||
pub offset: u32,
|
||||
pub cseg_16: u16,
|
||||
pub dseg: u16,
|
||||
pub flags: u16,
|
||||
pub cseg_len: u16,
|
||||
pub cseg_16_len: u16,
|
||||
pub dseg_len: u16,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
#[repr(C, packed)]
|
||||
pub struct IstInfo {
|
||||
pub signature: u32,
|
||||
pub command: u32,
|
||||
pub event: u32,
|
||||
pub perf_level: u32,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
#[repr(C, packed)]
|
||||
pub struct SysDescTable {
|
||||
pub length: u16,
|
||||
pub table: [u8; 14],
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
#[repr(C, packed)]
|
||||
pub struct OlpcOfwHeader {
|
||||
pub ofw_magic: u32, /* OFW signature */
|
||||
pub ofw_version: u32,
|
||||
pub cif_handler: u32, /* callback into OFW */
|
||||
pub irq_desc_table: u32,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
#[repr(C)]
|
||||
pub struct EdidInfo {
|
||||
pub dummy: [u8; 128],
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
#[repr(C)]
|
||||
pub struct EfiInfo {
|
||||
pub efi_loader_signature: u32,
|
||||
pub efi_systab: u32,
|
||||
pub efi_memdesc_size: u32,
|
||||
pub efi_memdesc_version: u32,
|
||||
pub efi_memmap: u32,
|
||||
pub efi_memmap_size: u32,
|
||||
pub efi_systab_hi: u32,
|
||||
pub efi_memmap_hi: u32,
|
||||
}
|
||||
|
||||
/// Magic stored in SetupHeader.header.
|
||||
pub const LINUX_BOOT_HEADER_MAGIC: u32 = 0x53726448;
|
||||
|
||||
/// Linux Boot Protocol Header.
|
||||
///
|
||||
/// Originally defined in the linux source tree:
|
||||
/// `linux/arch/x86/include/uapi/asm/bootparam.h`
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
#[repr(C, packed)]
|
||||
pub struct SetupHeader {
|
||||
pub setup_sects: u8,
|
||||
pub root_flags: u16,
|
||||
pub syssize: u32,
|
||||
pub ram_size: u16,
|
||||
pub vid_mode: u16,
|
||||
pub root_dev: u16,
|
||||
pub boot_flag: u16,
|
||||
pub jump: u16,
|
||||
pub header: u32,
|
||||
pub version: u16,
|
||||
pub realmode_swtch: u32,
|
||||
pub start_sys_seg: u16,
|
||||
pub kernel_version: u16,
|
||||
pub type_of_loader: u8,
|
||||
pub loadflags: u8,
|
||||
pub setup_move_size: u16,
|
||||
pub code32_start: u32,
|
||||
pub ramdisk_image: u32,
|
||||
pub ramdisk_size: u32,
|
||||
pub bootsect_kludge: u32,
|
||||
pub heap_end_ptr: u16,
|
||||
pub ext_loader_ver: u8,
|
||||
pub ext_loader_type: u8,
|
||||
pub cmd_line_ptr: u32,
|
||||
pub initrd_addr_max: u32,
|
||||
pub kernel_alignment: u32,
|
||||
pub relocatable_kernel: u8,
|
||||
pub min_alignment: u8,
|
||||
pub xloadflags: u16,
|
||||
pub cmdline_size: u32,
|
||||
pub hardware_subarch: u32,
|
||||
pub hardware_subarch_data: u64,
|
||||
pub payload_offset: u32,
|
||||
pub payload_length: u32,
|
||||
pub setup_data: u64,
|
||||
pub pref_address: u64,
|
||||
pub init_size: u32,
|
||||
pub handover_offset: u32,
|
||||
pub kernel_info_offset: u32,
|
||||
}
|
||||
|
||||
/// The E820 types known to the kernel.
|
||||
///
|
||||
/// Originally defined in the linux source tree:
|
||||
/// `linux/arch/x86/include/asm/e820/types.h`
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
#[repr(u32)]
|
||||
pub enum E820Type {
|
||||
Ram = 1,
|
||||
Reserved = 2,
|
||||
Acpi = 3,
|
||||
Nvs = 4,
|
||||
Unusable = 5,
|
||||
Pmem = 7,
|
||||
/*
|
||||
* This is a non-standardized way to represent ADR or
|
||||
* NVDIMM regions that persist over a reboot.
|
||||
*
|
||||
* The kernel will ignore their special capabilities
|
||||
* unless the CONFIG_X86_PMEM_LEGACY=y option is set.
|
||||
*
|
||||
* ( Note that older platforms also used 6 for the same
|
||||
* type of memory, but newer versions switched to 12 as
|
||||
* 6 was assigned differently. Some time they will learn... )
|
||||
*/
|
||||
Pram = 12,
|
||||
/*
|
||||
* Special-purpose memory is indicated to the system via the
|
||||
* EFI_MEMORY_SP attribute. Define an e820 translation of this
|
||||
* memory type for the purpose of reserving this range and
|
||||
* marking it with the IORES_DESC_SOFT_RESERVED designation.
|
||||
*/
|
||||
SoftReserved = 0xefffffff,
|
||||
/*
|
||||
* Reserved RAM used by the kernel itself if
|
||||
* CONFIG_INTEL_TXT=y is enabled, memory of this type
|
||||
* will be included in the S3 integrity calculation
|
||||
* and so should not include any memory that the BIOS
|
||||
* might alter over the S3 transition:
|
||||
*/
|
||||
ReservedKern = 128,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
#[repr(C, packed)]
|
||||
pub struct BootE820Entry {
|
||||
pub addr: u64,
|
||||
pub size: u64,
|
||||
pub typ: E820Type,
|
||||
}
|
||||
|
||||
const E820_MAX_ENTRIES_ZEROPAGE: usize = 128;
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
#[repr(C, packed)]
|
||||
pub struct EddDeviceParams {
|
||||
// TODO: We currently have no plans to support the edd device,
|
||||
// and we need unnamed fields (Rust RFC 2102) to implement this
|
||||
// FFI neatly. So we put a dummy implementation here conforming
|
||||
// to the BootParams struct ABI.
|
||||
pub _dummy: [u8; (0xeec - 0xd00) / 6 - 8],
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
#[repr(C, packed)]
|
||||
pub struct EddInfo {
|
||||
pub device: u8,
|
||||
pub version: u8,
|
||||
pub interface_support: u16,
|
||||
pub legacy_max_cylinder: u16,
|
||||
pub legacy_max_head: u8,
|
||||
pub legacy_sectors_per_track: u8,
|
||||
pub params: EddDeviceParams,
|
||||
}
|
||||
|
||||
const EDD_MBR_SIG_MAX: usize = 16;
|
||||
const EDDMAXNR: usize = 6;
|
||||
|
||||
/// Linux 32/64-bit Boot Protocol parameter struct.
|
||||
///
|
||||
/// Originally defined in the linux source tree:
|
||||
/// `linux/arch/x86/include/uapi/asm/bootparam.h`
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
#[repr(C, packed)]
|
||||
pub struct BootParams {
|
||||
pub screen_info: ScreenInfo, /* 0x000 */
|
||||
pub apm_bios_info: ApmBiosInfo, /* 0x040 */
|
||||
pub _pad2: [u8; 4], /* 0x054 */
|
||||
pub tboot_addr: u64, /* 0x058 */
|
||||
pub ist_info: IstInfo, /* 0x060 */
|
||||
pub acpi_rsdp_addr: u64, /* 0x070 */
|
||||
pub _pad3: [u8; 8], /* 0x078 */
|
||||
pub hd0_info: [u8; 16], /* obsolete! 0x080 */
|
||||
pub hd1_info: [u8; 16], /* obsolete! 0x090 */
|
||||
pub sys_desc_table: SysDescTable, /* obsolete! 0x0a0 */
|
||||
pub olpc_ofw_header: OlpcOfwHeader, /* 0x0b0 */
|
||||
pub ext_ramdisk_image: u32, /* 0x0c0 */
|
||||
pub ext_ramdisk_size: u32, /* 0x0c4 */
|
||||
pub ext_cmd_line_ptr: u32, /* 0x0c8 */
|
||||
pub _pad4: [u8; 112], /* 0x0cc */
|
||||
pub cc_blob_address: u32, /* 0x13c */
|
||||
pub edid_info: EdidInfo, /* 0x140 */
|
||||
pub efi_info: EfiInfo, /* 0x1c0 */
|
||||
pub alt_mem_k: u32, /* 0x1e0 */
|
||||
pub scratch: u32, /* Scratch field! 0x1e4 */
|
||||
pub e820_entries: u8, /* 0x1e8 */
|
||||
pub eddbuf_entries: u8, /* 0x1e9 */
|
||||
pub edd_mbr_sig_buf_entries: u8, /* 0x1ea */
|
||||
pub kbd_status: u8, /* 0x1eb */
|
||||
pub secure_boot: u8, /* 0x1ec */
|
||||
pub _pad5: [u8; 2], /* 0x1ed */
|
||||
/*
|
||||
* The sentinel is set to a nonzero value (0xff) in header.S.
|
||||
*
|
||||
* A bootloader is supposed to only take setup_header and put
|
||||
* it into a clean boot_params buffer. If it turns out that
|
||||
* it is clumsy or too generous with the buffer, it most
|
||||
* probably will pick up the sentinel variable too. The fact
|
||||
* that this variable then is still 0xff will let kernel
|
||||
* know that some variables in boot_params are invalid and
|
||||
* kernel should zero out certain portions of boot_params.
|
||||
*/
|
||||
pub sentinel: u8, /* 0x1ef */
|
||||
pub _pad6: [u8; 1], /* 0x1f0 */
|
||||
pub hdr: SetupHeader, /* setup header 0x1f1 */
|
||||
pub _pad7: [u8; 0x290 - 0x1f1 - core::mem::size_of::<SetupHeader>()],
|
||||
pub edd_mbr_sig_buffer: [u32; EDD_MBR_SIG_MAX], /* 0x290 */
|
||||
pub e820_table: [BootE820Entry; E820_MAX_ENTRIES_ZEROPAGE], /* 0x2d0 */
|
||||
pub _pad8: [u8; 48], /* 0xcd0 */
|
||||
pub eddbuf: [EddInfo; EDDMAXNR], /* 0xd00 */
|
||||
pub _pad9: [u8; 276], /* 0xeec */
|
||||
}
|
9
framework/libs/boot-trojan/trojan/.cargo/config.toml
Normal file
9
framework/libs/boot-trojan/trojan/.cargo/config.toml
Normal file
@ -0,0 +1,9 @@
|
||||
[target.x86_64-unknown-none]
|
||||
rustflags = [
|
||||
"-Ccode-model=kernel",
|
||||
"-Crelocation-model=pie",
|
||||
"-Ctarget-feature=+crt-static",
|
||||
"-Zplt=yes",
|
||||
"-Zrelax-elf-relocations=yes",
|
||||
"-Zrelro-level=full",
|
||||
]
|
@ -7,5 +7,11 @@ edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
cfg-if = "1.0.0"
|
||||
linux_boot_params = { path = "../linux-boot-params" }
|
||||
uart_16550 = "0.3.0"
|
||||
xmas-elf = "0.8.0"
|
||||
|
||||
[target.x86_64-unknown-none.dependencies]
|
||||
log = "0.4.20"
|
||||
uefi = "0.26.0"
|
||||
uefi-services = "0.23.0"
|
||||
|
@ -4,15 +4,12 @@ fn main() {
|
||||
let source_dir = PathBuf::from(std::env::var("CARGO_MANIFEST_DIR").unwrap());
|
||||
let target_arch = std::env::var("TARGET").unwrap();
|
||||
let linker_script = if target_arch == "x86_64-unknown-none" {
|
||||
source_dir.join("src/arch/x86_64.linker.ld")
|
||||
source_dir.join("src/arch/x86_64/linker.ld")
|
||||
} else if target_arch == "x86_64-i386_pm-none" {
|
||||
source_dir.join("src/arch/i386.linker.ld")
|
||||
source_dir.join("src/arch/i386/linker.ld")
|
||||
} else {
|
||||
panic!("Unsupported target_arch: {}", target_arch);
|
||||
};
|
||||
println!("cargo:rerun-if-changed={}", linker_script.display());
|
||||
println!(
|
||||
"cargo:rustc-link-arg-bins=--script={}",
|
||||
linker_script.display()
|
||||
);
|
||||
println!("cargo:rustc-link-arg=-T{}", linker_script.display());
|
||||
}
|
||||
|
@ -42,7 +42,7 @@ initrd_addr_max: .long 0x7fffffff
|
||||
kernel_alignment: .long 0x1000000
|
||||
relocatable_kernel: .byte 0
|
||||
min_alignment: .byte 0x10
|
||||
xloadflags: .word 0b01111 # all handover protocols except kexec
|
||||
xloadflags: .word 0
|
||||
cmdline_size: .long 4096-1
|
||||
hardware_subarch: .long 0
|
||||
hardware_subarch_data: .quad 0
|
||||
@ -51,6 +51,6 @@ payload_length: .long 0xabababab # at 0x24c/4, to be filled by the build
|
||||
setup_data: .quad 0
|
||||
pref_address: .quad CODE32_START - 0x200 * (SETUP_SECTS + 1);
|
||||
init_size: .long 0xabababab # at 0x260/4, to be filled by the builder
|
||||
handover_offset: .long CODE32_START
|
||||
handover_offset: .long 0
|
||||
kernel_info_offset: .long 0
|
||||
hdr_end:
|
@ -1,3 +1,5 @@
|
||||
use crate::println;
|
||||
|
||||
use core::arch::{asm, global_asm};
|
||||
|
||||
global_asm!(include_str!("header.S"));
|
||||
@ -6,9 +8,11 @@ global_asm!(include_str!("setup.S"));
|
||||
|
||||
#[no_mangle]
|
||||
extern "cdecl" fn _trojan_entry_32(boot_params_ptr: u32) -> ! {
|
||||
crate::trojan_entry(boot_params_ptr);
|
||||
crate::trojan_entry(0x100000, boot_params_ptr.try_into().unwrap());
|
||||
}
|
||||
|
||||
pub const ASTER_ENTRY_POINT: u32 = 0x8001000;
|
||||
|
||||
pub unsafe fn call_aster_entrypoint(entrypoint: u32, boot_params_ptr: u32) -> ! {
|
||||
asm!("mov esi, {}", in(reg) boot_params_ptr);
|
||||
asm!("mov eax, {}", in(reg) entrypoint);
|
||||
@ -16,3 +20,9 @@ pub unsafe fn call_aster_entrypoint(entrypoint: u32, boot_params_ptr: u32) -> !
|
||||
|
||||
unreachable!();
|
||||
}
|
||||
|
||||
#[panic_handler]
|
||||
fn panic(info: &core::panic::PanicInfo) -> ! {
|
||||
println!("panic: {:?}", info);
|
||||
loop {}
|
||||
}
|
@ -1,16 +0,0 @@
|
||||
.section ".setup", "ax"
|
||||
.code64
|
||||
.org 0x200
|
||||
// start_of_setup64 should be at start_of_setup32 + 0x200
|
||||
.global start_of_setup64
|
||||
start_of_setup64:
|
||||
|
||||
.extern _trojan_entry_64
|
||||
lea rax, [rip + _trojan_entry_64]
|
||||
push rsi
|
||||
call rax
|
||||
|
||||
// Unreachable here.
|
||||
halt:
|
||||
hlt
|
||||
jmp halt
|
66
framework/libs/boot-trojan/trojan/src/arch/x86_64/efi.rs
Normal file
66
framework/libs/boot-trojan/trojan/src/arch/x86_64/efi.rs
Normal file
@ -0,0 +1,66 @@
|
||||
use core::fmt::Write;
|
||||
use uefi::{
|
||||
data_types::Handle,
|
||||
proto::loaded_image::LoadedImage,
|
||||
table::{Boot, SystemTable},
|
||||
};
|
||||
|
||||
use linux_boot_params::BootParams;
|
||||
|
||||
#[no_mangle]
|
||||
extern "sysv64" fn efi_stub_entry(handle: Handle, mut system_table: SystemTable<Boot>) -> ! {
|
||||
unsafe {
|
||||
system_table.boot_services().set_image_handle(handle);
|
||||
}
|
||||
uefi_services::init(&mut system_table).unwrap();
|
||||
|
||||
// Suppress TODO warning.
|
||||
#[allow(unreachable_code)]
|
||||
efi_entry(
|
||||
handle,
|
||||
system_table,
|
||||
todo!("Use EFI services to fill boot params"),
|
||||
);
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
extern "sysv64" fn efi_handover_entry(
|
||||
handle: Handle,
|
||||
mut system_table: SystemTable<Boot>,
|
||||
boot_params: *mut BootParams,
|
||||
) -> ! {
|
||||
unsafe {
|
||||
system_table.boot_services().set_image_handle(handle);
|
||||
}
|
||||
uefi_services::init(&mut system_table).unwrap();
|
||||
|
||||
efi_entry(handle, system_table, boot_params)
|
||||
}
|
||||
|
||||
fn efi_entry(
|
||||
handle: Handle,
|
||||
mut system_table: SystemTable<Boot>,
|
||||
boot_params: *mut BootParams,
|
||||
) -> ! {
|
||||
system_table
|
||||
.stdout()
|
||||
.write_str("[EFI stub] Exiting EFI boot services.\n")
|
||||
.unwrap();
|
||||
let memory_type = {
|
||||
let boot_services = system_table.boot_services();
|
||||
let Ok(loaded_image) = boot_services.open_protocol_exclusive::<LoadedImage>(handle) else {
|
||||
panic!("Failed to open LoadedImage protocol");
|
||||
};
|
||||
loaded_image.data_type().clone()
|
||||
};
|
||||
let _ = system_table.exit_boot_services(memory_type);
|
||||
|
||||
let loaded_base = {
|
||||
extern "C" {
|
||||
fn start_of_setup32();
|
||||
}
|
||||
start_of_setup32 as usize
|
||||
};
|
||||
|
||||
crate::trojan_entry(loaded_base, boot_params as usize);
|
||||
}
|
59
framework/libs/boot-trojan/trojan/src/arch/x86_64/header.S
Normal file
59
framework/libs/boot-trojan/trojan/src/arch/x86_64/header.S
Normal file
@ -0,0 +1,59 @@
|
||||
// The compatibility file for the Linux x86 Boot Protocol.
|
||||
// See https://www.kernel.org/doc/html/v5.6/x86/boot.html for
|
||||
// more information on the Linux x86 Boot Protocol.
|
||||
|
||||
// Some of the fields filled with a 0xab* values should be filled
|
||||
// by the torjan builder.
|
||||
// Asterinas will use only a few of these fields, and some of them
|
||||
// are filled by the loader and will be read by Asterinas.
|
||||
|
||||
.section ".header", "a"
|
||||
CODE32_START = 0x100000
|
||||
SETUP_SECTS = 7 # so that the legacy setup could occupy a page
|
||||
SETUP_SECTS_SIZE = 0x200 * (SETUP_SECTS + 1)
|
||||
.code16
|
||||
.org 0x01f1
|
||||
hdr_start:
|
||||
setup_sects: .byte SETUP_SECTS
|
||||
root_flags: .word 1
|
||||
syssize: .long 0
|
||||
ram_size: .word 0
|
||||
vid_mode: .word 0xfffd
|
||||
root_dev: .word 0
|
||||
boot_flag: .word 0xAA55
|
||||
jump: .byte 0xeb
|
||||
jump_addr: .byte hdr_end-jump_addr
|
||||
magic: .ascii "HdrS"
|
||||
.word 0x020f
|
||||
realmode_swtch: .word 0, 0
|
||||
start_sys_seg: .word 0
|
||||
.word 0
|
||||
type_of_loader: .byte 0
|
||||
loadflags: .byte (1 << 0)
|
||||
setup_move_size: .word 0
|
||||
code32_start: .long CODE32_START
|
||||
ramdisk_image: .long 0
|
||||
ramdisk_size: .long 0
|
||||
bootsect_kludge: .long 0
|
||||
heap_end_ptr: .word 65535
|
||||
ext_loader_ver: .byte 0
|
||||
ext_loader_type: .byte 0
|
||||
cmd_line_ptr: .long 0
|
||||
initrd_addr_max: .long 0x7fffffff
|
||||
kernel_alignment: .long 0x1000000
|
||||
relocatable_kernel: .byte 0
|
||||
min_alignment: .byte 0x10
|
||||
xloadflags: .word 0b01111 # all handover protocols except kexec
|
||||
cmdline_size: .long 4096-1
|
||||
hardware_subarch: .long 0
|
||||
hardware_subarch_data: .quad 0
|
||||
payload_offset: .long 0xabababab # at 0x248/4, to be filled by the builder
|
||||
payload_length: .long 0xabababab # at 0x24c/4, to be filled by the builder
|
||||
setup_data: .quad 0
|
||||
pref_address: .quad CODE32_START - SETUP_SECTS_SIZE
|
||||
init_size: .long 0xabababab # at 0x260/4, to be filled by the builder
|
||||
# The handover_offset should be efi_handover_setup_entry - CODE32_START - 0x200
|
||||
# But we use ABI workaround to avoid the relocation of efi_handover_setup_entry
|
||||
handover_offset: .long 0x10
|
||||
kernel_info_offset: .long 0
|
||||
hdr_end:
|
@ -1,4 +1,4 @@
|
||||
ENTRY(start_of_setup64)
|
||||
ENTRY(efi_handover_setup_entry)
|
||||
OUTPUT_ARCH(i386:x86-64)
|
||||
OUTPUT_FORMAT(elf64-x86-64)
|
||||
|
||||
@ -17,7 +17,6 @@ SECTIONS
|
||||
.setup : { KEEP(*(.setup)) }
|
||||
|
||||
.text : { *(.text .text.*) }
|
||||
.rodata : { *(.rodata .rodata.*) }
|
||||
|
||||
.data : { *(.data .data.*) }
|
||||
.bss : {
|
||||
@ -26,6 +25,15 @@ SECTIONS
|
||||
PROVIDE(__bss_end = .);
|
||||
}
|
||||
|
||||
.got.plt : {
|
||||
*(.got.plt .got.plt.*)
|
||||
}
|
||||
.dynamic : {
|
||||
*(.dynamic .dynamic.*)
|
||||
}
|
||||
|
||||
.rodata : { *(.rodata .rodata.*) }
|
||||
|
||||
.eh_frame : {
|
||||
*(.eh_frame .eh_frame.*)
|
||||
}
|
||||
@ -36,4 +44,10 @@ SECTIONS
|
||||
.rela.dyn : {
|
||||
*(.rela.dyn .rela.dyn.*)
|
||||
}
|
||||
|
||||
.rela.plt : {
|
||||
*(.rela.plt .rela.plt.*)
|
||||
}
|
||||
|
||||
.comment : { *(.comment) }
|
||||
}
|
@ -1,13 +1,12 @@
|
||||
mod efi;
|
||||
|
||||
use core::arch::{asm, global_asm};
|
||||
|
||||
global_asm!(include_str!("header.S"));
|
||||
|
||||
global_asm!(include_str!("setup64.S"));
|
||||
global_asm!(include_str!("setup.S"));
|
||||
|
||||
#[no_mangle]
|
||||
extern "cdecl" fn _trojan_entry_64(boot_params_ptr: u64) -> ! {
|
||||
crate::trojan_entry(boot_params_ptr as u32);
|
||||
}
|
||||
pub const ASTER_ENTRY_POINT: u32 = 0x8001200;
|
||||
|
||||
pub unsafe fn call_aster_entrypoint(entrypoint: u64, boot_params_ptr: u64) -> ! {
|
||||
asm!("mov rsi, {}", in(reg) boot_params_ptr as u64);
|
41
framework/libs/boot-trojan/trojan/src/arch/x86_64/setup.S
Normal file
41
framework/libs/boot-trojan/trojan/src/arch/x86_64/setup.S
Normal file
@ -0,0 +1,41 @@
|
||||
.section ".setup", "ax"
|
||||
.code64
|
||||
// start_of_setup32 should be loaded at CODE32_START, which is our base.
|
||||
.global start_of_setup32
|
||||
start_of_setup32:
|
||||
|
||||
// `efi_handover_setup_entry64` should be at efi_handover_setup_entry32 + 0x200, but
|
||||
// we could provide the 32 bit dummy entry point as the 64 bit entry point - 0x200
|
||||
// since we do not provide 32-bit entry point in the x86_64 specific implementation.
|
||||
.org 0x210
|
||||
.global efi_handover_setup_entry
|
||||
efi_handover_setup_entry:
|
||||
// The 3 parameters of is stored in rdi, rsi and rdx (sysv64).
|
||||
// Do not use them.
|
||||
|
||||
// Setup the stack.
|
||||
lea rsp, [rip + setup_stack_top]
|
||||
lea rax, [rip + halt]
|
||||
push rax # the return address
|
||||
mov rbp, rsp
|
||||
add rbp, -4
|
||||
push rbp
|
||||
mov rbp, rsp
|
||||
|
||||
.extern efi_handover_entry
|
||||
lea rax, [rip + efi_handover_entry]
|
||||
call rax
|
||||
|
||||
// Unreachable here.
|
||||
halt:
|
||||
hlt
|
||||
jmp halt
|
||||
|
||||
// A small stack for the setup code.
|
||||
.section .data
|
||||
.align 0x1000 / 8
|
||||
.global setup_stack
|
||||
setup_stack:
|
||||
.skip 0x1000
|
||||
.global setup_stack_top
|
||||
setup_stack_top:
|
@ -1,12 +0,0 @@
|
||||
const FIELD_PAYLOAD_OFFSET: u32 = 0x248;
|
||||
const FIELD_PAYLOAD_LENGTH: u32 = 0x24c;
|
||||
|
||||
/// Safty: user must ensure that the boot_params_ptr is valid
|
||||
pub unsafe fn get_payload_offset(boot_params_ptr: u32) -> u32 {
|
||||
*((boot_params_ptr + FIELD_PAYLOAD_OFFSET) as *const u32)
|
||||
}
|
||||
|
||||
/// Safty: user must ensure that the boot_params_ptr is valid
|
||||
pub unsafe fn get_payload_length(boot_params_ptr: u32) -> u32 {
|
||||
*((boot_params_ptr + FIELD_PAYLOAD_LENGTH) as *const u32)
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
use core::fmt::{self, Write};
|
||||
use core::fmt::Write;
|
||||
|
||||
use uart_16550::SerialPort;
|
||||
|
||||
@ -17,37 +17,45 @@ pub unsafe fn init() {
|
||||
|
||||
impl Stdout {
|
||||
/// safety: this function must only be called once
|
||||
pub unsafe fn init() -> Self {
|
||||
unsafe fn init() -> Self {
|
||||
let mut serial_port = unsafe { SerialPort::new(0x3F8) };
|
||||
serial_port.init();
|
||||
Self { serial_port }
|
||||
}
|
||||
}
|
||||
|
||||
impl Write for Stdout {
|
||||
fn write_str(&mut self, s: &str) -> fmt::Result {
|
||||
impl Stdout {
|
||||
fn write_str(&mut self, s: &str) {
|
||||
self.serial_port.write_str(s).unwrap();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn write_char(&mut self, c: char) {
|
||||
self.serial_port.send(c as u8);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn print(args: fmt::Arguments) {
|
||||
// safety: init() must be called before print() and there is no race condition
|
||||
unsafe {
|
||||
STDOUT.write_fmt(args).unwrap();
|
||||
}
|
||||
/// Safety: init() must be called before print() and there should be no race condition
|
||||
pub unsafe fn print(s: &str) {
|
||||
STDOUT.write_str(s);
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! print {
|
||||
($fmt: literal $(, $($arg: tt)+)?) => {
|
||||
$crate::console::print(format_args!($fmt $(, $($arg)+)?))
|
||||
}
|
||||
/// Safety: init() must be called before print_char() and there should be no race condition
|
||||
pub unsafe fn print_char(c: char) {
|
||||
STDOUT.write_char(c);
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! println {
|
||||
($fmt: literal $(, $($arg: tt)+)?) => {
|
||||
$crate::console::print(format_args!(concat!($fmt, "\n") $(, $($arg)+)?))
|
||||
// Safety: init() must be called before print_hex() and there should be no race condition
|
||||
pub unsafe fn print_hex(n: usize) {
|
||||
print("0x");
|
||||
let mut n = n;
|
||||
for _ in 0..16 {
|
||||
let digit = (n & 0xf) as u8;
|
||||
n >>= 4;
|
||||
let c = if digit < 10 {
|
||||
(b'0' + digit) as char
|
||||
} else {
|
||||
(b'a' + digit - 10) as char
|
||||
};
|
||||
print_char(c);
|
||||
}
|
||||
}
|
||||
|
@ -24,6 +24,6 @@ pub fn load_elf(file: &[u8]) -> u32 {
|
||||
}
|
||||
}
|
||||
|
||||
// Return the Linux 32-bit Boot Protocol entry point defined by Asterinas.
|
||||
0x8001000
|
||||
// Return the Linux Boot Protocol entry point defined by Asterinas.
|
||||
crate::arch::ASTER_ENTRY_POINT
|
||||
}
|
||||
|
@ -1,32 +1,48 @@
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
use linux_boot_params::BootParams;
|
||||
|
||||
mod arch;
|
||||
mod boot_params;
|
||||
mod console;
|
||||
mod loader;
|
||||
|
||||
fn trojan_entry(boot_params_ptr: u32) -> ! {
|
||||
use console::{print, print_hex};
|
||||
|
||||
/// The entrypoint of the trojan. The architecture-specific entrypoint will call this function.
|
||||
///
|
||||
/// The loaded address of the CODE32_START should be passed in as `loaded_base`, since the trojan
|
||||
/// may be loaded at any address, and offsets in the header are not position-independent.
|
||||
fn trojan_entry(loaded_base: usize, boot_params_ptr: usize) -> ! {
|
||||
// Safety: this init function is only called once.
|
||||
unsafe { console::init() };
|
||||
println!("[setup] boot_params_ptr: {:#x}", boot_params_ptr);
|
||||
unsafe {
|
||||
print("[setup] bzImage loaded at ");
|
||||
print_hex(loaded_base);
|
||||
print("\n");
|
||||
}
|
||||
|
||||
let payload_offset = unsafe { boot_params::get_payload_offset(boot_params_ptr) };
|
||||
let payload_length = unsafe { boot_params::get_payload_length(boot_params_ptr) };
|
||||
// Safety: the boot_params_ptr is a valid pointer to be borrowed.
|
||||
let boot_params = unsafe { &*(boot_params_ptr as *const BootParams) };
|
||||
let hdr = &boot_params.hdr;
|
||||
let payload_offset = loaded_base + hdr.payload_offset as usize;
|
||||
let payload_length = hdr.payload_length as usize;
|
||||
let payload = unsafe {
|
||||
core::slice::from_raw_parts_mut(payload_offset as *mut u8, payload_length as usize)
|
||||
};
|
||||
|
||||
println!("[setup] loading ELF payload...");
|
||||
unsafe {
|
||||
print("[setup] loading ELF payload at ");
|
||||
print_hex(payload_offset);
|
||||
print("...\n");
|
||||
}
|
||||
let entrypoint = loader::load_elf(payload);
|
||||
println!("[setup] entrypoint: {:#x}", entrypoint);
|
||||
|
||||
unsafe {
|
||||
print("[setup] jumping to payload entrypoint at ");
|
||||
print_hex(entrypoint as usize);
|
||||
print("...\n");
|
||||
}
|
||||
// Safety: the entrypoint and the ptr is valid.
|
||||
unsafe { arch::call_aster_entrypoint(entrypoint.into(), boot_params_ptr.into()) };
|
||||
}
|
||||
|
||||
#[panic_handler]
|
||||
fn panic(info: &core::panic::PanicInfo) -> ! {
|
||||
println!("panic: {:?}", info);
|
||||
loop {}
|
||||
unsafe { arch::call_aster_entrypoint(entrypoint.into(), boot_params_ptr.try_into().unwrap()) };
|
||||
}
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
# AUTOMATICALLY GENERATED FILE, DO NOT EDIT IF YOU KNOW WHAT YOU ARE DOING
|
||||
|
||||
# set debug=linux,efi
|
||||
# set debug=linux,efi,linuxefi
|
||||
|
||||
set timeout_style=#GRUB_TIMEOUT_STYLE#
|
||||
set timeout=#GRUB_TIMEOUT#
|
||||
|
@ -10,7 +10,7 @@ use std::{fs::OpenOptions, io::Write, path::PathBuf, process::Command};
|
||||
/// When debugging grub, the OVMF firmware will load the grub kernel at an
|
||||
/// address unknown at the moment. You should use the debug message from our
|
||||
/// custom built OVMF firmware and read the entrypoint address
|
||||
/// (often `0x0007E685000`). Then use the following GDB command to load symbols:
|
||||
/// (often `0x0007E684000`). Then use the following GDB command to load symbols:
|
||||
/// `dynamic_load_symbols ${ENTRY_ADDRESS}`.
|
||||
/// During each run, the address is unlikely to change. But the address will
|
||||
/// depend on the versions of grub or OVMF.
|
||||
|
Loading…
x
Reference in New Issue
Block a user