-
Notifications
You must be signed in to change notification settings - Fork 50
/
cheshire_bootrom.S
183 lines (164 loc) · 4.7 KB
/
cheshire_bootrom.S
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
// Copyright 2022 ETH Zurich and University of Bologna.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
//
// Nicole Narr <[email protected]>
// Christopher Reinwardt <[email protected]>
// Paul Scheffler <[email protected]>
// Enrico Zelioli <[email protected]>
#include <regs/cheshire.h>
#include <regs/axi_llc.h>
// The hart that non-SMP tests should run on
#ifndef NONSMP_HART
#define NONSMP_HART 0
#endif
.section .text._start
// Minimal bootrom loader
.global _start
_start:
// Reset all integer GPRs; we do *not* assume FP in the boot ROM.
li x1, 0
li x4, 0
li x5, 0
li x6, 0
li x7, 0
li x8, 0
li x9, 0
li x10, 0
li x11, 0
li x12, 0
li x13, 0
li x14, 0
li x15, 0
li x16, 0
li x17, 0
li x18, 0
li x19, 0
li x20, 0
li x21, 0
li x22, 0
li x23, 0
li x24, 0
li x25, 0
li x26, 0
li x27, 0
li x28, 0
li x29, 0
li x30, 0
li x31, 0
// Pause SMP harts
li t1, 0x8
csrw mie, t1
li t0, NONSMP_HART
csrr t1, mhartid
bne t0, t1, _wait_for_ipi
// Init stack and global pointer with safe, linked values
la sp, __stack_pointer$
.option push
.option norelax
la gp, __global_pointer$
.option pop
// If LLC present: Wait for end of BIST, then extend stack and set to all SPM
la t0, __base_regs
lw t0, CHESHIRE_HW_FEATURES_REG_OFFSET(t0)
andi t0, t0, 2 // HW_FEATURES.llc
beqz t0, _prom_check_run
la t0, __base_llc
_wait_llc_bist:
lw t1, AXI_LLC_BIST_STATUS_REG_OFFSET(t0) // Check BIST status done bit
beqz t1, _wait_llc_bist
li t1, -1
sw t1, AXI_LLC_CFG_SPM_LOW_REG_OFFSET(t0)
sw t1, AXI_LLC_CFG_SPM_HIGH_REG_OFFSET(t0)
li t1, 1
sw t1, AXI_LLC_COMMIT_CFG_REG_OFFSET(t0)
// Correct stack to start at end of SPM
la t0, __base_regs
la sp, __base_spm
lw t0, CHESHIRE_LLC_SIZE_REG_OFFSET(t0)
add sp, sp, t0
addi sp, sp, -8
// Enter Platform ROM if present.
_prom_check_run:
// Note that we have internal access to SPM here *if and only if* there is an LLC.
la t0, __base_regs
lw t0, CHESHIRE_PLATFORM_ROM_REG_OFFSET(t0)
beqz t0, _boot
jalr t0
// Move to next stage of booting
// 1. Write the address of next stage boot loader in Cheshire's scratch registers
// 2. Resume execution of all other harts
.global boot_next_stage
boot_next_stage:
// Non-SMP hart: write boot address into global scratch registers
la t0, __base_regs
sw a0, CHESHIRE_SCRATCH_4_REG_OFFSET(t0)
srli a0, a0, 32
sw a0, CHESHIRE_SCRATCH_5_REG_OFFSET(t0)
fence
// Resume SMP harts: set CLINT IPI registers
// NOTE: this will cause CLINT to send IPIs to all cores, therefore also the
// non-smp hart will receive one. The following instructions make sure that
// all harts will wait until the IPI is received (WFI with global ie disabled),
// then clear the IPI in the CLINT and wait until all other harts are done with it.
la t0, __base_clint
la t2, __base_regs
lw t2, CHESHIRE_NUM_INT_HARTS_REG_OFFSET(t2)
slli t2, t2, 2
add t2, t0, t2 // t2 = CLINT_BASE + (n_harts * 4)
1:
li t1, 1
sw t1, 0(t0)
addi t0, t0, 4
blt t0, t2, 1b
// Stall hart until IPI is raised
_wait_for_ipi:
// Wait until this hart receives IPI
wfi
csrr t1, mip
andi t1, t1, 0x8
beqz t1, _wait_for_ipi
// Clear CLINT IPI register for this hart
la t0, __base_clint
csrr t1, mhartid
slli t1, t1, 2
add t1, t1, t0
sw zero, 0(t1) // *(CLINT_BASE + hart_id * 4) = 0
la t2, __base_regs
lw t2, CHESHIRE_NUM_INT_HARTS_REG_OFFSET(t2)
slli t2, t2, 2
add t2, t0, t2 // t2 = CLINT_BASE + (n_harts * 4)
// Wait until *all* CLINT IPI registers are cleared
1:
lw t1, 0(t0)
bnez t1, 1b
addi t0, t0, 4
blt t0, t2, 1b
// Jump to next stage
// Load boot address from global scratch registers
la t0, __base_regs
lwu t1, CHESHIRE_SCRATCH_5_REG_OFFSET(t0)
slli t1, t1, 32
lwu t0, CHESHIRE_SCRATCH_4_REG_OFFSET(t0)
or t0, t0, t1
csrr a0, mhartid // Store hartid to a0
jalr ra, 0(t0) // Jump to boot address
ret // We should never get here
// Reset regs, full fence, then jump to main
_boot:
li t0, 0
li t1, 0
fence
fence.i
call main
// If main returns, we end up here
.global _exit
_exit:
// Save the return value to scratch register 2 and wait forever
// Set bit 0 to signal that the execution is done.
slli a0, a0, 1
ori a0, a0, 1
la t0, __base_regs
sw a0, CHESHIRE_SCRATCH_2_REG_OFFSET(t0)
1: wfi
j 1b