📄 builtins.c
字号:
tmp1 == 2 ? "2 = 1.44M floppy" : tmp1 == 3 ? "3 = 2.88M floppy" : "Hard Disk"); /* No emulation mode uses 2048-byte sector size. */ if (tmp1 == 0 && buf_geom.sector_size != 2048) goto failure_exec_format;// chainloader_file[1] = tmp1; /* 01: boot media type */// chainloader_file[2] = ((tmp1 == 0) ? current_drive : (tmp1 == 4) ? 0x80 : 0x00); /* 02: drive number */ if (tmp1 == 0) /* no-emulation mode */ { //kernel_type = KERNEL_TYPE_CHAINLOADER; sprintf (chainloader_file, "(%d)%d+%d", current_drive, tmp, (i + 3) / 4); chainloader_load_segment = tmp2;//0x0000; chainloader_load_offset = 0;//0x7c00; chainloader_load_length = i * 512;//0x200; chainloader_skip_length = 0; chainloader_boot_CS = tmp2;//0x0000; chainloader_boot_IP = 0;//0x7c00; //chainloader_ebx = 0; //chainloader_ebx_set = 0; chainloader_edx = current_drive; chainloader_edx_set = 1; //chainloader_disable_A20 = 0; /* update lba_cd_boot if there are any maps */ if (! unset_int13_handler (0)) /* a successful unset */ { if (drive_map_slot_empty (bios_drive_map[0])) if (atapi_dev_count == 0) { errnum = ERR_NO_DRIVE_MAPPED; goto failure_exec_format; } lba_cd_boot = tmp; set_int13_handler (bios_drive_map); } /* needn't clear disk buffer */ /* buf_drive = -1; */ /* buf_track = -1; */ return ! (errnum = 0); } /* floppy or hard drive emulation. LBA=tmp */ /*******************************************************/ /* read the first 512 bytes of the image at 0000:7C00 */ /*******************************************************/ filepos = tmp * 0x800; /* we cannot use SCRATCHADDR because map_func and geometry_func may * use it. So we use 1 sector below 0x2B0000 instead. */ if (grub_read ((char *)(HMA_ADDR - 0x200), 512) != 512) goto failure_exec_format; if (tmp1 == 4) { if (probe_mbr ((struct master_and_dos_boot_sector *)(HMA_ADDR - 0x200), 0, 1, 0)) { errnum = ERR_BAD_PART_TABLE; goto failure_exec_format; } } else { if (probe_bpb((struct master_and_dos_boot_sector *)(HMA_ADDR - 0x200))) { probed_total_sectors = (tmp1 == 1 ? 2400 : tmp1 == 2 ? 2880 : 5760); } } /* map the image */ sprintf (chainloader_file, "--read-only --heads=0 --sectors-per-track=0 (%d)%d+%d (%d)", current_drive, tmp, (probed_total_sectors + 3) / 4, //0x3FFFFFFF, (tmp1 == 4) ? 0x80 : 0x00); tmp = ( (tmp1 == 4) ? (*(char *)0x475) : ((*(char*)0x410) & 1) ); disable_map_info = 1; map_func (chainloader_file, flags); disable_map_info = 0; if (errnum) goto failure_exec_format; /* move the former fd0 or hd0 up. */ if (tmp) { sprintf (chainloader_file, "(%d) (%d)", (tmp1 == 4) ? 0x80 : 0x00, (tmp1 == 4) ? (0x80 + tmp) : 0x01); map_func (chainloader_file, flags); if (errnum) { if (debug > 0) { printf ("Failed 'map %s'(error=%d). But you may ignore it and continue to 'boot' the CD.\n", chainloader_file, errnum); } errnum = 0; } } /* rehook */ unset_int13_handler (0); if (drive_map_slot_empty (bios_drive_map[0])) if (atapi_dev_count == 0) { errnum = ERR_NO_DRIVE_MAPPED; goto failure_exec_format; } set_int13_handler (bios_drive_map); buf_drive = -1; buf_track = -1; grub_memmove ((char *)0x7C00, (char *)(HMA_ADDR - 0x200), 512); sprintf (chainloader_file, "(%d)+1", (tmp1 == 4) ? 0x80 : 0x00); chainloader_load_segment = 0;//tmp2; chainloader_load_offset = 0x7c00; chainloader_load_length = 512; chainloader_skip_length = 0; chainloader_boot_CS = 0;//tmp2; chainloader_boot_IP = 0x7c00; //chainloader_ebx = 0; chainloader_ebx_set = 0; chainloader_edx_set = 0; //chainloader_disable_A20 = 0; saved_drive = ((tmp1 == 4) ? 0x80 : 0x00); chainloader_edx = saved_drive; saved_partition = ((tmp1 == 4) ? 0x00FFFF : 0xFFFFFF); return ! (errnum = 0); }#endif /* ! GRUB_UTIL */// if (debug > 0)// printf ("Debug: chainloader_func: grub_open(%s)...", arg); /* Open the file. */ grub_open (arg);// if (debug > 0)// /* wipe out debug message. */// printf ("\r \r"); if (errnum) goto failure;// if (debug > 0)// printf ("Debug: chainloader_func: grub_read(512 bytes)..."); /* Read the first block. */ { unsigned long len; len = grub_read ((char *) SCRATCHADDR, 512);// if (debug > 0)// /* wipe out debug message. */// printf ("\r \r"); if (len != 512) goto failure_exec_format; } if (chainloader_skip_length > filemax) { errnum = ERR_INVALID_SKIP_LENGTH; goto failure_exec_format; }// hidden_sectors = part_start; if (*((long *)SCRATCHADDR) == 0x49445324 /* $SDI */) { is_sdi = 1; if (debug > 0) grub_printf("SDI signature: %s\n", (char *)(SCRATCHADDR)); } else if ((*(long long *)SCRATCHADDR | 0xFF00LL) == 0x4749464E4F43FFEBLL && filemax > 0x4000) { if (chainloader_load_segment == -1) chainloader_load_segment = 0x0060; if (chainloader_load_offset == -1) chainloader_load_offset = 0; if (chainloader_load_length == -1) chainloader_load_length = filemax; if (! chainloader_ebx_set) { chainloader_ebx = current_drive | ((current_partition >> 8) & 0xFF00); chainloader_ebx_set = 1; } grub_close (); /* FIXME: Where should the BPB be placed for FreeDOS's KERNEL.SYS? * In the current implementation it is placed at 0000:7C00 * but has no effect, since the KERNEL.SYS body will later * overwrite 0000:7C00 on issuing the `boot' command. */ if ((chainloader_ebx & 0xFF00) == 0xFF00) /* check if partition number == 0xFF */ grub_sprintf ((char *)SCRATCHADDR, "(%d)+1", (chainloader_ebx & 0xff)); else grub_sprintf ((char *)SCRATCHADDR, "(%d,%d)+1", (chainloader_ebx & 0xff), ((chainloader_ebx >> 8) & 0xff)); if (! grub_open ((char *)SCRATCHADDR)) goto failure; /* Read the boot sector of the partition onto 0000:7C00 */ if (grub_read ((char *) SCRATCHADDR, 512) != 512) goto failure_exec_format; /* modify the hidden sectors */ /* FIXME: Does the boot drive number also need modifying? */ if (*((unsigned long *) (SCRATCHADDR + BOOTSEC_BPB_HIDDEN_SECTORS))) *((unsigned long *) (SCRATCHADDR + BOOTSEC_BPB_HIDDEN_SECTORS)) = part_start; if (debug > 0) grub_printf("Will boot FreeDOS from drive=0x%x, partition=0x%x(hidden sectors=0x%x)\n", current_drive/*(chainloader_ebx & 0x80)*/, ((current_partition >> 16) & 0xff), part_start); } else if (*(short *)SCRATCHADDR == 0x5A4D && filemax > 0x10000 && *((unsigned short *) (SCRATCHADDR + BOOTSEC_SIG_OFFSET)) == 0 /* && (*(long *)(SCRATCHADDR + 0xA2)) == 0 */ ) { int err; /* Read the second sector. */ if (grub_read ((char *) SCRATCHADDR, 512) != 512) goto failure_exec_format; err = (*(short *)SCRATCHADDR != 0x4A42); filepos += 0x200; /* skip the third sector */ /* Read the fourth sector. */ if (grub_read ((char *) SCRATCHADDR, 512) != 512) goto failure_exec_format; err |= (*((unsigned short *) (SCRATCHADDR + BOOTSEC_SIG_OFFSET)) != 0x534D); /* Read the fifth sector. * check the compress signature "CM" of IO.SYS of WinME */ if (grub_read ((char *) SCRATCHADDR, 512) != 512) goto failure_exec_format; if (! err) { if (chainloader_load_segment == -1) chainloader_load_segment = 0x0070; if (chainloader_load_offset == -1) chainloader_load_offset = 0; if (chainloader_load_length == -1) chainloader_load_length = filemax; if (chainloader_skip_length == 0) chainloader_skip_length = 0x0800; /* WinME support by bean. Thanks! */ // Input parameter for SYSINIT // BX,AX: Start sector for the data area of FAT. It doesn't needs to // be set. However, we should at least clear BX, otherwise, // it would have some minor problem when booting WinME. // DI: Length of the boot code, don't need to be set. // BP: 0x7C00, boot sector pointer, don't need to be set. // DH: Media ID (BS[0x15]) , 0xF0 for floppy, 0xF8 for harddisk // DL: Drive number (BS[0x40] for FAT32) if (! chainloader_edx_set) { chainloader_edx = current_drive | ((current_partition >> 8) & 0xFF00); chainloader_edx_set = 1; } if (! chainloader_ebx_set) { chainloader_ebx = 0; // clear BX for WinME chainloader_ebx_set = 1; } /* save partition number to the high word */ chainloader_edx = (chainloader_edx & 0xFF00FFFF) | ((chainloader_edx & 0xFF00) << 8); // set media descriptor in DH for WinME chainloader_edx = (chainloader_edx & 0xFFFF00FF) | 0xF000 | ((chainloader_edx & 0x80) << 4); grub_close (); /* FIXME: Where should the BPB be placed for MS-DOS's IO.SYS? * In the current implementation it is placed at 0000:7C00 * but has no effect, since the IO.SYS body will later * overwrite 0000:7C00 on issuing the `boot' command. */ if ((chainloader_edx & 0xFF0000) == 0xFF0000) /* check if partition number == 0xFF */ grub_sprintf ((char *)SCRATCHADDR, "(%d)+1", (chainloader_edx & 0xff)); else grub_sprintf ((char *)SCRATCHADDR, "(%d,%d)+1", (chainloader_edx & 0xff), ((chainloader_edx >> 16) & 0xff)); if (! grub_open ((char *)SCRATCHADDR)) goto failure; /* Read the boot sector of the partition onto 0000:7C00 */ if (grub_read ((char *) SCRATCHADDR, 512) != 512) goto failure_exec_format; /* modify the hidden sectors */ /* FIXME: Does the boot drive number also need modifying? */ if (*((unsigned long *) (SCRATCHADDR + BOOTSEC_BPB_HIDDEN_SECTORS))) *((unsigned long *) (SCRATCHADDR + BOOTSEC_BPB_HIDDEN_SECTORS)) = part_start; if (debug > 0) grub_printf("Will boot MS-DOS %c.x from drive=0x%x, partition=0x%x(hidden sectors=0x%x)\n", ((*(unsigned short *) SCRATCHADDR) == 0x4D43)? '8' : '7', current_drive/*(chainloader_edx & 0x80)*/, ((current_partition >> 16) & 0xff), part_start); } } else if (((*(long *)SCRATCHADDR) & 0x00FF00FF) == 0x000100E9 && filemax > 0x30000 && (*((unsigned short *) (SCRATCHADDR + BOOTSEC_SIG_OFFSET)) != BOOTSEC_SIGNATURE)) {//grub_printf("current_drive=0x%x, current_partition=0x%x(part_start=0x%x)\n", current_drive, current_partition, part_start); if (chainloader_load_segment == -1) chainloader_load_segment = 0x2000; if (chainloader_load_offset == -1) chainloader_load_offset = 0; if (chainloader_load_length == -1) chainloader_load_length = filemax; if (! chainloader_edx_set) { chainloader_edx = current_drive | ((current_partition >> 8) & 0xFF00); chainloader_edx_set = 1; } grub_close (); if ((chainloader_edx & 0xFF00) == 0xFF00) grub_sprintf ((char *)SCRATCHADDR, "(%d)+1", (chainloader_edx & 0xff)); else grub_sprintf ((char *)SCRATCHADDR, "(%d,%d)+1", (chainloader_edx & 0xff), ((chainloader_edx >> 8) & 0xff)); if (! grub_open ((char *)SCRATCHADDR)) goto failure; /* Read the boot sector of the partition onto 0000:7C00 */ if (grub_read ((char *) SCRATCHADDR, SECTOR_SIZE) != SECTOR_SIZE) goto failure_exec_format;//grub_printf("current_drive=0x%x, current_partition=0x%x(part_start=0x%x)\n", current_drive, current_partition, part_start); /* modify the hidden sectors */ /* FIXME: Does the boot drive number also need modifying? */ if (*((unsigned long *) (SCRATCHADDR + BOOTSEC_BPB_HIDDEN_SECTORS))) *((unsigned long *) (SCRATCHADDR + BOOTSEC_BPB_HIDDEN_SECTORS)) = part_start; if (debug > 0) grub_printf("Will boot NTLDR from drive=0x%x, partition=0x%x(hidden sectors=0x%x)\n", current_drive, ((current_partition >> 16) & 0xff), part_start); } else if (((*(long long *)SCRATCHADDR) & 0xFFFFFFFFFFFFLL) == 0x7C40EAFALL && filemax > 0x2000 && filemax < 0x20000 && (*((unsigned short *) (SCRATCHADDR + 0x40)) == 0x892E) && (*((unsigned short *) (SCRATCHADDR + 0x45)) == 0x8C2E) && (*((unsigned long *) (SCRATCHADDR + 0x4A)) == 0xD08EC031) && (*((unsigned long *) (SCRATCHADDR + 0x4E)) == 0x8E7BD4BC) ) { if (buf_geom.sector_size != 2048) { if (debug > 0) printf ("\nCannot chainload ISOLINUX from a non-CDROM device.\n"); goto failure_exec_format; } chainloader_load_segment = 0; chainloader_load_offset = 0x7c00; chainloader_load_length = filemax; chainloader_edx = current_drive; chainloader_edx_set = 1; is_isolinux = 1; } else /* If not loading it forcibly, check for the signature. */ if (! force && (*((unsigned short *) (SCRATCHADDR + BOOTSEC_SIG_OFFSET)) != BOOTSEC_SIGNATURE)) goto failure_exec_format; grub_close (); /* if BPB exists, we can reliablly modify the hidden sectors. */ if (! probe_bpb((struct master_and_dos_boot_sector *)SCRATCHADDR)) if (*((unsigned long *) (SCRATCHADDR + BOOTSEC_BPB_HIDDEN_SECTORS))) *((unsigned long *) (SCRATCHADDR + BOOTSEC_BPB_HIDDEN_SECTORS)) = part_start; if (chainloader_load_length == -1) chainloader_load_length = filemax; if (chainloader_load_length > 0xA0000) chainloader_load_length = 0xA0000; grub_memmove ((char *)0x7C00, (char *)SCRATCHADDR, 512); errnum = ERR_NONE; return 1;failure_exec_format: grub_close (); if (errnum == ERR_NONE) errnum = ERR_EXEC_FORMAT;failure: chainloader_load_segment = chainloader_load_segment_orig; chainloader_load_offset = chainloader_load_offset_orig; chainloader_load_length = chainloader_load_length_orig; chainloader_skip_length = chainloader_skip_length_orig; chainloader_boot_CS = chainloader_boot_CS_orig; chainloader_boot_IP = chainloader_boot_IP_orig; chainloader_ebx = chainloader_ebx_orig; chainloader_ebx_set = chainloader_ebx_set_orig; chainloader_edx = chainloader_edx_orig; chainloader_edx_set = chainloader_edx_set_orig; chainloader_disable_A20 = chainloader_disable_A20_orig; is_sdi = is_sdi_orig; is_raw = is_raw_orig; is_isolinux = is_isolinux_orig; kernel_type = kernel_type_orig; force = errnum; /* backup the errnum */ grub_memmove ((char *)chainloader_file, (char *)chainloader_file_orig, sizeof(chainloader_file)); errnum = force; /* restore the errnum */ return 0; /* return failure */}static struct builtin builtin_chainloader ={ "chainloader", chainloader_func, BUILTIN_MENU | BUILTIN_CMDLINE | BUILTIN_HELP_LIST, "chainloader [--force] [--load-segment=LS] [--load-offset=LO]" "\n[--load-length=LL] [--skip-length=SL] [--boot-cs=CS] [--boot-ip=IP]" "\n[--ebx=EBX] [--edx=EDX] [--sdi] [--disable-a20] FILE", "Load the chain-loader FILE. If --force is specified, then load it" " forcibly, whether the boot loader signature is present or not." " LS:LO specifies the load address other than 0000:7C00. LL specifies" " the length of the boot image(between 512 and 640K). CS:IP specifies" " the address where the boot image will gain control. EBX/EDX specifies" " the EBX/EDX register value when the boot image gets control. Use --sdi" " if FILE is a System Deployment Image, which is of the Windows XP" " RAM boot file format. Use --disable-a20 if you wish to turn off" " A20 when transferring cont
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -