1 #define UNPAGED 1 /* for proper kmain() prototype */
3 #include "kernel/kernel.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>
15 #include "arch_proto.h"
16 #include "direct_utils.h"
17 #include "bsp_serial.h"
19 #include <machine/multiboot.h>
22 #define MULTIBOOT_VERBOSE 1
25 /* to-be-built kinfo struct, diagnostics buffer */
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;
44 /* kernel unpaged bss */
45 extern char _kern_unpaged_edata
;
46 extern char _kern_unpaged_end
;
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
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
63 int find_value(char * content
,char * key
,char *value
,int value_max_len
){
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
) {
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) {
83 /* now find the key in the contents */
85 for (iter
= content
,keyp
=key
; match_len
< key_len
&& *iter
!= '\0' ; iter
++) {
91 /* The current key does not match the value , reset */
96 if (match_len
== key_len
) {
97 printf("key found at %d %s\n", match_len
, &content
[match_len
]);
99 /* copy the content to the value char iter already points to the first
101 while(*iter
!= '\0' && *iter
!= ' ' && value_len
+ 1< value_max_len
) {
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*/
116 char *bufend
= bigbuf
+ MULTIBOOT_PARAM_BUF_SIZE
;
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 */
127 if (strncmp(p
, name
, namelen
) == 0 && p
[namelen
] == '=') {
129 /* let q point to the end of the entry */
131 /* now copy the remained of the buffer */
132 for (q
++; q
< bufend
; q
++, p
++)
137 /* find the end of the buffer */
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 */
149 /* Make sure there's enough space for the new parameter */
150 if (p
+ namelen
+ valuelen
+ 3 > bufend
) {
156 strcpy(p
+ namelen
+ 1, value
);
157 p
[namelen
+ valuelen
+ 1] = 0;
158 p
[namelen
+ valuelen
+ 2] = 0; /* end with a second delimiter */
162 int overlaps(multiboot_module_t
*mod
, int n
, int cmp_mod
)
164 multiboot_module_t
*cmp
= &mod
[cmp_mod
];
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
)) {
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
;
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
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
;
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
;
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
;
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
);
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
++ ;
263 if (*p
++ != '=') continue; /* skip if not name=value */
264 while (*p
&& *p
!= ' ' && value_i
< BUF
- 1) {
265 value
[value_i
++] = *p
++ ;
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
) {
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
);
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
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;
327 for(m
= 0; m
< cbi
->mods_with_kernel
; m
++) {
329 printf("checking overlap of module %08lx-%08lx\n",
330 cbi
->module_list
[m
].mod_start
, cbi
->module_list
[m
].mod_end
);
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.
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
)
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
)
377 /* This is the main "c" entry point into the kernel. It gets called
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
389 POORMANS_FAILURE_NOTIFICATION
;
393 set_machine_id(bootargs
);
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 */
407 kinfo
.freepde_start
= pg_mapkernel();
411 /* Done, return boot info so it can be passed to kmain(). */
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 */