📄 setup.c
字号:
uint8_t pad[105];} __attribute__((packed));const struct geometry *get_disk_image_geometry(uint32_t where, uint32_t size){ static struct geometry hd_geometry = { 0, 0, 0, 0, 0, 0, 0x80 }; struct ptab_entry ptab[4]; /* Partition table buffer */ struct dosemu_header dosemu; unsigned int sectors, v; unsigned int max_c, max_h, max_s; unsigned int c, h, s, offset; int i; int drive_specified; const char *p; printf("command line: %s\n", shdr->cmdline); offset = 0; if ( CMD_HASDATA(p = getcmditem("offset")) && (v = atou(p)) ) offset = v; sectors = (size-offset) >> 9; for ( i = 0 ; i < known_geometries ; i++ ) { if ( sectors == geometries[i].sectors ) { hd_geometry = geometries[i]; break; } } hd_geometry.sectors = sectors; hd_geometry.offset = offset; /* Do we have a DOSEMU header? */ memcpy(&dosemu, (char *)where+hd_geometry.offset, sizeof dosemu); if ( !__builtin_memcmp("DOSEMU", dosemu.magic, 7) ) { /* Always a hard disk unless overruled by command-line options */ hd_geometry.driveno = 0x80; hd_geometry.type = 0; hd_geometry.c = dosemu.c; hd_geometry.h = dosemu.h; hd_geometry.s = dosemu.s; hd_geometry.offset += dosemu.offset; sectors = (size-hd_geometry.offset) >> 9; } if ( CMD_HASDATA(p = getcmditem("c")) && (v = atou(p)) ) hd_geometry.c = v; if ( CMD_HASDATA(p = getcmditem("h")) && (v = atou(p)) ) hd_geometry.h = v; if ( CMD_HASDATA(p = getcmditem("s")) && (v = atou(p)) ) hd_geometry.s = v; if ( getcmditem("floppy") != CMD_NOTFOUND ) { hd_geometry.driveno = 0; if ( hd_geometry.type == 0 ) hd_geometry.type = 0x10; /* ATAPI floppy, e.g. LS-120 */ drive_specified = 1; } else if ( getcmditem("harddisk") != CMD_NOTFOUND ) { hd_geometry.driveno = 0x80; hd_geometry.type = 0; drive_specified = 1; } if ( (hd_geometry.c == 0) || (hd_geometry.h == 0) || (hd_geometry.s == 0) ) { /* Hard disk image, need to examine the partition table for geometry */ memcpy(&ptab, (char *)where+hd_geometry.offset+(512-2-4*16), sizeof ptab); max_c = max_h = 0; max_s = 1; for ( i = 0 ; i < 4 ; i++ ) { if ( ptab[i].type ) { c = ptab[i].start_c + (ptab[i].start_s >> 6); s = (ptab[i].start_s & 0x3f); h = ptab[i].start_h; if ( max_c < c ) max_c = c; if ( max_h < h ) max_h = h; if ( max_s < s ) max_s = s; c = ptab[i].end_c + (ptab[i].end_s >> 6); s = (ptab[i].end_s & 0x3f); h = ptab[i].end_h; if ( max_c < c ) max_c = c; if ( max_h < h ) max_h = h; if ( max_s < s ) max_s = s; } } max_c++; max_h++; /* Convert to count (1-based) */ if ( !hd_geometry.h ) hd_geometry.h = max_h; if ( !hd_geometry.s ) hd_geometry.s = max_s; if ( !hd_geometry.c ) hd_geometry.c = sectors/(hd_geometry.h*hd_geometry.s); } if ( (size-hd_geometry.offset) & 0x1ff ) { puts("MEMDISK: Image has fractional end sector\n"); } if ( sectors % (hd_geometry.h*hd_geometry.s) ) { puts("MEMDISK: Image seems to have fractional end cylinder\n"); } if ( (hd_geometry.c*hd_geometry.h*hd_geometry.s) > sectors ) { puts("MEMDISK: Image appears to be truncated\n"); } return &hd_geometry;}/* * Jump here if all hope is gone... */void __attribute__((noreturn)) die(void){ asm volatile("sti"); for(;;) asm volatile("hlt");}#define STACK_NEEDED 256 /* Number of bytes of stack *//* * Actual setup routine * Returns the drive number (which is then passed in %dl to the * called routine.) */syscall_t syscall;void *sys_bounce;uint32_t setup(syscall_t cs_syscall, void *cs_bounce){ unsigned int bin_size = (int) &_binary_memdisk_bin_size; struct memdisk_header *hptr; struct patch_area *pptr; uint16_t driverseg; uint32_t driverptr, driveraddr; uint16_t dosmem_k; uint32_t stddosmem; const struct geometry *geometry; int total_size, cmdlinelen; com32sys_t regs; uint32_t ramdisk_image, ramdisk_size; /* Set up global variables */ syscall = cs_syscall; sys_bounce = cs_bounce; /* Show signs of life */ printf("%s %s\n", memdisk_version, copyright); if ( !shdr->ramdisk_image || !shdr->ramdisk_size ) { puts("MEMDISK: No ramdisk image specified!\n"); die(); } ramdisk_image = shdr->ramdisk_image; ramdisk_size = shdr->ramdisk_size; e820map_init(); /* Initialize memory data structure */ get_mem(); /* Query BIOS for memory map */ parse_mem(); /* Parse memory map */ printf("Ramdisk at 0x%08x, length 0x%08x\n", ramdisk_image, ramdisk_size); unzip_if_needed(&ramdisk_image, &ramdisk_size); geometry = get_disk_image_geometry(ramdisk_image, ramdisk_size); printf("Disk is %s, %u K, C/H/S = %u/%u/%u\n", geometry->driveno ? "hard disk" : "floppy", geometry->sectors >> 1, geometry->c, geometry->h, geometry->s); /* Reserve the ramdisk memory */ insertrange(ramdisk_image, ramdisk_size, 2); parse_mem(); /* Recompute variables */ /* Figure out where it needs to go */ hptr = (struct memdisk_header *) &_binary_memdisk_bin_start; pptr = (struct patch_area *)(_binary_memdisk_bin_start + hptr->patch_offs); dosmem_k = rdz_16(BIOS_BASEMEM); pptr->olddosmem = dosmem_k; stddosmem = dosmem_k << 10; /* If INT 15 E820 and INT 12 disagree, go with the most conservative */ if ( stddosmem > dos_mem ) stddosmem = dos_mem; pptr->driveno = geometry->driveno; pptr->drivetype = geometry->type; pptr->cylinders = geometry->c; pptr->heads = geometry->h; pptr->sectors = geometry->s; pptr->disksize = geometry->sectors; pptr->diskbuf = ramdisk_image + geometry->offset; pptr->statusptr = (geometry->driveno & 0x80) ? 0x474 : 0x441; /* Set up a drive parameter table */ if ( geometry->driveno & 0x80 ) { /* Hard disk */ pptr->dpt.hd.max_cyl = geometry->c-1; pptr->dpt.hd.max_head = geometry->h-1; pptr->dpt.hd.ctrl = (geometry->h > 8) ? 0x08: 0; } else { /* Floppy - most of these fields are bogus and mimic a 1.44 MB floppy drive */ pptr->dpt.fd.specify1 = 0xdf; pptr->dpt.fd.specify2 = 0x02; pptr->dpt.fd.delay = 0x25; pptr->dpt.fd.sectors = geometry->s; pptr->dpt.fd.bps = 0x02; pptr->dpt.fd.isgap = 0x12; pptr->dpt.fd.dlen = 0xff; pptr->dpt.fd.fgap = 0x6c; pptr->dpt.fd.ffill = 0xf6; pptr->dpt.fd.settle = 0x0f; pptr->dpt.fd.mstart = 0x05; pptr->dpt.fd.old_fd_dpt = rdz_32(BIOS_INT1E); } /* The size is given by hptr->total_size plus the size of the E820 map -- 12 bytes per range; we may need as many as 2 additional ranges (each insertrange() can worst-case turn 1 area into 3) plus the terminating range, over what nranges currently show. */ cmdlinelen = strlen(shdr->cmdline)+1; total_size = hptr->total_size; /* Actual memdisk code */ total_size += (nranges+3)*sizeof(ranges[0]); /* E820 memory ranges */ total_size += cmdlinelen; /* Command line */ total_size += STACK_NEEDED; /* Stack */ printf("Total size needed = %u bytes, allocating %uK\n", total_size, (total_size+0x3ff) >> 10); if ( total_size > dos_mem ) { puts("MEMDISK: Insufficient low memory\n"); die(); } driveraddr = stddosmem - total_size; driveraddr &= ~0x3FF; printf("Old dos memory at 0x%05x (map says 0x%05x), loading at 0x%05x\n", stddosmem, dos_mem, driveraddr); /* Reserve this range of memory */ wrz_16(BIOS_BASEMEM, driveraddr >> 10); insertrange(driveraddr, dos_mem-driveraddr, 2); parse_mem(); pptr->mem1mb = low_mem >> 10; pptr->mem16mb = high_mem >> 16; if ( low_mem == (15 << 20) ) { /* lowmem maxed out */ uint32_t int1588mem = (high_mem >> 10)+(low_mem >> 10); pptr->memint1588 = (int1588mem > 0xffff) ? 0xffff : int1588mem; } else { pptr->memint1588 = low_mem >> 10; } printf("1588: 0x%04x 15E801: 0x%04x 0x%04x\n", pptr->memint1588, pptr->mem1mb, pptr->mem16mb); driverseg = driveraddr >> 4; driverptr = driverseg << 16; /* Anything beyond the end is for the stack */ pptr->mystack = (uint16_t)(stddosmem-driveraddr); pptr->oldint13 = rdz_32(BIOS_INT13); pptr->oldint15 = rdz_32(BIOS_INT15); /* Adjust the E820 table: if there are null ranges (type 0) at the end, change them to type end of list (-1). This is necessary for the driver to be able to report end of list correctly. */ while ( nranges && ranges[nranges-1].type == 0 ) { ranges[--nranges].type = -1; } /* Query drive parameters of this type */ memset(®s, 0, sizeof regs); regs.es = 0; regs.eax.b[1] = 0x08; regs.edx.b[0] = geometry->driveno; syscall(0x13, ®s, ®s); if ( regs.eflags.l & 1 ) { printf("INT 13 08: Failure, assuming this is the only drive\n"); pptr->drivecnt = 1; } else { printf("INT 13 08: Success, count = %u, BPT = %04x:%04x\n", regs.edx.b[0], regs.es, regs.edi.w[0]); pptr->drivecnt = regs.edx.b[0]+1; } /* Pointer to the command line */ pptr->cmdline_off = bin_size + (nranges+1)*sizeof(ranges[0]); pptr->cmdline_seg = driverseg; /* Copy driver followed by E820 table followed by command line */ { unsigned char *dpp = (unsigned char *)(driverseg << 4); dpp = memcpy_endptr(dpp, &_binary_memdisk_bin_start, bin_size); dpp = memcpy_endptr(dpp, ranges, (nranges+1)*sizeof(ranges[0])); dpp = memcpy_endptr(dpp, shdr->cmdline, cmdlinelen+1); } /* Install the interrupt handlers */ printf("old: int13 = %08x int15 = %08x\n", rdz_32(BIOS_INT13), rdz_32(BIOS_INT15)); wrz_32(BIOS_INT13, driverptr+hptr->int13_offs); wrz_32(BIOS_INT15, driverptr+hptr->int15_offs); printf("new: int13 = %08x int15 = %08x\n", rdz_32(BIOS_INT13), rdz_32(BIOS_INT15)); /* Update various BIOS magic data areas (gotta love this shit) */ if ( geometry->driveno & 0x80 ) { /* Update BIOS hard disk count */ wrz_8(BIOS_HD_COUNT, rdz_8(BIOS_HD_COUNT)+1); } else { /* Update BIOS floppy disk count */ uint8_t equip = rdz_8(BIOS_EQUIP); if ( equip & 1 ) { if ( (equip & (3 << 6)) != (3 << 6) ) { equip += (1 << 6); } } else { equip |= 1; equip &= ~(3 << 6); } wrz_8(BIOS_EQUIP, equip); } /* Reboot into the new "disk"; this is also a test for the interrupt hooks */ puts("Loading boot sector... "); memset(®s, 0, sizeof regs); // regs.es = 0; regs.eax.w[0] = 0x0201; /* Read sector */ regs.ebx.w[0] = 0x7c00; /* 0000:7C00 */ regs.ecx.w[0] = 1; /* One sector */ regs.edx.w[0] = geometry->driveno; syscall(0x13, ®s, ®s); if ( regs.eflags.l & 1 ) { puts("MEMDISK: Failed to load new boot sector\n"); die(); } if ( getcmditem("pause") != CMD_NOTFOUND ) { puts("press any key to boot... "); regs.eax.w[0] = 0; syscall(0x16, ®s, NULL); } puts("booting...\n"); /* On return the assembly code will jump to the boot vector */ return geometry->driveno;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -