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;
45 * The following function combines a few things together
46 * that can well be done using standard libc like strlen/strstr
47 * and such but these are not available in pre_init stage.
49 * The function expects content to be in the form of space separated
51 * param content the contents to search in
52 * param key the key to find (this *should* include the key/value delimiter)
53 * param value a pointer to an initialized char * of at least value_max_len length
54 * param value_max_len the maximum length of the value to store in value including
58 int find_value(char * content
,char * key
,char *value
,int value_max_len
){
61 int key_len
,content_len
,match_len
,value_len
;
63 /* return if the input is invalid */
64 if (key
== NULL
|| content
== NULL
|| value
== NULL
) {
68 /* find the key and content length */
69 key_len
= content_len
=0;
70 for(iter
= key
; *iter
!= '\0'; iter
++, key_len
++);
71 for(iter
= content
; *iter
!= '\0'; iter
++, content_len
++);
73 /* return if key or content length invalid */
74 if (key_len
== 0 || content_len
== 0) {
78 /* now find the key in the contents */
80 for (iter
= content
,keyp
=key
; match_len
< key_len
&& *iter
!= '\0' ; iter
++) {
86 /* The current key does not match the value , reset */
91 if (match_len
== key_len
) {
92 printf("key found at %d %s\n", match_len
, &content
[match_len
]);
94 /* copy the content to the value char iter already points to the first
96 while(*iter
!= '\0' && *iter
!= ' ' && value_len
+ 1< value_max_len
) {
103 return 1; /* not found */
106 static int mb_set_param(char *bigbuf
,char *name
,char *value
, kinfo_t
*cbi
)
108 /* bigbuf contains a list of key=value pairs separated by \0 char.
109 * The list itself is ended by a second \0 terminator*/
111 char *bufend
= bigbuf
+ MULTIBOOT_PARAM_BUF_SIZE
;
113 int namelen
= strlen(name
);
114 int valuelen
= strlen(value
);
116 /* Some variables we recognize */
117 if(!strcmp(name
, SERVARNAME
)) { cbi
->do_serial_debug
= 1; }
118 if(!strcmp(name
, SERBAUDVARNAME
)) { cbi
->serial_debug_baud
= atoi(value
); }
120 /* Delete the item if already exists */
122 if (strncmp(p
, name
, namelen
) == 0 && p
[namelen
] == '=') {
124 /* let q point to the end of the entry */
126 /* now copy the remained of the buffer */
127 for (q
++; q
< bufend
; q
++, p
++)
132 /* find the end of the buffer */
138 /* find the first empty spot */
139 for (p
= bigbuf
; p
< bufend
&& (*p
|| *(p
+ 1)); p
++);
141 /* unless we are the first entry step over the delimiter */
144 /* Make sure there's enough space for the new parameter */
145 if (p
+ namelen
+ valuelen
+ 3 > bufend
) {
151 strcpy(p
+ namelen
+ 1, value
);
152 p
[namelen
+ valuelen
+ 1] = 0;
153 p
[namelen
+ valuelen
+ 2] = 0; /* end with a second delimiter */
157 int overlaps(multiboot_module_t
*mod
, int n
, int cmp_mod
)
159 multiboot_module_t
*cmp
= &mod
[cmp_mod
];
162 #define INRANGE(mod, v) ((v) >= mod->mod_start && (v) <= thismod->mod_end)
163 #define OVERLAP(mod1, mod2) (INRANGE(mod1, mod2->mod_start) || \
164 INRANGE(mod1, mod2->mod_end))
165 for(m
= 0; m
< n
; m
++) {
166 multiboot_module_t
*thismod
= &mod
[m
];
167 if(m
== cmp_mod
) continue;
168 if(OVERLAP(thismod
, cmp
)) {
175 /* XXX: hard-coded stuff for modules */
176 #define MB_MODS_NR NR_BOOT_MODULES
177 #define MB_MODS_BASE 0x82000000
178 #define MB_MODS_ALIGN 0x00800000 /* 8 MB */
179 #define MB_MMAP_START 0x80000000
180 #define MB_MMAP_SIZE 0x10000000 /* 256 MB */
182 multiboot_module_t mb_modlist
[MB_MODS_NR
];
183 multiboot_memory_map_t mb_memmap
;
185 void setup_mbi(multiboot_info_t
*mbi
, char *bootargs
)
187 memset(mbi
, 0, sizeof(*mbi
));
188 mbi
->flags
= MULTIBOOT_INFO_MODS
| MULTIBOOT_INFO_MEM_MAP
|
189 MULTIBOOT_INFO_CMDLINE
;
190 mbi
->mi_mods_count
= MB_MODS_NR
;
191 mbi
->mods_addr
= (u32_t
)&mb_modlist
;
194 for (i
= 0; i
< MB_MODS_NR
; ++i
) {
195 mb_modlist
[i
].mod_start
= MB_MODS_BASE
+ i
* MB_MODS_ALIGN
;
196 mb_modlist
[i
].mod_end
= mb_modlist
[i
].mod_start
+ MB_MODS_ALIGN
198 mb_modlist
[i
].cmdline
= 0;
201 /* morph the bootargs into multiboot */
202 mbi
->cmdline
= (u32_t
) bootargs
;
204 mbi
->mmap_addr
=(u32_t
)&mb_memmap
;
205 mbi
->mmap_length
= sizeof(mb_memmap
);
207 mb_memmap
.size
= sizeof(multiboot_memory_map_t
);
208 mb_memmap
.mm_base_addr
= MB_MMAP_START
;
209 mb_memmap
.mm_length
= MB_MMAP_SIZE
;
210 mb_memmap
.type
= MULTIBOOT_MEMORY_AVAILABLE
;
213 void get_parameters(kinfo_t
*cbi
, char *bootargs
)
215 multiboot_memory_map_t
*mmap
;
216 multiboot_info_t
*mbi
= &cbi
->mbi
;
217 int var_i
,value_i
, m
, k
;
219 extern char _kern_phys_base
, _kern_vir_base
, _kern_size
,
220 _kern_unpaged_start
, _kern_unpaged_end
;
221 phys_bytes kernbase
= (phys_bytes
) &_kern_phys_base
,
222 kernsize
= (phys_bytes
) &_kern_size
;
224 static char cmdline
[BUF
];
226 /* get our own copy of the multiboot info struct and module list */
227 setup_mbi(mbi
, bootargs
);
229 /* Set various bits of info for the higher-level kernel. */
230 cbi
->mem_high_phys
= 0;
231 cbi
->user_sp
= (vir_bytes
) &_kern_vir_base
;
232 cbi
->vir_kern_start
= (vir_bytes
) &_kern_vir_base
;
233 cbi
->bootstrap_start
= (vir_bytes
) &_kern_unpaged_start
;
234 cbi
->bootstrap_len
= (vir_bytes
) &_kern_unpaged_end
-
235 cbi
->bootstrap_start
;
238 /* set some configurable defaults */
239 cbi
->do_serial_debug
= 1;
240 cbi
->serial_debug_baud
= 115200;
242 /* parse boot command line */
243 if (mbi
->flags
&MULTIBOOT_INFO_CMDLINE
) {
244 static char var
[BUF
];
245 static char value
[BUF
];
247 /* Override values with cmdline argument */
248 memcpy(cmdline
, (void *) mbi
->cmdline
, BUF
);
253 while (*p
== ' ') p
++; /* skip spaces */
254 if (!*p
) break; /* is this the end? */
255 while (*p
&& *p
!= '=' && *p
!= ' ' && var_i
< BUF
- 1)
256 var
[var_i
++] = *p
++ ;
258 if (*p
++ != '=') continue; /* skip if not name=value */
259 while (*p
&& *p
!= ' ' && value_i
< BUF
- 1) {
260 value
[value_i
++] = *p
++ ;
264 mb_set_param(cbi
->param_buf
, var
, value
, cbi
);
268 /* let higher levels know what we are booting on */
269 mb_set_param(cbi
->param_buf
, ARCHVARNAME
, (char *)get_board_arch_name(machine
.board_id
), cbi
);
270 mb_set_param(cbi
->param_buf
, BOARDVARNAME
,(char *)get_board_name(machine
.board_id
) , cbi
);
273 /* round user stack down to leave a gap to catch kernel
274 * stack overflow; and to distinguish kernel and user addresses
275 * at a glance (0xf.. vs 0xe..)
277 cbi
->user_sp
&= 0xF0000000;
278 cbi
->user_end
= cbi
->user_sp
;
280 /* kernel bytes without bootstrap code/data that is currently
281 * still needed but will be freed after bootstrapping.
283 kinfo
.kernel_allocated_bytes
= (phys_bytes
) &_kern_size
;
284 kinfo
.kernel_allocated_bytes
-= cbi
->bootstrap_len
;
286 assert(!(cbi
->bootstrap_start
% ARM_PAGE_SIZE
));
287 cbi
->bootstrap_len
= rounddown(cbi
->bootstrap_len
, ARM_PAGE_SIZE
);
288 assert(mbi
->flags
& MULTIBOOT_INFO_MODS
);
289 assert(mbi
->mi_mods_count
< MULTIBOOT_MAX_MODS
);
290 assert(mbi
->mi_mods_count
> 0);
291 memcpy(&cbi
->module_list
, (void *) mbi
->mods_addr
,
292 mbi
->mi_mods_count
* sizeof(multiboot_module_t
));
294 memset(cbi
->memmap
, 0, sizeof(cbi
->memmap
));
295 /* mem_map has a variable layout */
296 if(mbi
->flags
& MULTIBOOT_INFO_MEM_MAP
) {
298 for (mmap
= (multiboot_memory_map_t
*) mbi
->mmap_addr
;
299 (unsigned long) mmap
< mbi
->mmap_addr
+ mbi
->mmap_length
;
300 mmap
= (multiboot_memory_map_t
*)
301 ((unsigned long) mmap
+ mmap
->size
+ sizeof(mmap
->size
))) {
302 if(mmap
->type
!= MULTIBOOT_MEMORY_AVAILABLE
) continue;
303 add_memmap(cbi
, mmap
->mm_base_addr
, mmap
->mm_length
);
306 assert(mbi
->flags
& MULTIBOOT_INFO_MEMORY
);
307 add_memmap(cbi
, 0, mbi
->mem_lower_unused
*1024);
308 add_memmap(cbi
, 0x100000, mbi
->mem_upper_unused
*1024);
311 /* Sanity check: the kernel nor any of the modules may overlap
312 * with each other. Pretend the kernel is an extra module for a
315 k
= mbi
->mi_mods_count
;
316 assert(k
< MULTIBOOT_MAX_MODS
);
317 cbi
->module_list
[k
].mod_start
= kernbase
;
318 cbi
->module_list
[k
].mod_end
= kernbase
+ kernsize
;
319 cbi
->mods_with_kernel
= mbi
->mi_mods_count
+1;
322 for(m
= 0; m
< cbi
->mods_with_kernel
; m
++) {
324 printf("checking overlap of module %08lx-%08lx\n",
325 cbi
->module_list
[m
].mod_start
, cbi
->module_list
[m
].mod_end
);
327 if(overlaps(cbi
->module_list
, cbi
->mods_with_kernel
, m
))
328 panic("overlapping boot modules/kernel");
329 /* We cut out the bits of memory that we know are
330 * occupied by the kernel and boot modules.
333 cbi
->module_list
[m
].mod_start
,
334 cbi
->module_list
[m
].mod_end
);
339 * During low level init many things are not supposed to work
340 * serial being one of them. We therefore can't rely on the
341 * serial to debug. POORMANS_FAILURE_NOTIFICATION can be used
342 * before we setup our own vector table and will result in calling
343 * the bootloader's debugging methods that will hopefully show some
344 * information like the currnet PC at on the serial.
346 #define POORMANS_FAILURE_NOTIFICATION asm volatile("svc #00\n")
348 /* use the passed cmdline argument to determine the machine id */
349 void set_machine_id(char *cmdline
)
353 memset(boardname
,'\0',20);
354 if (find_value(cmdline
,"board_name=",boardname
,20)){
355 /* we expect the bootloader to pass a board_name as argument
356 * this however did not happen and given we still are in early
357 * boot we can't use the serial. We therefore generate an interrupt
358 * and hope the bootloader will do something nice with it */
359 POORMANS_FAILURE_NOTIFICATION
;
361 machine
.board_id
= get_board_id_by_short_name(boardname
);
363 if (machine
.board_id
==0){
364 /* same thing as above there is no safe escape */
365 POORMANS_FAILURE_NOTIFICATION
;
369 kinfo_t
*pre_init(int argc
, char **argv
)
372 /* This is the main "c" entry point into the kernel. It gets called
376 memset(&_edata
, 0, (u32_t
)&_end
- (u32_t
)&_edata
);
378 /* we get called in a c like fashion where the first arg
379 * is the program name (load address) and the rest are
380 * arguments. by convention the second argument is the
383 POORMANS_FAILURE_NOTIFICATION
;
387 set_machine_id(bootargs
);
389 /* Get our own copy boot params pointed to by ebx.
390 * Here we find out whether we should do serial output.
392 get_parameters(&kinfo
, bootargs
);
394 /* Make and load a pagetable that will map the kernel
395 * to where it should be; but first a 1:1 mapping so
396 * this code stays where it should be.
398 dcache_clean(); /* clean the caches */
401 kinfo
.freepde_start
= pg_mapkernel();
405 /* Done, return boot info so it can be passed to kmain(). */
409 /* pre_init gets executed at the memory location where the kernel was loaded by the boot loader.
410 * at that stage we only have a minimum set of functionality present (all symbols gets renamed to
411 * ensure this). The following methods are used in that context. Once we jump to kmain they are no
412 * longer used and the "real" implementations are visible
414 void send_diag_sig(void) { }
415 void minix_shutdown(minix_timer_t
*t
) { arch_shutdown(0); }
416 void busy_delay_ms(int x
) { }
417 int raise(int n
) { panic("raise(%d)\n", n
); }
418 int kern_phys_map_ptr( phys_bytes base_address
, vir_bytes io_size
, int vm_flags
,
419 struct kern_phys_map
* priv
, vir_bytes ptr
) {};
420 struct machine machine
; /* pre init stage machine */