Skip to content

Commit f507c5a

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 f507c5a

2 files changed

Lines changed: 62 additions & 124 deletions

File tree

‎src/arch/aarch64/entry.rs‎

Lines changed: 53 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -2,48 +2,18 @@
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;
711

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

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-
3914
/// Number of virtual address bits for 4KB page
4015
const VA_BITS: u64 = 48;
4116

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

6131
/* disable interrupts */
32+
/* FIXME: Migrate to aarch64_cpu's DAIFSet definition once released */
6233
unsafe {
6334
asm!("msr daifset, 0b111", options(nostack));
6435
}
6536

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

7141
/*
7242
* Disable the MMU. We may have entered the kernel with it on and
@@ -75,87 +45,72 @@ unsafe fn pre_init() -> ! {
7545
* but in this case the code to find where we are running from
7646
* would have also failed.
7747
*/
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-
}
48+
barrier::dsb(barrier::SY);
49+
SCTLR_EL1.modify(SCTLR_EL1::M::Disable);
50+
barrier::isb(barrier::SY);
8851

8952
unsafe {
90-
asm!("ic iallu", "tlbi vmalle1is", "dsb ish", options(nostack));
53+
asm!("ic iallu", "tlbi vmalle1is", options(nostack));
9154
}
55+
barrier::dsb(barrier::ISH);
9256

9357
/*
9458
* 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)
10559
*/
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-
}
60+
MAIR_EL1.write(
61+
MAIR_EL1::Attr0_Device::nonGathering_nonReordering_noEarlyWriteAck
62+
+ MAIR_EL1::Attr1_Device::nonGathering_nonReordering_EarlyWriteAck
63+
+ MAIR_EL1::Attr2_Device::Gathering_Reordering_EarlyWriteAck
64+
+ MAIR_EL1::Attr3_Normal_Inner::NonCacheable
65+
+ MAIR_EL1::Attr3_Normal_Outer::NonCacheable
66+
+ MAIR_EL1::Attr4_Normal_Inner::WriteBack_NonTransient_ReadWriteAlloc
67+
+ MAIR_EL1::Attr4_Normal_Outer::WriteBack_NonTransient_ReadWriteAlloc,
68+
);
11769

11870
/*
11971
* Setup translation control register (TCR)
12072
*/
12173

12274
// 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-
}
75+
let pa_range = ID_AA64MMFR0_EL1
76+
.read_as_enum::<ID_AA64MMFR0_EL1::PARange::Value>(ID_AA64MMFR0_EL1::PARange);
77+
let ips = match pa_range {
78+
Some(ID_AA64MMFR0_EL1::PARange::Value::Bits_32) => TCR_EL1::IPS::Bits_32,
79+
Some(ID_AA64MMFR0_EL1::PARange::Value::Bits_36) => TCR_EL1::IPS::Bits_36,
80+
Some(ID_AA64MMFR0_EL1::PARange::Value::Bits_40) => TCR_EL1::IPS::Bits_40,
81+
Some(ID_AA64MMFR0_EL1::PARange::Value::Bits_42) => TCR_EL1::IPS::Bits_42,
82+
Some(ID_AA64MMFR0_EL1::PARange::Value::Bits_44) => TCR_EL1::IPS::Bits_44,
83+
Some(ID_AA64MMFR0_EL1::PARange::Value::Bits_48) => TCR_EL1::IPS::Bits_48,
84+
Some(ID_AA64MMFR0_EL1::PARange::Value::Bits_52) => TCR_EL1::IPS::Bits_52,
85+
// The spec technically also has 56 bits as an option and marks all other
86+
// cases as reserved
87+
None => panic!("Unknown physical address range"),
88+
};
89+
90+
TCR_EL1.write(
91+
ips + TCR_EL1::T1SZ.val(64 - VA_BITS)
92+
+ TCR_EL1::T0SZ.val(64 - VA_BITS)
93+
+ TCR_EL1::TG1::KiB_4
94+
+ TCR_EL1::IRGN0::WriteBack_ReadAlloc_WriteAlloc_Cacheable
95+
+ TCR_EL1::IRGN1::WriteBack_ReadAlloc_WriteAlloc_Cacheable
96+
+ TCR_EL1::ORGN0::WriteBack_ReadAlloc_WriteAlloc_Cacheable
97+
+ TCR_EL1::ORGN1::WriteBack_ReadAlloc_WriteAlloc_Cacheable
98+
+ TCR_EL1::SH0::Inner
99+
+ TCR_EL1::SH1::Inner,
100+
);
136101

137102
/*
138103
* Enable FP/ASIMD in Architectural Feature Access Control Register,
139104
*/
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-
}
105+
CPACR_EL1.write(CPACR_EL1::FPEN::TrapNothing);
147106

148107
/*
149108
* Reset debug control register
150109
*/
151-
unsafe {
152-
asm!("msr mdscr_el1, xzr", options(nostack));
153-
}
110+
MDSCR_EL1.set(0);
154111

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

160115
/*
161116
* Prepare system control register (SCTRL)
@@ -195,10 +150,8 @@ unsafe fn pre_init() -> ! {
195150
}
196151
}
197152

198-
pub unsafe fn wait_forever() -> ! {
153+
pub fn wait_forever() -> ! {
199154
loop {
200-
unsafe {
201-
asm!("wfe");
202-
}
155+
wfe();
203156
}
204157
}

‎src/arch/aarch64/mod.rs‎

Lines changed: 9 additions & 24 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, SP, 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

@@ -249,11 +235,10 @@ unsafe fn enter_kernel(stack: *mut u8, entry: *const (), raw_boot_info: &'static
249235
dmb(SY);
250236
dsb(NSH);
251237

238+
SP.set(stack as u64);
252239
unsafe {
253240
asm!(
254-
"mov sp, {stack}",
255241
"br {entry}",
256-
stack = in(reg) stack,
257242
entry = in(reg) entry,
258243
in("x0") raw_boot_info,
259244
in("x1") 0,

0 commit comments

Comments
 (0)