Add simple bootloader for mipsel

Signed-off-by: Harry Chen <i@harrychen.xyz>
master
Harry Chen 6 years ago
parent 9bdac887f0
commit 52758e6620

@ -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)

@ -10,14 +10,22 @@ fn main() {
}
}
/// include payload and dtb in sections of asm
fn gen_payload_asm() -> Result<std::path::PathBuf> {
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<std::path::PathBuf> {
_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)
}

@ -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

@ -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*) }
}

@ -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<ProgramHeader32>) {
// 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);
}
}
}

@ -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 {}
}

@ -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
}
Loading…
Cancel
Save