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 * ----------------------------------------------------------------------- */
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
{
34 /* The Disk Parameter Table may be required */
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 */
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 */
66 uint16_t cmdline_off
, cmdline_seg
;
89 #define CONFIG_READONLY 0x01
90 #define CONFIG_RAW 0x02
91 #define CONFIG_SAFEINT 0x04
92 #define CONFIG_BIGRAW 0x08 /* MUST be 8! */
100 /* This is the header in the boot sector/setup area */
101 struct setup_header
{
113 uint32_t realmode_swtch
;
115 uint8_t type_of_loader
;
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
;
124 uint32_t cmd_line_ptr
;
125 uint32_t initrd_addr_max
;
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 */
136 wrz_8(uint32_t addr
, uint8_t data
)
138 *((uint8_t *)addr
) = data
;
141 wrz_16(uint32_t addr
, uint16_t data
)
143 *((uint16_t *)addr
) = data
;
146 wrz_32(uint32_t addr
, uint32_t data
)
148 *((uint32_t *)addr
) = data
;
150 static inline uint8_t
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
)
190 const char *wp
= what
;
193 for ( p
= shdr
->cmdline
; *p
; p
++ ) {
195 case 0: /* Ground state */
203 case 1: /* Matching */
207 else if ( *p
== ' ' )
218 case 2: /* Mismatch, skip rest of option */
220 match
= 0; /* Next option */
225 /* Check for matching string at end of line */
226 if ( match
== 1 && *wp
== '\0' )
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
;
244 uint32_t startrange
, endrange
;
245 uint32_t gzdatasize
, gzwhere
;
246 uint32_t orig_crc
, offset
;
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
257 puts("internal error: check_zip returned nonsense\n");
261 /* Find a good place to put it: search memory ranges in descending order
262 until we find one that is legal and fits */
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. */
269 if ( ranges
[i
].type
!= 1 )
273 if ( ranges
[i
].start
>= 0xFFFFFFFF )
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
)
293 /* Must be large enough... don't rely on gzwhere for this (wraparound) */
294 if ( endrange
-startrange
< gzdatasize
)
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 */
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",
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
);
324 printf("Not enough memory to decompress image (need 0x%08x bytes)\n",
329 printf("gzip image: decompressed addr 0x%08x, len 0x%08x: ",
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
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 */
365 uint8_t start_h
, start_s
, start_c
;
367 uint8_t end_h
, end_s
, end_c
;
372 /* Format of a DOSEMU header */
373 struct dosemu_header
{
374 uint8_t magic
[7]; /* DOSEMU\0 */
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
;
396 printf("command line: %s\n", shdr
->cmdline
);
399 if ( CMD_HASDATA(p
= getcmditem("offset")) && (v
= atou(p
)) )
402 sectors
= (size
-offset
) >> 9;
403 for ( i
= 0 ; i
< known_geometries
; i
++ ) {
404 if ( sectors
== geometries
[i
].sectors
) {
405 hd_geometry
= geometries
[i
];
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
)) )
428 if ( CMD_HASDATA(p
= getcmditem("h")) && (v
= atou(p
)) )
430 if ( CMD_HASDATA(p
= getcmditem("s")) && (v
= atou(p
)) )
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 */
438 } else if ( (p
= getcmditem("harddisk")) != CMD_NOTFOUND
) {
439 hd_geometry
.driveno
= CMD_HASDATA(p
) ? atou(p
) | 0x80 : 0x80;
440 hd_geometry
.type
= 0;
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);
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);
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");
494 * Jump here if all hope is gone...
496 void __attribute__((noreturn
)) die(void)
504 * Find a $PnP installation check structure; return (ES << 16) + DI value
506 static uint32_t pnp_install_check(void)
509 unsigned char *p
, csum
;
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
;
519 for (i
= len
; i
; i
--)
524 return (0xf000 << 16) + (uint16_t)(unsigned long)seg
;
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
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
;
547 uint32_t driverptr
, driveraddr
;
550 const struct geometry
*geometry
;
551 int total_size
, cmdlinelen
;
553 uint32_t ramdisk_image
, ramdisk_size
;
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");
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
)
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 ) {
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;
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");
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);
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
;
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(®s
, 0, sizeof regs
);
721 regs
.eax
.b
[1] = 0x08;
722 regs
.edx
.b
[0] = geometry
->driveno
& 0x80;
723 syscall(0x13, ®s
, ®s
);
725 if ( regs
.eflags
.l
& 1 ) {
726 printf("INT 13 08: Failure, assuming this is the only drive\n");
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
);
738 uint8_t equip
= rdz_8(BIOS_EQUIP
);
741 bios_drives
= (equip
>> 6)+1;
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
;
786 wrz_8(BIOS_HD_COUNT
, nhd
);
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 */
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(®s
, 0, sizeof regs
);
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, ®s
, ®s
);
813 if ( regs
.eflags
.l
& 1 ) {
814 puts("MEMDISK: Failed to load new boot sector\n");
818 if ( getcmditem("pause") != CMD_NOTFOUND
) {
819 puts("press any key to boot... ");
821 syscall(0x16, ®s
, 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
;