Skip to content

Commit 72fd55b

Browse files
committed
refactor(aarch64): Use aarch64-cpu for register access and some memory barriers
Definitions for DAIFSet were added recently, but are not yet in a release, so the inline assembly that accesses it directly is marked with a FIXME comment. There are three differences I noticed while going through this: - In the TCR setup, the `bfi` instruction was redundant since it was inserting the same 3 bits that were already shifted to the same position there earlier - In TCR_EL1, 0 << 30 was being used to configure 4KiB granule size, which is incorrect. This is not even a valid value for TG1 (bits 30-31). 0x10 is the correct value for 4KiB (the 0x01 for 16KiB was correct but unused) - After enabling the MMU, the code performed a branch to flush the pipeline, which we can do more cleanly by inserting an instruction synchronization barrier
1 parent af60a8a commit 72fd55b

5 files changed

Lines changed: 70 additions & 122 deletions

File tree

‎Cargo.lock‎

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎Cargo.toml‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ aarch64-cpu = "11"
2323
enum_dispatch = "0.3"
2424
fdt = { version = "0.1" }
2525
goblin = { version = "0.10", default-features = false, features = ["elf64"] }
26+
tock-registers = "0.10"
2627
volatile = { version = "0.6", features = ["derive"] }
2728

2829
[target.'cfg(target_arch = "riscv64")'.dependencies]

‎src/arch/aarch64/entry.rs‎

Lines changed: 49 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -2,48 +2,19 @@
22

33
use core::arch::{asm, global_asm};
44

5-
use aarch64_cpu::registers::{SCTLR_EL1, Writeable};
5+
use aarch64_cpu::asm::{barrier, wfe};
6+
use aarch64_cpu::registers::{
7+
CPACR_EL1, ID_AA64MMFR0_EL1, MAIR_EL1, MDSCR_EL1, ReadWriteable, Readable, SCTLR_EL1, TCR_EL1,
8+
TPIDR_EL0, TPIDR_EL1, Writeable,
9+
};
610
use log::info;
11+
use tock_registers::fields::{FieldValue, TryFromValue};
712

813
const BOOT_CORE_ID: u64 = 0; // ID of CPU for booting on SMP systems - this might be board specific in the future
914

10-
/*
11-
* Memory types available.
12-
*/
13-
#[allow(non_upper_case_globals)]
14-
const MT_DEVICE_nGnRnE: u64 = 0;
15-
#[allow(non_upper_case_globals)]
16-
const MT_DEVICE_nGnRE: u64 = 1;
17-
const MT_DEVICE_GRE: u64 = 2;
18-
const MT_NORMAL_NC: u64 = 3;
19-
const MT_NORMAL: u64 = 4;
20-
21-
#[inline(always)]
22-
const fn mair(attr: u64, mt: u64) -> u64 {
23-
attr << (mt * 8)
24-
}
25-
26-
/*
27-
* TCR flags
28-
*/
29-
const TCR_IRGN_WBWA: u64 = ((1) << 8) | ((1) << 24);
30-
const TCR_ORGN_WBWA: u64 = ((1) << 10) | ((1) << 26);
31-
const TCR_SHARED: u64 = ((3) << 12) | ((3) << 28);
32-
const TCR_TBI0: u64 = 1 << 37;
33-
const TCR_TBI1: u64 = 1 << 38;
34-
const TCR_ASID16: u64 = 1 << 36;
35-
const TCR_TG1_16K: u64 = 1 << 30;
36-
const TCR_TG1_4K: u64 = 0 << 30;
37-
const TCR_FLAGS: u64 = TCR_IRGN_WBWA | TCR_ORGN_WBWA | TCR_SHARED;
38-
3915
/// Number of virtual address bits for 4KB page
4016
const VA_BITS: u64 = 48;
4117

42-
#[inline(always)]
43-
const fn tcr_size(x: u64) -> u64 {
44-
((64 - x) << 16) | (64 - x)
45-
}
46-
4718
global_asm!(
4819
include_str!("entry.s"),
4920
start_rust = sym start_rust,
@@ -59,14 +30,14 @@ unsafe fn pre_init() -> ! {
5930
info!("Enter startup code");
6031

6132
/* disable interrupts */
33+
/* FIXME: Migrate to aarch64_cpu's DAIFSet definition once released */
6234
unsafe {
6335
asm!("msr daifset, 0b111", options(nostack));
6436
}
6537

6638
/* reset thread id registers */
67-
unsafe {
68-
asm!("msr tpidr_el0, xzr", "msr tpidr_el1, xzr", options(nostack));
69-
}
39+
TPIDR_EL0.set(0);
40+
TPIDR_EL1.set(0);
7041

7142
/*
7243
* Disable the MMU. We may have entered the kernel with it on and
@@ -75,87 +46,67 @@ unsafe fn pre_init() -> ! {
7546
* but in this case the code to find where we are running from
7647
* would have also failed.
7748
*/
78-
unsafe {
79-
asm!("dsb sy",
80-
"mrs x2, sctlr_el1",
81-
"bic x2, x2, 0x1",
82-
"msr sctlr_el1, x2",
83-
"isb",
84-
out("x2") _,
85-
options(nostack),
86-
);
87-
}
49+
barrier::dsb(barrier::SY);
50+
SCTLR_EL1.modify(SCTLR_EL1::M::Disable);
51+
barrier::isb(barrier::SY);
8852

8953
unsafe {
90-
asm!("ic iallu", "tlbi vmalle1is", "dsb ish", options(nostack));
54+
asm!("ic iallu", "tlbi vmalle1is", options(nostack));
9155
}
56+
barrier::dsb(barrier::ISH);
9257

9358
/*
9459
* Setup memory attribute type tables
95-
*
96-
* Memory regioin attributes for LPAE:
97-
*
98-
* n = AttrIndx[2:0]
99-
* n MAIR
100-
* DEVICE_nGnRnE 000 00000000 (0x00)
101-
* DEVICE_nGnRE 001 00000100 (0x04)
102-
* DEVICE_GRE 010 00001100 (0x0c)
103-
* NORMAL_NC 011 01000100 (0x44)
104-
* NORMAL 100 11111111 (0xff)
10560
*/
106-
let mair_el1 = mair(0x00, MT_DEVICE_nGnRnE)
107-
| mair(0x04, MT_DEVICE_nGnRE)
108-
| mair(0x0c, MT_DEVICE_GRE)
109-
| mair(0x44, MT_NORMAL_NC)
110-
| mair(0xff, MT_NORMAL);
111-
unsafe {
112-
asm!("msr mair_el1, {}",
113-
in(reg) mair_el1,
114-
options(nostack),
115-
);
116-
}
61+
MAIR_EL1.write(
62+
MAIR_EL1::Attr0_Device::nonGathering_nonReordering_noEarlyWriteAck
63+
+ MAIR_EL1::Attr1_Device::nonGathering_nonReordering_EarlyWriteAck
64+
+ MAIR_EL1::Attr2_Device::Gathering_Reordering_EarlyWriteAck
65+
+ MAIR_EL1::Attr3_Normal_Inner::NonCacheable
66+
+ MAIR_EL1::Attr3_Normal_Outer::NonCacheable
67+
+ MAIR_EL1::Attr4_Normal_Inner::WriteBack_NonTransient_ReadWriteAlloc
68+
+ MAIR_EL1::Attr4_Normal_Outer::WriteBack_NonTransient_ReadWriteAlloc,
69+
);
11770

11871
/*
11972
* Setup translation control register (TCR)
12073
*/
12174

12275
// determine physical address size
123-
unsafe {
124-
asm!("mrs x0, id_aa64mmfr0_el1",
125-
"and x0, x0, 0xF",
126-
"lsl x0, x0, 32",
127-
"orr x0, x0, {tcr_bits}",
128-
"mrs x1, id_aa64mmfr0_el1",
129-
"bfi x0, x1, #32, #3",
130-
"msr tcr_el1, x0",
131-
tcr_bits = in(reg) tcr_size(VA_BITS) | TCR_TG1_4K | TCR_FLAGS,
132-
out("x0") _,
133-
out("x1") _,
134-
);
135-
}
76+
let Some(pa_range) = ID_AA64MMFR0_EL1
77+
.read_as_enum::<ID_AA64MMFR0_EL1::PARange::Value>(ID_AA64MMFR0_EL1::PARange)
78+
else {
79+
panic!("Unknown physical address range")
80+
};
81+
let Some(ips) = TCR_EL1::IPS::Value::try_from_value(pa_range as u64) else {
82+
panic!("Invalid physical address size")
83+
};
84+
85+
TCR_EL1.write(
86+
FieldValue::from(ips)
87+
+ TCR_EL1::T1SZ.val(64 - VA_BITS)
88+
+ TCR_EL1::T0SZ.val(64 - VA_BITS)
89+
+ TCR_EL1::TG1::KiB_4
90+
+ TCR_EL1::IRGN0::WriteBack_ReadAlloc_WriteAlloc_Cacheable
91+
+ TCR_EL1::IRGN1::WriteBack_ReadAlloc_WriteAlloc_Cacheable
92+
+ TCR_EL1::ORGN0::WriteBack_ReadAlloc_WriteAlloc_Cacheable
93+
+ TCR_EL1::ORGN1::WriteBack_ReadAlloc_WriteAlloc_Cacheable
94+
+ TCR_EL1::SH0::Inner
95+
+ TCR_EL1::SH1::Inner,
96+
);
13697

13798
/*
13899
* Enable FP/ASIMD in Architectural Feature Access Control Register,
139100
*/
140-
let bit_mask: u64 = 3 << 20;
141-
unsafe {
142-
asm!("msr cpacr_el1, {mask}",
143-
mask = in(reg) bit_mask,
144-
options(nostack),
145-
);
146-
}
101+
CPACR_EL1.write(CPACR_EL1::FPEN::TrapNothing);
147102

148103
/*
149104
* Reset debug control register
150105
*/
151-
unsafe {
152-
asm!("msr mdscr_el1, xzr", options(nostack));
153-
}
106+
MDSCR_EL1.set(0);
154107

155108
/* Memory barrier */
156-
unsafe {
157-
asm!("dsb sy", options(nostack));
158-
}
109+
barrier::dsb(barrier::SY);
159110

160111
/*
161112
* Prepare system control register (SCTRL)
@@ -195,10 +146,8 @@ unsafe fn pre_init() -> ! {
195146
}
196147
}
197148

198-
pub unsafe fn wait_forever() -> ! {
149+
pub fn wait_forever() -> ! {
199150
loop {
200-
unsafe {
201-
asm!("wfe");
202-
}
151+
wfe();
203152
}
204153
}

‎src/arch/aarch64/memory.ld‎

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
/*
2+
* Copyright 2025 The aarch64-rt Authors.
3+
*
4+
* This project is dual-licensed under Apache 2.0 and MIT terms.
5+
* See LICENSE-APACHE and LICENSE-MIT for details.
6+
*/
7+
8+
MEMORY
9+
{
10+
image : ORIGIN = 0x40200000, LENGTH = 2M
11+
}

‎src/arch/aarch64/mod.rs‎

Lines changed: 8 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@ pub mod paging;
88
use core::arch::asm;
99
use core::ptr;
1010

11-
use aarch64_cpu::asm::barrier::{NSH, SY, dmb, dsb, isb};
11+
use aarch64_cpu::asm::barrier::{self, NSH, SY, dmb, dsb, isb};
12+
use aarch64_cpu::registers::{ReadWriteable, SCTLR_EL1, TTBR0_EL1, TTBR1_EL1, Writeable};
1213
use align_address::Align;
1314
use fdt::Fdt;
1415
use goblin::elf::header::header64::{EI_DATA, ELFDATA2LSB, ELFMAG, Header, SELFMAG};
@@ -168,29 +169,14 @@ pub unsafe fn boot_kernel(kernel_info: LoadedKernel) -> ! {
168169
CONSOLE.lock().get().set_stdout(0x1000);
169170

170171
// Load TTBRx
171-
unsafe {
172-
asm!(
173-
"msr ttbr1_el1, xzr",
174-
"msr ttbr0_el1, {}",
175-
"dsb sy",
176-
"isb",
177-
in(reg) ptr::addr_of_mut!(l0_pgtable),
178-
options(nostack),
179-
)
180-
};
172+
TTBR1_EL1.set(0);
173+
TTBR0_EL1.set(&raw mut l0_pgtable as u64);
174+
barrier::dsb(barrier::SY);
175+
barrier::isb(barrier::SY);
181176

182177
// Enable paging
183-
unsafe {
184-
asm!(
185-
"mrs x0, sctlr_el1",
186-
"orr x0, x0, #1",
187-
"msr sctlr_el1, x0",
188-
"bl 0f",
189-
"0:",
190-
out("x0") _,
191-
options(nostack),
192-
);
193-
}
178+
SCTLR_EL1.modify(SCTLR_EL1::M::Enable);
179+
barrier::isb(barrier::SY);
194180

195181
info!("Successfully set up paging.");
196182

0 commit comments

Comments
 (0)