Remove building with NOCRYPTO option
[minix.git] / minix / kernel / arch / earm / pre_init.c
blob445f6acd52afd2457253e6efac48b8cfd2921999
1 #define UNPAGED 1 /* for proper kmain() prototype */
3 #include "kernel/kernel.h"
4 #include <assert.h>
5 #include <stdlib.h>
6 #include <minix/minlib.h>
7 #include <minix/const.h>
8 #include <minix/type.h>
9 #include <minix/board.h>
10 #include <minix/com.h>
11 #include <sys/types.h>
12 #include <sys/param.h>
13 #include <sys/reboot.h>
14 #include "string.h"
15 #include "arch_proto.h"
16 #include "direct_utils.h"
17 #include "bsp_serial.h"
18 #include "glo.h"
19 #include <machine/multiboot.h>
21 #if USE_SYSDEBUG
22 #define MULTIBOOT_VERBOSE 1
23 #endif
25 /* to-be-built kinfo struct, diagnostics buffer */
26 kinfo_t kinfo;
27 struct kmessages kmessages;
29 /* pg_utils.c uses this; in this phase, there is a 1:1 mapping. */
30 phys_bytes vir2phys(void *addr) { return (phys_bytes) addr; }
32 static void setup_mbi(multiboot_info_t *mbi, char *bootargs);
34 /* String length used for mb_itoa */
35 #define ITOA_BUFFER_SIZE 20
37 /* Kernel may use memory */
38 int kernel_may_alloc = 1;
40 /* kernel bss */
41 extern u32_t _edata;
42 extern u32_t _end;
44 /* kernel unpaged bss */
45 extern char _kern_unpaged_edata;
46 extern char _kern_unpaged_end;
48 /**
50 * The following function combines a few things together
51 * that can well be done using standard libc like strlen/strstr
52 * and such but these are not available in pre_init stage.
54 * The function expects content to be in the form of space separated
55 * key value pairs.
56 * param content the contents to search in
57 * param key the key to find (this *should* include the key/value delimiter)
58 * param value a pointer to an initialized char * of at least value_max_len length
59 * param value_max_len the maximum length of the value to store in value including
60 * the end char
62 **/
63 int find_value(char * content,char * key,char *value,int value_max_len){
65 char *iter,*keyp;
66 int key_len,content_len,match_len,value_len;
68 /* return if the input is invalid */
69 if (key == NULL || content == NULL || value == NULL) {
70 return 1;
73 /* find the key and content length */
74 key_len = content_len =0;
75 for(iter = key ; *iter != '\0'; iter++, key_len++);
76 for(iter = content ; *iter != '\0'; iter++, content_len++);
78 /* return if key or content length invalid */
79 if (key_len == 0 || content_len == 0) {
80 return 1;
83 /* now find the key in the contents */
84 match_len =0;
85 for (iter = content ,keyp=key; match_len < key_len && *iter != '\0' ; iter++) {
86 if (*iter == *keyp) {
87 match_len++;
88 keyp++;
89 continue;
91 /* The current key does not match the value , reset */
92 match_len =0;
93 keyp=key;
96 if (match_len == key_len) {
97 printf("key found at %d %s\n", match_len, &content[match_len]);
98 value_len = 0;
99 /* copy the content to the value char iter already points to the first
100 char value */
101 while(*iter != '\0' && *iter != ' ' && value_len + 1< value_max_len) {
102 *value++ = *iter++;
103 value_len++;
105 *value='\0';
106 return 0;
108 return 1; /* not found */
111 static int mb_set_param(char *bigbuf,char *name,char *value, kinfo_t *cbi)
113 /* bigbuf contains a list of key=value pairs separated by \0 char.
114 * The list itself is ended by a second \0 terminator*/
115 char *p = bigbuf;
116 char *bufend = bigbuf + MULTIBOOT_PARAM_BUF_SIZE;
117 char *q;
118 int namelen = strlen(name);
119 int valuelen = strlen(value);
121 /* Some variables we recognize */
122 if(!strcmp(name, SERVARNAME)) { cbi->do_serial_debug = 1; }
123 if(!strcmp(name, SERBAUDVARNAME)) { cbi->serial_debug_baud = atoi(value); }
125 /* Delete the item if already exists */
126 while (*p) {
127 if (strncmp(p, name, namelen) == 0 && p[namelen] == '=') {
128 q = p;
129 /* let q point to the end of the entry */
130 while (*q) q++;
131 /* now copy the remained of the buffer */
132 for (q++; q < bufend; q++, p++)
133 *p = *q;
134 break;
137 /* find the end of the buffer */
138 while (*p++);
139 p++;
143 /* find the first empty spot */
144 for (p = bigbuf; p < bufend && (*p || *(p + 1)); p++);
146 /* unless we are the first entry step over the delimiter */
147 if (p > bigbuf) p++;
149 /* Make sure there's enough space for the new parameter */
150 if (p + namelen + valuelen + 3 > bufend) {
151 return -1;
154 strcpy(p, name);
155 p[namelen] = '=';
156 strcpy(p + namelen + 1, value);
157 p[namelen + valuelen + 1] = 0;
158 p[namelen + valuelen + 2] = 0; /* end with a second delimiter */
159 return 0;
162 int overlaps(multiboot_module_t *mod, int n, int cmp_mod)
164 multiboot_module_t *cmp = &mod[cmp_mod];
165 int m;
167 #define INRANGE(mod, v) ((v) >= mod->mod_start && (v) <= thismod->mod_end)
168 #define OVERLAP(mod1, mod2) (INRANGE(mod1, mod2->mod_start) || \
169 INRANGE(mod1, mod2->mod_end))
170 for(m = 0; m < n; m++) {
171 multiboot_module_t *thismod = &mod[m];
172 if(m == cmp_mod) continue;
173 if(OVERLAP(thismod, cmp)) {
174 return 1;
177 return 0;
180 /* XXX: hard-coded stuff for modules */
181 #define MB_MODS_NR NR_BOOT_MODULES
182 #define MB_MODS_BASE 0x82000000
183 #define MB_MODS_ALIGN 0x00800000 /* 8 MB */
184 #define MB_MMAP_START 0x80000000
185 #define MB_MMAP_SIZE 0x10000000 /* 256 MB */
187 multiboot_module_t mb_modlist[MB_MODS_NR];
188 multiboot_memory_map_t mb_memmap;
190 void setup_mbi(multiboot_info_t *mbi, char *bootargs)
192 memset(mbi, 0, sizeof(*mbi));
193 mbi->flags = MULTIBOOT_INFO_MODS | MULTIBOOT_INFO_MEM_MAP |
194 MULTIBOOT_INFO_CMDLINE;
195 mbi->mi_mods_count = MB_MODS_NR;
196 mbi->mods_addr = (u32_t)&mb_modlist;
198 int i;
199 for (i = 0; i < MB_MODS_NR; ++i) {
200 mb_modlist[i].mod_start = MB_MODS_BASE + i * MB_MODS_ALIGN;
201 mb_modlist[i].mod_end = mb_modlist[i].mod_start + MB_MODS_ALIGN
202 - ARM_PAGE_SIZE;
203 mb_modlist[i].cmdline = 0;
206 /* morph the bootargs into multiboot */
207 mbi->cmdline = (u32_t) bootargs;
209 mbi->mmap_addr =(u32_t)&mb_memmap;
210 mbi->mmap_length = sizeof(mb_memmap);
212 mb_memmap.size = sizeof(multiboot_memory_map_t);
213 mb_memmap.mm_base_addr = MB_MMAP_START;
214 mb_memmap.mm_length = MB_MMAP_SIZE;
215 mb_memmap.type = MULTIBOOT_MEMORY_AVAILABLE;
218 void get_parameters(kinfo_t *cbi, char *bootargs)
220 multiboot_memory_map_t *mmap;
221 multiboot_info_t *mbi = &cbi->mbi;
222 int var_i,value_i, m, k;
223 char *p;
224 extern char _kern_phys_base, _kern_vir_base, _kern_size,
225 _kern_unpaged_start, _kern_unpaged_end;
226 phys_bytes kernbase = (phys_bytes) &_kern_phys_base,
227 kernsize = (phys_bytes) &_kern_size;
228 #define BUF 1024
229 static char cmdline[BUF];
231 /* get our own copy of the multiboot info struct and module list */
232 setup_mbi(mbi, bootargs);
234 /* Set various bits of info for the higher-level kernel. */
235 cbi->mem_high_phys = 0;
236 cbi->user_sp = (vir_bytes) &_kern_vir_base;
237 cbi->vir_kern_start = (vir_bytes) &_kern_vir_base;
238 cbi->bootstrap_start = (vir_bytes) &_kern_unpaged_start;
239 cbi->bootstrap_len = (vir_bytes) &_kern_unpaged_end -
240 cbi->bootstrap_start;
241 cbi->kmess = &kmess;
243 /* set some configurable defaults */
244 cbi->do_serial_debug = 1;
245 cbi->serial_debug_baud = 115200;
247 /* parse boot command line */
248 if (mbi->flags&MULTIBOOT_INFO_CMDLINE) {
249 static char var[BUF];
250 static char value[BUF];
252 /* Override values with cmdline argument */
253 memcpy(cmdline, (void *) mbi->cmdline, BUF);
254 p = cmdline;
255 while (*p) {
256 var_i = 0;
257 value_i = 0;
258 while (*p == ' ') p++; /* skip spaces */
259 if (!*p) break; /* is this the end? */
260 while (*p && *p != '=' && *p != ' ' && var_i < BUF - 1)
261 var[var_i++] = *p++ ;
262 var[var_i] = 0;
263 if (*p++ != '=') continue; /* skip if not name=value */
264 while (*p && *p != ' ' && value_i < BUF - 1) {
265 value[value_i++] = *p++ ;
267 value[value_i] = 0;
269 mb_set_param(cbi->param_buf, var, value, cbi);
273 /* let higher levels know what we are booting on */
274 mb_set_param(cbi->param_buf, ARCHVARNAME, (char *)get_board_arch_name(machine.board_id), cbi);
275 mb_set_param(cbi->param_buf, BOARDVARNAME,(char *)get_board_name(machine.board_id) , cbi);
278 /* move user stack/data down to leave a gap to catch kernel
279 * stack overflow; and to distinguish kernel and user addresses
280 * at a glance (0xf.. vs 0xe..)
282 cbi->user_sp = USR_STACKTOP;
283 cbi->user_end = USR_DATATOP;
285 /* kernel bytes without bootstrap code/data that is currently
286 * still needed but will be freed after bootstrapping.
288 kinfo.kernel_allocated_bytes = (phys_bytes) &_kern_size;
289 kinfo.kernel_allocated_bytes -= cbi->bootstrap_len;
291 assert(!(cbi->bootstrap_start % ARM_PAGE_SIZE));
292 cbi->bootstrap_len = rounddown(cbi->bootstrap_len, ARM_PAGE_SIZE);
293 assert(mbi->flags & MULTIBOOT_INFO_MODS);
294 assert(mbi->mi_mods_count < MULTIBOOT_MAX_MODS);
295 assert(mbi->mi_mods_count > 0);
296 memcpy(&cbi->module_list, (void *) mbi->mods_addr,
297 mbi->mi_mods_count * sizeof(multiboot_module_t));
299 memset(cbi->memmap, 0, sizeof(cbi->memmap));
300 /* mem_map has a variable layout */
301 if(mbi->flags & MULTIBOOT_INFO_MEM_MAP) {
302 cbi->mmap_size = 0;
303 for (mmap = (multiboot_memory_map_t *) mbi->mmap_addr;
304 (unsigned long) mmap < mbi->mmap_addr + mbi->mmap_length;
305 mmap = (multiboot_memory_map_t *)
306 ((unsigned long) mmap + mmap->size + sizeof(mmap->size))) {
307 if(mmap->type != MULTIBOOT_MEMORY_AVAILABLE) continue;
308 add_memmap(cbi, mmap->mm_base_addr, mmap->mm_length);
310 } else {
311 assert(mbi->flags & MULTIBOOT_INFO_MEMORY);
312 add_memmap(cbi, 0, mbi->mem_lower_unused*1024);
313 add_memmap(cbi, 0x100000, mbi->mem_upper_unused*1024);
316 /* Sanity check: the kernel nor any of the modules may overlap
317 * with each other. Pretend the kernel is an extra module for a
318 * second.
320 k = mbi->mi_mods_count;
321 assert(k < MULTIBOOT_MAX_MODS);
322 cbi->module_list[k].mod_start = kernbase;
323 cbi->module_list[k].mod_end = kernbase + kernsize;
324 cbi->mods_with_kernel = mbi->mi_mods_count+1;
325 cbi->kern_mod = k;
327 for(m = 0; m < cbi->mods_with_kernel; m++) {
328 #if 0
329 printf("checking overlap of module %08lx-%08lx\n",
330 cbi->module_list[m].mod_start, cbi->module_list[m].mod_end);
331 #endif
332 if(overlaps(cbi->module_list, cbi->mods_with_kernel, m))
333 panic("overlapping boot modules/kernel");
334 /* We cut out the bits of memory that we know are
335 * occupied by the kernel and boot modules.
337 cut_memmap(cbi,
338 cbi->module_list[m].mod_start,
339 cbi->module_list[m].mod_end);
344 * During low level init many things are not supposed to work
345 * serial being one of them. We therefore can't rely on the
346 * serial to debug. POORMANS_FAILURE_NOTIFICATION can be used
347 * before we setup our own vector table and will result in calling
348 * the bootloader's debugging methods that will hopefully show some
349 * information like the currnet PC at on the serial.
351 #define POORMANS_FAILURE_NOTIFICATION asm volatile("svc #00\n")
353 /* use the passed cmdline argument to determine the machine id */
354 void set_machine_id(char *cmdline)
357 char boardname[20];
358 memset(boardname,'\0',20);
359 if (find_value(cmdline,"board_name=",boardname,20)){
360 /* we expect the bootloader to pass a board_name as argument
361 * this however did not happen and given we still are in early
362 * boot we can't use the serial. We therefore generate an interrupt
363 * and hope the bootloader will do something nice with it */
364 POORMANS_FAILURE_NOTIFICATION;
366 machine.board_id = get_board_id_by_short_name(boardname);
368 if (machine.board_id ==0){
369 /* same thing as above there is no safe escape */
370 POORMANS_FAILURE_NOTIFICATION;
374 kinfo_t *pre_init(int argc, char **argv)
376 char *bootargs;
377 /* This is the main "c" entry point into the kernel. It gets called
378 from head.S */
380 /* Clear BSS */
381 memset(&_edata, 0, (u32_t)&_end - (u32_t)&_edata);
382 memset(&_kern_unpaged_edata, 0, (u32_t)&_kern_unpaged_end - (u32_t)&_kern_unpaged_edata);
384 /* we get called in a c like fashion where the first arg
385 * is the program name (load address) and the rest are
386 * arguments. by convention the second argument is the
387 * command line */
388 if (argc != 2) {
389 POORMANS_FAILURE_NOTIFICATION;
392 bootargs = argv[1];
393 set_machine_id(bootargs);
394 bsp_ser_init();
395 /* Get our own copy boot params pointed to by ebx.
396 * Here we find out whether we should do serial output.
398 get_parameters(&kinfo, bootargs);
400 /* Make and load a pagetable that will map the kernel
401 * to where it should be; but first a 1:1 mapping so
402 * this code stays where it should be.
404 dcache_clean(); /* clean the caches */
405 pg_clear();
406 pg_identity(&kinfo);
407 kinfo.freepde_start = pg_mapkernel();
408 pg_load();
409 vm_enable_paging();
411 /* Done, return boot info so it can be passed to kmain(). */
412 return &kinfo;
415 /* pre_init gets executed at the memory location where the kernel was loaded by the boot loader.
416 * at that stage we only have a minimum set of functionality present (all symbols gets renamed to
417 * ensure this). The following methods are used in that context. Once we jump to kmain they are no
418 * longer used and the "real" implementations are visible
420 void send_diag_sig(void) { }
421 void minix_shutdown(int how) { arch_shutdown(how); }
422 void busy_delay_ms(int x) { }
423 int raise(int n) { panic("raise(%d)\n", n); }
424 int kern_phys_map_ptr( phys_bytes base_address, vir_bytes io_size, int vm_flags,
425 struct kern_phys_map * priv, vir_bytes ptr) { return -1; };
426 struct machine machine; /* pre init stage machine */