wok-current annotate linld/stuff/src/LOAD.CPP @ rev 19515

linld: multi initrd support
author Pascal Bellard <pascal.bellard@slitaz.org>
date Tue Nov 22 21:19:01 2016 +0100 (2016-11-22)
parents
children 7f92b23984dc
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 }