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 +}