wok view linld/stuff/src/LOAD.CPP @ rev 19546

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