litex: reorganize things, first work working version
[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 #include <net/microudp.h>
13 #include <net/tftp.h>
14 #include "sfl.h"
15 #include "boot.h"
16
17 extern void boot_helper(unsigned int r1, unsigned int r2, unsigned int r3, unsigned int addr);
18
19 static void __attribute__((noreturn)) boot(unsigned int r1, unsigned int r2, unsigned int r3, unsigned int addr)
20 {
21 printf("Executing booted program.\n");
22 uart_sync();
23 irq_setmask(0);
24 irq_setie(0);
25 flush_cpu_icache();
26 boot_helper(r1, r2, r3, addr);
27 while(1);
28 }
29
30 static int check_ack(void)
31 {
32 int recognized;
33 static const char str[SFL_MAGIC_LEN] = SFL_MAGIC_ACK;
34
35 timer0_en_write(0);
36 timer0_reload_write(0);
37 timer0_load_write(identifier_frequency_read()/4);
38 timer0_en_write(1);
39 timer0_update_value_write(1);
40 recognized = 0;
41 while(timer0_value_read()) {
42 if(uart_read_nonblock()) {
43 char c;
44 c = uart_read();
45 if(c == str[recognized]) {
46 recognized++;
47 if(recognized == SFL_MAGIC_LEN)
48 return 1;
49 } else {
50 if(c == str[0])
51 recognized = 1;
52 else
53 recognized = 0;
54 }
55 }
56 timer0_update_value_write(1);
57 }
58 return 0;
59 }
60
61 #define MAX_FAILED 5
62
63 void serialboot(void)
64 {
65 struct sfl_frame frame;
66 int failed;
67 unsigned int cmdline_adr, initrdstart_adr, initrdend_adr;
68 static const char str[SFL_MAGIC_LEN+1] = SFL_MAGIC_REQ;
69 const char *c;
70
71 printf("Booting from serial...\n");
72
73 c = str;
74 while(*c) {
75 uart_write(*c);
76 c++;
77 }
78 if(!check_ack()) {
79 printf("Timeout\n");
80 return;
81 }
82
83 failed = 0;
84 cmdline_adr = initrdstart_adr = initrdend_adr = 0;
85 while(1) {
86 int i;
87 int actualcrc;
88 int goodcrc;
89
90 /* Grab one frame */
91 frame.length = uart_read();
92 frame.crc[0] = uart_read();
93 frame.crc[1] = uart_read();
94 frame.cmd = uart_read();
95 for(i=0;i<frame.length;i++)
96 frame.payload[i] = uart_read();
97
98 /* Check CRC */
99 actualcrc = ((int)frame.crc[0] << 8)|(int)frame.crc[1];
100 goodcrc = crc16(&frame.cmd, frame.length+1);
101 if(actualcrc != goodcrc) {
102 failed++;
103 if(failed == MAX_FAILED) {
104 printf("Too many consecutive errors, aborting");
105 return;
106 }
107 uart_write(SFL_ACK_CRCERROR);
108 continue;
109 }
110
111 /* CRC OK */
112 switch(frame.cmd) {
113 case SFL_CMD_ABORT:
114 failed = 0;
115 uart_write(SFL_ACK_SUCCESS);
116 return;
117 case SFL_CMD_LOAD: {
118 char *writepointer;
119
120 failed = 0;
121 writepointer = (char *)(
122 ((unsigned int)frame.payload[0] << 24)
123 |((unsigned int)frame.payload[1] << 16)
124 |((unsigned int)frame.payload[2] << 8)
125 |((unsigned int)frame.payload[3] << 0));
126 for(i=4;i<frame.length;i++)
127 *(writepointer++) = frame.payload[i];
128 uart_write(SFL_ACK_SUCCESS);
129 break;
130 }
131 case SFL_CMD_JUMP: {
132 unsigned int addr;
133
134 failed = 0;
135 addr = ((unsigned int)frame.payload[0] << 24)
136 |((unsigned int)frame.payload[1] << 16)
137 |((unsigned int)frame.payload[2] << 8)
138 |((unsigned int)frame.payload[3] << 0);
139 uart_write(SFL_ACK_SUCCESS);
140 boot(cmdline_adr, initrdstart_adr, initrdend_adr, addr);
141 break;
142 }
143 case SFL_CMD_CMDLINE:
144 failed = 0;
145 cmdline_adr = ((unsigned int)frame.payload[0] << 24)
146 |((unsigned int)frame.payload[1] << 16)
147 |((unsigned int)frame.payload[2] << 8)
148 |((unsigned int)frame.payload[3] << 0);
149 uart_write(SFL_ACK_SUCCESS);
150 break;
151 case SFL_CMD_INITRDSTART:
152 failed = 0;
153 initrdstart_adr = ((unsigned int)frame.payload[0] << 24)
154 |((unsigned int)frame.payload[1] << 16)
155 |((unsigned int)frame.payload[2] << 8)
156 |((unsigned int)frame.payload[3] << 0);
157 uart_write(SFL_ACK_SUCCESS);
158 break;
159 case SFL_CMD_INITRDEND:
160 failed = 0;
161 initrdend_adr = ((unsigned int)frame.payload[0] << 24)
162 |((unsigned int)frame.payload[1] << 16)
163 |((unsigned int)frame.payload[2] << 8)
164 |((unsigned int)frame.payload[3] << 0);
165 uart_write(SFL_ACK_SUCCESS);
166 break;
167 default:
168 failed++;
169 if(failed == MAX_FAILED) {
170 printf("Too many consecutive errors, aborting");
171 return;
172 }
173 uart_write(SFL_ACK_UNKNOWN);
174 break;
175 }
176 }
177 }
178
179 #ifdef CSR_ETHMAC_BASE
180
181 #define LOCALIP1 192
182 #define LOCALIP2 168
183 #define LOCALIP3 0
184 #define LOCALIP4 42
185 #define REMOTEIP1 192
186 #define REMOTEIP2 168
187 #define REMOTEIP3 0
188 #define REMOTEIP4 14
189
190 static int tftp_get_v(unsigned int ip, const char *filename, char *buffer)
191 {
192 int r;
193
194 r = tftp_get(ip, filename, buffer);
195 if(r > 0)
196 printf("Successfully downloaded %d bytes from %s over TFTP\n", r, filename);
197 else
198 printf("Unable to download %s over TFTP\n", filename);
199 return r;
200 }
201
202 static const unsigned char macadr[6] = {0x10, 0xe2, 0xd5, 0x00, 0x00, 0x00};
203
204 void netboot(void)
205 {
206 int size;
207 unsigned int cmdline_adr, initrdstart_adr, initrdend_adr;
208 unsigned int ip;
209
210 printf("Booting from network...\n");
211 printf("Local IP : %d.%d.%d.%d\n", LOCALIP1, LOCALIP2, LOCALIP3, LOCALIP4);
212 printf("Remote IP: %d.%d.%d.%d\n", REMOTEIP1, REMOTEIP2, REMOTEIP3, REMOTEIP4);
213
214 ip = IPTOINT(REMOTEIP1, REMOTEIP2, REMOTEIP3, REMOTEIP4);
215
216 microudp_start(macadr, IPTOINT(LOCALIP1, LOCALIP2, LOCALIP3, LOCALIP4));
217
218 if(tftp_get_v(ip, "boot.bin", (void *)MAIN_RAM_BASE) <= 0) {
219 printf("Network boot failed\n");
220 return;
221 }
222
223 cmdline_adr = MAIN_RAM_BASE+0x1000000;
224 size = tftp_get_v(ip, "cmdline.txt", (void *)cmdline_adr);
225 if(size <= 0) {
226 printf("No command line parameters found\n");
227 cmdline_adr = 0;
228 } else
229 *((char *)(cmdline_adr+size)) = 0x00;
230
231 initrdstart_adr = MAIN_RAM_BASE+0x1002000;
232 size = tftp_get_v(ip, "initrd.bin", (void *)initrdstart_adr);
233 if(size <= 0) {
234 printf("No initial ramdisk found\n");
235 initrdstart_adr = 0;
236 initrdend_adr = 0;
237 } else
238 initrdend_adr = initrdstart_adr + size;
239
240 boot(cmdline_adr, initrdstart_adr, initrdend_adr, MAIN_RAM_BASE);
241 }
242
243 #endif
244
245 #ifdef FLASH_BOOT_ADDRESS
246 void flashboot(void)
247 {
248 unsigned int *flashbase;
249 unsigned int length;
250 unsigned int crc;
251 unsigned int got_crc;
252
253 printf("Booting from flash...\n");
254 flashbase = (unsigned int *)FLASH_BOOT_ADDRESS;
255 length = *flashbase++;
256 crc = *flashbase++;
257 if((length < 32) || (length > 4*1024*1024)) {
258 printf("Error: Invalid flash boot image length 0x%08x\n", length);
259 return;
260 }
261
262 printf("Loading %d bytes from flash...\n", length);
263 memcpy((void *)MAIN_RAM_BASE, flashbase, length);
264 got_crc = crc32((unsigned char *)MAIN_RAM_BASE, length);
265 if(crc != got_crc) {
266 printf("CRC failed (expected %08x, got %08x)\n", crc, got_crc);
267 return;
268 }
269 boot(0, 0, 0, MAIN_RAM_BASE);
270 }
271 #endif
272
273 #ifdef ROM_BOOT_ADDRESS
274 /* When firmware is small enough, it can be interesting to run code from an
275 embedded blockram memory (faster and not impacted by memory controller
276 activity). Define ROM_BOOT_ADDRESS for that and initialize the blockram
277 with the firmware data. */
278 void romboot(void)
279 {
280 boot(0, 0, 0, ROM_BOOT_ADDRESS);
281 }
282 #endif