wok diff 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 |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/linld/stuff/src/LOAD.CPP Tue Nov 22 21:19:01 2016 +0100 1.3 @@ -0,0 +1,384 @@ 1.4 +// This file is distributed under GPL 1.5 + 1.6 +#include "crtl.h" 1.7 +#include "common.h" 1.8 + 1.9 +/*************** 1.10 + Memory layout assumed by kernel boot process 1.11 + -------------------------------------------- 1.12 + Note: claims that kernel setup is relocatable are 1.13 + still not 100% valid: 1.14 + bzImage decompressing trashes 10000-8ffff range, 1.15 + so rm loader -> pm kernel info is lost if it was here... 1.16 + So I had to stick to 90000. 1.17 + 1.18 +10000000+------------------------+ <- 256m 1.19 + | initrd | initrd is at top of mem, but 1.20 + | | not higher than 256m 1.21 + +------------------------+ 1.22 + +------------------------+ 1.23 + | bzImage | bzImage is at 1m 1.24 + | | VCPI/XMS/64k offset tricks used... 1.25 +00100000+------------------------+ <- 1m 1.26 + | video, BIOS etc | Do not use. 1.27 +000A0000+------------------------+ 1.28 + | Reserved for BIOS | Do not use. Reserved for BIOS EBDA. 1.29 +0009A000+------------------------+ <- stack top for kernel rm code 1.30 + | Cmdline | 1.31 +00098000+------------------------+ <- heap top for kernel rm code 1.32 + | Kernel setup | The kernel real-mode code. 1.33 +00090200+------------------------+ 1.34 + | Kernel boot sector | The kernel legacy boot sector. 1.35 +00090000+------------------------+ 1.36 + | Zapped by ungzip | Historically zImages were loaded here 1.37 + | (zImage once was here) | bzImages use this space for ungzipping 1.38 +00010000+------------------------+ 1.39 + | Boot loader | <- Boot sector entry point 0000:7C00 1.40 +00001000+------------------------+ 1.41 + | Reserved for MBR/BIOS | 1.42 +00000800+------------------------+ 1.43 + | Typically used by MBR | 1.44 +00000600+------------------------+ 1.45 + | BIOS use only | 1.46 +00000000+------------------------+ 1.47 +*/ 1.48 + 1.49 +struct first1k_t { 1.50 + // these two set by rm setup: 1.51 + u16 curr_curs; // 0000 saved cursor position 1.52 + u16 ext_mem_size; // 0002 extended memory size in Kb (from int 0x15 fn 0x88) 1.53 + u8 pad00[0x20-4]; 1.54 + // old-style cmdline (not used in LINLD (yet?)) 1.55 + u16 cl_magic; // 0020 commandline magic number (=0xA33F) 1.56 + u16 cl_ofs; // 0022 commandline offset 1.57 + u8 pad10[0x80-0x24]; 1.58 + // these two set by rm setup: 1.59 + u8 hd0_disk_par[16]; // 0080 hd0-disk-parameter from intvector 0x41 1.60 + u8 hd1_disk_par[16]; // 0090 hd1-disk-parameter from intvector 0x46 1.61 + u8 pad20[0x01e0-0xa0]; 1.62 + // this is set by rm setup: 1.63 + u32 alt_mem_size; // 01E0 extended memory size in Kb (from int 0x15 fn 0xe801) 1.64 + u8 pad28[0x01f1-0x1e4]; 1.65 + 1.66 + u8 setup_sects; // 01F1 The size of the setup in sectors 1.67 + // boot sector is NOT included here 1.68 + u16 ro_flag; // 01F2 If set, the root is mounted readonly 1.69 + u16 syssize; // 01F4 DO NOT USE - for bootsect.S use only: 1.70 + // size of pm part of kernel 1.71 + // (in 16 byte units, rounded up) 1.72 + u16 swap_dev; // 01F6 DO NOT USE - obsolete 1.73 + u16 ram_size; // 01F8 DO NOT USE - for bootsect.S use only: 1.74 + // if nonzero then kernel 1.75 + // (driver/block/ramdisk.c: rd_load()) 1.76 + // will try to load the contents for the ramdisk 1.77 + // from the "root_dev" which MUST then have the 1.78 + // floppyMAJOR 1.79 + // The file-system on that floppy must be MINIX 1.80 + // If rd_load() succeeds it sets the root_dev 1.81 + // to the ramdisk for mounting it 1.82 + u16 vid_mode; // 01FA Video mode control 1.83 + u16 root_dev; // 01FC Default root device number 1.84 + u16 boot_flag; // 01FE 0xAA55 magic number 1.85 + u16 jump; // 0200 Jump instruction 1.86 + u32 header; // 0202 Magic signature "HdrS" 1.87 + u16 version; // 0206 Boot protocol version supported 1.88 + u16 realmode_switch_ofs; // 0208 Hook called just before rm->pm 1.89 + u16 realmode_switch_seg; 1.90 + u16 start_sys_seg; // 020E 1.91 + u16 kernel_version; // 020C Points to kernel version string 1.92 + u8 type_of_loader; // 0210 Boot loader identifier 1.93 + u8 loadflags; // 0211 Boot protocol option flags 1.94 + u16 setup_move_size;// 0212 Move to high memory size (used with hooks) 1.95 + u32 code32_start; // 0214 Boot loader hook (see below) 1.96 + u32 initrd_buf; // 0218 initrd load address (set by boot loader) 1.97 + u32 initrd_size; // 021C initrd size (set by boot loader) 1.98 + u32 bootsect_kludge;// 0220 DO NOT USE - for bootsect.S use only 1.99 + u16 heap_end_ptr; // 0224 Free memory after setup end 1.100 + u16 pad1; // 0226 Unused 1.101 + u32 cmd_line_ptr; // 0228 32-bit pointer to the kernel command line 1.102 + u8 pad30[0x400-0x22c]; // 022C 1.103 + // 02D0 up to 32 20-byte mem info structs from 1.104 + // int 0x15 fn 0xe820 1.105 +}; //__attribute((packed)); 1.106 + 1.107 +#if sizeof(first1k_t)!=0x400 1.108 +#error BUG: Bad first1k 1.109 +#endif 1.110 + 1.111 +const u32 HdrS = 'H' + ('d'<<8) + (u32('r')<<16) + (u32('S')<<24); 1.112 + 1.113 +u8* rm_buf; 1.114 +static u16 rm_size; 1.115 +u8 pm_high; 1.116 +struct image_himem pm; 1.117 +struct image_himem initrd; 1.118 + 1.119 +static void memcpy_image(struct image_himem *m) { 1.120 + if (m->fallback != m->buf) 1.121 + memcpy32( 1.122 + 0, m->fallback, // dst seg,ofs 1.123 + 0, m->buf, // src seg,ofs 1.124 + m->size // size 1.125 + ); 1.126 +} 1.127 + 1.128 +// Called from inside kernel just before rm->pm 1.129 +// _loadds _saveregs: done by hand 1.130 +void far last_ditch() { 1.131 + cli(); // we start doing *really* destructive things to DOS/BIOS 1.132 + // it means: do not even try to enable ints 1.133 + // or call BIOS services after this 1.134 + asm { 1.135 + push ds 1.136 + push cs 1.137 + pop ds 1.138 +#ifndef NO386 1.139 + pusha 1.140 +#else 1.141 + push ax 1.142 + push bx 1.143 + push cx 1.144 + push dx 1.145 +#endif 1.146 + } 1.147 + if(pm.fallback > _1m) pm.fallback = _1m; 1.148 + if(vcpi==0) { 1.149 + // Move kernel 1.150 + memcpy_image(&pm); 1.151 + // Move initrd 1.152 + memcpy_image(&initrd); 1.153 + } else { //vcpi 1.154 + vm2rm(); 1.155 + // Move kernel 1.156 + // 'Gathering' copy in chunks of PAGE_SIZE 1.157 + // No risk of overlapping: kernel is copied from above to 1m mark 1.158 + pm.size = PAGE_SIZE; 1.159 + u32 *p = pm.bufv; 1.160 + if (p) while(*p) { 1.161 + pm.buf = *p; 1.162 + memcpy_image(&pm); 1.163 + p++; pm.fallback+=PAGE_SIZE; 1.164 + } 1.165 + // Move initrd 1.166 + if(initrd.fallback) { 1.167 + // This is tricky: copy initrd backwards to reduce 1.168 + // risk of overlapping: use the fact that initrd is copied 1.169 + // to the very top of ram 1.170 + // (overlapping still can happen with more than 256mb ram) 1.171 + // (generic solution for this overwrite problem, anyone?) 1.172 + p=initrd.bufv; 1.173 + initrd.size = PAGE_SIZE; 1.174 + do { 1.175 + p++; initrd.fallback+=PAGE_SIZE; 1.176 + } while(*p); 1.177 + do { 1.178 + p--; initrd.fallback-=PAGE_SIZE; 1.179 + initrd.buf = *p; 1.180 + memcpy_image(&initrd); 1.181 + } while(p != initrd.bufv); 1.182 + } 1.183 + } 1.184 + asm { 1.185 +#ifndef NO386 1.186 + popa 1.187 +#else 1.188 + pop dx 1.189 + pop cx 1.190 + pop bx 1.191 + pop ax 1.192 +#endif 1.193 + pop ds 1.194 + } 1.195 +} 1.196 + 1.197 +// register value to launch the kernel real mode code 1.198 +#ifdef NO386 1.199 +static u32 sssp; 1.200 +static u32 csip; 1.201 +extern "C" u16 topseg(); 1.202 +#else 1.203 +const u32 sssp=0x9000A000; 1.204 +static u32 csip=0x90200000; 1.205 +#define topseg() 0x9000 1.206 +#endif 1.207 + 1.208 +static const char kernel_file_error[] = "Can't use kernel file"; 1.209 +char* load_kernel() { 1.210 + 1.211 +#ifdef NO386 1.212 + sssp=((u32)topseg()<<16)+0xA000; 1.213 + csip=((u32)(topseg()+0x20)<<16); 1.214 +#endif 1.215 + // Open kernel, read first kb, check it 1.216 + pm.errmsg = kernel_file_error; 1.217 + open_image(kernel_name, &pm); 1.218 + 1.219 + char *version_string; 1.220 + { 1.221 + struct first1k_t *first1k; 1.222 + first1k = (first1k_t*) (rm_buf = malloc_or_die(_32k)); 1.223 + { 1.224 + u16 rm_seek; 1.225 + 1.226 + // Do not use malloc below until heap_top adjustment (see <*>) 1.227 + if (read(pm.fd, rm_buf, rm_seek=0x400) != 0x400) { 1.228 + readfail: 1.229 + die(kernel_file_error); 1.230 + } 1.231 + 1.232 + if(!first1k->setup_sects) { 1.233 +#if 1 1.234 + if(* (int *) &first1k->pad10[0x3F-0x24] == 0x3AE8) { 1.235 + lseek(pm.fd,rm_seek=0x200,SEEK_SET); 1.236 + csip=((u32)topseg()<<16)+0x0042; 1.237 + } 1.238 + else 1.239 +#endif 1.240 + first1k->setup_sects=4; 1.241 + } 1.242 + rm_size = 0x200*(first1k->setup_sects+1); // 0th sector is not counted there 1.243 + if(rm_size>_32k || first1k->boot_flag != 0xAA55) 1.244 + die("It's not a kernel"); 1.245 + heap_top = rm_buf+rm_size; // <*> 1.246 + 1.247 + // Read remaining rm loader 1.248 + 1.249 + { 1.250 + u16 cnt = rm_size-rm_seek; 1.251 + if (read(pm.fd, rm_buf+rm_seek, cnt) != cnt) goto readfail; 1.252 + } 1.253 + } 1.254 + 1.255 + // Tell rm loader some info 1.256 + 1.257 + if(vid_mode) first1k->vid_mode = vid_mode; 1.258 + if(root_dev) first1k->root_dev = root_dev; 1.259 + version_string = 0; 1.260 + 1.261 +#if 1 1.262 + if(first1k->header == HdrS) { // starting linux 1.3.73 1.263 + if(first1k->loadflags & 1) { 1.264 +#else 1.265 + if((first1k->header != HdrS) || (first1k->loadflags & 1) == 0) 1.266 + die("I can't load bzImage low"); 1.267 + { 1.268 + { 1.269 +#endif 1.270 + pm_high++; 1.271 + 1.272 + // Hook on int15 to work around fn 88 DOS breakage 1.273 + hook_int15_88(); 1.274 + 1.275 + // * will be called just before rm -> pm 1.276 + first1k->realmode_switch_ofs = ofs(last_ditch); 1.277 + first1k->realmode_switch_seg = seg(last_ditch); 1.278 + } 1.279 + if(first1k->kernel_version) 1.280 + version_string = (char *) first1k+first1k->kernel_version+0x200; 1.281 + first1k->type_of_loader = 0xff; // kernel do not know us (yet :-) 1.282 + if(first1k->version >= 0x201) { 1.283 + // * offset limit of the setup heap 1.284 + // heap_end_ptr appears to be relative to the start of setup (ofs 0x0200) 1.285 + first1k->heap_end_ptr = _32k-0x0200; 1.286 + first1k->loadflags |= 0x80; // says to rm loader it's ok to use heap 1.287 + } 1.288 + // * if we will ever stop moving ourself to 0x90000 1.289 + // we must say setup.S how much to move 1.290 + //first1k->setup_move_size = _32k; 1.291 + if(first1k->version >= 0x202) { // starting linux 2.4.0-test3-pre3 1.292 + first1k->cmd_line_ptr = (((u32)(topseg()+0x0800))<<4); 1.293 + goto cmd_line_ok; 1.294 + } 1.295 + } 1.296 + first1k->cl_magic = 0xA33F; 1.297 + first1k->cl_ofs = 0x8000; 1.298 + } 1.299 + 1.300 +cmd_line_ok: 1.301 + // Check and enable A20 if needed 1.302 + enable_a20_or_die(); 1.303 + 1.304 + // Read remaining kernel (pm part) 1.305 + // Try to load kernel high, maybe even blindly storing it 1.306 + // in unallocated memory as a last resort 1.307 + 1.308 + pm.fallback = (u32((u16(_CS)+0x1FFF)&0xF000)<<4); 1.309 + pm.size -= rm_size; 1.310 + if(pm.fallback+pm.size > (((u32)topseg())<<4) || pm_high) { 1.311 + pm.fallback = _1m+_64k; 1.312 + } 1.313 + 1.314 + load_image(&pm); 1.315 + return version_string; 1.316 +} 1.317 + 1.318 +// Read initrd if needed 1.319 + 1.320 +static const char msg_initrd[] = "Can't use initrd file"; 1.321 +void load_initrd() { 1.322 + struct image_himem *m = &initrd; 1.323 + if (!initrd_name && !initrd.fd) return; 1.324 + if (!pm.fd) { 1.325 +noinitrd: 1.326 + puts(msg_initrd); 1.327 + return; 1.328 + } 1.329 + m->errmsg = msg_initrd; 1.330 + open_image(initrd_name, m); 1.331 + 1.332 + m->fallback = (memtop()-m->size) & (~PAGE_MASK); 1.333 + if (m->fallback < pm.fallback + pm.size) { 1.334 + close(m->fd); 1.335 + goto noinitrd; 1.336 + } 1.337 + 1.338 + load_image(m); 1.339 + struct first1k_t *first1k = (first1k_t*)rm_buf; 1.340 + if(first1k->header == HdrS) { 1.341 + first1k->initrd_buf = m->fallback; 1.342 + first1k->initrd_size = m->size; 1.343 + } 1.344 +} 1.345 + 1.346 +void boot_kernel() { 1.347 + 1.348 + // Shrink stack: we won't need much of it now and have no malloc() plans 1.349 + { 1.350 + u16 new_SP=u16(heap_top)+0x100; 1.351 + if(_SP>new_SP) _SP=new_SP; 1.352 + } 1.353 + if( u16(_CS)+(u16(_SP)>>4) >= topseg() ) { 1.354 + // Oops! We can stomp on our toes... better stop now 1.355 + die("Loaded too close to 9000:0"); 1.356 + } 1.357 + 1.358 + cli(); // we start doing destructive things to DOS 1.359 + 1.360 + // Move rm loader & commandline to 0x90000 1.361 + if(vcpi==0) { 1.362 + memcpy32( 1.363 + topseg(),0, 1.364 + seg(rm_buf),ofs(rm_buf), 1.365 + rm_size //_32k 1.366 + ); 1.367 + memcpy32( 1.368 + topseg()+0x0800,0, 1.369 + seg(cmdline),ofs(cmdline), 1.370 + PAGE_SIZE 1.371 + ); 1.372 + } else { //vcpi 1.373 + u32 dst=((u32)topseg()<<4); 1.374 + u16 pos=ofs(rm_buf); 1.375 + do { 1.376 + memcpy_vcpi(dst,seg(rm_buf),pos); 1.377 + dst+=PAGE_SIZE; 1.378 + pos+=PAGE_SIZE; 1.379 + rm_size-=PAGE_SIZE; 1.380 + } while(s16(rm_size) > 0); 1.381 + // overkill: copy PAGE_SIZE bytes 1.382 + memcpy_vcpi(((u32)(topseg()+0x0800)<<4),seg(cmdline),ofs(cmdline)); 1.383 + } 1.384 + 1.385 + // Jump to kernel rm code 1.386 + set_sregs_jump_seg_ofs(csip, sssp); 1.387 +}