Skip to content

Commit b06846d

Browse files
author
ccj
committed
[linux_boot]新增 Linux EL2 启动、Stage-2 内存映射及 PSCI HVC 转发支持
1 parent 3d87085 commit b06846d

4 files changed

Lines changed: 320 additions & 3 deletions

File tree

bsp/qemu-virt64-aarch64/applications/linux_trampoline.S

Lines changed: 189 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,206 @@
88

99
#define LINUX_IMAGE_ENTRY 0x48200000
1010
#define LINUX_DTB_ADDRESS 0x4f000000
11+
#define LINUX_RAM_BASE 0x48000000
12+
#define LINUX_RAM_2M_BLOCKS 64
13+
#define VIRTIO_MMIO_BASE 0x0a000000
14+
#define GIC_2M_BASE 0x08000000
15+
#define GICD_BASE 0x08000000
16+
#define GICC_BASE 0x08010000
17+
#define GICH_BASE 0x08030000
18+
#define HCR_EL2_RW (1 << 31)
19+
#define HCR_EL2_SWIO (1 << 1)
20+
#define HCR_EL2_VM (1 << 0)
21+
#define SPSR_EL1H_DAIF 0x3c5
22+
#define VTCR_EL2_RES1 (1 << 31)
23+
#define VTCR_EL2_SL0_LVL1 (1 << 6)
24+
#define VTCR_EL2_IRGN0_WBWA (1 << 8)
25+
#define VTCR_EL2_ORGN0_WBWA (1 << 10)
26+
#define VTCR_EL2_SH0_INNER (3 << 12)
27+
#define S2_TABLE_DESC 0x3
28+
#define S2_BLOCK_NORMAL_RW 0x7fd
29+
#define S2_BLOCK_DEVICE_RW 0x4c1
30+
#define S2_PAGE_DEVICE_RW 0x4c3
1131

32+
33+
34+
/* linux的启动入口,先搭建stage-2 */
1235
.section ".text.linux_trampoline", "ax"
1336
.align 6
1437
.global linux_cpu3_trampoline
1538
linux_cpu3_trampoline:
39+
/*
40+
* PSCI enters the target CPU at EL2 on QEMU virt with virtualization=on.
41+
* Keep EL2 owned by our monitor, then enter Linux as an EL1 kernel.
42+
*/
43+
mrs x5, CurrentEL
44+
lsr x5, x5, #2
45+
cmp x5, #2
46+
b.ne .linux_enter_current_el /* 跳到 Linux 镜像入口 */
47+
48+
ldr x5, =linux_cpu3_hyp_stack_top
49+
mov sp, x5
50+
51+
ldr x5, =hyp_vectors
52+
msr vbar_el2, x5 /* EL2 异常有入口 */
53+
isb
54+
55+
mrs x5, cnthctl_el2
56+
orr x5, x5, #0x3
57+
msr cnthctl_el2, x5 /* 放开 EL1 访问物理计时器 */
58+
msr cntvoff_el2, xzr
59+
60+
bl linux_stage2_setup
61+
62+
movz x5, #(HCR_EL2_RW >> 16), lsl #16
63+
orr x5, x5, #HCR_EL2_SWIO
64+
orr x5, x5, #HCR_EL2_VM
65+
msr hcr_el2, x5 /* 再写 HCR_EL2 打开虚拟化翻译 */
66+
67+
mov x5, #SPSR_EL1H_DAIF
68+
msr spsr_el2, x5
69+
70+
ldr x0, =LINUX_DTB_ADDRESS
71+
mov x1, xzr
72+
mov x2, xzr
73+
mov x3, xzr
74+
ldr x5, =LINUX_IMAGE_ENTRY
75+
msr elr_el2, x5
76+
eret
77+
78+
.linux_enter_current_el:
1679
ldr x0, =LINUX_DTB_ADDRESS
1780
mov x1, xzr
1881
mov x2, xzr
1982
mov x3, xzr
2083
ldr x4, =LINUX_IMAGE_ENTRY
2184
br x4
2285

86+
/* 真正建 Stage-2 */
87+
/* 4 块内存缓冲区,运行时被手工填成 Stage-2 页表 */
88+
linux_stage2_setup:
89+
ldr x6, =linux_stage2_l1
90+
mov x7, x6
91+
mov x8, #0x4000
92+
93+
.linux_stage2_clear:
94+
str xzr, [x7], #8
95+
subs x8, x8, #8
96+
b.ne .linux_stage2_clear
97+
98+
ldr x6, =linux_stage2_l1
99+
ldr x7, =linux_stage2_l2_low
100+
ldr x8, =linux_stage2_l2_high
101+
ldr x9, =linux_stage2_l3_gic
102+
103+
orr x10, x7, #S2_TABLE_DESC
104+
str x10, [x6, #0]
105+
orr x10, x8, #S2_TABLE_DESC
106+
str x10, [x6, #8]
107+
108+
orr x10, x9, #S2_TABLE_DESC
109+
str x10, [x7, #(64 * 8)]
110+
111+
ldr x10, =VIRTIO_MMIO_BASE
112+
lsr x11, x10, #21
113+
and x11, x11, #0x1ff
114+
movz x12, #S2_BLOCK_DEVICE_RW
115+
orr x13, x10, x12
116+
str x13, [x7, x11, lsl #3]
117+
118+
ldr x10, =LINUX_RAM_BASE
119+
mov x11, #LINUX_RAM_2M_BLOCKS
120+
movz x12, #S2_BLOCK_NORMAL_RW
121+
122+
.linux_stage2_map_ram:
123+
lsr x13, x10, #21
124+
and x13, x13, #0x1ff
125+
orr x14, x10, x12
126+
str x14, [x8, x13, lsl #3]
127+
add x10, x10, #0x200000
128+
subs x11, x11, #1
129+
b.ne .linux_stage2_map_ram
130+
131+
/*
132+
* Keep GICD writable for now so Linux can finish its early interrupt
133+
* controller bring-up. Once console output is stable again we can
134+
* re-introduce finer-grained GICD trapping incrementally.
135+
*/
136+
ldr x10, =GICD_BASE
137+
mov x11, #16
138+
movz x12, #S2_PAGE_DEVICE_RW /* 如果设置为只读权限就会被stage-2拦截 */
139+
140+
.linux_stage2_map_gicd:
141+
lsr x13, x10, #12
142+
and x13, x13, #0x1ff
143+
orr x14, x10, x12
144+
str x14, [x9, x13, lsl #3]
145+
add x10, x10, #0x1000
146+
subs x11, x11, #1
147+
b.ne .linux_stage2_map_gicd
148+
149+
ldr x10, =GICC_BASE
150+
mov x11, #16
151+
movz x12, #S2_PAGE_DEVICE_RW
152+
153+
.linux_stage2_map_gicc:
154+
lsr x13, x10, #12
155+
and x13, x13, #0x1ff
156+
orr x14, x10, x12
157+
str x14, [x9, x13, lsl #3]
158+
add x10, x10, #0x1000
159+
subs x11, x11, #1
160+
b.ne .linux_stage2_map_gicc
161+
162+
ldr x10, =GICH_BASE
163+
mov x11, #32
164+
movz x12, #S2_PAGE_DEVICE_RW
165+
166+
.linux_stage2_map_gich_gicv:
167+
lsr x13, x10, #12
168+
and x13, x13, #0x1ff
169+
orr x14, x10, x12
170+
str x14, [x9, x13, lsl #3]
171+
add x10, x10, #0x1000
172+
subs x11, x11, #1
173+
b.ne .linux_stage2_map_gich_gicv
174+
175+
ldr x6, =linux_stage2_l1
176+
movz x7, #1, lsl #48
177+
orr x6, x6, x7
178+
msr vttbr_el2, x6
179+
180+
mrs x7, id_aa64mmfr0_el1
181+
and x7, x7, #0xf
182+
lsl x7, x7, #16
183+
movz x6, #(VTCR_EL2_RES1 >> 16), lsl #16
184+
orr x6, x6, #32
185+
orr x6, x6, #VTCR_EL2_SL0_LVL1
186+
orr x6, x6, #VTCR_EL2_IRGN0_WBWA
187+
orr x6, x6, #VTCR_EL2_ORGN0_WBWA
188+
orr x6, x6, #VTCR_EL2_SH0_INNER
189+
orr x6, x6, x7
190+
msr vtcr_el2, x6
191+
192+
dsb sy
193+
tlbi vmalls12e1
194+
dsb sy
195+
isb
196+
ret
197+
23198
.global linux_cpu3_trampoline_end
24199
linux_cpu3_trampoline_end:
200+
201+
.section ".bss.noclean.linux_hyp", "aw"
202+
.align 12
203+
linux_stage2_l1:
204+
.space 4096
205+
linux_stage2_l2_low:
206+
.space 4096
207+
linux_stage2_l2_high:
208+
.space 4096
209+
linux_stage2_l3_gic:
210+
.space 4096
211+
linux_cpu3_hyp_stack:
212+
.space 4096
213+
linux_cpu3_hyp_stack_top:

bsp/qemu-virt64-aarch64/linux.dts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
cpu_on = <0xc4000003>;
1414
cpu_off = <0x84000002>;
1515
cpu_suspend = <0xc4000001>;
16-
method = "smc";
16+
method = "hvc";
1717
compatible = "arm,psci-1.0", "arm,psci-0.2", "arm,psci";
1818
};
1919

libcpu/aarch64/common/hyp_vector_gcc.S

Lines changed: 127 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,19 @@
88

99
#define ESR_EL2_EC_SHIFT 26
1010
#define ESR_EL2_EC_HVC64 0x16
11+
#define ESR_EL2_EC_DABT_LOW 0x24
12+
#define ESR_EL2_DABT_WNR (1 << 6)
1113

1214
#define HYPERCALL_VERSION_ID 0xc5000000
1315
#define HYPERCALL_DEBUG_ID 0xc5000001
1416
#define HYPERCALL_CPU_ON_ID 0xc5000003
1517
#define HYP_VERSION_0_1 0x00010000
1618
#define HYP_CUSTOM_TEST_VALUE 0x48564321
1719
#define PSCI_0_2_FN64_CPU_ON 0xc4000003
20+
#define PSCI_32_PREFIX 0x84
21+
#define PSCI_64_PREFIX 0xc4
22+
#define GICD_BASE 0x08000000
23+
#define GICD_END 0x08010000
1824

1925
.text
2026
.align 11
@@ -45,7 +51,10 @@ hyp_vectors:
4551

4652
/* Exception from lower EL, AArch64 */
4753
.org (HYP_VBAR + 0x400)
48-
b hyp_sync_lower_aarch64
54+
b hyp_sync_lower_aarch64 /* EL1/EL0 触发同步异常后,EL2 的统一分发入口 */
55+
/* ESR_EL2.EC == HVC64 主要是 Linux 发 PSCI 的 hvc,或者你自定义的 hypercall */
56+
/* ESR_EL2.EC == DABT_LOW EL1 对某个地址读/写时发生数据访问异常 */
57+
4958
.org (HYP_VBAR + 0x480)
5059
b hyp_panic
5160
.org (HYP_VBAR + 0x500)
@@ -63,11 +72,33 @@ hyp_vectors:
6372
.org (HYP_VBAR + 0x780)
6473
b hyp_panic
6574

75+
76+
77+
78+
79+
80+
81+
82+
6683
hyp_sync_lower_aarch64:
84+
sub sp, sp, #16
85+
stp x16, x17, [sp]
86+
6787
mrs x16, esr_el2
6888
lsr x17, x16, #ESR_EL2_EC_SHIFT
6989
cmp x17, #ESR_EL2_EC_HVC64
70-
b.ne hyp_panic
90+
b.eq hyp_hvc_lower_aarch64
91+
cmp x17, #ESR_EL2_EC_DABT_LOW
92+
b.eq hyp_dabt_lower_aarch64
93+
ldp x16, x17, [sp], #16
94+
b hyp_panic
95+
96+
97+
98+
99+
/* hypercall */
100+
hyp_hvc_lower_aarch64:
101+
add sp, sp, #16
71102

72103
movz w16, #(HYPERCALL_VERSION_ID >> 16), lsl #16
73104
cmp w0, w16
@@ -83,6 +114,16 @@ hyp_sync_lower_aarch64:
83114
cmp w0, w16
84115
b.eq hyp_hvc_cpu_on
85116

117+
/*
118+
* Linux is given PSCI method = "hvc". EL2 owns the HVC trap and
119+
* proxies standard PSCI calls down to QEMU/EL3 with SMC.
120+
*/
121+
lsr w16, w0, #24
122+
cmp w16, #PSCI_32_PREFIX
123+
b.eq hyp_hvc_psci_proxy
124+
cmp w16, #PSCI_64_PREFIX
125+
b.eq hyp_hvc_psci_proxy
126+
86127
b hyp_hvc_not_supported
87128

88129
hyp_hvc_version:
@@ -117,13 +158,97 @@ hyp_hvc_cpu_on:
117158
mov x3, xzr
118159
eret
119160

161+
.global hyp_hvc_psci_proxy
162+
hyp_hvc_psci_proxy:
163+
smc #0
164+
eret
165+
120166
hyp_hvc_not_supported:
121167
mov x0, #-1
122168
mov x1, xzr
123169
mov x2, xzr
124170
mov x3, xzr
125171
eret
126172

173+
174+
175+
176+
/* 数据访问的问题 */
177+
hyp_dabt_lower_aarch64:
178+
sub sp, sp, #64
179+
stp x16, x17, [sp, #0]
180+
stp x18, x19, [sp, #16]
181+
stp x20, x21, [sp, #32]
182+
stp x22, x23, [sp, #48]
183+
184+
/*
185+
* Stage-2 permission fault on the real GIC distributor. For now this
186+
* drops guest GICD writes instead of letting Linux modify global GICD
187+
* state directly. Reads should be handled by the read-only mapping.
188+
*/
189+
tbz x16, #6, hyp_dabt_restore_panic
190+
191+
mrs x18, hpfar_el2
192+
lsl x18, x18, #8
193+
mrs x19, far_el2
194+
and x19, x19, #0xfff
195+
orr x18, x18, x19
196+
197+
ldr x19, =GICD_BASE
198+
cmp x18, x19
199+
b.lo hyp_dabt_restore_panic
200+
ldr x19, =GICD_END
201+
cmp x18, x19
202+
b.hs hyp_dabt_restore_panic
203+
204+
ldr x19, =hyp_gicd_write_trap_count
205+
ldr x20, [x19]
206+
add x20, x20, #1
207+
str x20, [x19]
208+
209+
ldr x19, =hyp_last_gicd_write_ipa
210+
str x18, [x19]
211+
ldr x19, =hyp_last_gicd_write_esr
212+
str x16, [x19]
213+
214+
mrs x20, elr_el2
215+
add x20, x20, #4
216+
msr elr_el2, x20
217+
218+
ldp x16, x17, [sp, #0]
219+
ldp x18, x19, [sp, #16]
220+
ldp x20, x21, [sp, #32]
221+
ldp x22, x23, [sp, #48]
222+
add sp, sp, #64
223+
ldp x16, x17, [sp], #16
224+
eret
225+
226+
hyp_dabt_restore_panic:
227+
ldp x16, x17, [sp, #0]
228+
ldp x18, x19, [sp, #16]
229+
ldp x20, x21, [sp, #32]
230+
ldp x22, x23, [sp, #48]
231+
add sp, sp, #64
232+
ldp x16, x17, [sp], #16
233+
b hyp_panic
234+
235+
236+
237+
238+
239+
127240
hyp_panic:
128241
wfe
129242
b hyp_panic
243+
244+
.section ".bss.noclean.hyp", "aw"
245+
.align 3
246+
.global hyp_gicd_write_trap_count
247+
hyp_gicd_write_trap_count:
248+
.quad 0
249+
.global hyp_last_gicd_write_ipa
250+
hyp_last_gicd_write_ipa:
251+
.quad 0
252+
.global hyp_last_gicd_write_esr
253+
hyp_last_gicd_write_esr:
254+
.quad 0

0 commit comments

Comments
 (0)