123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200 |
- #include "realmode.h"
-
- struct segheader
- {
- unsigned char length;
- unsigned char vendortag;
- unsigned char reserved;
- unsigned char flags;
- unsigned long loadaddr;
- unsigned long imglength;
- unsigned long memlength;
- };
-
- struct imgheader
- {
- unsigned long magic;
- unsigned long length; /* and flags */
- union
- {
- segoff_t segoff;
- unsigned long location;
- } u;
- unsigned long execaddr;
- };
-
- /* Keep all context about loaded image in one place */
- static struct tagged_context
- {
- struct imgheader img; /* copy of header */
- unsigned long linlocation; /* addr of header */
- unsigned long last0, last1; /* of prev segment */
- unsigned long segaddr, seglen; /* of current segment */
- unsigned char segflags;
- unsigned char first;
- unsigned long curaddr;
- } tctx;
-
- #define TAGGED_PROGRAM_RETURNS (tctx.img.length & 0x00000100) /* bit 8 */
- #define LINEAR_EXEC_ADDR (tctx.img.length & 0x80000000) /* bit 31 */
-
- static sector_t tagged_download(unsigned char *data, unsigned int len, int eof);
- void xstart16 (unsigned long execaddr, segoff_t location,
- void *bootp);
-
- static inline os_download_t tagged_probe(unsigned char *data, unsigned int len)
- {
- struct segheader *sh;
- unsigned long loc;
- if (*((uint32_t *)data) != 0x1B031336L) {
- return 0;
- }
- printf("(NBI)");
- /* If we don't have enough data give up */
- if (len < 512)
- return dead_download;
- /* Zero all context info */
- memset(&tctx, 0, sizeof(tctx));
- /* Copy first 4 longwords */
- memcpy(&tctx.img, data, sizeof(tctx.img));
- /* Memory location where we are supposed to save it */
- tctx.segaddr = tctx.linlocation =
- ((tctx.img.u.segoff.segment) << 4) + tctx.img.u.segoff.offset;
- if (!prep_segment(tctx.segaddr, tctx.segaddr + 512, tctx.segaddr + 512,
- 0, 512)) {
- return dead_download;
- }
- /* Now verify the segments we are about to load */
- loc = 512;
- for(sh = (struct segheader *)(data
- + ((tctx.img.length & 0x0F) << 2)
- + ((tctx.img.length & 0xF0) >> 2) );
- (sh->length > 0) && ((unsigned char *)sh < data + 512);
- sh = (struct segheader *)((unsigned char *)sh
- + ((sh->length & 0x0f) << 2) + ((sh->length & 0xf0) >> 2)) ) {
- if (!prep_segment(
- sh->loadaddr,
- sh->loadaddr + sh->imglength,
- sh->loadaddr + sh->imglength,
- loc, loc + sh->imglength)) {
- return dead_download;
- }
- loc = loc + sh->imglength;
- if (sh->flags & 0x04)
- break;
- }
- if (!(sh->flags & 0x04))
- return dead_download;
- /* Grab a copy */
- memcpy(phys_to_virt(tctx.segaddr), data, 512);
- /* Advance to first segment descriptor */
- tctx.segaddr += ((tctx.img.length & 0x0F) << 2)
- + ((tctx.img.length & 0xF0) >> 2);
- /* Remember to skip the first 512 data bytes */
- tctx.first = 1;
-
- return tagged_download;
-
- }
- static sector_t tagged_download(unsigned char *data, unsigned int len, int eof)
- {
- int i;
-
- if (tctx.first) {
- tctx.first = 0;
- if (len > 512) {
- len -= 512;
- data += 512;
- /* and fall through to deal with rest of block */
- } else
- return 0;
- }
- for (;;) {
- if (len == 0) /* Detect truncated files */
- eof = 0;
- while (tctx.seglen == 0) {
- struct segheader sh;
- if (tctx.segflags & 0x04) {
- done(1);
- if (LINEAR_EXEC_ADDR) {
- int result;
- /* no gateA20_unset for PM call */
- result = xstart32(tctx.img.execaddr,
- virt_to_phys(&loaderinfo),
- tctx.linlocation,
- virt_to_phys(BOOTP_DATA_ADDR));
- printf("Secondary program returned %d\n",
- result);
- if (!TAGGED_PROGRAM_RETURNS) {
- /* We shouldn't have returned */
- result = -2;
- }
- if (result == 0)
- result = -2;
- longjmp(restart_etherboot, result);
-
- } else {
- gateA20_unset();
- xstart16(tctx.img.execaddr,
- tctx.img.u.segoff,
- BOOTP_DATA_ADDR);
- longjmp(restart_etherboot, -2);
- }
- }
- sh = *((struct segheader *)phys_to_virt(tctx.segaddr));
- tctx.seglen = sh.imglength;
- if ((tctx.segflags = sh.flags & 0x03) == 0)
- tctx.curaddr = sh.loadaddr;
- else if (tctx.segflags == 0x01)
- tctx.curaddr = tctx.last1 + sh.loadaddr;
- else if (tctx.segflags == 0x02)
- tctx.curaddr = (Address)(meminfo.memsize * 1024L
- + 0x100000L)
- - sh.loadaddr;
- else
- tctx.curaddr = tctx.last0 - sh.loadaddr;
- tctx.last1 = (tctx.last0 = tctx.curaddr) + sh.memlength;
- tctx.segflags = sh.flags;
- tctx.segaddr += ((sh.length & 0x0F) << 2)
- + ((sh.length & 0xF0) >> 2);
- /* Avoid lock-up */
- if ( sh.length == 0 ) longjmp(restart_etherboot, -2);
- }
- if ((len <= 0) && !eof)
- break;
- i = (tctx.seglen > len) ? len : tctx.seglen;
- memcpy(phys_to_virt(tctx.curaddr), data, i);
- tctx.seglen -= i;
- tctx.curaddr += i;
- len -= i;
- data += i;
- }
- return 0;
- }
-
- void xstart16 (unsigned long execaddr, segoff_t location,
- void *bootp) {
- struct {
- segoff_t execaddr;
- segoff_t location;
- segoff_t bootp;
- } PACKED in_stack;
-
- /* AFAICT, execaddr is actually already a segment:offset */
- *((unsigned long *)&in_stack.execaddr) = execaddr;
- in_stack.location = location;
- in_stack.bootp.segment = SEGMENT(bootp);
- in_stack.bootp.offset = OFFSET(bootp);
-
- RM_FRAGMENT(rm_xstart16,
- "popl %eax\n\t" /* Calculated lcall */
- "pushw %cs\n\t"
- "call 1f\n1:\tpopw %bp\n\t"
- "leaw (2f-1b)(%bp), %bx\n\t"
- "pushw %bx\n\t"
- "pushl %eax\n\t"
- "lret\n2:\n\t"
- );
-
- real_call ( rm_xstart16, &in_stack, NULL );
- }
|