summaryrefslogtreecommitdiffstats
path: root/qemu/roms/SLOF/board-js2x/llfw/stage2.c
blob: d05a49493eac3c3a0d68aefc19cb13264f48e784 (plain)
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
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
/******************************************************************************
 * Copyright (c) 2004, 2008 IBM Corporation
 * All rights reserved.
 * This program and the accompanying materials
 * are made available under the terms of the BSD License
 * which accompanies this distribution, and is available at
 * http://www.opensource.org/licenses/bsd-license.php
 *
 * Contributors:
 *     IBM Corporation - initial implementation
 *****************************************************************************/

#include <stdint.h>
#include <xvect.h>
#include <hw.h>
#include <stdio.h>
#include <romfs.h>
#include "memmap.h"
#include "stage2.h"
#include <termctrl.h>
#include "product.h"
#include "calculatecrc.h"
#include <cpu.h>
#include <libelf.h>
#include <string.h>

uint64_t uart;
uint64_t gVecNum;
uint8_t u4Flag;

uint64_t exception_stack_frame;

typedef void (*pInterruptFunc_t) (void);

pInterruptFunc_t vectorTable[0x2E << 1];

extern void proceedInterrupt(void);

/* Prototypes for functions in this file: */
void c_interrupt(uint64_t vecNum);
void set_exceptionVector(int num, void *func);
int io_getchar(char *ch);
void early_c_entry(uint64_t start_addr);


static void
exception_forward(void)
{
	uint64_t val;

	if (*(uint64_t *) XVECT_M_HANDLER) {
		proceedInterrupt();
	}

	printf("\r\n exception %llx ", gVecNum);
	asm volatile ("mfsrr0	%0":"=r" (val):);
	printf("\r\nSRR0 = %08llx%08llx ", val >> 32, val);
	asm volatile ("mfsrr1	%0":"=r" (val):);
	printf(" SRR1 = %08llx%08llx ", val >> 32, val);

	asm volatile ("mfsprg	%0,2":"=r" (val):);
	printf("\r\nSPRG2 = %08llx%08llx ", val >> 32, val);
	asm volatile ("mfsprg	%0,3":"=r" (val):);
	printf(" SPRG3 = %08llx%08llx \r\n", val >> 32, val);
	while (1);
}

void
c_interrupt(uint64_t vecNum)
{
	gVecNum = vecNum;
	if (vectorTable[vecNum >> 7]) {
		vectorTable[vecNum >> 7] ();
	} else {
		exception_forward();
	}
}

void
set_exceptionVector(int num, void *func)
{
	vectorTable[num >> 7] = (pInterruptFunc_t) func;
}

static void
io_init(void)
{
	// read ID register: only if it is a PC87427, enable serial2
	store8_ci(0xf400002e, 0x20);
	if (load8_ci(0xf400002f) != 0xf2) {
		uart = 0xf40003f8;
		u4Flag = 0;
	} else {
		uart = 0xf40002f8;
		u4Flag = 1;
	}
}

int
io_getchar(char *ch)
{
	int retVal = 0;
	if ((load8_ci(uart + 5) & 0x01)) {
		*ch = load8_ci(uart);
		retVal = 1;
	}
	return retVal;
}


void copy_from_flash(uint64_t cnt, uint64_t src, uint64_t dest);

const uint32_t CrcTableHigh[16] = {
	0x00000000, 0x4C11DB70, 0x9823B6E0, 0xD4326D90,
	0x34867077, 0x7897AB07, 0xACA5C697, 0xE0B41DE7,
	0x690CE0EE, 0x251D3B9E, 0xF12F560E, 0xBD3E8D7E,
	0x5D8A9099, 0x119B4BE9, 0xC5A92679, 0x89B8FD09
};
const uint32_t CrcTableLow[16] = {
	0x00000000, 0x04C11DB7, 0x09823B6E, 0x0D4326D9,
	0x130476DC, 0x17C56B6B, 0x1A864DB2, 0x1E475005,
	0x2608EDB8, 0x22C9F00F, 0x2F8AD6D6, 0x2B4BCB61,
	0x350C9B64, 0x31CD86D3, 0x3C8EA00A, 0x384FBDBD
};

static unsigned long
check_flash_image(unsigned long rombase, unsigned long length,
		  unsigned long start_crc)
{

	uint32_t AccumCRC = start_crc;
	char val;
	uint32_t Temp;
	while (length-- > 0) {
		val = load8_ci(rombase++);
		Temp = ((AccumCRC >> 24) ^ val) & 0x000000ff;
		AccumCRC <<= 8;
		AccumCRC ^= CrcTableHigh[Temp / 16];
		AccumCRC ^= CrcTableLow[Temp % 16];
	}

	return AccumCRC;
}

static void
load_file(uint64_t destAddr, char *name, uint64_t maxSize, uint64_t romfs_base)
{
	uint64_t *src, *dest, cnt;
	struct romfs_lookup_t fileInfo;
	c_romfs_lookup(name, romfs_base, &fileInfo);
	if (maxSize) {
		cnt = maxSize / 8;
	} else {
		cnt = (fileInfo.size_data + 7) / 8;
	}
	dest = (uint64_t *) destAddr;
	src = (uint64_t *) fileInfo.addr_data;
	while (cnt--) {
		store64_ci((uint64_t) dest, *src);
		dest++;
		src++;
	}
	flush_cache((void *) destAddr, fileInfo.size_data);
}

/***************************************************************************
 * Function: early_c_entry
 * Input   : start_addr
 *
 * Description:
 **************************************************************************/
void
early_c_entry(uint64_t start_addr)
{
	struct romfs_lookup_t fileInfo;
	uint32_t crc;
	void (*ofw_start) (uint64_t, uint64_t, uint64_t, uint64_t, uint64_t);
	uint64_t *boot_info;
	exception_stack_frame = 0;
	/* destination for the flash image; we copy it to RAM
	 * because from flash it is much too slow
	 * the flash is copied at 224MB - 4MB (max flash size)
	 * at 224MB starts SLOF
	 * at 256MB is the SLOF load-base */
	uint64_t romfs_base = 0xe000000 - 0x400000;
	// romfs header values
	struct stH *header = (struct stH *) (start_addr + 0x28);
	//since we cannot read the fh_magic directly from flash as a string, we need to copy it to memory
	uint64_t magic_val = 0;
	uint64_t startVal = 0;
	uint64_t flashlen = 0;
	unsigned long ofw_addr;

	io_init();

	flashlen = load64_ci((uint64_t) (&header->flashlen));

	//copy fh_magic to magic_val since, we cannot use it as a string from flash
	magic_val = load64_ci((uint64_t) (header->magic));

	printf(" Check ROM  = ");
	if (strncmp((char *) &magic_val, FLASHFS_MAGIC, 8) == 0) {
		// somehow, the first 8 bytes in flashfs are overwritten, if booting from drone...
		// so if we find "IMG1" in the first 4 bytes, we skip the CRC check...
		startVal = load64_ci((uint64_t) start_addr);
		if (strncmp((char *) &startVal, "IMG1", 4) == 0) {
			printf
			    ("start from RAM detected, skipping CRC check!\r\n");
			// for romfs accesses (c_romfs_lookup) to work, we must fix the first uint64_t to the value we expect...
			store64_ci((uint64_t) start_addr, 0xd8);
		} else {
			//checking CRC in flash, we must use cache_inhibit
			// since the crc is included as the last 32 bits in the image, the resulting crc should be 0
			crc =
			    check_flash_image((uint64_t) start_addr,
					      load64_ci((uint64_t)
							(&header->flashlen)),
					      0);
			if (crc == 0) {
				printf("OK\r\n");
			} else {
				printf("failed!\r\n");
				while (1);
			}
		}
	} else {
		printf
		    ("failed (magic string is \"%.8s\" should be \"%.8s\")\r\n",
		     (char *) &magic_val, FLASHFS_MAGIC);
		while (1);
	}

	printf(" Press \"s\" to enter Open Firmware.\r\n\r\n");

	if ((start_addr > 0xF0000000) && u4Flag)
		u4memInit();

	/* here we have real ram avail -> hopefully
	 * copy flash to ram; size is in 64 byte blocks */
	flashlen /= 64;
	/* align it a bit */
	flashlen += 7;
	flashlen &= ~7;
	copy_from_flash(flashlen, start_addr, romfs_base);
	/* takeover sometimes fails if the image running on the system
	 * has a different size; flushing the cache helps, because it is
	 * the right thing to do anyway */
	flush_cache((void *) romfs_base, flashlen * 64);

	c_romfs_lookup("bootinfo", romfs_base, &fileInfo);
	boot_info = (uint64_t *) fileInfo.addr_data;
	boot_info[1] = start_addr;
	load_file(0x100, "xvect", 0, romfs_base);
	load_file(SLAVELOOP_LOADBASE, "stageS", 0, romfs_base);
	c_romfs_lookup("ofw_main", romfs_base, &fileInfo);

	elf_load_file((void *) fileInfo.addr_data, &ofw_addr,
		      NULL, flush_cache);
	ofw_start =
	    (void (*)(uint64_t, uint64_t, uint64_t, uint64_t, uint64_t))
	    &ofw_addr;
	// re-enable the cursor
	printf("%s%s", TERM_CTRL_RESET, TERM_CTRL_CRSON);
	/* ePAPR 0.5
	 * r3 = R3 Effective address of the device tree image. Note: this
	 *      address must be 8-byte aligned in memory.
	 * r4 = implementation dependent
	 * r5 = 0
	 * r6 = 0x65504150 -- ePAPR magic value-to distinguish from
	 *      non-ePAPR-compliant firmware
	 * r7 = implementation dependent
	 */
	asm volatile("isync; sync;" : : : "memory");
	ofw_start(0, romfs_base, 0, 0, 0);
	// never return
}