xref: /minix/minix/kernel/arch/i386/pre_init.c (revision 9f988b79)
1 
2 #define UNPAGED 1	/* for proper kmain() prototype */
3 
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>
22 
23 #if USE_SYSDEBUG
24 #define MULTIBOOT_VERBOSE 1
25 #endif
26 
27 /* to-be-built kinfo struct, diagnostics buffer */
28 kinfo_t kinfo;
29 struct kmessages kmessages;
30 
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; }
33 
34 /* mb_utils.c uses this; we can reach it directly */
35 char *video_mem = (char *) MULTIBOOT_VIDEO_BUFFER;
36 
37 /* String length used for mb_itoa */
38 #define ITOA_BUFFER_SIZE 20
39 
40 /* Kernel may use memory */
41 int kernel_may_alloc = 1;
42 
43 static int mb_set_param(char *bigbuf, char *name, char *value, kinfo_t *cbi)
44 {
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);
50 
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); }
54 
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;
63 		}
64 		while (*p++)
65 			;
66 		p++;
67 	}
68 
69 	for (p = bigbuf; p < bufend && (*p || *(p + 1)); p++)
70 		;
71 	if (p > bigbuf) p++;
72 
73 	/* Make sure there's enough space for the new parameter */
74 	if (p + namelen + valuelen + 3 > bufend)
75 		return -1;
76 
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;
83 }
84 
85 int overlaps(multiboot_module_t *mod, int n, int cmp_mod)
86 {
87 	multiboot_module_t *cmp = &mod[cmp_mod];
88 	int m;
89 
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;
98 	}
99 	return 0;
100 }
101 
102 void get_parameters(u32_t ebx, kinfo_t *cbi)
103 {
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];
114 
115 	/* get our own copy of the multiboot info struct and module list */
116 	memcpy((void *) mbi, (void *) ebx, sizeof(*mbi));
117 
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;
126 
127 	/* set some configurable defaults */
128 	cbi->do_serial_debug = 0;
129 	cbi->serial_debug_baud = 115200;
130 
131 	/* parse boot command line */
132 	if (mbi->mi_flags & MULTIBOOT_INFO_HAS_CMDLINE) {
133 		static char var[BUF];
134 		static char value[BUF];
135 
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;
151 
152 			mb_set_param(cbi->param_buf, var, value, cbi);
153 		}
154 	}
155 
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);
159 
160 	/* move user stack/data 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..)
163 	 */
164 	cbi->user_sp = USR_STACKTOP;
165 	cbi->user_end = USR_DATATOP;
166 
167 	/* kernel bytes without bootstrap code/data that is currently
168 	 * still needed but will be freed after bootstrapping.
169 	 */
170 	kinfo.kernel_allocated_bytes = (phys_bytes) &_kern_size;
171 	kinfo.kernel_allocated_bytes -= cbi->bootstrap_len;
172 
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));
180 
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);
191 		}
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);
196 	}
197 
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.
201 	 */
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;
208 
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.
218 		 */
219 		cut_memmap(cbi,
220 			cbi->module_list[m].mod_start,
221 			cbi->module_list[m].mod_end);
222 	}
223 }
224 
225 kinfo_t *pre_init(u32_t magic, u32_t ebx)
226 {
227 	assert(magic == MULTIBOOT_INFO_MAGIC);
228 
229 	/* Get our own copy boot params pointed to by ebx.
230 	 * Here we find out whether we should do serial output.
231 	 */
232 	get_parameters(ebx, &kinfo);
233 
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.
237 	 */
238 	pg_clear();
239 	pg_identity(&kinfo);
240 	kinfo.freepde_start = pg_mapkernel();
241 	pg_load();
242 	vm_enable_paging();
243 
244 	/* Done, return boot info so it can be passed to kmain(). */
245 	return &kinfo;
246 }
247 
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); }
252