📄 builtins.c
字号:
static long expand_file(char* src,char* dst);static void ibuf_init(char* buf){ //int i; ibuf_ptr=buf; ibuf_pos=0; // ibuf_tab[i]=(1<<(i+1))-1 ibuf_tab[0]=1; for (i=1;i<16;i++) ibuf_tab[i]=ibuf_tab[i-1]*2+1;}static unsigned short ibuf_read(int nbits){ unsigned short res; res=(unsigned short)((*((unsigned long*)ibuf_ptr)>>ibuf_pos) & ibuf_tab[nbits-1]); ibuf_pos+=nbits; if (ibuf_pos>=8) { ibuf_ptr+=(ibuf_pos>>3); ibuf_pos&=7; } return res;}#define obuf_init(buf) obuf_ptr=buf#define obuf_putc(ch) *(obuf_ptr++)=ch#define obuf_copy(ofs,len) do { for (;len>0;obuf_ptr++,len--) *(obuf_ptr)=*(obuf_ptr-ofs); } while (0)// Don't use memcpy, otherwise we could be screwed !static int expand_block(int nsec){ while (nsec>0) { int cnt; cnt=0x200; while (1) { int flg,ofs,bts,bse,del,len; flg=ibuf_read(2); if (flg==0) ofs=ibuf_read(6); else if (flg==3) { if (ibuf_read(1)) { ofs=ibuf_read(12)+0x140; if (ofs==0x113F) break; } else ofs=ibuf_read(8)+0x40; } else { char ch; cnt--; if (cnt<0) { grub_putstr("Data corrupted"); return 1; } ch=ibuf_read(7); if (flg & 1) ch|=0x80; obuf_putc(ch); continue; } if (ofs==0) { grub_putstr("Data corrupted"); return 1; } bse=2; del=0; for (bts=0;bts<9;bts++) { if (ibuf_read(1)) break; bse+=del+1; del=del*2+1; } if (bts==9) { grub_putstr("Data corrupted"); return 1; } len=(bts)?bse+ibuf_read(bts):bse; if ((cnt=cnt-len)<0) { grub_putstr("Data corrupted"); return 1; } obuf_copy(ofs,len); } nsec--; if ((cnt) && (nsec)) { grub_putstr("Data corrupted"); return 1; } } return 0;}static long expand_file(char* src,char* dst){ ibuf_init(src); obuf_init(dst); if (ibuf_read(16)!=0x4D43) { grub_putstr("First CM signature not found"); return -1; } while (1) { unsigned short flg,len; flg=ibuf_read(8); len=ibuf_read(16); if (len==0) { int n; n=(ibuf_ptr-src) & 0xF; if ((n) || (ibuf_pos)) { ibuf_ptr+=16-n; ibuf_pos=0; } if (ibuf_read(16)!=0x4D43) { grub_putstr("Second CM signature not found"); return -1; } return obuf_ptr-dst; } if (flg==0) { memcpy(obuf_ptr,ibuf_ptr,len); ibuf_ptr+=len; obuf_ptr+=len; } else { char* save_ptr; unsigned short sec; sec=(ibuf_read(16)+511)>>9; save_ptr=ibuf_ptr; if (ibuf_read(16)!=0x5344) { grub_putstr("0x5344 signature not found"); return -1; } ibuf_read(16); if (expand_block(sec)) return -1; ibuf_ptr=save_ptr+len; ibuf_pos=0; } }}#endif /* ! defined(GRUB_UTIL) && ! defined (STAGE1_5) */#ifndef GRUB_UTIL/* boot */static intboot_func (char *arg, int flags){ int old_cursor, old_errnum; struct term_entry *prev_term = current_term; /* Clear the int15 handler if we can boot the kernel successfully. This assumes that the boot code never fails only if KERNEL_TYPE is not KERNEL_TYPE_NONE. Is this assumption is bad? */ if (kernel_type != KERNEL_TYPE_NONE) unset_int15_handler (); /* if our terminal needed initialization, we should shut it down * before booting the kernel, but we want to save what it was so * we can come back if needed */ if (current_term->shutdown) { (*current_term->shutdown)(); current_term = term_table; /* assumption: console is first */ }#ifdef FSYS_PXE if (kernel_type!=KERNEL_TYPE_CHAINLOADER) pxe_unload();#endif#ifdef SUPPORT_NETBOOT /* Shut down the networking. */ cleanup_net ();#endif old_cursor = setcursor (1); errnum = 0; //errorcheck = 1; /* clear keyboard buffer before boot */ while (console_checkkey () != -1) console_getkey (); switch (kernel_type) { case KERNEL_TYPE_FREEBSD: case KERNEL_TYPE_NETBSD: /* *BSD */ bsd_boot (kernel_type, bootdev, (char *) mbi.cmdline); break; case KERNEL_TYPE_LINUX: /* Linux */ linux_boot (); break; case KERNEL_TYPE_BIG_LINUX: /* Big Linux */ big_linux_boot (); break; case KERNEL_TYPE_CHAINLOADER: /* Chainloader */ /* set boot drive to the root device. * the boot drive should be either (fd0) or (hd0) for normal * MS-style boot sectors. the BIOS only passes (fd0) or (hd0) * to DL, because these two are the only devices that can be * booted by BIOS. * * You should set boot drive using the rootnoverify command just * before the boot command. */ boot_drive = saved_drive;#ifndef GRUB_UTIL /* extended chainloader */ if (chainloader_load_length > 512 || chainloader_boot_CS > 0 || chainloader_skip_length || chainloader_ebx_set || chainloader_edx_set || is_sdi || is_raw || //chainloader_disable_A20 || (chainloader_boot_IP >= 0 && chainloader_boot_IP != 0x7c00) || (((chainloader_load_segment >= 0)? chainloader_load_segment : 0) << 4) + ((chainloader_load_offset >= 0)? chainloader_load_offset : 0x7c00) != 0x7c00 ) { unsigned long read_length; /* load high */ if (chainloader_load_segment == -1) chainloader_load_segment = 0; if (chainloader_load_offset == -1) { if (chainloader_load_segment) chainloader_load_offset = 0; else chainloader_load_offset = 0x7c00; } if (chainloader_boot_CS == -1) chainloader_boot_CS = chainloader_load_segment; if (chainloader_boot_IP == -1) chainloader_boot_IP = chainloader_load_offset; /* Open the file. */ if (! grub_open (chainloader_file)) { kernel_type = KERNEL_TYPE_NONE; return 0; } if (is_sdi) { unsigned long long bytes_needed = filemax; unsigned long long base = 0; if (mbi.flags & MB_INFO_MEM_MAP) { struct AddrRangeDesc *map = (struct AddrRangeDesc *) saved_mmap_addr; unsigned long end_addr = saved_mmap_addr + saved_mmap_length; for (; end_addr > (unsigned long) map; map = (struct AddrRangeDesc *) (((int) map) + 4 + map->size)) { unsigned long long top_end; if (map->Type != MB_ARD_MEMORY) continue; top_end = map->BaseAddr + map->Length; if (top_end > 0x100000000ULL) top_end = 0x100000000ULL;#define MIN_EMU_BASE 0x200000ULL if (map->Length >= bytes_needed && (base = (top_end - bytes_needed) & 0xfffff000) >= MIN_EMU_BASE /* page align */ && map->Length >= top_end - base) break; /* success */ base = 0; } } else grub_printf ("Address Map BIOS Interface is not activated.\n"); if (base < MIN_EMU_BASE) { grub_close (); return ! (errnum = ERR_WONT_FIT); } #undef MIN_EMU_BASE //filepos = 0; if (grub_read ((char *)((int)base), -1) != filemax) { grub_close (); if (errnum == ERR_NONE) errnum = ERR_READ; return 0; } grub_close (); unset_int13_handler (0); #define BootCodeOffsetLow (*(unsigned long *)((int)base + 0x10))#define BootCodeSizeLow (*(unsigned long *)((int)base + 0x18)) read_length = BootCodeSizeLow; if (read_length > 0x90000) read_length = 0x90000; grub_memmove((char *)0x200000, (char *)((unsigned int)base + BootCodeOffsetLow), read_length);#undef BootCodeOffsetLow#undef BootCodeSizeLow if (! chainloader_edx_set) { chainloader_edx = (unsigned int)base | 0x41; chainloader_edx_set = 1; } }else{ /* Read the first 640K */ read_length = filemax - chainloader_skip_length; filepos = ((*(unsigned short *)0x413)<<10) - (chainloader_load_segment<<4) - chainloader_load_offset; if (read_length > filepos) read_length = filepos; filepos = chainloader_skip_length; /* read the new loader to physical address 2MB, overwriting * the backup area of DOS memory. */ if (grub_read ((char *) 0x200000, read_length) != read_length) { grub_close (); kernel_type = KERNEL_TYPE_NONE; if (errnum == ERR_NONE) errnum = ERR_EXEC_FORMAT; break; } grub_close ();#ifdef FSYS_PXE pxe_unload();#endif /* WinMe support by bean. Thanks! */ // Not a very neat way to test WinME, works anyway if ((*(unsigned short*)0x200000==0x4D43) && // ((*(char*)0x110002==0) || (*(unsigned short*)0x110000==0x4D43)) && (chainloader_skip_length==0x800)) { unsigned long len; len=(unsigned long)expand_file((char*)0x200000,(char*)0x2A0000); if (len==0xffffffff || len==0) { kernel_type = KERNEL_TYPE_NONE; errnum = ERR_EXEC_FORMAT; break; } grub_memmove((char*)0x200000,(char*)0x2A0000,len); chainloader_load_length=read_length=len; } /* create boot info table for isolinux */ if (is_isolinux) { int p; query_block_entries = -1; /* query block list only */ blocklist_func (chainloader_file, flags); if (errnum) break; if (query_block_entries != 1) { errnum = ERR_NON_CONTIGUOUS; break; } *(unsigned long*)0x20000C = map_start_sector; *(unsigned long*)0x200010 = chainloader_load_length; old_errnum = 0; /* init to calculate the checksum */ *(unsigned long*)(0x200000 + chainloader_load_length) = 0; for (p = 0; p < (chainloader_load_length - 0x40 + 3) / 4; p++) { old_errnum += *(long *)(0x200040 + (p << 2)); } *(unsigned long*)0x200014 = old_errnum; /* checksum */ } /* Turn off A20 here if --disable-a20 was specified. * Note: we won't have access to the odd megas of the memory * when A20 is off. */ if (chainloader_disable_A20) { if (! gateA20 (0)) { /* to asure A20 is on when we return to grub. */ gateA20 (1); /* turn on A20 in case it is off */ errnum = ERR_DISABLE_A20; break; } if (debug > 0) grub_printf("\nGate A20 is turned off successfully.\n"); } if (! chainloader_edx_set) { chainloader_edx_set = 1; chainloader_edx = boot_drive; } if (chainloader_edx & 0x80) { if (! probe_bpb((struct master_and_dos_boot_sector *)0x200000)) if (*((unsigned long *) (0x20001C)) == 0) { if (probe_mbr ((struct master_and_dos_boot_sector *)0x200000, 0, ((chainloader_load_length + 511) >> 9), 0)) { errnum = ERR_HD_VOL_START_0; break; } } } else { /* clear number of hidden sectors for floppy */ if (! probe_bpb((struct master_and_dos_boot_sector *)0x200000)) if (*((unsigned long *) (0x20001C))) *((unsigned long *) (0x20001C)) = 0; } } if (chainloader_load_length == -1 || chainloader_load_length > read_length) chainloader_load_length = read_length;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -