rev |
line source |
pascal@19515
|
1 // This file is distributed under GPL
|
pascal@19515
|
2
|
pascal@19515
|
3 #include "crtl.h"
|
pascal@19515
|
4 #include "common.h"
|
pascal@19515
|
5
|
pascal@19515
|
6 /***************
|
pascal@19515
|
7 Memory layout assumed by kernel boot process
|
pascal@19515
|
8 --------------------------------------------
|
pascal@19515
|
9 Note: claims that kernel setup is relocatable are
|
pascal@19515
|
10 still not 100% valid:
|
pascal@19515
|
11 bzImage decompressing trashes 10000-8ffff range,
|
pascal@19515
|
12 so rm loader -> pm kernel info is lost if it was here...
|
pascal@19515
|
13 So I had to stick to 90000.
|
pascal@19515
|
14
|
pascal@19515
|
15 10000000+------------------------+ <- 256m
|
pascal@19515
|
16 | initrd | initrd is at top of mem, but
|
pascal@19515
|
17 | | not higher than 256m
|
pascal@19515
|
18 +------------------------+
|
pascal@19515
|
19 +------------------------+
|
pascal@19515
|
20 | bzImage | bzImage is at 1m
|
pascal@19515
|
21 | | VCPI/XMS/64k offset tricks used...
|
pascal@19515
|
22 00100000+------------------------+ <- 1m
|
pascal@19515
|
23 | video, BIOS etc | Do not use.
|
pascal@19515
|
24 000A0000+------------------------+
|
pascal@19515
|
25 | Reserved for BIOS | Do not use. Reserved for BIOS EBDA.
|
pascal@19515
|
26 0009A000+------------------------+ <- stack top for kernel rm code
|
pascal@19515
|
27 | Cmdline |
|
pascal@19515
|
28 00098000+------------------------+ <- heap top for kernel rm code
|
pascal@19515
|
29 | Kernel setup | The kernel real-mode code.
|
pascal@19515
|
30 00090200+------------------------+
|
pascal@19515
|
31 | Kernel boot sector | The kernel legacy boot sector.
|
pascal@19515
|
32 00090000+------------------------+
|
pascal@19515
|
33 | Zapped by ungzip | Historically zImages were loaded here
|
pascal@19515
|
34 | (zImage once was here) | bzImages use this space for ungzipping
|
pascal@19515
|
35 00010000+------------------------+
|
pascal@19515
|
36 | Boot loader | <- Boot sector entry point 0000:7C00
|
pascal@19515
|
37 00001000+------------------------+
|
pascal@19515
|
38 | Reserved for MBR/BIOS |
|
pascal@19515
|
39 00000800+------------------------+
|
pascal@19515
|
40 | Typically used by MBR |
|
pascal@19515
|
41 00000600+------------------------+
|
pascal@19515
|
42 | BIOS use only |
|
pascal@19515
|
43 00000000+------------------------+
|
pascal@19515
|
44 */
|
pascal@19515
|
45
|
pascal@19515
|
46 struct first1k_t {
|
pascal@19515
|
47 // these two set by rm setup:
|
pascal@19515
|
48 u16 curr_curs; // 0000 saved cursor position
|
pascal@19515
|
49 u16 ext_mem_size; // 0002 extended memory size in Kb (from int 0x15 fn 0x88)
|
pascal@19515
|
50 u8 pad00[0x20-4];
|
pascal@19515
|
51 // old-style cmdline (not used in LINLD (yet?))
|
pascal@19515
|
52 u16 cl_magic; // 0020 commandline magic number (=0xA33F)
|
pascal@19515
|
53 u16 cl_ofs; // 0022 commandline offset
|
pascal@19515
|
54 u8 pad10[0x80-0x24];
|
pascal@19515
|
55 // these two set by rm setup:
|
pascal@19515
|
56 u8 hd0_disk_par[16]; // 0080 hd0-disk-parameter from intvector 0x41
|
pascal@19515
|
57 u8 hd1_disk_par[16]; // 0090 hd1-disk-parameter from intvector 0x46
|
pascal@19515
|
58 u8 pad20[0x01e0-0xa0];
|
pascal@19515
|
59 // this is set by rm setup:
|
pascal@19515
|
60 u32 alt_mem_size; // 01E0 extended memory size in Kb (from int 0x15 fn 0xe801)
|
pascal@19515
|
61 u8 pad28[0x01f1-0x1e4];
|
pascal@19515
|
62
|
pascal@19515
|
63 u8 setup_sects; // 01F1 The size of the setup in sectors
|
pascal@19515
|
64 // boot sector is NOT included here
|
pascal@19515
|
65 u16 ro_flag; // 01F2 If set, the root is mounted readonly
|
pascal@19515
|
66 u16 syssize; // 01F4 DO NOT USE - for bootsect.S use only:
|
pascal@19515
|
67 // size of pm part of kernel
|
pascal@19515
|
68 // (in 16 byte units, rounded up)
|
pascal@19515
|
69 u16 swap_dev; // 01F6 DO NOT USE - obsolete
|
pascal@19515
|
70 u16 ram_size; // 01F8 DO NOT USE - for bootsect.S use only:
|
pascal@19515
|
71 // if nonzero then kernel
|
pascal@19515
|
72 // (driver/block/ramdisk.c: rd_load())
|
pascal@19515
|
73 // will try to load the contents for the ramdisk
|
pascal@19515
|
74 // from the "root_dev" which MUST then have the
|
pascal@19515
|
75 // floppyMAJOR
|
pascal@19515
|
76 // The file-system on that floppy must be MINIX
|
pascal@19515
|
77 // If rd_load() succeeds it sets the root_dev
|
pascal@19515
|
78 // to the ramdisk for mounting it
|
pascal@19515
|
79 u16 vid_mode; // 01FA Video mode control
|
pascal@19515
|
80 u16 root_dev; // 01FC Default root device number
|
pascal@19515
|
81 u16 boot_flag; // 01FE 0xAA55 magic number
|
pascal@19515
|
82 u16 jump; // 0200 Jump instruction
|
pascal@19515
|
83 u32 header; // 0202 Magic signature "HdrS"
|
pascal@19515
|
84 u16 version; // 0206 Boot protocol version supported
|
pascal@19515
|
85 u16 realmode_switch_ofs; // 0208 Hook called just before rm->pm
|
pascal@19515
|
86 u16 realmode_switch_seg;
|
pascal@19515
|
87 u16 start_sys_seg; // 020E
|
pascal@19515
|
88 u16 kernel_version; // 020C Points to kernel version string
|
pascal@19515
|
89 u8 type_of_loader; // 0210 Boot loader identifier
|
pascal@19515
|
90 u8 loadflags; // 0211 Boot protocol option flags
|
pascal@19515
|
91 u16 setup_move_size;// 0212 Move to high memory size (used with hooks)
|
pascal@19515
|
92 u32 code32_start; // 0214 Boot loader hook (see below)
|
pascal@19515
|
93 u32 initrd_buf; // 0218 initrd load address (set by boot loader)
|
pascal@19515
|
94 u32 initrd_size; // 021C initrd size (set by boot loader)
|
pascal@19515
|
95 u32 bootsect_kludge;// 0220 DO NOT USE - for bootsect.S use only
|
pascal@19515
|
96 u16 heap_end_ptr; // 0224 Free memory after setup end
|
pascal@19515
|
97 u16 pad1; // 0226 Unused
|
pascal@19515
|
98 u32 cmd_line_ptr; // 0228 32-bit pointer to the kernel command line
|
pascal@19515
|
99 u8 pad30[0x400-0x22c]; // 022C
|
pascal@19515
|
100 // 02D0 up to 32 20-byte mem info structs from
|
pascal@19515
|
101 // int 0x15 fn 0xe820
|
pascal@19515
|
102 }; //__attribute((packed));
|
pascal@19515
|
103
|
pascal@19515
|
104 #if sizeof(first1k_t)!=0x400
|
pascal@19515
|
105 #error BUG: Bad first1k
|
pascal@19515
|
106 #endif
|
pascal@19515
|
107
|
pascal@19515
|
108 const u32 HdrS = 'H' + ('d'<<8) + (u32('r')<<16) + (u32('S')<<24);
|
pascal@19515
|
109
|
pascal@19515
|
110 u8* rm_buf;
|
pascal@19515
|
111 static u16 rm_size;
|
pascal@19515
|
112 u8 pm_high;
|
pascal@19515
|
113 struct image_himem pm;
|
pascal@19515
|
114 struct image_himem initrd;
|
pascal@19515
|
115
|
pascal@19515
|
116 static void memcpy_image(struct image_himem *m) {
|
pascal@19515
|
117 if (m->fallback != m->buf)
|
pascal@19515
|
118 memcpy32(
|
pascal@19515
|
119 0, m->fallback, // dst seg,ofs
|
pascal@19515
|
120 0, m->buf, // src seg,ofs
|
pascal@19515
|
121 m->size // size
|
pascal@19515
|
122 );
|
pascal@19515
|
123 }
|
pascal@19515
|
124
|
pascal@19515
|
125 // Called from inside kernel just before rm->pm
|
pascal@19515
|
126 // _loadds _saveregs: done by hand
|
pascal@19515
|
127 void far last_ditch() {
|
pascal@19515
|
128 cli(); // we start doing *really* destructive things to DOS/BIOS
|
pascal@19515
|
129 // it means: do not even try to enable ints
|
pascal@19515
|
130 // or call BIOS services after this
|
pascal@19515
|
131 asm {
|
pascal@19515
|
132 push ds
|
pascal@19515
|
133 push cs
|
pascal@19515
|
134 pop ds
|
pascal@19515
|
135 #ifndef NO386
|
pascal@19515
|
136 pusha
|
pascal@19515
|
137 #else
|
pascal@19515
|
138 push ax
|
pascal@19515
|
139 push bx
|
pascal@19515
|
140 push cx
|
pascal@19515
|
141 push dx
|
pascal@19515
|
142 #endif
|
pascal@19515
|
143 }
|
pascal@19515
|
144 if(pm.fallback > _1m) pm.fallback = _1m;
|
pascal@19515
|
145 if(vcpi==0) {
|
pascal@19515
|
146 // Move kernel
|
pascal@19515
|
147 memcpy_image(&pm);
|
pascal@19515
|
148 // Move initrd
|
pascal@19515
|
149 memcpy_image(&initrd);
|
pascal@19515
|
150 } else { //vcpi
|
pascal@19515
|
151 vm2rm();
|
pascal@19515
|
152 // Move kernel
|
pascal@19515
|
153 // 'Gathering' copy in chunks of PAGE_SIZE
|
pascal@19515
|
154 // No risk of overlapping: kernel is copied from above to 1m mark
|
pascal@19515
|
155 pm.size = PAGE_SIZE;
|
pascal@19515
|
156 u32 *p = pm.bufv;
|
pascal@19515
|
157 if (p) while(*p) {
|
pascal@19515
|
158 pm.buf = *p;
|
pascal@19515
|
159 memcpy_image(&pm);
|
pascal@19515
|
160 p++; pm.fallback+=PAGE_SIZE;
|
pascal@19515
|
161 }
|
pascal@19515
|
162 // Move initrd
|
pascal@19515
|
163 if(initrd.fallback) {
|
pascal@19515
|
164 // This is tricky: copy initrd backwards to reduce
|
pascal@19515
|
165 // risk of overlapping: use the fact that initrd is copied
|
pascal@19515
|
166 // to the very top of ram
|
pascal@19515
|
167 // (overlapping still can happen with more than 256mb ram)
|
pascal@19515
|
168 // (generic solution for this overwrite problem, anyone?)
|
pascal@19515
|
169 p=initrd.bufv;
|
pascal@19515
|
170 initrd.size = PAGE_SIZE;
|
pascal@19515
|
171 do {
|
pascal@19515
|
172 p++; initrd.fallback+=PAGE_SIZE;
|
pascal@19515
|
173 } while(*p);
|
pascal@19515
|
174 do {
|
pascal@19515
|
175 p--; initrd.fallback-=PAGE_SIZE;
|
pascal@19515
|
176 initrd.buf = *p;
|
pascal@19515
|
177 memcpy_image(&initrd);
|
pascal@19515
|
178 } while(p != initrd.bufv);
|
pascal@19515
|
179 }
|
pascal@19515
|
180 }
|
pascal@19515
|
181 asm {
|
pascal@19515
|
182 #ifndef NO386
|
pascal@19515
|
183 popa
|
pascal@19515
|
184 #else
|
pascal@19515
|
185 pop dx
|
pascal@19515
|
186 pop cx
|
pascal@19515
|
187 pop bx
|
pascal@19515
|
188 pop ax
|
pascal@19515
|
189 #endif
|
pascal@19515
|
190 pop ds
|
pascal@19515
|
191 }
|
pascal@19515
|
192 }
|
pascal@19515
|
193
|
pascal@19515
|
194 // register value to launch the kernel real mode code
|
pascal@19515
|
195 #ifdef NO386
|
pascal@19515
|
196 static u32 sssp;
|
pascal@19515
|
197 static u32 csip;
|
pascal@19515
|
198 extern "C" u16 topseg();
|
pascal@19515
|
199 #else
|
pascal@19515
|
200 const u32 sssp=0x9000A000;
|
pascal@19515
|
201 static u32 csip=0x90200000;
|
pascal@19515
|
202 #define topseg() 0x9000
|
pascal@19515
|
203 #endif
|
pascal@19515
|
204
|
pascal@19515
|
205 static const char kernel_file_error[] = "Can't use kernel file";
|
pascal@19515
|
206 char* load_kernel() {
|
pascal@19515
|
207
|
pascal@19515
|
208 #ifdef NO386
|
pascal@19515
|
209 sssp=((u32)topseg()<<16)+0xA000;
|
pascal@19515
|
210 csip=((u32)(topseg()+0x20)<<16);
|
pascal@19515
|
211 #endif
|
pascal@19515
|
212 // Open kernel, read first kb, check it
|
pascal@19515
|
213 pm.errmsg = kernel_file_error;
|
pascal@19515
|
214 open_image(kernel_name, &pm);
|
pascal@19515
|
215
|
pascal@19515
|
216 char *version_string;
|
pascal@19515
|
217 {
|
pascal@19515
|
218 struct first1k_t *first1k;
|
pascal@19515
|
219 first1k = (first1k_t*) (rm_buf = malloc_or_die(_32k));
|
pascal@19515
|
220 {
|
pascal@19515
|
221 u16 rm_seek;
|
pascal@19515
|
222
|
pascal@19515
|
223 // Do not use malloc below until heap_top adjustment (see <*>)
|
pascal@19515
|
224 if (read(pm.fd, rm_buf, rm_seek=0x400) != 0x400) {
|
pascal@19515
|
225 readfail:
|
pascal@19515
|
226 die(kernel_file_error);
|
pascal@19515
|
227 }
|
pascal@19515
|
228
|
pascal@19515
|
229 if(!first1k->setup_sects) {
|
pascal@19515
|
230 #if 1
|
pascal@19515
|
231 if(* (int *) &first1k->pad10[0x3F-0x24] == 0x3AE8) {
|
pascal@19515
|
232 lseek(pm.fd,rm_seek=0x200,SEEK_SET);
|
pascal@19515
|
233 csip=((u32)topseg()<<16)+0x0042;
|
pascal@19515
|
234 }
|
pascal@19515
|
235 else
|
pascal@19515
|
236 #endif
|
pascal@19515
|
237 first1k->setup_sects=4;
|
pascal@19515
|
238 }
|
pascal@19515
|
239 rm_size = 0x200*(first1k->setup_sects+1); // 0th sector is not counted there
|
pascal@19515
|
240 if(rm_size>_32k || first1k->boot_flag != 0xAA55)
|
pascal@19515
|
241 die("It's not a kernel");
|
pascal@19515
|
242 heap_top = rm_buf+rm_size; // <*>
|
pascal@19515
|
243
|
pascal@19515
|
244 // Read remaining rm loader
|
pascal@19515
|
245
|
pascal@19515
|
246 {
|
pascal@19515
|
247 u16 cnt = rm_size-rm_seek;
|
pascal@19515
|
248 if (read(pm.fd, rm_buf+rm_seek, cnt) != cnt) goto readfail;
|
pascal@19515
|
249 }
|
pascal@19515
|
250 }
|
pascal@19515
|
251
|
pascal@19515
|
252 // Tell rm loader some info
|
pascal@19515
|
253
|
pascal@19515
|
254 if(vid_mode) first1k->vid_mode = vid_mode;
|
pascal@19515
|
255 if(root_dev) first1k->root_dev = root_dev;
|
pascal@19515
|
256 version_string = 0;
|
pascal@19515
|
257
|
pascal@19515
|
258 #if 1
|
pascal@19515
|
259 if(first1k->header == HdrS) { // starting linux 1.3.73
|
pascal@19515
|
260 if(first1k->loadflags & 1) {
|
pascal@19515
|
261 #else
|
pascal@19515
|
262 if((first1k->header != HdrS) || (first1k->loadflags & 1) == 0)
|
pascal@19515
|
263 die("I can't load bzImage low");
|
pascal@19515
|
264 {
|
pascal@19515
|
265 {
|
pascal@19515
|
266 #endif
|
pascal@19515
|
267 pm_high++;
|
pascal@19515
|
268
|
pascal@19515
|
269 // Hook on int15 to work around fn 88 DOS breakage
|
pascal@19515
|
270 hook_int15_88();
|
pascal@19515
|
271
|
pascal@19515
|
272 // * will be called just before rm -> pm
|
pascal@19515
|
273 first1k->realmode_switch_ofs = ofs(last_ditch);
|
pascal@19515
|
274 first1k->realmode_switch_seg = seg(last_ditch);
|
pascal@19515
|
275 }
|
pascal@19515
|
276 if(first1k->kernel_version)
|
pascal@19515
|
277 version_string = (char *) first1k+first1k->kernel_version+0x200;
|
pascal@19515
|
278 first1k->type_of_loader = 0xff; // kernel do not know us (yet :-)
|
pascal@19515
|
279 if(first1k->version >= 0x201) {
|
pascal@19515
|
280 // * offset limit of the setup heap
|
pascal@19515
|
281 // heap_end_ptr appears to be relative to the start of setup (ofs 0x0200)
|
pascal@19515
|
282 first1k->heap_end_ptr = _32k-0x0200;
|
pascal@19515
|
283 first1k->loadflags |= 0x80; // says to rm loader it's ok to use heap
|
pascal@19515
|
284 }
|
pascal@19515
|
285 // * if we will ever stop moving ourself to 0x90000
|
pascal@19515
|
286 // we must say setup.S how much to move
|
pascal@19515
|
287 //first1k->setup_move_size = _32k;
|
pascal@19515
|
288 if(first1k->version >= 0x202) { // starting linux 2.4.0-test3-pre3
|
pascal@19515
|
289 first1k->cmd_line_ptr = (((u32)(topseg()+0x0800))<<4);
|
pascal@19515
|
290 goto cmd_line_ok;
|
pascal@19515
|
291 }
|
pascal@19515
|
292 }
|
pascal@19515
|
293 first1k->cl_magic = 0xA33F;
|
pascal@19515
|
294 first1k->cl_ofs = 0x8000;
|
pascal@19515
|
295 }
|
pascal@19515
|
296
|
pascal@19515
|
297 cmd_line_ok:
|
pascal@19515
|
298 // Check and enable A20 if needed
|
pascal@19515
|
299 enable_a20_or_die();
|
pascal@19515
|
300
|
pascal@19515
|
301 // Read remaining kernel (pm part)
|
pascal@19515
|
302 // Try to load kernel high, maybe even blindly storing it
|
pascal@19515
|
303 // in unallocated memory as a last resort
|
pascal@19515
|
304
|
pascal@19515
|
305 pm.fallback = (u32((u16(_CS)+0x1FFF)&0xF000)<<4);
|
pascal@19515
|
306 pm.size -= rm_size;
|
pascal@19515
|
307 if(pm.fallback+pm.size > (((u32)topseg())<<4) || pm_high) {
|
pascal@19515
|
308 pm.fallback = _1m+_64k;
|
pascal@19515
|
309 }
|
pascal@19515
|
310
|
pascal@19515
|
311 load_image(&pm);
|
pascal@19515
|
312 return version_string;
|
pascal@19515
|
313 }
|
pascal@19515
|
314
|
pascal@19515
|
315 // Read initrd if needed
|
pascal@19515
|
316
|
pascal@19515
|
317 static const char msg_initrd[] = "Can't use initrd file";
|
pascal@19515
|
318 void load_initrd() {
|
pascal@19515
|
319 struct image_himem *m = &initrd;
|
pascal@19515
|
320 if (!initrd_name && !initrd.fd) return;
|
pascal@19515
|
321 if (!pm.fd) {
|
pascal@19515
|
322 noinitrd:
|
pascal@19515
|
323 puts(msg_initrd);
|
pascal@19515
|
324 return;
|
pascal@19515
|
325 }
|
pascal@19515
|
326 m->errmsg = msg_initrd;
|
pascal@19515
|
327 open_image(initrd_name, m);
|
pascal@19515
|
328
|
pascal@19515
|
329 m->fallback = (memtop()-m->size) & (~PAGE_MASK);
|
pascal@19515
|
330 if (m->fallback < pm.fallback + pm.size) {
|
pascal@19515
|
331 close(m->fd);
|
pascal@19515
|
332 goto noinitrd;
|
pascal@19515
|
333 }
|
pascal@19515
|
334
|
pascal@19515
|
335 load_image(m);
|
pascal@19515
|
336 struct first1k_t *first1k = (first1k_t*)rm_buf;
|
pascal@19515
|
337 if(first1k->header == HdrS) {
|
pascal@19515
|
338 first1k->initrd_buf = m->fallback;
|
pascal@19515
|
339 first1k->initrd_size = m->size;
|
pascal@19515
|
340 }
|
pascal@19515
|
341 }
|
pascal@19515
|
342
|
pascal@19515
|
343 void boot_kernel() {
|
pascal@19515
|
344
|
pascal@19515
|
345 // Shrink stack: we won't need much of it now and have no malloc() plans
|
pascal@19515
|
346 {
|
pascal@19515
|
347 u16 new_SP=u16(heap_top)+0x100;
|
pascal@19515
|
348 if(_SP>new_SP) _SP=new_SP;
|
pascal@19515
|
349 }
|
pascal@19515
|
350 if( u16(_CS)+(u16(_SP)>>4) >= topseg() ) {
|
pascal@19515
|
351 // Oops! We can stomp on our toes... better stop now
|
pascal@19515
|
352 die("Loaded too close to 9000:0");
|
pascal@19515
|
353 }
|
pascal@19515
|
354
|
pascal@19515
|
355 cli(); // we start doing destructive things to DOS
|
pascal@19515
|
356
|
pascal@19515
|
357 // Move rm loader & commandline to 0x90000
|
pascal@19515
|
358 if(vcpi==0) {
|
pascal@19515
|
359 memcpy32(
|
pascal@19515
|
360 topseg(),0,
|
pascal@19515
|
361 seg(rm_buf),ofs(rm_buf),
|
pascal@19515
|
362 rm_size //_32k
|
pascal@19515
|
363 );
|
pascal@19515
|
364 memcpy32(
|
pascal@19515
|
365 topseg()+0x0800,0,
|
pascal@19515
|
366 seg(cmdline),ofs(cmdline),
|
pascal@19515
|
367 PAGE_SIZE
|
pascal@19515
|
368 );
|
pascal@19515
|
369 } else { //vcpi
|
pascal@19515
|
370 u32 dst=((u32)topseg()<<4);
|
pascal@19515
|
371 u16 pos=ofs(rm_buf);
|
pascal@19515
|
372 do {
|
pascal@19515
|
373 memcpy_vcpi(dst,seg(rm_buf),pos);
|
pascal@19515
|
374 dst+=PAGE_SIZE;
|
pascal@19515
|
375 pos+=PAGE_SIZE;
|
pascal@19515
|
376 rm_size-=PAGE_SIZE;
|
pascal@19515
|
377 } while(s16(rm_size) > 0);
|
pascal@19515
|
378 // overkill: copy PAGE_SIZE bytes
|
pascal@19515
|
379 memcpy_vcpi(((u32)(topseg()+0x0800)<<4),seg(cmdline),ofs(cmdline));
|
pascal@19515
|
380 }
|
pascal@19515
|
381
|
pascal@19515
|
382 // Jump to kernel rm code
|
pascal@19515
|
383 set_sregs_jump_seg_ofs(csip, sssp);
|
pascal@19515
|
384 }
|