Adding upstream version 3.35.
[syslinux-debian/hramrach.git] / memdisk / setup.c
blob8c83f039d1a7096193b9283049993ae784ef23a2
1 /* ----------------------------------------------------------------------- *
3 * Copyright 2001-2006 H. Peter Anvin - All Rights Reserved
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, Inc., 53 Temple Place Ste 330,
8 * Boston MA 02111-1307, USA; either version 2 of the License, or
9 * (at your option) any later version; incorporated herein by reference.
11 * ----------------------------------------------------------------------- */
13 #include <stdint.h>
14 #include "e820.h"
15 #include "conio.h"
16 #include "version.h"
17 #include "memdisk.h"
19 const char memdisk_version[] =
20 "MEMDISK " VERSION " " DATE;
21 const char copyright[] =
22 "Copyright " FIRSTYEAR "-" COPYYEAR " H. Peter Anvin";
24 extern const char _binary_memdisk_bin_start[], _binary_memdisk_bin_end[];
25 extern const char _binary_memdisk_bin_size[]; /* Weird, I know */
27 struct memdisk_header {
28 uint16_t int13_offs;
29 uint16_t int15_offs;
30 uint16_t patch_offs;
31 uint16_t total_size;
34 /* The Disk Parameter Table may be required */
35 typedef union {
36 struct hd_dpt {
37 uint16_t max_cyl; /* Max cylinder */
38 uint8_t max_head; /* Max head */
39 uint8_t junk1[5]; /* Obsolete junk, leave at zero */
40 uint8_t ctrl; /* Control byte */
41 uint8_t junk2[7]; /* More obsolete junk */
42 } hd;
43 struct fd_dpt {
44 uint8_t specify1; /* "First specify byte" */
45 uint8_t specify2; /* "Second specify byte" */
46 uint8_t delay; /* Delay until motor turn off */
47 uint8_t sectors; /* Sectors/track */
49 uint8_t bps; /* Bytes/sector (02h = 512) */
50 uint8_t isgap; /* Length of intersector gap */
51 uint8_t dlen; /* Data length (0FFh) */
52 uint8_t fgap; /* Formatting gap */
54 uint8_t ffill; /* Format fill byte */
55 uint8_t settle; /* Head settle time (ms) */
56 uint8_t mstart; /* Motor start time */
57 uint8_t _pad1; /* Padding */
59 uint32_t old_fd_dpt; /* Extension: pointer to old INT 1Eh */
60 } fd;
61 } dpt_t;
63 struct patch_area {
64 uint32_t diskbuf;
65 uint32_t disksize;
66 uint16_t cmdline_off, cmdline_seg;
68 uint32_t oldint13;
69 uint32_t oldint15;
71 uint16_t olddosmem;
72 uint8_t bootloaderid;
74 uint8_t _pad[3];
75 uint16_t memint1588;
77 uint16_t cylinders;
78 uint16_t heads;
79 uint32_t sectors;
81 uint32_t mem1mb;
82 uint32_t mem16mb;
84 uint8_t driveno;
85 uint8_t drivetype;
86 uint8_t drivecnt;
87 uint8_t configflags;
89 #define CONFIG_READONLY 0x01
90 #define CONFIG_RAW 0x02
91 #define CONFIG_SAFEINT 0x04
92 #define CONFIG_BIGRAW 0x08 /* MUST be 8! */
94 uint16_t mystack;
95 uint16_t statusptr;
97 dpt_t dpt;
100 /* This is the header in the boot sector/setup area */
101 struct setup_header {
102 char cmdline[0x1f1];
103 uint8_t setup_secs;
104 uint16_t syssize;
105 uint16_t swap_dev;
106 uint16_t ram_size;
107 uint16_t vid_mode;
108 uint16_t root_dev;
109 uint16_t boot_flag;
110 uint16_t jump;
111 char header[4];
112 uint16_t version;
113 uint32_t realmode_swtch;
114 uint32_t start_sys;
115 uint8_t type_of_loader;
116 uint8_t loadflags;
117 uint16_t setup_move_size;
118 uint32_t code32_start;
119 uint32_t ramdisk_image;
120 uint32_t ramdisk_size;
121 uint32_t bootsect_kludge;
122 uint16_t head_end_ptr;
123 uint16_t pad1;
124 uint32_t cmd_line_ptr;
125 uint32_t initrd_addr_max;
126 uint32_t esdi;
127 uint32_t edx;
130 struct setup_header * const shdr = (struct setup_header *)(LOW_SEG << 4);
132 /* Access to high memory */
134 /* Access to objects in the zero page */
135 static inline void
136 wrz_8(uint32_t addr, uint8_t data)
138 *((uint8_t *)addr) = data;
140 static inline void
141 wrz_16(uint32_t addr, uint16_t data)
143 *((uint16_t *)addr) = data;
145 static inline void
146 wrz_32(uint32_t addr, uint32_t data)
148 *((uint32_t *)addr) = data;
150 static inline uint8_t
151 rdz_8(uint32_t addr)
153 return *((uint8_t *)addr);
155 static inline uint16_t
156 rdz_16(uint32_t addr)
158 return *((uint16_t *)addr);
160 static inline uint32_t
161 rdz_32(uint32_t addr)
163 return *((uint32_t *)addr);
166 /* Addresses in the zero page */
167 #define BIOS_INT13 (0x13*4) /* INT 13h vector */
168 #define BIOS_INT15 (0x15*4) /* INT 15h vector */
169 #define BIOS_INT1E (0x1E*4) /* INT 1Eh vector */
170 #define BIOS_INT40 (0x40*4) /* INT 13h vector */
171 #define BIOS_INT41 (0x41*4) /* INT 41h vector */
172 #define BIOS_INT46 (0x46*4) /* INT 46h vector */
173 #define BIOS_BASEMEM 0x413 /* Amount of DOS memory */
174 #define BIOS_EQUIP 0x410 /* BIOS equipment list */
175 #define BIOS_HD_COUNT 0x475 /* Number of hard drives present */
178 * Routine to seek for a command-line item and return a pointer
179 * to the data portion, if present
182 /* Magic return values */
183 #define CMD_NOTFOUND ((char *)-1) /* Not found */
184 #define CMD_BOOL ((char *)-2) /* Found boolean option */
185 #define CMD_HASDATA(X) ((int)(X) >= 0)
187 const char *getcmditem(const char *what)
189 const char *p;
190 const char *wp = what;
191 int match = 0;
193 for ( p = shdr->cmdline ; *p ; p++ ) {
194 switch ( match ) {
195 case 0: /* Ground state */
196 if ( *p == ' ' )
197 break;
199 wp = what;
200 match = 1;
201 /* Fall through */
203 case 1: /* Matching */
204 if ( *wp == '\0' ) {
205 if ( *p == '=' )
206 return p+1;
207 else if ( *p == ' ' )
208 return CMD_BOOL;
209 else {
210 match = 2;
211 break;
214 if ( *p != *wp++ )
215 match = 2;
216 break;
218 case 2: /* Mismatch, skip rest of option */
219 if ( *p == ' ' )
220 match = 0; /* Next option */
221 break;
225 /* Check for matching string at end of line */
226 if ( match == 1 && *wp == '\0' )
227 return CMD_BOOL;
229 return CMD_NOTFOUND;
233 * Check to see if this is a gzip image
235 #define UNZIP_ALIGN 512
237 extern void _end; /* Symbol signalling end of data */
239 void unzip_if_needed(uint32_t *where_p, uint32_t *size_p)
241 uint32_t where = *where_p;
242 uint32_t size = *size_p;
243 uint32_t zbytes;
244 uint32_t startrange, endrange;
245 uint32_t gzdatasize, gzwhere;
246 uint32_t orig_crc, offset;
247 uint32_t target = 0;
248 int i, okmem;
250 /* Is it a gzip image? */
251 if (check_zip ((void *)where, size, &zbytes, &gzdatasize,
252 &orig_crc, &offset) == 0) {
254 if (offset + zbytes > size) {
255 /* Assertion failure; check_zip is supposed to guarantee this
256 never happens. */
257 puts("internal error: check_zip returned nonsense\n");
258 die();
261 /* Find a good place to put it: search memory ranges in descending order
262 until we find one that is legal and fits */
263 okmem = 0;
264 for ( i = nranges-1 ; i >= 0 ; i-- ) {
265 /* We can't use > 4G memory (32 bits only.) Truncate to 2^32-1
266 so we don't have to deal with funny wraparound issues. */
268 /* Must be memory */
269 if ( ranges[i].type != 1 )
270 continue;
272 /* Range start */
273 if ( ranges[i].start >= 0xFFFFFFFF )
274 continue;
275 startrange = (uint32_t)ranges[i].start;
277 /* Range end (0 for end means 2^64) */
278 endrange = ((ranges[i+1].start >= 0xFFFFFFFF ||
279 ranges[i+1].start == 0)
280 ? 0xFFFFFFFF : (uint32_t)ranges[i+1].start);
282 /* Make sure we don't overwrite ourselves */
283 if ( startrange < (uint32_t)&_end )
284 startrange = (uint32_t)&_end;
286 /* Allow for alignment */
287 startrange = (ranges[i].start + (UNZIP_ALIGN-1)) & ~(UNZIP_ALIGN-1);
289 /* In case we just killed the whole range... */
290 if ( startrange >= endrange )
291 continue;
293 /* Must be large enough... don't rely on gzwhere for this (wraparound) */
294 if ( endrange-startrange < gzdatasize )
295 continue;
297 /* This is where the gz image should be put if we put it in this range */
298 gzwhere = (endrange - gzdatasize) & ~(UNZIP_ALIGN-1);
300 /* Cast to uint64_t just in case we're flush with the top byte */
301 if ( (uint64_t)where+size >= gzwhere && where < endrange ) {
302 /* Need to move source data to avoid compressed/uncompressed overlap */
303 uint32_t newwhere;
305 if ( gzwhere-startrange < size )
306 continue; /* Can't fit both old and new */
308 newwhere = (gzwhere - size) & ~(UNZIP_ALIGN-1);
309 printf("Moving compressed data from 0x%08x to 0x%08x\n",
310 where, newwhere);
312 /* Our memcpy() is OK, because we always move from a higher
313 address to a lower one */
314 memcpy((void *)newwhere, (void *)where, size);
315 where = newwhere;
318 target = gzwhere;
319 okmem = 1;
320 break;
323 if ( !okmem ) {
324 printf("Not enough memory to decompress image (need 0x%08x bytes)\n",
325 gzdatasize);
326 die();
329 printf("gzip image: decompressed addr 0x%08x, len 0x%08x: ",
330 target, gzdatasize);
332 *size_p = gzdatasize;
333 *where_p = (uint32_t)unzip((void *)(where + offset), zbytes,
334 gzdatasize, orig_crc, (void *)target);
339 * Figure out the "geometry" of the disk in question
341 struct geometry {
342 uint32_t sectors; /* 512-byte sector count */
343 uint32_t c, h, s; /* C/H/S geometry */
344 uint32_t offset; /* Byte offset for disk */
345 uint8_t type; /* Type byte for INT 13h AH=08h */
346 uint8_t driveno; /* Drive no */
349 static const struct geometry geometries[] =
351 { 360*2, 40, 2, 9, 0, 0x01, 0 }, /* 360 K */
352 { 720*2, 80, 2, 9, 0, 0x03, 0 }, /* 720 K*/
353 { 1200*2, 80, 2, 15, 0, 0x02, 0 }, /* 1200 K */
354 { 1440*2, 80, 2, 18, 0, 0x04, 0 }, /* 1440 K */
355 { 1680*2, 80, 2, 21, 0, 0x04, 0 }, /* 1680 K */
356 { 1722*2, 82, 2, 21, 0, 0x04, 0 }, /* 1722 K */
357 { 2880*2, 80, 2, 36, 0, 0x06, 0 }, /* 2880 K */
358 { 3840*2, 80, 2, 48, 0, 0x06, 0 }, /* 3840 K */
360 #define known_geometries (sizeof(geometries)/sizeof(struct geometry))
362 /* Format of a DOS partition table entry */
363 struct ptab_entry {
364 uint8_t active;
365 uint8_t start_h, start_s, start_c;
366 uint8_t type;
367 uint8_t end_h, end_s, end_c;
368 uint32_t start;
369 uint32_t size;
372 /* Format of a DOSEMU header */
373 struct dosemu_header {
374 uint8_t magic[7]; /* DOSEMU\0 */
375 uint32_t h;
376 uint32_t s;
377 uint32_t c;
378 uint32_t offset;
379 uint8_t pad[105];
380 } __attribute__((packed));
382 #define FOUR(a,b,c,d) (((a) << 24)|((b) << 16)|((c) << 8)|(d))
384 const struct geometry *get_disk_image_geometry(uint32_t where, uint32_t size)
386 static struct geometry hd_geometry = { 0, 0, 0, 0, 0, 0, 0x80 };
387 struct ptab_entry ptab[4]; /* Partition table buffer */
388 struct dosemu_header dosemu;
389 unsigned int sectors, v;
390 unsigned int max_c, max_h, max_s;
391 unsigned int c, h, s, offset;
392 int i;
393 int drive_specified;
394 const char *p;
396 printf("command line: %s\n", shdr->cmdline);
398 offset = 0;
399 if ( CMD_HASDATA(p = getcmditem("offset")) && (v = atou(p)) )
400 offset = v;
402 sectors = (size-offset) >> 9;
403 for ( i = 0 ; i < known_geometries ; i++ ) {
404 if ( sectors == geometries[i].sectors ) {
405 hd_geometry = geometries[i];
406 break;
410 hd_geometry.sectors = sectors;
411 hd_geometry.offset = offset;
413 /* Do we have a DOSEMU header? */
414 memcpy(&dosemu, (char *)where+hd_geometry.offset, sizeof dosemu);
415 if ( !memcmp("DOSEMU", dosemu.magic, 7) ) {
416 /* Always a hard disk unless overruled by command-line options */
417 hd_geometry.driveno = 0x80;
418 hd_geometry.type = 0;
419 hd_geometry.c = dosemu.c;
420 hd_geometry.h = dosemu.h;
421 hd_geometry.s = dosemu.s;
422 hd_geometry.offset += dosemu.offset;
423 sectors = (size-hd_geometry.offset) >> 9;
426 if ( CMD_HASDATA(p = getcmditem("c")) && (v = atou(p)) )
427 hd_geometry.c = v;
428 if ( CMD_HASDATA(p = getcmditem("h")) && (v = atou(p)) )
429 hd_geometry.h = v;
430 if ( CMD_HASDATA(p = getcmditem("s")) && (v = atou(p)) )
431 hd_geometry.s = v;
433 if ( (p = getcmditem("floppy")) != CMD_NOTFOUND ) {
434 hd_geometry.driveno = CMD_HASDATA(p) ? atou(p) & 0x7f : 0;
435 if ( hd_geometry.type == 0 )
436 hd_geometry.type = 0x10; /* ATAPI floppy, e.g. LS-120 */
437 drive_specified = 1;
438 } else if ( (p = getcmditem("harddisk")) != CMD_NOTFOUND ) {
439 hd_geometry.driveno = CMD_HASDATA(p) ? atou(p) | 0x80 : 0x80;
440 hd_geometry.type = 0;
441 drive_specified = 1;
444 if ( (hd_geometry.c == 0) || (hd_geometry.h == 0) ||
445 (hd_geometry.s == 0) ) {
446 /* Hard disk image, need to examine the partition table for geometry */
447 memcpy(&ptab, (char *)where+hd_geometry.offset+(512-2-4*16), sizeof ptab);
449 max_c = max_h = 0; max_s = 1;
450 for ( i = 0 ; i < 4 ; i++ ) {
451 if ( ptab[i].type ) {
452 c = ptab[i].start_c + (ptab[i].start_s >> 6);
453 s = (ptab[i].start_s & 0x3f);
454 h = ptab[i].start_h;
456 if ( max_c < c ) max_c = c;
457 if ( max_h < h ) max_h = h;
458 if ( max_s < s ) max_s = s;
460 c = ptab[i].end_c + (ptab[i].end_s >> 6);
461 s = (ptab[i].end_s & 0x3f);
462 h = ptab[i].end_h;
464 if ( max_c < c ) max_c = c;
465 if ( max_h < h ) max_h = h;
466 if ( max_s < s ) max_s = s;
470 max_c++; max_h++; /* Convert to count (1-based) */
472 if ( !hd_geometry.h )
473 hd_geometry.h = max_h;
474 if ( !hd_geometry.s )
475 hd_geometry.s = max_s;
476 if ( !hd_geometry.c )
477 hd_geometry.c = sectors/(hd_geometry.h*hd_geometry.s);
480 if ( (size-hd_geometry.offset) & 0x1ff ) {
481 puts("MEMDISK: Image has fractional end sector\n");
483 if ( sectors % (hd_geometry.h*hd_geometry.s) ) {
484 puts("MEMDISK: Image seems to have fractional end cylinder\n");
486 if ( (hd_geometry.c*hd_geometry.h*hd_geometry.s) > sectors ) {
487 puts("MEMDISK: Image appears to be truncated\n");
490 return &hd_geometry;
494 * Jump here if all hope is gone...
496 void __attribute__((noreturn)) die(void)
498 asm volatile("sti");
499 for(;;)
500 asm volatile("hlt");
504 * Find a $PnP installation check structure; return (ES << 16) + DI value
506 static uint32_t pnp_install_check(void)
508 uint32_t *seg;
509 unsigned char *p, csum;
510 int i, len;
512 for (seg = (uint32_t *)0xf0000; seg < (uint32_t *)0x100000; seg += 4) {
513 if (*seg == ('$'+('P' << 8)+('n' << 16)+('P' << 24))) {
514 p = (unsigned char *)seg;
515 len = p[5];
516 if (len < 0x21)
517 continue;
518 csum = 0;
519 for (i = len; i; i--)
520 csum += *p++;
521 if (csum != 0)
522 continue;
524 return (0xf000 << 16) + (uint16_t)(unsigned long)seg;
528 return 0;
531 #define STACK_NEEDED 512 /* Number of bytes of stack */
534 * Actual setup routine
535 * Returns the drive number (which is then passed in %dl to the
536 * called routine.)
538 syscall_t syscall;
539 void *sys_bounce;
541 void setup(syscall_t cs_syscall, void *cs_bounce)
543 unsigned int bin_size = (int) &_binary_memdisk_bin_size;
544 struct memdisk_header *hptr;
545 struct patch_area *pptr;
546 uint16_t driverseg;
547 uint32_t driverptr, driveraddr;
548 uint16_t dosmem_k;
549 uint32_t stddosmem;
550 const struct geometry *geometry;
551 int total_size, cmdlinelen;
552 com32sys_t regs;
553 uint32_t ramdisk_image, ramdisk_size;
554 int bios_drives;
556 /* Set up global variables */
557 syscall = cs_syscall;
558 sys_bounce = cs_bounce;
560 /* Show signs of life */
561 printf("%s %s\n", memdisk_version, copyright);
563 if ( !shdr->ramdisk_image || !shdr->ramdisk_size ) {
564 puts("MEMDISK: No ramdisk image specified!\n");
565 die();
568 ramdisk_image = shdr->ramdisk_image;
569 ramdisk_size = shdr->ramdisk_size;
571 e820map_init(); /* Initialize memory data structure */
572 get_mem(); /* Query BIOS for memory map */
573 parse_mem(); /* Parse memory map */
575 printf("Ramdisk at 0x%08x, length 0x%08x\n",
576 ramdisk_image, ramdisk_size);
578 unzip_if_needed(&ramdisk_image, &ramdisk_size);
580 geometry = get_disk_image_geometry(ramdisk_image, ramdisk_size);
582 printf("Disk is %s %d, %u K, C/H/S = %u/%u/%u\n",
583 (geometry->driveno & 0x80) ? "hard disk" : "floppy",
584 geometry->driveno & 0x7f,
585 geometry->sectors >> 1,
586 geometry->c, geometry->h, geometry->s);
588 /* Reserve the ramdisk memory */
589 insertrange(ramdisk_image, ramdisk_size, 2);
590 parse_mem(); /* Recompute variables */
592 /* Figure out where it needs to go */
593 hptr = (struct memdisk_header *) &_binary_memdisk_bin_start;
594 pptr = (struct patch_area *)(_binary_memdisk_bin_start + hptr->patch_offs);
596 dosmem_k = rdz_16(BIOS_BASEMEM);
597 pptr->olddosmem = dosmem_k;
598 stddosmem = dosmem_k << 10;
599 /* If INT 15 E820 and INT 12 disagree, go with the most conservative */
600 if ( stddosmem > dos_mem )
601 stddosmem = dos_mem;
603 pptr->driveno = geometry->driveno;
604 pptr->drivetype = geometry->type;
605 pptr->cylinders = geometry->c;
606 pptr->heads = geometry->h;
607 pptr->sectors = geometry->s;
608 pptr->disksize = geometry->sectors;
609 pptr->diskbuf = ramdisk_image + geometry->offset;
610 pptr->statusptr = (geometry->driveno & 0x80) ? 0x474 : 0x441;
612 pptr->bootloaderid = shdr->type_of_loader;
614 pptr->configflags = 0;
615 /* Set config flags */
616 if ( getcmditem("ro") != CMD_NOTFOUND ) {
617 puts("Marking disk readonly\n");
618 pptr->configflags |= CONFIG_READONLY;
620 if ( getcmditem("raw") != CMD_NOTFOUND ) {
621 puts("Using raw access to high memory\n");
622 pptr->configflags &= ~CONFIG_SAFEINT|CONFIG_BIGRAW;
623 pptr->configflags |= CONFIG_RAW;
625 if ( getcmditem("safeint") != CMD_NOTFOUND ) {
626 puts("Using safe INT 15h access to high memory\n");
627 pptr->configflags &= ~CONFIG_RAW|CONFIG_BIGRAW;
628 pptr->configflags |= CONFIG_SAFEINT;
630 if ( getcmditem("bigraw") != CMD_NOTFOUND ) {
631 puts("Using raw access to high memory - assuming big real mode\n");
632 pptr->configflags &= ~CONFIG_SAFEINT;
633 pptr->configflags |= CONFIG_BIGRAW|CONFIG_RAW;
636 /* Set up a drive parameter table */
637 if ( geometry->driveno & 0x80 ) {
638 /* Hard disk */
639 pptr->dpt.hd.max_cyl = geometry->c-1;
640 pptr->dpt.hd.max_head = geometry->h-1;
641 pptr->dpt.hd.ctrl = (geometry->h > 8) ? 0x08: 0;
642 } else {
643 /* Floppy - most of these fields are bogus and mimic
644 a 1.44 MB floppy drive */
645 pptr->dpt.fd.specify1 = 0xdf;
646 pptr->dpt.fd.specify2 = 0x02;
647 pptr->dpt.fd.delay = 0x25;
648 pptr->dpt.fd.sectors = geometry->s;
649 pptr->dpt.fd.bps = 0x02;
650 pptr->dpt.fd.isgap = 0x12;
651 pptr->dpt.fd.dlen = 0xff;
652 pptr->dpt.fd.fgap = 0x6c;
653 pptr->dpt.fd.ffill = 0xf6;
654 pptr->dpt.fd.settle = 0x0f;
655 pptr->dpt.fd.mstart = 0x05;
657 pptr->dpt.fd.old_fd_dpt = rdz_32(BIOS_INT1E);
660 /* The size is given by hptr->total_size plus the size of the E820
661 map -- 12 bytes per range; we may need as many as 2 additional
662 ranges (each insertrange() can worst-case turn 1 area into 3)
663 plus the terminating range, over what nranges currently show. */
664 cmdlinelen = strlen(shdr->cmdline)+1;
665 total_size = hptr->total_size; /* Actual memdisk code */
666 total_size += (nranges+3)*sizeof(ranges[0]); /* E820 memory ranges */
667 total_size += cmdlinelen; /* Command line */
668 total_size += STACK_NEEDED; /* Stack */
669 printf("Total size needed = %u bytes, allocating %uK\n",
670 total_size, (total_size+0x3ff) >> 10);
672 if ( total_size > dos_mem ) {
673 puts("MEMDISK: Insufficient low memory\n");
674 die();
677 driveraddr = stddosmem - total_size;
678 driveraddr &= ~0x3FF;
680 printf("Old dos memory at 0x%05x (map says 0x%05x), loading at 0x%05x\n",
681 stddosmem, dos_mem, driveraddr);
683 /* Reserve this range of memory */
684 wrz_16(BIOS_BASEMEM, driveraddr >> 10);
685 insertrange(driveraddr, dos_mem-driveraddr, 2);
686 parse_mem();
688 pptr->mem1mb = low_mem >> 10;
689 pptr->mem16mb = high_mem >> 16;
690 if ( low_mem == (15 << 20) ) {
691 /* lowmem maxed out */
692 uint32_t int1588mem = (high_mem >> 10)+(low_mem >> 10);
693 pptr->memint1588 = (int1588mem > 0xffff) ? 0xffff : int1588mem;
694 } else {
695 pptr->memint1588 = low_mem >> 10;
698 printf("1588: 0x%04x 15E801: 0x%04x 0x%04x\n",
699 pptr->memint1588, pptr->mem1mb, pptr->mem16mb);
701 driverseg = driveraddr >> 4;
702 driverptr = driverseg << 16;
704 /* Anything beyond the end is for the stack */
705 pptr->mystack = (uint16_t)(stddosmem-driveraddr);
707 pptr->oldint13 = rdz_32(BIOS_INT13);
708 pptr->oldint15 = rdz_32(BIOS_INT15);
710 /* Adjust the E820 table: if there are null ranges (type 0)
711 at the end, change them to type end of list (-1).
712 This is necessary for the driver to be able to report end
713 of list correctly. */
714 while ( nranges && ranges[nranges-1].type == 0 ) {
715 ranges[--nranges].type = -1;
718 /* Query drive parameters of this type */
719 memset(&regs, 0, sizeof regs);
720 regs.es = 0;
721 regs.eax.b[1] = 0x08;
722 regs.edx.b[0] = geometry->driveno & 0x80;
723 syscall(0x13, &regs, &regs);
725 if ( regs.eflags.l & 1 ) {
726 printf("INT 13 08: Failure, assuming this is the only drive\n");
727 pptr->drivecnt = 0;
728 } else {
729 printf("INT 13 08: Success, count = %u, BPT = %04x:%04x\n",
730 regs.edx.b[0], regs.es, regs.edi.w[0]);
731 pptr->drivecnt = regs.edx.b[0];
734 /* Compare what INT 13h returned with the appropriate equipment byte */
735 if ( geometry->driveno & 0x80 ) {
736 bios_drives = rdz_8(BIOS_HD_COUNT);
737 } else {
738 uint8_t equip = rdz_8(BIOS_EQUIP);
740 if (equip & 1)
741 bios_drives = (equip >> 6)+1;
742 else
743 bios_drives = 0;
746 if (pptr->drivecnt > bios_drives) {
747 printf("BIOS equipment byte says count = %d, go with that\n", bios_drives);
748 pptr->drivecnt = bios_drives;
751 /* Discontiguous drive space. There is no really good solution for this. */
752 if ( pptr->drivecnt <= (geometry->driveno & 0x7f) )
753 pptr->drivecnt = (geometry->driveno & 0x7f) + 1;
755 /* Pointer to the command line */
756 pptr->cmdline_off = bin_size + (nranges+1)*sizeof(ranges[0]);
757 pptr->cmdline_seg = driverseg;
759 /* Copy driver followed by E820 table followed by command line */
761 unsigned char *dpp = (unsigned char *)(driverseg << 4);
762 dpp = memcpy_endptr(dpp, &_binary_memdisk_bin_start, bin_size);
763 dpp = memcpy_endptr(dpp, ranges, (nranges+1)*sizeof(ranges[0]));
764 dpp = memcpy_endptr(dpp, shdr->cmdline, cmdlinelen+1);
767 /* Install the interrupt handlers */
768 printf("old: int13 = %08x int15 = %08x\n",
769 rdz_32(BIOS_INT13), rdz_32(BIOS_INT15));
771 wrz_32(BIOS_INT13, driverptr+hptr->int13_offs);
772 wrz_32(BIOS_INT15, driverptr+hptr->int15_offs);
774 printf("new: int13 = %08x int15 = %08x\n",
775 rdz_32(BIOS_INT13), rdz_32(BIOS_INT15));
777 /* Update various BIOS magic data areas (gotta love this shit) */
779 if ( geometry->driveno & 0x80 ) {
780 /* Update BIOS hard disk count */
781 uint8_t nhd = pptr->drivecnt;
783 if ( nhd > 128 )
784 nhd = 128;
786 wrz_8(BIOS_HD_COUNT, nhd);
787 } else {
788 /* Update BIOS floppy disk count */
789 uint8_t equip = rdz_8(BIOS_EQUIP);
790 uint8_t nflop = pptr->drivecnt;
792 if ( nflop > 4 ) /* Limit of equipment byte */
793 nflop = 4;
795 equip &= 0x3E;
796 if ( nflop )
797 equip |= ((nflop-1) << 6) | 0x01;
799 wrz_8(BIOS_EQUIP, equip);
802 /* Reboot into the new "disk"; this is also a test for the interrupt hooks */
803 puts("Loading boot sector... ");
805 memset(&regs, 0, sizeof regs);
806 // regs.es = 0;
807 regs.eax.w[0] = 0x0201; /* Read sector */
808 regs.ebx.w[0] = 0x7c00; /* 0000:7C00 */
809 regs.ecx.w[0] = 1; /* One sector */
810 regs.edx.w[0] = geometry->driveno;
811 syscall(0x13, &regs, &regs);
813 if ( regs.eflags.l & 1 ) {
814 puts("MEMDISK: Failed to load new boot sector\n");
815 die();
818 if ( getcmditem("pause") != CMD_NOTFOUND ) {
819 puts("press any key to boot... ");
820 regs.eax.w[0] = 0;
821 syscall(0x16, &regs, NULL);
824 puts("booting...\n");
826 /* On return the assembly code will jump to the boot vector */
827 shdr->esdi = pnp_install_check();
828 shdr->edx = geometry->driveno;