summaryrefslogtreecommitdiffstats
path: root/c/src/lib/libbsp/powerpc/shared/bootloader/qemu_fakerom.S
blob: b77c3bd138bf0a698f82498078227b05e57bb64f (plain) (blame)
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
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
/* A fake 'bios' which does nothing but move a kernel image 
 * to RAM address zero and then starts that...
 */

#include <bsp/residual.h>

#define LD_CACHE_LINE_SIZE  5
#define INIT_STACK (0x100 - 16) /* 16-byte/svr4 aligned */

/* These offsets must correspond to declaration in qemu_fakeres.c */
#define DAT_LEN    0
#define RES_OFF    4
#define CMD_OFF    8
#define CMD_LEN   12
#define IMG_ADR   16

/* Non-volatile registers */
#define OBASE     30
#define PCID      25
#define PCIA      26

#define PCI_MAX_DEV 32

#define BA_OPCODE(tgt)  ((18<<(31-5)) | 2 | ((tgt) & 0x03fffffc))

	.global fake_data
	.global res_set_memsz

	.global _start
_start:
	lis    1,  INIT_STACK@h
	ori    1,1,INIT_STACK@l

		/* qemu 0.14.1 has the wrong exception prefix for 74xx CPUs
		 * (bug 811683). Work around this by putting a stub at 0x00000X00
		 * which simply jumps to high memory. We only need the SC exception
		 * for now.
		 */
	lis  3,    BA_OPCODE(0xfff00000)@h
	ori  3, 3, BA_OPCODE(0xfff00000)@l
	li   4, 0x0c00
	add  3, 3, 4
	stw  3, 0(4)
	dcbf 0, 4
	icbi 0, 4

	bl     pci_irq_set
		/* copy residual to RAM and fix up; 
		 * this routine returns a pointer to
		 * a 'fake_data' struct. If reading
		 * NVRAM failed then the return value
		 * points to a fall-back version in
		 * ROM...
		 */
	bl     res_copy
		/* fake_data pointer to R29 */
	mr     29, 3

		/* Load up R3..R5 with PreP mandated 
		 * values (R3: residual, R4: kernel image,
		 * R5: OpenFirmware PTR (or NULL).
		 */

		/* load R3 with residual pointer  */
	lwz    3, RES_OFF(29)
	add    3, 3, 29

		/* load R4 with image address     */
	lwz    4, IMG_ADR(29)

		/* load R5 with zero (OFW = NULL) */
	li     5, 0
		/* EXTENSION: R6 = cmdline start  */
	lwz    6, CMD_OFF(29)
	add    6, 6, 29
		/* EXTENSION: R7 = cmdline end    */
	lwz    7, CMD_LEN(29)
	add    7, 7, 6

		/* jump to image address          */
	mtctr  4
	bctr

	.org 0x100
	b    _start

	.org 0x110
template:
	mfsrr0 30
	mfsrr1 31
1:  b      1b
template_end:

	.org 0xc00
	b    monitor
	

	.org 0x4000
codemove: /* src/dst are cache-aligned */
	addi   5,5,(1<<LD_CACHE_LINE_SIZE)-1
	srwi   5,5,LD_CACHE_LINE_SIZE
	addi   3,3,-4
	addi   4,4,-4
1:
	li     0,  (1<<LD_CACHE_LINE_SIZE)
	mtctr  0
2:
	lwzu   0,  4(3)
	stwu   0,  4(4)
	bdnz   2b
	dcbf   0,4
	icbi   0,4
	addic. 5,5,-1
	bne  1b
	blr

cpexc:
	lis    3,template@h
	ori    3,3,template@l
	li     5,template_end-template
	b      codemove

monitor:
	stwu   1,-16(1)
	stw    OBASE, 8(1)
	lis    OBASE, 0x80000000@h
	cmplwi 10,0x63 /* enter_monitor -> RESET */
	bne    10f
hwreset:
	li   3,1
	stb  3,0x92(OBASE)
1:  b 1b
10: cmplwi 10,0x1d /* .NETCTRL -> ignore */
	bne    10f
	b      ret_from_mon
10: b hwreset      /* unknown -> RESET */ 

ret_from_mon:
	lwz    OBASE,8(1)
	lwz    1,0(1)
	rfi

rcb:
	stwbrx 3, 0, PCIA
	lbzx   3, 0, PCID
	blr

wcb:
	stwbrx 3, 0, PCIA
	stbx   4, 0, PCID
	blr

rcd:
	stwbrx 3, 0, PCIA
	lwbrx  3, 0, PCID
	blr

/* fixup pci interrupt line register according to what
 * qemu does: line = ((pin-1) +  slot_no) & 1 ? 11 : 9;
 */
pci_irq_set:
		/* set up stack frame */
	stwu    1, -32(1)
	mflr    0
	stw     0,  32+4(1)
		/* load counter with # of PCI devs */	
	li      0, PCI_MAX_DEV
	mtctr   0
		/* save non-volatile registers we use
		 * in stack frame
		 */
	stw    20,               8(1)
	stw  PCIA,              12(1)
	stw  PCID,              16(1)
		/* load non-volatile registers with
		 * intended values.
		 */
	lis  20,         0x80000000@h /* key for slot # 0             */
	lis  PCIA,       0x80000cf8@h /* PCI config space address reg */
	ori  PCIA, PCIA, 0x80000cf8@l 
	addi PCID, PCIA, 4            /* PCI config space data    reg */

		/* loop over all slots and fix up PCI IRQ LINE */
1:
	mr   3, 20
	bl   rcd
	addi 3, 3, 1
	cmplwi 3, 0      /* slot empty (= -1 + 1 = 0) ? */
	beq  2f
	addi 3, 20, 0x3d
	bl   rcb
	cmplwi 3, 0
	beq  2f
	slwi  4, 3, 11
	addi  3, 20, 0x3c
	xor   4, 4, 3    /* bit 11 = slot # + irq_num [zero-based] + 1 */
	andi. 4, 4, 0x0800
	li   4, 11
	beq  3f
	li   4,  9
3:
	bl   wcb
2:
	addi 20, 20, 0x0800 /* next slot */
    bdnz 1b

		/* restore and return */
	lwz 20,  32+4(1)
	mtlr 20
	lwz PCID, 16(1)
	lwz PCIA, 12(1)
	lwz 20,    8(1)
	lwz 1,     0(1)
	blr

	.section .romentry, "ax"
	b     _start