901b27445818f1f59a469d93edcb1827f966d639
[litex.git] / litex / soc / software / bios / boot.c
1 #include <stdio.h>
2 #include <console.h>
3 #include <uart.h>
4 #include <system.h>
5 #include <crc.h>
6 #include <string.h>
7 #include <irq.h>
8
9 #include <generated/mem.h>
10 #include <generated/csr.h>
11
12 #ifdef CSR_ETHMAC_BASE
13 #include <net/microudp.h>
14 #include <net/tftp.h>
15 #endif
16
17 #include "sfl.h"
18 #include "boot.h"
19
20 extern void boot_helper(unsigned long r1, unsigned long r2, unsigned long r3, unsigned long addr);
21
22 static void __attribute__((noreturn)) boot(unsigned long r1, unsigned long r2, unsigned long r3, unsigned long addr)
23 {
24 printf("Executing booted program at 0x%08x\n", addr);
25 uart_sync();
26 irq_setmask(0);
27 irq_setie(0);
28 /* FIXME: understand why flushing icache on Vexriscv make boot fail */
29 #ifndef __vexriscv__
30 flush_cpu_icache();
31 #endif
32 flush_cpu_dcache();
33 #ifdef L2_SIZE
34 flush_l2_cache();
35 #endif
36 boot_helper(r1, r2, r3, addr);
37 while(1);
38 }
39
40 enum {
41 ACK_TIMEOUT,
42 ACK_CANCELLED,
43 ACK_OK
44 };
45
46 static int check_ack(void)
47 {
48 int recognized;
49 static const char str[SFL_MAGIC_LEN] = SFL_MAGIC_ACK;
50
51 timer0_en_write(0);
52 timer0_reload_write(0);
53 timer0_load_write(SYSTEM_CLOCK_FREQUENCY/4);
54 timer0_en_write(1);
55 timer0_update_value_write(1);
56 recognized = 0;
57 while(timer0_value_read()) {
58 if(uart_read_nonblock()) {
59 char c;
60 c = uart_read();
61 if((c == 'Q') || (c == '\e'))
62 return ACK_CANCELLED;
63 if(c == str[recognized]) {
64 recognized++;
65 if(recognized == SFL_MAGIC_LEN)
66 return ACK_OK;
67 } else {
68 if(c == str[0])
69 recognized = 1;
70 else
71 recognized = 0;
72 }
73 }
74 timer0_update_value_write(1);
75 }
76 return ACK_TIMEOUT;
77 }
78
79 #define MAX_FAILED 5
80
81 /* Returns 1 if other boot methods should be tried */
82 int serialboot(void)
83 {
84 struct sfl_frame frame;
85 int failed;
86 unsigned long cmdline_adr, initrdstart_adr, initrdend_adr;
87 static const char str[SFL_MAGIC_LEN+1] = SFL_MAGIC_REQ;
88 const char *c;
89 int ack_status;
90
91 printf("Booting from serial...\n");
92 printf("Press Q or ESC to abort boot completely.\n");
93
94 c = str;
95 while(*c) {
96 uart_write(*c);
97 c++;
98 }
99 ack_status = check_ack();
100 if(ack_status == ACK_TIMEOUT) {
101 printf("Timeout\n");
102 return 1;
103 }
104 if(ack_status == ACK_CANCELLED) {
105 printf("Cancelled\n");
106 return 0;
107 }
108 /* assume ACK_OK */
109
110 failed = 0;
111 cmdline_adr = initrdstart_adr = initrdend_adr = 0;
112 while(1) {
113 int i;
114 int actualcrc;
115 int goodcrc;
116
117 /* Grab one frame */
118 frame.length = uart_read();
119 frame.crc[0] = uart_read();
120 frame.crc[1] = uart_read();
121 frame.cmd = uart_read();
122 for(i=0;i<frame.length;i++)
123 frame.payload[i] = uart_read();
124
125 /* Check CRC */
126 actualcrc = ((int)frame.crc[0] << 8)|(int)frame.crc[1];
127 goodcrc = crc16(&frame.cmd, frame.length+1);
128 if(actualcrc != goodcrc) {
129 failed++;
130 if(failed == MAX_FAILED) {
131 printf("Too many consecutive errors, aborting");
132 return 1;
133 }
134 uart_write(SFL_ACK_CRCERROR);
135 continue;
136 }
137
138 /* CRC OK */
139 switch(frame.cmd) {
140 case SFL_CMD_ABORT:
141 failed = 0;
142 uart_write(SFL_ACK_SUCCESS);
143 return 1;
144 case SFL_CMD_LOAD: {
145 char *writepointer;
146
147 failed = 0;
148 writepointer = (char *)(
149 ((unsigned long)frame.payload[0] << 24)
150 |((unsigned long)frame.payload[1] << 16)
151 |((unsigned long)frame.payload[2] << 8)
152 |((unsigned long)frame.payload[3] << 0));
153 for(i=4;i<frame.length;i++)
154 *(writepointer++) = frame.payload[i];
155 uart_write(SFL_ACK_SUCCESS);
156 break;
157 }
158 case SFL_CMD_JUMP: {
159 unsigned long addr;
160
161 failed = 0;
162 addr = ((unsigned long)frame.payload[0] << 24)
163 |((unsigned long)frame.payload[1] << 16)
164 |((unsigned long)frame.payload[2] << 8)
165 |((unsigned long)frame.payload[3] << 0);
166 uart_write(SFL_ACK_SUCCESS);
167 boot(cmdline_adr, initrdstart_adr, initrdend_adr, addr);
168 break;
169 }
170 case SFL_CMD_CMDLINE:
171 failed = 0;
172 cmdline_adr = ((unsigned long)frame.payload[0] << 24)
173 |((unsigned long)frame.payload[1] << 16)
174 |((unsigned long)frame.payload[2] << 8)
175 |((unsigned long)frame.payload[3] << 0);
176 uart_write(SFL_ACK_SUCCESS);
177 break;
178 case SFL_CMD_INITRDSTART:
179 failed = 0;
180 initrdstart_adr = ((unsigned long)frame.payload[0] << 24)
181 |((unsigned long)frame.payload[1] << 16)
182 |((unsigned long)frame.payload[2] << 8)
183 |((unsigned long)frame.payload[3] << 0);
184 uart_write(SFL_ACK_SUCCESS);
185 break;
186 case SFL_CMD_INITRDEND:
187 failed = 0;
188 initrdend_adr = ((unsigned long)frame.payload[0] << 24)
189 |((unsigned long)frame.payload[1] << 16)
190 |((unsigned long)frame.payload[2] << 8)
191 |((unsigned long)frame.payload[3] << 0);
192 uart_write(SFL_ACK_SUCCESS);
193 break;
194 default:
195 failed++;
196 if(failed == MAX_FAILED) {
197 printf("Too many consecutive errors, aborting");
198 return 1;
199 }
200 uart_write(SFL_ACK_UNKNOWN);
201 break;
202 }
203 }
204 return 1;
205 }
206
207 #ifdef CSR_ETHMAC_BASE
208
209 #ifndef LOCALIP1
210 #define LOCALIP1 192
211 #define LOCALIP2 168
212 #define LOCALIP3 1
213 #define LOCALIP4 50
214 #endif
215
216 #ifndef REMOTEIP1
217 #define REMOTEIP1 192
218 #define REMOTEIP2 168
219 #define REMOTEIP3 1
220 #define REMOTEIP4 100
221 #endif
222
223 #define DEFAULT_TFTP_SERVER_PORT 69 /* IANA well known port: UDP/69 */
224 #ifndef TFTP_SERVER_PORT
225 #define TFTP_SERVER_PORT DEFAULT_TFTP_SERVER_PORT
226 #endif
227
228 static int tftp_get_v(unsigned int ip, unsigned short server_port,
229 const char *filename, char *buffer)
230 {
231 int r;
232
233 r = tftp_get(ip, server_port, filename, buffer);
234 if(r > 0)
235 printf("Successfully downloaded %d bytes from %s over TFTP\n", r, filename);
236 else
237 printf("Unable to download %s over TFTP\n", filename);
238 return r;
239 }
240
241 static const unsigned char macadr[6] = {0x10, 0xe2, 0xd5, 0x00, 0x00, 0x00};
242
243 void netboot(void)
244 {
245 int size;
246 unsigned long cmdline_adr, initrdstart_adr, initrdend_adr;
247 unsigned int ip;
248 unsigned short tftp_port;
249
250 printf("Booting from network...\n");
251 printf("Local IP : %d.%d.%d.%d\n", LOCALIP1, LOCALIP2, LOCALIP3, LOCALIP4);
252 printf("Remote IP: %d.%d.%d.%d\n", REMOTEIP1, REMOTEIP2, REMOTEIP3, REMOTEIP4);
253
254 ip = IPTOINT(REMOTEIP1, REMOTEIP2, REMOTEIP3, REMOTEIP4);
255
256 microudp_start(macadr, IPTOINT(LOCALIP1, LOCALIP2, LOCALIP3, LOCALIP4));
257
258 tftp_port = TFTP_SERVER_PORT;
259 printf("Fetching from: UDP/%d\n", tftp_port);
260
261 size = tftp_get_v(ip, tftp_port, "boot.bin", (void *)MAIN_RAM_BASE);
262
263 if ((size <= 0) && (tftp_port != DEFAULT_TFTP_SERVER_PORT)) {
264 /* Try default TFTP port if timed out on non-standard port */
265 tftp_port = DEFAULT_TFTP_SERVER_PORT;
266 printf("Fetching from: UDP/%d\n", tftp_port);
267
268 size = tftp_get_v(ip, tftp_port, "boot.bin",
269 (void *)MAIN_RAM_BASE);
270 }
271
272 if (size <= 0) {
273 printf("Network boot failed\n");
274 return;
275 }
276
277 cmdline_adr = MAIN_RAM_BASE+0x1000000;
278 size = tftp_get_v(ip, tftp_port, "cmdline.txt", (void *)cmdline_adr);
279 if(size <= 0) {
280 printf("No command line parameters found\n");
281 cmdline_adr = 0;
282 } else
283 *((char *)(cmdline_adr+size)) = 0x00;
284
285 initrdstart_adr = MAIN_RAM_BASE+0x1002000;
286 size = tftp_get_v(ip, tftp_port, "initrd.bin", (void *)initrdstart_adr);
287 if(size <= 0) {
288 printf("No initial ramdisk found\n");
289 initrdstart_adr = 0;
290 initrdend_adr = 0;
291 } else
292 initrdend_adr = initrdstart_adr + size;
293
294 boot(cmdline_adr, initrdstart_adr, initrdend_adr, MAIN_RAM_BASE);
295 }
296
297 #endif
298
299 #ifdef FLASH_BOOT_ADDRESS
300
301 /* On systems with exernal SDRAM we copy out of the SPI flash into the SDRAM
302 before running, as it is faster. If we have no SDRAM then we have to
303 execute directly out of the SPI flash. */
304 #ifdef MAIN_RAM_BASE
305 #define FIRMWARE_BASE_ADDRESS MAIN_RAM_BASE
306 #else
307 /* Firmware code starts after (a) length and (b) CRC -- both unsigned ints */
308 #define FIRMWARE_BASE_ADDRESS (FLASH_BOOT_ADDRESS + 2 * sizeof(unsigned int))
309 #endif
310
311 void flashboot(void)
312 {
313 unsigned int *flashbase;
314 unsigned int length;
315 unsigned int crc;
316 unsigned int got_crc;
317
318 printf("Booting from flash...\n");
319 flashbase = (unsigned int *)FLASH_BOOT_ADDRESS;
320 length = *flashbase++;
321 crc = *flashbase++;
322 if((length < 32) || (length > 4*1024*1024)) {
323 printf("Error: Invalid flash boot image length 0x%08x\n", length);
324 return;
325 }
326
327 #ifdef MAIN_RAM_BASE
328 printf("Loading %d bytes from flash...\n", length);
329 memcpy((void *)MAIN_RAM_BASE, flashbase, length);
330 #endif
331
332 got_crc = crc32((unsigned char *)FIRMWARE_BASE_ADDRESS, length);
333 if(crc != got_crc) {
334 printf("CRC failed (expected %08x, got %08x)\n", crc, got_crc);
335 return;
336 }
337 boot(0, 0, 0, FIRMWARE_BASE_ADDRESS);
338 }
339 #endif
340
341 #ifdef ROM_BOOT_ADDRESS
342 /* When firmware is small enough, it can be interesting to run code from an
343 embedded blockram memory (faster and not impacted by memory controller
344 activity). Define ROM_BOOT_ADDRESS for that and initialize the blockram
345 with the firmware data. */
346 void romboot(void)
347 {
348 boot(0, 0, 0, ROM_BOOT_ADDRESS);
349 }
350 #endif