1433d6423SLionel Sambuc
2433d6423SLionel Sambuc #define UNPAGED 1 /* for proper kmain() prototype */
3433d6423SLionel Sambuc
4433d6423SLionel Sambuc #include <assert.h>
5433d6423SLionel Sambuc #include <stdlib.h>
6433d6423SLionel Sambuc #include <minix/minlib.h>
7433d6423SLionel Sambuc #include <minix/board.h>
8433d6423SLionel Sambuc #include <sys/reboot.h>
9433d6423SLionel Sambuc #include <machine/partition.h>
10433d6423SLionel Sambuc #include "string.h"
11433d6423SLionel Sambuc #include "direct_utils.h"
12433d6423SLionel Sambuc #include "serial.h"
13433d6423SLionel Sambuc #include "glo.h"
14433d6423SLionel Sambuc
15433d6423SLionel Sambuc #if USE_SYSDEBUG
16433d6423SLionel Sambuc #define MULTIBOOT_VERBOSE 1
17433d6423SLionel Sambuc #endif
18433d6423SLionel Sambuc
19433d6423SLionel Sambuc /* to-be-built kinfo struct, diagnostics buffer */
20433d6423SLionel Sambuc kinfo_t kinfo;
21433d6423SLionel Sambuc struct kmessages kmessages;
22433d6423SLionel Sambuc
23433d6423SLionel Sambuc /* pg_utils.c uses this; in this phase, there is a 1:1 mapping. */
vir2phys(void * addr)24433d6423SLionel Sambuc phys_bytes vir2phys(void *addr) { return (phys_bytes) addr; }
25433d6423SLionel Sambuc
26433d6423SLionel Sambuc /* mb_utils.c uses this; we can reach it directly */
27433d6423SLionel Sambuc char *video_mem = (char *) MULTIBOOT_VIDEO_BUFFER;
28433d6423SLionel Sambuc
29433d6423SLionel Sambuc /* String length used for mb_itoa */
30433d6423SLionel Sambuc #define ITOA_BUFFER_SIZE 20
31433d6423SLionel Sambuc
32433d6423SLionel Sambuc /* Kernel may use memory */
33433d6423SLionel Sambuc int kernel_may_alloc = 1;
34433d6423SLionel Sambuc
mb_set_param(char * bigbuf,char * name,char * value,kinfo_t * cbi)35433d6423SLionel Sambuc static int mb_set_param(char *bigbuf, char *name, char *value, kinfo_t *cbi)
36433d6423SLionel Sambuc {
37433d6423SLionel Sambuc char *p = bigbuf;
38433d6423SLionel Sambuc char *bufend = bigbuf + MULTIBOOT_PARAM_BUF_SIZE;
39433d6423SLionel Sambuc char *q;
40433d6423SLionel Sambuc int namelen = strlen(name);
41433d6423SLionel Sambuc int valuelen = strlen(value);
42433d6423SLionel Sambuc
43433d6423SLionel Sambuc /* Some variables we recognize */
44433d6423SLionel Sambuc if(!strcmp(name, SERVARNAME)) { cbi->do_serial_debug = 1; }
45433d6423SLionel Sambuc if(!strcmp(name, SERBAUDVARNAME)) { cbi->serial_debug_baud = atoi(value); }
46433d6423SLionel Sambuc
47433d6423SLionel Sambuc /* Delete the item if already exists */
48433d6423SLionel Sambuc while (*p) {
49433d6423SLionel Sambuc if (strncmp(p, name, namelen) == 0 && p[namelen] == '=') {
50433d6423SLionel Sambuc q = p;
51433d6423SLionel Sambuc while (*q) q++;
52433d6423SLionel Sambuc for (q++; q < bufend; q++, p++)
53433d6423SLionel Sambuc *p = *q;
54433d6423SLionel Sambuc break;
55433d6423SLionel Sambuc }
56433d6423SLionel Sambuc while (*p++)
57433d6423SLionel Sambuc ;
58433d6423SLionel Sambuc p++;
59433d6423SLionel Sambuc }
60433d6423SLionel Sambuc
61433d6423SLionel Sambuc for (p = bigbuf; p < bufend && (*p || *(p + 1)); p++)
62433d6423SLionel Sambuc ;
63433d6423SLionel Sambuc if (p > bigbuf) p++;
64433d6423SLionel Sambuc
65433d6423SLionel Sambuc /* Make sure there's enough space for the new parameter */
66433d6423SLionel Sambuc if (p + namelen + valuelen + 3 > bufend)
67433d6423SLionel Sambuc return -1;
68433d6423SLionel Sambuc
69433d6423SLionel Sambuc strcpy(p, name);
70433d6423SLionel Sambuc p[namelen] = '=';
71433d6423SLionel Sambuc strcpy(p + namelen + 1, value);
72433d6423SLionel Sambuc p[namelen + valuelen + 1] = 0;
73433d6423SLionel Sambuc p[namelen + valuelen + 2] = 0;
74433d6423SLionel Sambuc return 0;
75433d6423SLionel Sambuc }
76433d6423SLionel Sambuc
overlaps(multiboot_module_t * mod,int n,int cmp_mod)77433d6423SLionel Sambuc int overlaps(multiboot_module_t *mod, int n, int cmp_mod)
78433d6423SLionel Sambuc {
79433d6423SLionel Sambuc multiboot_module_t *cmp = &mod[cmp_mod];
80433d6423SLionel Sambuc int m;
81433d6423SLionel Sambuc
82433d6423SLionel Sambuc #define INRANGE(mod, v) ((v) >= mod->mod_start && (v) < mod->mod_end)
83433d6423SLionel Sambuc #define OVERLAP(mod1, mod2) (INRANGE(mod1, mod2->mod_start) || \
84433d6423SLionel Sambuc INRANGE(mod1, mod2->mod_end-1))
85433d6423SLionel Sambuc for(m = 0; m < n; m++) {
86433d6423SLionel Sambuc multiboot_module_t *thismod = &mod[m];
87433d6423SLionel Sambuc if(m == cmp_mod) continue;
88433d6423SLionel Sambuc if(OVERLAP(thismod, cmp))
89433d6423SLionel Sambuc return 1;
90433d6423SLionel Sambuc }
91433d6423SLionel Sambuc return 0;
92433d6423SLionel Sambuc }
93433d6423SLionel Sambuc
get_parameters(u32_t ebx,kinfo_t * cbi)94433d6423SLionel Sambuc void get_parameters(u32_t ebx, kinfo_t *cbi)
95433d6423SLionel Sambuc {
96433d6423SLionel Sambuc multiboot_memory_map_t *mmap;
97433d6423SLionel Sambuc multiboot_info_t *mbi = &cbi->mbi;
98433d6423SLionel Sambuc int var_i,value_i, m, k;
99433d6423SLionel Sambuc char *p;
100433d6423SLionel Sambuc extern char _kern_phys_base, _kern_vir_base, _kern_size,
101433d6423SLionel Sambuc _kern_unpaged_start, _kern_unpaged_end;
102433d6423SLionel Sambuc phys_bytes kernbase = (phys_bytes) &_kern_phys_base,
103433d6423SLionel Sambuc kernsize = (phys_bytes) &_kern_size;
104433d6423SLionel Sambuc #define BUF 1024
105433d6423SLionel Sambuc static char cmdline[BUF];
106433d6423SLionel Sambuc
107433d6423SLionel Sambuc /* get our own copy of the multiboot info struct and module list */
108433d6423SLionel Sambuc memcpy((void *) mbi, (void *) ebx, sizeof(*mbi));
109433d6423SLionel Sambuc
110433d6423SLionel Sambuc /* Set various bits of info for the higher-level kernel. */
111433d6423SLionel Sambuc cbi->mem_high_phys = 0;
112433d6423SLionel Sambuc cbi->user_sp = (vir_bytes) &_kern_vir_base;
113433d6423SLionel Sambuc cbi->vir_kern_start = (vir_bytes) &_kern_vir_base;
114433d6423SLionel Sambuc cbi->bootstrap_start = (vir_bytes) &_kern_unpaged_start;
115433d6423SLionel Sambuc cbi->bootstrap_len = (vir_bytes) &_kern_unpaged_end -
116433d6423SLionel Sambuc cbi->bootstrap_start;
117433d6423SLionel Sambuc cbi->kmess = &kmess;
118433d6423SLionel Sambuc
119433d6423SLionel Sambuc /* set some configurable defaults */
120433d6423SLionel Sambuc cbi->do_serial_debug = 0;
121433d6423SLionel Sambuc cbi->serial_debug_baud = 115200;
122433d6423SLionel Sambuc
123433d6423SLionel Sambuc /* parse boot command line */
124433d6423SLionel Sambuc if (mbi->mi_flags & MULTIBOOT_INFO_HAS_CMDLINE) {
125433d6423SLionel Sambuc static char var[BUF];
126433d6423SLionel Sambuc static char value[BUF];
127433d6423SLionel Sambuc
128433d6423SLionel Sambuc /* Override values with cmdline argument */
129433d6423SLionel Sambuc memcpy(cmdline, (void *) mbi->mi_cmdline, BUF);
130433d6423SLionel Sambuc p = cmdline;
131433d6423SLionel Sambuc while (*p) {
132433d6423SLionel Sambuc var_i = 0;
133433d6423SLionel Sambuc value_i = 0;
134433d6423SLionel Sambuc while (*p == ' ') p++;
135433d6423SLionel Sambuc if (!*p) break;
136433d6423SLionel Sambuc while (*p && *p != '=' && *p != ' ' && var_i < BUF - 1)
137433d6423SLionel Sambuc var[var_i++] = *p++ ;
138433d6423SLionel Sambuc var[var_i] = 0;
139433d6423SLionel Sambuc if (*p++ != '=') continue; /* skip if not name=value */
140433d6423SLionel Sambuc while (*p && *p != ' ' && value_i < BUF - 1)
141433d6423SLionel Sambuc value[value_i++] = *p++ ;
142433d6423SLionel Sambuc value[value_i] = 0;
143433d6423SLionel Sambuc
144433d6423SLionel Sambuc mb_set_param(cbi->param_buf, var, value, cbi);
145433d6423SLionel Sambuc }
146433d6423SLionel Sambuc }
147433d6423SLionel Sambuc
148433d6423SLionel Sambuc /* let higher levels know what we are booting on */
149433d6423SLionel Sambuc mb_set_param(cbi->param_buf, ARCHVARNAME, (char *)get_board_arch_name(BOARD_ID_INTEL), cbi);
150433d6423SLionel Sambuc mb_set_param(cbi->param_buf, BOARDVARNAME,(char *)get_board_name(BOARD_ID_INTEL) , cbi);
151433d6423SLionel Sambuc
15253398d73SCristiano Giuffrida /* move user stack/data down to leave a gap to catch kernel
153433d6423SLionel Sambuc * stack overflow; and to distinguish kernel and user addresses
154433d6423SLionel Sambuc * at a glance (0xf.. vs 0xe..)
155433d6423SLionel Sambuc */
15653398d73SCristiano Giuffrida cbi->user_sp = USR_STACKTOP;
15753398d73SCristiano Giuffrida cbi->user_end = USR_DATATOP;
158433d6423SLionel Sambuc
159433d6423SLionel Sambuc /* kernel bytes without bootstrap code/data that is currently
160433d6423SLionel Sambuc * still needed but will be freed after bootstrapping.
161433d6423SLionel Sambuc */
162433d6423SLionel Sambuc kinfo.kernel_allocated_bytes = (phys_bytes) &_kern_size;
163433d6423SLionel Sambuc kinfo.kernel_allocated_bytes -= cbi->bootstrap_len;
164433d6423SLionel Sambuc
165433d6423SLionel Sambuc assert(!(cbi->bootstrap_start % I386_PAGE_SIZE));
166433d6423SLionel Sambuc cbi->bootstrap_len = rounddown(cbi->bootstrap_len, I386_PAGE_SIZE);
167433d6423SLionel Sambuc assert(mbi->mi_flags & MULTIBOOT_INFO_HAS_MODS);
168433d6423SLionel Sambuc assert(mbi->mi_mods_count < MULTIBOOT_MAX_MODS);
169433d6423SLionel Sambuc assert(mbi->mi_mods_count > 0);
170433d6423SLionel Sambuc memcpy(&cbi->module_list, (void *) mbi->mi_mods_addr,
171433d6423SLionel Sambuc mbi->mi_mods_count * sizeof(multiboot_module_t));
172433d6423SLionel Sambuc
173433d6423SLionel Sambuc memset(cbi->memmap, 0, sizeof(cbi->memmap));
174433d6423SLionel Sambuc /* mem_map has a variable layout */
175433d6423SLionel Sambuc if(mbi->mi_flags & MULTIBOOT_INFO_HAS_MMAP) {
176433d6423SLionel Sambuc cbi->mmap_size = 0;
177433d6423SLionel Sambuc for (mmap = (multiboot_memory_map_t *) mbi->mmap_addr;
178433d6423SLionel Sambuc (unsigned long) mmap < mbi->mmap_addr + mbi->mmap_length;
179433d6423SLionel Sambuc mmap = (multiboot_memory_map_t *)
180433d6423SLionel Sambuc ((unsigned long) mmap + mmap->mm_size + sizeof(mmap->mm_size))) {
181433d6423SLionel Sambuc if(mmap->mm_type != MULTIBOOT_MEMORY_AVAILABLE) continue;
182433d6423SLionel Sambuc add_memmap(cbi, mmap->mm_base_addr, mmap->mm_length);
183433d6423SLionel Sambuc }
184433d6423SLionel Sambuc } else {
185433d6423SLionel Sambuc assert(mbi->mi_flags & MULTIBOOT_INFO_HAS_MEMORY);
186433d6423SLionel Sambuc add_memmap(cbi, 0, mbi->mi_mem_lower*1024);
187433d6423SLionel Sambuc add_memmap(cbi, 0x100000, mbi->mi_mem_upper*1024);
188433d6423SLionel Sambuc }
189433d6423SLionel Sambuc
190433d6423SLionel Sambuc /* Sanity check: the kernel nor any of the modules may overlap
191433d6423SLionel Sambuc * with each other. Pretend the kernel is an extra module for a
192433d6423SLionel Sambuc * second.
193433d6423SLionel Sambuc */
194433d6423SLionel Sambuc k = mbi->mi_mods_count;
195433d6423SLionel Sambuc assert(k < MULTIBOOT_MAX_MODS);
196433d6423SLionel Sambuc cbi->module_list[k].mod_start = kernbase;
197433d6423SLionel Sambuc cbi->module_list[k].mod_end = kernbase + kernsize;
198433d6423SLionel Sambuc cbi->mods_with_kernel = mbi->mi_mods_count+1;
199433d6423SLionel Sambuc cbi->kern_mod = k;
200433d6423SLionel Sambuc
201433d6423SLionel Sambuc for(m = 0; m < cbi->mods_with_kernel; m++) {
202433d6423SLionel Sambuc #if 0
203433d6423SLionel Sambuc printf("checking overlap of module %08lx-%08lx\n",
204433d6423SLionel Sambuc cbi->module_list[m].mod_start, cbi->module_list[m].mod_end);
205433d6423SLionel Sambuc #endif
206433d6423SLionel Sambuc if(overlaps(cbi->module_list, cbi->mods_with_kernel, m))
207433d6423SLionel Sambuc panic("overlapping boot modules/kernel");
208433d6423SLionel Sambuc /* We cut out the bits of memory that we know are
209433d6423SLionel Sambuc * occupied by the kernel and boot modules.
210433d6423SLionel Sambuc */
211433d6423SLionel Sambuc cut_memmap(cbi,
212433d6423SLionel Sambuc cbi->module_list[m].mod_start,
213433d6423SLionel Sambuc cbi->module_list[m].mod_end);
214433d6423SLionel Sambuc }
215433d6423SLionel Sambuc }
216433d6423SLionel Sambuc
pre_init(u32_t magic,u32_t ebx)217433d6423SLionel Sambuc kinfo_t *pre_init(u32_t magic, u32_t ebx)
218433d6423SLionel Sambuc {
219433d6423SLionel Sambuc assert(magic == MULTIBOOT_INFO_MAGIC);
220433d6423SLionel Sambuc
221433d6423SLionel Sambuc /* Get our own copy boot params pointed to by ebx.
222433d6423SLionel Sambuc * Here we find out whether we should do serial output.
223433d6423SLionel Sambuc */
224433d6423SLionel Sambuc get_parameters(ebx, &kinfo);
225433d6423SLionel Sambuc
226433d6423SLionel Sambuc /* Make and load a pagetable that will map the kernel
227433d6423SLionel Sambuc * to where it should be; but first a 1:1 mapping so
228433d6423SLionel Sambuc * this code stays where it should be.
229433d6423SLionel Sambuc */
230433d6423SLionel Sambuc pg_clear();
231433d6423SLionel Sambuc pg_identity(&kinfo);
232433d6423SLionel Sambuc kinfo.freepde_start = pg_mapkernel();
233433d6423SLionel Sambuc pg_load();
234433d6423SLionel Sambuc vm_enable_paging();
235433d6423SLionel Sambuc
236433d6423SLionel Sambuc /* Done, return boot info so it can be passed to kmain(). */
237433d6423SLionel Sambuc return &kinfo;
238433d6423SLionel Sambuc }
239433d6423SLionel Sambuc
send_diag_sig(void)240433d6423SLionel Sambuc void send_diag_sig(void) { }
minix_shutdown(int how)241*cfd712b4SDavid van Moolenbroek void minix_shutdown(int how) { arch_shutdown(how); }
busy_delay_ms(int x)242433d6423SLionel Sambuc void busy_delay_ms(int x) { }
raise(int sig)243433d6423SLionel Sambuc int raise(int sig) { panic("raise(%d)\n", sig); }
244