x86 multiboot.h
[minix3.git] / kernel / arch / i386 / pre_init.c
blob5f50d29e92452cc97ad3307b43325cd93dce311a
2 #define UNPAGED 1 /* for proper kmain() prototype */
4 #include "kernel/kernel.h"
5 #include <assert.h>
6 #include <stdlib.h>
7 #include <minix/minlib.h>
8 #include <minix/const.h>
9 #include <minix/type.h>
10 #include <minix/board.h>
11 #include <minix/com.h>
12 #include <sys/types.h>
13 #include <sys/param.h>
14 #include <sys/reboot.h>
15 #include <machine/partition.h>
16 #include "string.h"
17 #include "arch_proto.h"
18 #include "direct_utils.h"
19 #include "serial.h"
20 #include "glo.h"
21 #include <machine/multiboot.h>
23 #if USE_SYSDEBUG
24 #define MULTIBOOT_VERBOSE 1
25 #endif
27 /* to-be-built kinfo struct, diagnostics buffer */
28 kinfo_t kinfo;
29 struct kmessages kmessages;
31 /* pg_utils.c uses this; in this phase, there is a 1:1 mapping. */
32 phys_bytes vir2phys(void *addr) { return (phys_bytes) addr; }
34 /* mb_utils.c uses this; we can reach it directly */
35 char *video_mem = (char *) MULTIBOOT_VIDEO_BUFFER;
37 /* String length used for mb_itoa */
38 #define ITOA_BUFFER_SIZE 20
40 /* Kernel may use memory */
41 int kernel_may_alloc = 1;
43 static int mb_set_param(char *bigbuf, char *name, char *value, kinfo_t *cbi)
45 char *p = bigbuf;
46 char *bufend = bigbuf + MULTIBOOT_PARAM_BUF_SIZE;
47 char *q;
48 int namelen = strlen(name);
49 int valuelen = strlen(value);
51 /* Some variables we recognize */
52 if(!strcmp(name, SERVARNAME)) { cbi->do_serial_debug = 1; }
53 if(!strcmp(name, SERBAUDVARNAME)) { cbi->serial_debug_baud = atoi(value); }
55 /* Delete the item if already exists */
56 while (*p) {
57 if (strncmp(p, name, namelen) == 0 && p[namelen] == '=') {
58 q = p;
59 while (*q) q++;
60 for (q++; q < bufend; q++, p++)
61 *p = *q;
62 break;
64 while (*p++)
66 p++;
69 for (p = bigbuf; p < bufend && (*p || *(p + 1)); p++)
71 if (p > bigbuf) p++;
73 /* Make sure there's enough space for the new parameter */
74 if (p + namelen + valuelen + 3 > bufend)
75 return -1;
77 strcpy(p, name);
78 p[namelen] = '=';
79 strcpy(p + namelen + 1, value);
80 p[namelen + valuelen + 1] = 0;
81 p[namelen + valuelen + 2] = 0;
82 return 0;
85 int overlaps(multiboot_module_t *mod, int n, int cmp_mod)
87 multiboot_module_t *cmp = &mod[cmp_mod];
88 int m;
90 #define INRANGE(mod, v) ((v) >= mod->mod_start && (v) < mod->mod_end)
91 #define OVERLAP(mod1, mod2) (INRANGE(mod1, mod2->mod_start) || \
92 INRANGE(mod1, mod2->mod_end-1))
93 for(m = 0; m < n; m++) {
94 multiboot_module_t *thismod = &mod[m];
95 if(m == cmp_mod) continue;
96 if(OVERLAP(thismod, cmp))
97 return 1;
99 return 0;
102 void get_parameters(u32_t ebx, kinfo_t *cbi)
104 multiboot_memory_map_t *mmap;
105 multiboot_info_t *mbi = &cbi->mbi;
106 int var_i,value_i, m, k;
107 char *p;
108 extern char _kern_phys_base, _kern_vir_base, _kern_size,
109 _kern_unpaged_start, _kern_unpaged_end;
110 phys_bytes kernbase = (phys_bytes) &_kern_phys_base,
111 kernsize = (phys_bytes) &_kern_size;
112 #define BUF 1024
113 static char cmdline[BUF];
115 /* get our own copy of the multiboot info struct and module list */
116 memcpy((void *) mbi, (void *) ebx, sizeof(*mbi));
118 /* Set various bits of info for the higher-level kernel. */
119 cbi->mem_high_phys = 0;
120 cbi->user_sp = (vir_bytes) &_kern_vir_base;
121 cbi->vir_kern_start = (vir_bytes) &_kern_vir_base;
122 cbi->bootstrap_start = (vir_bytes) &_kern_unpaged_start;
123 cbi->bootstrap_len = (vir_bytes) &_kern_unpaged_end -
124 cbi->bootstrap_start;
125 cbi->kmess = &kmess;
127 /* set some configurable defaults */
128 cbi->do_serial_debug = 0;
129 cbi->serial_debug_baud = 115200;
131 /* parse boot command line */
132 if (mbi->mi_flags & MULTIBOOT_INFO_HAS_CMDLINE) {
133 static char var[BUF];
134 static char value[BUF];
136 /* Override values with cmdline argument */
137 memcpy(cmdline, (void *) mbi->mi_cmdline, BUF);
138 p = cmdline;
139 while (*p) {
140 var_i = 0;
141 value_i = 0;
142 while (*p == ' ') p++;
143 if (!*p) break;
144 while (*p && *p != '=' && *p != ' ' && var_i < BUF - 1)
145 var[var_i++] = *p++ ;
146 var[var_i] = 0;
147 if (*p++ != '=') continue; /* skip if not name=value */
148 while (*p && *p != ' ' && value_i < BUF - 1)
149 value[value_i++] = *p++ ;
150 value[value_i] = 0;
152 mb_set_param(cbi->param_buf, var, value, cbi);
156 /* let higher levels know what we are booting on */
157 mb_set_param(cbi->param_buf, ARCHVARNAME, (char *)get_board_arch_name(BOARD_ID_INTEL), cbi);
158 mb_set_param(cbi->param_buf, BOARDVARNAME,(char *)get_board_name(BOARD_ID_INTEL) , cbi);
160 /* round user stack down to leave a gap to catch kernel
161 * stack overflow; and to distinguish kernel and user addresses
162 * at a glance (0xf.. vs 0xe..)
164 cbi->user_sp &= 0xF0000000;
165 cbi->user_end = cbi->user_sp;
167 /* kernel bytes without bootstrap code/data that is currently
168 * still needed but will be freed after bootstrapping.
170 kinfo.kernel_allocated_bytes = (phys_bytes) &_kern_size;
171 kinfo.kernel_allocated_bytes -= cbi->bootstrap_len;
173 assert(!(cbi->bootstrap_start % I386_PAGE_SIZE));
174 cbi->bootstrap_len = rounddown(cbi->bootstrap_len, I386_PAGE_SIZE);
175 assert(mbi->mi_flags & MULTIBOOT_INFO_HAS_MODS);
176 assert(mbi->mi_mods_count < MULTIBOOT_MAX_MODS);
177 assert(mbi->mi_mods_count > 0);
178 memcpy(&cbi->module_list, (void *) mbi->mi_mods_addr,
179 mbi->mi_mods_count * sizeof(multiboot_module_t));
181 memset(cbi->memmap, 0, sizeof(cbi->memmap));
182 /* mem_map has a variable layout */
183 if(mbi->mi_flags & MULTIBOOT_INFO_HAS_MMAP) {
184 cbi->mmap_size = 0;
185 for (mmap = (multiboot_memory_map_t *) mbi->mmap_addr;
186 (unsigned long) mmap < mbi->mmap_addr + mbi->mmap_length;
187 mmap = (multiboot_memory_map_t *)
188 ((unsigned long) mmap + mmap->mm_size + sizeof(mmap->mm_size))) {
189 if(mmap->mm_type != MULTIBOOT_MEMORY_AVAILABLE) continue;
190 add_memmap(cbi, mmap->mm_base_addr, mmap->mm_length);
192 } else {
193 assert(mbi->mi_flags & MULTIBOOT_INFO_HAS_MEMORY);
194 add_memmap(cbi, 0, mbi->mi_mem_lower*1024);
195 add_memmap(cbi, 0x100000, mbi->mi_mem_upper*1024);
198 /* Sanity check: the kernel nor any of the modules may overlap
199 * with each other. Pretend the kernel is an extra module for a
200 * second.
202 k = mbi->mi_mods_count;
203 assert(k < MULTIBOOT_MAX_MODS);
204 cbi->module_list[k].mod_start = kernbase;
205 cbi->module_list[k].mod_end = kernbase + kernsize;
206 cbi->mods_with_kernel = mbi->mi_mods_count+1;
207 cbi->kern_mod = k;
209 for(m = 0; m < cbi->mods_with_kernel; m++) {
210 #if 0
211 printf("checking overlap of module %08lx-%08lx\n",
212 cbi->module_list[m].mod_start, cbi->module_list[m].mod_end);
213 #endif
214 if(overlaps(cbi->module_list, cbi->mods_with_kernel, m))
215 panic("overlapping boot modules/kernel");
216 /* We cut out the bits of memory that we know are
217 * occupied by the kernel and boot modules.
219 cut_memmap(cbi,
220 cbi->module_list[m].mod_start,
221 cbi->module_list[m].mod_end);
225 kinfo_t *pre_init(u32_t magic, u32_t ebx)
227 /* Get our own copy boot params pointed to by ebx.
228 * Here we find out whether we should do serial output.
230 get_parameters(ebx, &kinfo);
232 assert(magic == MULTIBOOT_INFO_MAGIC);
234 /* Make and load a pagetable that will map the kernel
235 * to where it should be; but first a 1:1 mapping so
236 * this code stays where it should be.
238 pg_clear();
239 pg_identity(&kinfo);
240 kinfo.freepde_start = pg_mapkernel();
241 pg_load();
242 vm_enable_paging();
244 /* Done, return boot info so it can be passed to kmain(). */
245 return &kinfo;
248 void send_diag_sig(void) { }
249 void minix_shutdown(minix_timer_t *t) { arch_shutdown(0); }
250 void busy_delay_ms(int x) { }
251 int raise(int sig) { panic("raise(%d)\n", sig); }