From 52758e6620fec4d515e87f3fa2fe24eae989ea2f Mon Sep 17 00:00:00 2001 From: Harry Chen Date: Mon, 1 Apr 2019 18:26:55 +0800 Subject: [PATCH] Add simple bootloader for mipsel Signed-off-by: Harry Chen --- bootloader/Makefile | 3 ++ bootloader/build.rs | 24 +++++++++++++++- bootloader/src/arch/mipsel/boot.S | 20 +++++++++++++ bootloader/src/arch/mipsel/boot.ld | 41 ++++++++++++++++++++++++++ bootloader/src/arch/mipsel/mod.rs | 34 ++++++++++++++++++++++ bootloader/src/main.rs | 46 ++++++++++++++++++++++++++++-- bootloader/targets/mipsel.json | 36 +++++++++++++++++++++++ 7 files changed, 201 insertions(+), 3 deletions(-) create mode 100644 bootloader/src/arch/mipsel/boot.S create mode 100644 bootloader/src/arch/mipsel/boot.ld create mode 100644 bootloader/src/arch/mipsel/mod.rs create mode 100644 bootloader/targets/mipsel.json diff --git a/bootloader/Makefile b/bootloader/Makefile index e675023..2e51b7d 100644 --- a/bootloader/Makefile +++ b/bootloader/Makefile @@ -13,6 +13,8 @@ else ifeq ($(arch), riscv32) prefix := riscv64-unknown-elf- else ifeq ($(arch), riscv64) prefix := riscv64-unknown-elf- +else ifeq ($(arch), mipsel) +prefix := mipsel-linux-gnu- else ifeq ($(arch), aarch64) prefix ?= aarch64-none-elf- ifeq (,$(shell which $(prefix)ld)) @@ -30,6 +32,7 @@ strip := $(prefix)strip export CC = $(cc) export PAYLOAD = $(payload) +export DTB = $(dtb) build_args := --target=targets/$(arch).json ifeq ($(mode), release) diff --git a/bootloader/build.rs b/bootloader/build.rs index 958e977..3a91fca 100644 --- a/bootloader/build.rs +++ b/bootloader/build.rs @@ -10,14 +10,22 @@ fn main() { } } +/// include payload and dtb in sections of asm fn gen_payload_asm() -> Result { let out_dir = std::env::var("OUT_DIR").unwrap(); let payload = std::env::var("PAYLOAD").unwrap(); + let dtb = std::env::var("DTB").unwrap(); if !Path::new(&payload).is_file() { panic!("Kernel payload `{}` not found", payload) } + let mut has_dtb = true; + + if !Path::new(&dtb).is_file() { + has_dtb = false; + } + let file_path = Path::new(&out_dir).join("payload.S"); let mut f = File::create(&file_path).unwrap(); @@ -31,10 +39,24 @@ fn gen_payload_asm() -> Result { _kernel_payload_start: .incbin "{}" _kernel_payload_end: -"#, payload)?; + "#, payload)?; println!("cargo:rerun-if-changed={}", payload); println!("cargo:rerun-if-env-changed=PAYLOAD"); + if has_dtb { + write!(f, r#" + .section .dtb,"a" + .align 12 + .global _dtb_start, _dtb_end +_dtb_start: + .incbin "{}" +_dtb_end: + "#, dtb)?; + println!("{:x?} {:x?}", dtb, file_path); + println!("cargo:rerun-if-changed={}", dtb); + println!("cargo:rerun-if-env-changed=DTB"); + } + Ok(file_path) } diff --git a/bootloader/src/arch/mipsel/boot.S b/bootloader/src/arch/mipsel/boot.S new file mode 100644 index 0000000..ffcf6da --- /dev/null +++ b/bootloader/src/arch/mipsel/boot.S @@ -0,0 +1,20 @@ +.section .text.boot +.globl _start + +_start: + # read cpu affinity, start core 0, halt the rest + mfc0 $8, $15, 1 + beqz $8, setup + andi $8, $8, 0x3ff # use bits 11 ~ 0 + +halt: + # core affinity != 0, halt it + b halt + nop + +setup: + # put the bootstack at 8MB offset of physical mem + la $29, 0x80800000 # $sp + la $28, _gp # $gp + b boot_main + nop \ No newline at end of file diff --git a/bootloader/src/arch/mipsel/boot.ld b/bootloader/src/arch/mipsel/boot.ld new file mode 100644 index 0000000..f62b631 --- /dev/null +++ b/bootloader/src/arch/mipsel/boot.ld @@ -0,0 +1,41 @@ +ENTRY(_start) + +SECTIONS { + + /* MIPS entry point after cold reset */ + . = 0xBFC00000; + + .text : { + KEEP(*(.text.boot)) /* from boot.S */ + *(.text .text.* .gnu.linkonce.t*) + . = ALIGN(4K); + } + + .rodata : { + *(.rodata .rodata.* .gnu.linkonce.r*) + . = ALIGN(4K); + } + + .data : { + *(.data .data.* .gnu.linkonce.d*) + . = ALIGN(4K); + } + + .bss : { + _sbss = .; + *(.bss .bss.*) + *(COMMON) + . = ALIGN(4K); + _ebss = .; + } + + .payload : { + *(.payload) + } + + .dtb : { + *(.dtb) + } + + /DISCARD/ : { *(.comment) *(.gnu*) *(.note*) *(.eh_frame*) } +} diff --git a/bootloader/src/arch/mipsel/mod.rs b/bootloader/src/arch/mipsel/mod.rs new file mode 100644 index 0000000..14237b6 --- /dev/null +++ b/bootloader/src/arch/mipsel/mod.rs @@ -0,0 +1,34 @@ +use core::ptr; +use fixedvec::FixedVec; +use xmas_elf::program::{ProgramHeader32, Type}; + +const KERNEL_OFFSET: u32 = 0x80000000; + +global_asm!(include_str!("boot.S")); + +pub fn copy_kernel(kernel_start: usize, segments: &FixedVec) { + // reverse program headers to avoid overlapping in memory copying + let mut space = alloc_stack!([ProgramHeader32; 32]); + let mut rev_segments = FixedVec::new(&mut space); + for i in (0..segments.len()).rev() { + rev_segments.push(segments[i]).unwrap(); + } + + for segment in &rev_segments { + if segment.get_type() != Ok(Type::Load) { + continue; + } + let virt_addr = segment.virtual_addr; + let offset = segment.offset; + let file_size = segment.file_size; + let mem_size = segment.mem_size; + + unsafe { + let src = (kernel_start as u32 + offset) as *const u8; + let dst = virt_addr.wrapping_sub(KERNEL_OFFSET) as *mut u8; + ptr::copy(src, dst, file_size as usize); + ptr::write_bytes(dst.offset(file_size as isize), 0, (mem_size - file_size) as usize); + } + } + +} diff --git a/bootloader/src/main.rs b/bootloader/src/main.rs index 88a6ac7..c886029 100644 --- a/bootloader/src/main.rs +++ b/bootloader/src/main.rs @@ -12,13 +12,18 @@ use core::slice; use fixedvec::FixedVec; use xmas_elf::{ header, - program::{ProgramHeader, ProgramHeader64}, + program::{ProgramHeader, ProgramHeader32, ProgramHeader64}, ElfFile, }; #[cfg(target_arch = "aarch64")] #[path = "arch/aarch64/mod.rs"] pub mod arch; + +#[cfg(target_arch = "mips")] +#[path = "arch/mipsel/mod.rs"] +pub mod arch; + pub mod lang_items; extern "C" { @@ -26,8 +31,15 @@ extern "C" { fn _kernel_payload_end(); } +#[cfg(target_arch = "mips")] +extern "C" { + fn _dtb_start(); + fn _dtb_end(); +} + /// The entry point of bootloader -#[no_mangle] // don't mangle the name of this function +#[cfg(target_arch = "aarch64")] +#[no_mangle] pub extern "C" fn boot_main() -> ! { let kernel_size = _kernel_payload_end as usize - _kernel_payload_start as usize; let kernel = unsafe { slice::from_raw_parts(_kernel_payload_start as *const u8, kernel_size) }; @@ -54,3 +66,33 @@ pub extern "C" fn boot_main() -> ! { loop {} } + + +#[cfg(target_arch = "mips")] +#[no_mangle] +pub extern "C" fn boot_main() -> ! { + let kernel_size = _kernel_payload_end as usize - _kernel_payload_start as usize; + let kernel = unsafe { slice::from_raw_parts(_kernel_payload_start as *const u8, kernel_size) }; + let kernel_elf = ElfFile::new(kernel).unwrap(); + header::sanity_check(&kernel_elf).unwrap(); + + let mut preallocated_space = alloc_stack!([ProgramHeader32; 32]); + let mut segments = FixedVec::new(&mut preallocated_space); + + for program_header in kernel_elf.program_iter() { + match program_header { + ProgramHeader::Ph32(header) => segments + .push(*header) + .expect("does not support more than 32 program segments"), + ProgramHeader::Ph64(_) => panic!("does not support 64 bit elf files"), + } + } + + let entry = kernel_elf.header.pt2.entry_point() as u32; + let kernel_main: extern "C" fn(dtb: usize) = unsafe { transmute(entry) }; + + arch::copy_kernel(_kernel_payload_start as usize, &segments); + kernel_main(_dtb_start as usize); + + loop {} +} diff --git a/bootloader/targets/mipsel.json b/bootloader/targets/mipsel.json new file mode 100644 index 0000000..d343fe4 --- /dev/null +++ b/bootloader/targets/mipsel.json @@ -0,0 +1,36 @@ +{ + "arch": "mips", + "cpu": "mips32r2", + "llvm-target": "mipsel-unknown-none", + "data-layout": "e-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64", + "target-endian": "little", + "target-pointer-width": "32", + "target-c-int-width": "32", + "os": "none", + "features": "+mips32r2", + "max-atomic-width": "32", + "linker": "rust-lld", + "linker-flavor": "ld.lld", + "pre-link-args": { + "ld.lld": [ + "-Tsrc/arch/mipsel/boot.ld" + ] + }, + "executables": true, + "panic-strategy": "abort", + "relocation-model": "static", + "abi-blacklist": [ + "cdecl", + "stdcall", + "fastcall", + "vectorcall", + "thiscall", + "aapcs", + "win64", + "sysv64", + "ptx-kernel", + "msp430-interrupt", + "x86-interrupt" + ], + "eliminate-frame-pointer": false +}