software: put network code in a library
[litex.git] / software / bios / main.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <console.h>
4 #include <string.h>
5 #include <uart.h>
6 #include <system.h>
7 #include <board.h>
8 #include <irq.h>
9 #include <version.h>
10 #include <crc.h>
11 #include <timer.h>
12
13 #include <hw/mem.h>
14 #include <net/microudp.h>
15
16 #include "sdram.h"
17 #include "dataflow.h"
18 #include "boot.h"
19
20 enum {
21 CSR_IE = 1, CSR_IM, CSR_IP, CSR_ICC, CSR_DCC, CSR_CC, CSR_CFG, CSR_EBA,
22 CSR_DC, CSR_DEBA, CSR_JTX, CSR_JRX, CSR_BP0, CSR_BP1, CSR_BP2, CSR_BP3,
23 CSR_WP0, CSR_WP1, CSR_WP2, CSR_WP3,
24 };
25
26 /* General address space functions */
27
28 #define NUMBER_OF_BYTES_ON_A_LINE 16
29 static void dump_bytes(unsigned int *ptr, int count, unsigned addr)
30 {
31 char *data = (char *)ptr;
32 int line_bytes = 0, i = 0;
33
34 putsnonl("Memory dump:");
35 while(count > 0){
36 line_bytes =
37 (count > NUMBER_OF_BYTES_ON_A_LINE)?
38 NUMBER_OF_BYTES_ON_A_LINE : count;
39
40 printf("\n0x%08x ", addr);
41 for(i=0;i<line_bytes;i++)
42 printf("%02x ", *(unsigned char *)(data+i));
43
44 for(;i<NUMBER_OF_BYTES_ON_A_LINE;i++)
45 printf(" ");
46
47 printf(" ");
48
49 for(i=0;i<line_bytes;i++) {
50 if((*(data+i) < 0x20) || (*(data+i) > 0x7e))
51 printf(".");
52 else
53 printf("%c", *(data+i));
54 }
55
56 for(;i<NUMBER_OF_BYTES_ON_A_LINE;i++)
57 printf(" ");
58
59 data += (char)line_bytes;
60 count -= line_bytes;
61 addr += line_bytes;
62 }
63 printf("\n");
64 }
65
66 static void mr(char *startaddr, char *len)
67 {
68 char *c;
69 unsigned int *addr;
70 unsigned int length;
71
72 if(*startaddr == 0) {
73 printf("mr <address> [length]\n");
74 return;
75 }
76 addr = (unsigned *)strtoul(startaddr, &c, 0);
77 if(*c != 0) {
78 printf("incorrect address\n");
79 return;
80 }
81 if(*len == 0) {
82 length = 4;
83 } else {
84 length = strtoul(len, &c, 0);
85 if(*c != 0) {
86 printf("incorrect length\n");
87 return;
88 }
89 }
90
91 dump_bytes(addr, length, (unsigned)addr);
92 }
93
94 static void mw(char *addr, char *value, char *count)
95 {
96 char *c;
97 unsigned int *addr2;
98 unsigned int value2;
99 unsigned int count2;
100 unsigned int i;
101
102 if((*addr == 0) || (*value == 0)) {
103 printf("mw <address> <value> [count]\n");
104 return;
105 }
106 addr2 = (unsigned int *)strtoul(addr, &c, 0);
107 if(*c != 0) {
108 printf("incorrect address\n");
109 return;
110 }
111 value2 = strtoul(value, &c, 0);
112 if(*c != 0) {
113 printf("incorrect value\n");
114 return;
115 }
116 if(*count == 0) {
117 count2 = 1;
118 } else {
119 count2 = strtoul(count, &c, 0);
120 if(*c != 0) {
121 printf("incorrect count\n");
122 return;
123 }
124 }
125 for (i=0;i<count2;i++) *addr2++ = value2;
126 }
127
128 static void mc(char *dstaddr, char *srcaddr, char *count)
129 {
130 char *c;
131 unsigned int *dstaddr2;
132 unsigned int *srcaddr2;
133 unsigned int count2;
134 unsigned int i;
135
136 if((*dstaddr == 0) || (*srcaddr == 0)) {
137 printf("mc <dst> <src> [count]\n");
138 return;
139 }
140 dstaddr2 = (unsigned int *)strtoul(dstaddr, &c, 0);
141 if(*c != 0) {
142 printf("incorrect destination address\n");
143 return;
144 }
145 srcaddr2 = (unsigned int *)strtoul(srcaddr, &c, 0);
146 if(*c != 0) {
147 printf("incorrect source address\n");
148 return;
149 }
150 if(*count == 0) {
151 count2 = 1;
152 } else {
153 count2 = strtoul(count, &c, 0);
154 if(*c != 0) {
155 printf("incorrect count\n");
156 return;
157 }
158 }
159 for (i=0;i<count2;i++) *dstaddr2++ = *srcaddr2++;
160 }
161
162 static void crc(char *startaddr, char *len)
163 {
164 char *c;
165 char *addr;
166 unsigned int length;
167
168 if((*startaddr == 0)||(*len == 0)) {
169 printf("crc <address> <length>\n");
170 return;
171 }
172 addr = (char *)strtoul(startaddr, &c, 0);
173 if(*c != 0) {
174 printf("incorrect address\n");
175 return;
176 }
177 length = strtoul(len, &c, 0);
178 if(*c != 0) {
179 printf("incorrect length\n");
180 return;
181 }
182
183 printf("CRC32: %08x\n", crc32((unsigned char *)addr, length));
184 }
185
186 /* processor registers */
187 static int parse_csr(const char *csr)
188 {
189 if(!strcmp(csr, "ie")) return CSR_IE;
190 if(!strcmp(csr, "im")) return CSR_IM;
191 if(!strcmp(csr, "ip")) return CSR_IP;
192 if(!strcmp(csr, "icc")) return CSR_ICC;
193 if(!strcmp(csr, "dcc")) return CSR_DCC;
194 if(!strcmp(csr, "cc")) return CSR_CC;
195 if(!strcmp(csr, "cfg")) return CSR_CFG;
196 if(!strcmp(csr, "eba")) return CSR_EBA;
197 if(!strcmp(csr, "dc")) return CSR_DC;
198 if(!strcmp(csr, "deba")) return CSR_DEBA;
199 if(!strcmp(csr, "jtx")) return CSR_JTX;
200 if(!strcmp(csr, "jrx")) return CSR_JRX;
201 if(!strcmp(csr, "bp0")) return CSR_BP0;
202 if(!strcmp(csr, "bp1")) return CSR_BP1;
203 if(!strcmp(csr, "bp2")) return CSR_BP2;
204 if(!strcmp(csr, "bp3")) return CSR_BP3;
205 if(!strcmp(csr, "wp0")) return CSR_WP0;
206 if(!strcmp(csr, "wp1")) return CSR_WP1;
207 if(!strcmp(csr, "wp2")) return CSR_WP2;
208 if(!strcmp(csr, "wp3")) return CSR_WP3;
209
210 return 0;
211 }
212
213 static void rcsr(char *csr)
214 {
215 unsigned int csr2;
216 register unsigned int value;
217
218 if(*csr == 0) {
219 printf("rcsr <csr>\n");
220 return;
221 }
222
223 csr2 = parse_csr(csr);
224 if(csr2 == 0) {
225 printf("incorrect csr\n");
226 return;
227 }
228
229 switch(csr2) {
230 case CSR_IE: asm volatile ("rcsr %0,ie":"=r"(value)); break;
231 case CSR_IM: asm volatile ("rcsr %0,im":"=r"(value)); break;
232 case CSR_IP: asm volatile ("rcsr %0,ip":"=r"(value)); break;
233 case CSR_CC: asm volatile ("rcsr %0,cc":"=r"(value)); break;
234 case CSR_CFG: asm volatile ("rcsr %0,cfg":"=r"(value)); break;
235 case CSR_EBA: asm volatile ("rcsr %0,eba":"=r"(value)); break;
236 case CSR_DEBA: asm volatile ("rcsr %0,deba":"=r"(value)); break;
237 case CSR_JTX: asm volatile ("rcsr %0,jtx":"=r"(value)); break;
238 case CSR_JRX: asm volatile ("rcsr %0,jrx":"=r"(value)); break;
239 default: printf("csr write only\n"); return;
240 }
241
242 printf("%08x\n", value);
243 }
244
245 static void wcsr(char *csr, char *value)
246 {
247 char *c;
248 unsigned int csr2;
249 register unsigned int value2;
250
251 if((*csr == 0) || (*value == 0)) {
252 printf("wcsr <csr> <address>\n");
253 return;
254 }
255
256 csr2 = parse_csr(csr);
257 if(csr2 == 0) {
258 printf("incorrect csr\n");
259 return;
260 }
261 value2 = strtoul(value, &c, 0);
262 if(*c != 0) {
263 printf("incorrect value\n");
264 return;
265 }
266
267 switch(csr2) {
268 case CSR_IE: asm volatile ("wcsr ie,%0"::"r"(value2)); break;
269 case CSR_IM: asm volatile ("wcsr im,%0"::"r"(value2)); break;
270 case CSR_ICC: asm volatile ("wcsr icc,%0"::"r"(value2)); break;
271 case CSR_DCC: asm volatile ("wcsr dcc,%0"::"r"(value2)); break;
272 case CSR_EBA: asm volatile ("wcsr eba,%0"::"r"(value2)); break;
273 case CSR_DC: asm volatile ("wcsr dcc,%0"::"r"(value2)); break;
274 case CSR_DEBA: asm volatile ("wcsr deba,%0"::"r"(value2)); break;
275 case CSR_JTX: asm volatile ("wcsr jtx,%0"::"r"(value2)); break;
276 case CSR_JRX: asm volatile ("wcsr jrx,%0"::"r"(value2)); break;
277 case CSR_BP0: asm volatile ("wcsr bp0,%0"::"r"(value2)); break;
278 case CSR_BP1: asm volatile ("wcsr bp1,%0"::"r"(value2)); break;
279 case CSR_BP2: asm volatile ("wcsr bp2,%0"::"r"(value2)); break;
280 case CSR_BP3: asm volatile ("wcsr bp3,%0"::"r"(value2)); break;
281 case CSR_WP0: asm volatile ("wcsr wp0,%0"::"r"(value2)); break;
282 case CSR_WP1: asm volatile ("wcsr wp1,%0"::"r"(value2)); break;
283 case CSR_WP2: asm volatile ("wcsr wp2,%0"::"r"(value2)); break;
284 case CSR_WP3: asm volatile ("wcsr wp3,%0"::"r"(value2)); break;
285 default: printf("csr read only\n"); return;
286 }
287 }
288
289 static void dfs(char *baseaddr)
290 {
291 char *c;
292 unsigned int addr;
293
294 if(*baseaddr == 0) {
295 printf("dfs <address>\n");
296 return;
297 }
298 addr = strtoul(baseaddr, &c, 0);
299 if(*c != 0) {
300 printf("incorrect address\n");
301 return;
302 }
303 print_isd_info(addr);
304 }
305
306 /* Init + command line */
307
308 static void help(void)
309 {
310 puts("Milkymist(tm) BIOS");
311 puts("Don't know what to do? Try 'flashboot'.\n");
312 puts("Available commands:");
313 puts("mr - read address space");
314 puts("mw - write address space");
315 puts("mc - copy address space");
316 puts("crc - compute CRC32 of a part of the address space");
317 puts("rcsr - read processor CSR");
318 puts("wcsr - write processor CSR");
319 puts("netboot - boot via TFTP");
320 puts("serialboot - boot via SFL");
321 puts("flashboot - boot from flash");
322 puts("version - display version");
323 }
324
325 static char *get_token(char **str)
326 {
327 char *c, *d;
328
329 c = (char *)strchr(*str, ' ');
330 if(c == NULL) {
331 d = *str;
332 *str = *str+strlen(*str);
333 return d;
334 }
335 *c = 0;
336 d = *str;
337 *str = c+1;
338 return d;
339 }
340
341 static void do_command(char *c)
342 {
343 char *token;
344
345 token = get_token(&c);
346
347 if(strcmp(token, "mr") == 0) mr(get_token(&c), get_token(&c));
348 else if(strcmp(token, "mw") == 0) mw(get_token(&c), get_token(&c), get_token(&c));
349 else if(strcmp(token, "mc") == 0) mc(get_token(&c), get_token(&c), get_token(&c));
350 else if(strcmp(token, "crc") == 0) crc(get_token(&c), get_token(&c));
351
352 else if(strcmp(token, "flashboot") == 0) flashboot();
353 else if(strcmp(token, "serialboot") == 0) serialboot();
354 else if(strcmp(token, "netboot") == 0) netboot();
355
356 else if(strcmp(token, "version") == 0) puts(VERSION);
357
358 else if(strcmp(token, "help") == 0) help();
359
360 else if(strcmp(token, "rcsr") == 0) rcsr(get_token(&c));
361 else if(strcmp(token, "wcsr") == 0) wcsr(get_token(&c), get_token(&c));
362
363 else if(strcmp(token, "ddrrow") == 0) ddrrow(get_token(&c));
364 else if(strcmp(token, "ddrsw") == 0) ddrsw();
365 else if(strcmp(token, "ddrhw") == 0) ddrhw();
366 else if(strcmp(token, "ddrrd") == 0) ddrrd(get_token(&c));
367 else if(strcmp(token, "ddrwr") == 0) ddrwr(get_token(&c));
368 else if(strcmp(token, "memtest") == 0) memtest();
369 else if(strcmp(token, "ddrinit") == 0) ddrinit();
370 else if(strcmp(token, "asmiprobe") == 0) asmiprobe();
371
372 else if(strcmp(token, "dfs") == 0) dfs(get_token(&c));
373
374 else if(strcmp(token, "") != 0)
375 printf("Command not found\n");
376 }
377
378 int rescue;
379 extern unsigned int _edata;
380
381 static void crcbios(void)
382 {
383 unsigned int offset_bios;
384 unsigned int length;
385 unsigned int expected_crc;
386 unsigned int actual_crc;
387
388 /*
389 * _edata is located right after the end of the flat
390 * binary image. The CRC tool writes the 32-bit CRC here.
391 * We also use the address of _edata to know the length
392 * of our code.
393 */
394 offset_bios = rescue ? FLASH_OFFSET_RESCUE_BIOS : FLASH_OFFSET_REGULAR_BIOS;
395 expected_crc = _edata;
396 length = (unsigned int)&_edata - offset_bios;
397 actual_crc = crc32((unsigned char *)offset_bios, length);
398 if(expected_crc == actual_crc)
399 printf("BIOS CRC passed (%08x)\n", actual_crc);
400 else {
401 printf("BIOS CRC failed (expected %08x, got %08x)\n", expected_crc, actual_crc);
402 printf("The system will continue, but expect problems.\n");
403 }
404 }
405
406 static void print_mac(void)
407 {
408 unsigned char *macadr = (unsigned char *)FLASH_OFFSET_MAC_ADDRESS;
409
410 printf("MAC address: %02x:%02x:%02x:%02x:%02x:%02x\n", macadr[0], macadr[1], macadr[2], macadr[3], macadr[4], macadr[5]);
411 }
412
413 static const char banner[] =
414 "\nMILKYMIST(tm) v"VERSION" BIOS http://www.milkymist.org\n"
415 "(c) Copyright 2007-2013 Sebastien Bourdeauducq\n"
416 "Built "__DATE__" "__TIME__"\n\n"
417 "This program is free software: you can redistribute it and/or modify\n"
418 "it under the terms of the GNU General Public License as published by\n"
419 "the Free Software Foundation, version 3 of the License.";
420
421 static void readstr(char *s, int size)
422 {
423 char c[2];
424 int ptr;
425
426 c[1] = 0;
427 ptr = 0;
428 while(1) {
429 c[0] = readchar();
430 switch(c[0]) {
431 case 0x7f:
432 case 0x08:
433 if(ptr > 0) {
434 ptr--;
435 putsnonl("\x08 \x08");
436 }
437 break;
438 case 0x07:
439 break;
440 case '\r':
441 case '\n':
442 s[ptr] = 0x00;
443 putsnonl("\n");
444 return;
445 default:
446 putsnonl(c);
447 s[ptr] = c[0];
448 ptr++;
449 break;
450 }
451 }
452 }
453
454 static int test_user_abort(void)
455 {
456 char c;
457
458 printf("Automatic boot in 2 seconds...\n");
459 printf("Q/ESC: abort boot\n");
460 printf("F7: boot from serial\n");
461 printf("F8: boot from network\n");
462 timer_enable(0);
463 timer_set_reload(0);
464 timer_set_counter(get_system_frequency()*2);
465 timer_enable(1);
466 while(timer_get()) {
467 if(readchar_nonblock()) {
468 c = readchar();
469 if((c == 'Q')||(c == '\e')) {
470 puts("Aborted");
471 return 0;
472 }
473 if(c == 0x06) {
474 serialboot();
475 return 0;
476 }
477 if(c == 0x07) {
478 netboot();
479 return 0;
480 }
481 }
482 }
483 return 1;
484 }
485
486 static void boot_sequence(void)
487 {
488 if(test_user_abort()) {
489 if(rescue) {
490 serialboot();
491 netboot();
492 flashboot();
493 } else {
494 flashboot();
495 serialboot();
496 netboot();
497 }
498 printf("No boot medium found\n");
499 }
500 }
501
502 int main(int i, char **c)
503 {
504 char buffer[64];
505 int ddr_ok;
506
507 rescue = !((unsigned int)main > FLASH_OFFSET_REGULAR_BIOS);
508
509 irq_setmask(0);
510 irq_setie(1);
511 uart_init();
512 puts(banner);
513 crcbios();
514 if(rescue)
515 printf("Rescue mode\n");
516 board_init();
517 ethreset();
518 print_mac();
519 ddr_ok = ddrinit();
520 if(ddr_ok)
521 boot_sequence();
522 else
523 printf("Memory initialization failed\n");
524
525 while(1) {
526 putsnonl("\e[1mBIOS>\e[0m ");
527 readstr(buffer, 64);
528 do_command(buffer);
529 }
530 return 0;
531 }