Skip to content

Commit 9a9aa1e

Browse files
committed
build: Add initial support for aarch64 build
This commit adds initial support for aarch64 build. The goal is to boot Linux with this firmware on aarch64 Cloud Hypervisor. This commit includes a bootstrap assembly and build configs for building a binary that complies the Linux kernel image format [1]. It also includes some stub code to make the aarch64 target buildable with minimal changes. The later commits will implement the code. [1] https://docs.kernel.org/arm64/booting.html#call-the-kernel-image Signed-off-by: Akira Moroo <retrage01@gmail.com>
1 parent 35cb326 commit 9a9aa1e

14 files changed

+155
-4
lines changed

aarch64-unknown-none.json

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
{
2+
"llvm-target": "aarch64-unknown-none",
3+
"abi": "softfloat",
4+
"arch": "aarch64",
5+
"data-layout": "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128",
6+
"disable-redzone": true,
7+
"features": "+strict-align,-neon,-fp-armv8",
8+
"linker": "rust-lld",
9+
"linker-flavor": "ld.lld",
10+
"os": "none",
11+
"executables": true,
12+
"max-atomic-width": 128,
13+
"panic-strategy": "abort",
14+
"code-model": "small",
15+
"relocation-model": "pic",
16+
"target-pointer-width": "64",
17+
"pre-link-args": {
18+
"ld.lld": ["--script=aarch64-unknown-none.ld", "--oformat=binary"]
19+
}
20+
}

aarch64-unknown-none.ld

+38
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
ENTRY(ram64_start)
2+
3+
/* Cloud Hypervisor Memory layout:
4+
DRAM: [0x4000_0000-0xfc00_0000]
5+
FDT: [0x4000_0000-0x401f_ffff)
6+
ACPI: [0x4020_0000-0x403f_ffff)
7+
kernel: [0x4048_0000-]
8+
The stack start is at the end of the DRAM region. */
9+
ram_min = 0x40480000;
10+
11+
SECTIONS
12+
{
13+
/* Mapping the program headers and note into RAM makes the file smaller. */
14+
. = ram_min;
15+
16+
/* These sections are mapped into RAM from the file. Omitting :ram from
17+
later sections avoids emitting empty sections in the final binary. */
18+
text_start = .;
19+
.text.boot : { *(.text.boot) }
20+
.text : { *(.text .text.*) }
21+
. = ALIGN(4K);
22+
text_end = .;
23+
.data : { *(.data .data.*) }
24+
.rodata : { *(.rodata .rodata.*) }
25+
26+
/* The BSS section isn't mapped from file data. It is just zeroed in RAM. */
27+
.bss : {
28+
bss_start = .;
29+
*(.bss .bss.*)
30+
bss_size = . - bss_start;
31+
}
32+
33+
/* Strip symbols from the output binary (comment out to get symbols) */
34+
/DISCARD/ : {
35+
*(.symtab)
36+
*(.strtab)
37+
}
38+
}

build.rs

+2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
fn main() {
2+
println!("cargo:rerun-if-changed=aarch64-unknown-none.json");
3+
println!("cargo:rerun-if-changed=aarch64-unknown-none.ld");
24
println!("cargo:rerun-if-changed=x86_64-unknown-none.json");
35
println!("cargo:rerun-if-changed=x86_64-unknown-none.ld");
46
}

rust-toolchain.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
[toolchain]
22
channel = "nightly-2022-06-10"
33
components = ["rust-src", "clippy", "rustfmt"]
4-
targets = ["x86_64-unknown-linux-gnu"]
4+
targets = ["aarch64-unknown-linux-gnu", "x86_64-unknown-linux-gnu"]
55
profile = "default"

src/arch/aarch64/asm.rs

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
// SPDX-License-Identifier: Apache-2.0
2+
// Copyright (C) 2022 Akira Moroo
3+
4+
use core::arch::global_asm;
5+
6+
global_asm!(include_str!("ram64.s"));

src/arch/aarch64/mod.rs

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
// SPDX-License-Identifier: Apache-2.0
2+
// Copyright (C) 2022 Akira Moroo
3+
4+
#[cfg(not(test))]
5+
pub mod asm;

src/arch/aarch64/ram64.s

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/* SPDX-License-Identifier: Apache-2.0 */
2+
/* Copyright (C) 2022 Akira Moroo */
3+
4+
.section .text.boot, "ax"
5+
.global ram64_start
6+
7+
ram64_start:
8+
/* UEFI "MZ" signature magic instruction */
9+
add x13, x18, #0x16 /* code0 */
10+
b jump_to_rust /* code1 */
11+
12+
.quad 0 /* text_offset */
13+
.quad 0 /* image_size */
14+
.quad 0 /* flags */
15+
.quad 0 /* res2 */
16+
.quad 0 /* res3 */
17+
.quad 0 /* res4 */
18+
19+
.long 0x644d5241 /* "ARM\x64" magic number */
20+
.long 0 /* res5 */
21+
.align 3
22+
23+
jump_to_rust:
24+
/* x0 typically points to device tree at entry */
25+
ldr x0, =0x40000000
26+
27+
/* setup stack */
28+
ldr x30, =0xfc000000
29+
mov sp, x30
30+
31+
/* x0: pointer to device tree */
32+
b rust64_start

src/arch/mod.rs

+3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
// SPDX-License-Identifier: Apache-2.0
22
// Copyright (C) 2022 Akira Moroo
33

4+
#[cfg(target_arch = "aarch64")]
5+
pub mod aarch64;
6+
47
#[cfg(target_arch = "x86_64")]
58
pub mod x86_64;

src/delay.rs

+12
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,24 @@ const NSECS_PER_SEC: u64 = 1000000000;
1010
const CPU_KHZ_DEFAULT: u64 = 200;
1111
const PAUSE_THRESHOLD_TICKS: u64 = 150;
1212

13+
#[cfg(target_arch = "aarch64")]
14+
#[inline]
15+
unsafe fn rdtsc() -> u64 {
16+
todo!();
17+
}
18+
1319
#[cfg(target_arch = "x86_64")]
1420
#[inline]
1521
unsafe fn rdtsc() -> u64 {
1622
_rdtsc()
1723
}
1824

25+
#[cfg(target_arch = "aarch64")]
26+
#[inline]
27+
unsafe fn pause() {
28+
todo!();
29+
}
30+
1931
#[cfg(target_arch = "x86_64")]
2032
#[inline]
2133
unsafe fn pause() {

src/efi/mod.rs

+3
Original file line numberDiff line numberDiff line change
@@ -1255,6 +1255,9 @@ pub fn efi_exec(
12551255
let wrapped_fs = file::FileSystemWrapper::new(fs, efi_part_id);
12561256

12571257
let image = new_image_handle(
1258+
#[cfg(target_arch = "aarch64")]
1259+
"\\EFI\\BOOT\\BOOTAA64.EFI",
1260+
#[cfg(target_arch = "x86_64")]
12581261
"\\EFI\\BOOT\\BOOTX64.EFI",
12591262
0 as Handle,
12601263
&wrapped_fs as *const _ as Handle,

src/main.rs

+15-2
Original file line numberDiff line numberDiff line change
@@ -109,16 +109,23 @@ fn boot_from_device(device: &mut block::VirtioBlockDevice, info: &dyn boot::Info
109109
}
110110

111111
log!("Using EFI boot.");
112-
let mut file = match f.open("/EFI/BOOT/BOOTX64 EFI") {
112+
#[cfg(target_arch = "aarch64")]
113+
let efi_boot_path = "/EFI/BOOT/BOOTAA64.EFI";
114+
#[cfg(target_arch = "x86_64")]
115+
let efi_boot_path = "/EFI/BOOT/BOOTX64 EFI";
116+
let mut file = match f.open(efi_boot_path) {
113117
Ok(file) => file,
114118
Err(err) => {
115119
log!("Failed to load default EFI binary: {:?}", err);
116120
return false;
117121
}
118122
};
119-
log!("Found bootloader (BOOTX64.EFI)");
123+
log!("Found bootloader: {}", efi_boot_path);
120124

121125
let mut l = pe::Loader::new(&mut file);
126+
#[cfg(target_arch = "aarch64")]
127+
let load_addr = 0x4040_0000;
128+
#[cfg(target_arch = "x86_64")]
122129
let load_addr = 0x20_0000;
123130
let (entry_addr, load_addr, size) = match l.load(load_addr) {
124131
Ok(load_info) => load_info,
@@ -152,6 +159,12 @@ pub extern "C" fn rust64_start(#[cfg(not(feature = "coreboot"))] pvh_info: &pvh:
152159
main(info)
153160
}
154161

162+
#[cfg(target_arch = "aarch64")]
163+
#[no_mangle]
164+
pub extern "C" fn rust64_start(_x0: *const u8) -> ! {
165+
todo!();
166+
}
167+
155168
#[cfg(target_arch = "x86_64")]
156169
fn main(info: &dyn boot::Info) -> ! {
157170
log!("\nBooting with {}", info.name());

src/pe.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -38,10 +38,12 @@ struct Section {
3838
}
3939

4040
impl<'a> Loader<'a> {
41+
#[cfg(target_arch = "aarch64")]
42+
const MACHINE_TYPE: u16 = 0xaa64;
4143
#[cfg(target_arch = "x86_64")]
4244
const MACHINE_TYPE: u16 = 0x8664;
4345

44-
#[cfg(target_arch = "x86_64")]
46+
#[cfg(any(target_arch = "aarch64", target_arch = "x86_64"))]
4547
const OPTIONAL_HEADER_MAGIC: u16 = 0x20b; // PE32+
4648

4749
pub fn new(file: &'a mut dyn crate::fat::Read) -> Loader {

src/rtc.rs

+10
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,13 @@
33

44
#[cfg(target_arch = "x86_64")]
55
pub use crate::cmos::{read_date, read_time};
6+
7+
#[cfg(target_arch = "aarch64")]
8+
pub fn read_date() -> Result<(u8, u8, u8), ()> {
9+
todo!();
10+
}
11+
12+
#[cfg(target_arch = "aarch64")]
13+
pub fn read_time() -> Result<(u8, u8, u8), ()> {
14+
todo!();
15+
}

src/serial.rs

+5
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,11 @@ impl fmt::Write for Serial {
3232
fn write_str(&mut self, s: &str) -> fmt::Result {
3333
PORT.borrow_mut().write_str(s)
3434
}
35+
36+
#[cfg(target_arch = "aarch64")]
37+
fn write_str(&mut self, s: &str) -> fmt::Result {
38+
todo!();
39+
}
3540
}
3641

3742
#[macro_export]

0 commit comments

Comments
 (0)