📄 boot.c
字号:
/* boot.c - Boot image composition *//*Copyright 1992-1997 Werner Almesberger.Copyright 1999-2004 John Coffman.All rights reserved.Licensed under the terms contained in the file 'COPYING' in the source directory.*/#define BIG_CHAIN 5#define _GNU_SOURCE#include <stdlib.h>#include <stdio.h>#include <unistd.h>#include <string.h>#include <ctype.h>#include <fcntl.h>#include <errno.h>#include <sys/stat.h>#include "config.h"#include "lilo.h"#include "common.h"#include "geometry.h"#include "device.h"#include "cfg.h"#include "map.h"#include "partition.h"#include "boot.h"#include "loader.h"/* the number of sectors between the 15M memory hole and 1M this is the max. for a bzImage kernel + initrd unless "large-memory" or "mem=XXX" raises the limit */#define HIGH_SECTORS ((15-1)*1024*1024/SECTOR_SIZE) #define HIGH_4M (3*1024*1024/SECTOR_SIZE)static GEOMETRY geo;static struct stat st;static void check_size(char *name,int setup_secs,int sectors){ if (sectors > setup_secs+MAX_KERNEL_SECS) die("Kernel %s is too big",name);}void boot_image(char *spec,IMAGE_DESCR *descr){ BOOT_SECTOR buff; SETUP_HDR hdr; char *initrd; int setup,fd,sectors,hi_sectors=MAX_KERNEL_SECS*4; int modern_kernel; if (verbose > 0) { printf("Boot image: %s",spec); show_link(spec); /* in common.c */ printf("\n"); } fd = geo_open(&geo,spec,O_RDONLY); if (fstat(fd,&st) < 0) die("fstat %s: %s",spec,strerror(errno)); if (read(fd,(char *) &buff,SECTOR_SIZE) != SECTOR_SIZE) die("read %s: %s",spec,strerror(errno)); setup = buff.sector[VSS_NUM] ? buff.sector[VSS_NUM] : SETUPSECS; if (read(fd,(char *) &hdr,sizeof(hdr)) != sizeof(hdr)) die("read %s: %s",spec,strerror(errno)); modern_kernel = !strncmp(hdr.signature,NEW_HDR_SIG,4) && hdr.version >= NEW_HDR_VERSION; if (modern_kernel) descr->flags |= FLAG_MODKRN; if (verbose > 1) printf("Setup length is %d sector%s.\n",setup,setup == 1 ? "" : "s"); if (setup > MAX_SETUPSECS) die("Setup length exceeds %d maximum; kernel setup will overwrite boot loader", MAX_SETUPSECS); map_add(&geo,0,(st.st_size+SECTOR_SIZE-1)/SECTOR_SIZE); sectors = map_end_section(&descr->start,setup+SPECIAL_SECTORS+SPECIAL_BOOTSECT); if (!modern_kernel || !(hdr.flags & LFLAG_HIGH)) check_size(spec,setup,sectors); else { if (hdr.start % PAGE_SIZE) die("Can't load kernel at mis-aligned address 0x%08lx\n",hdr.start); descr->flags |= FLAG_LOADHI; /* load kernel high */ hi_sectors = sectors - setup; /* number of sectors loaded high */ hi_sectors *= 3; /* account for decompression */ if (hi_sectors < HIGH_4M) hi_sectors = HIGH_4M; } geo_close(&geo); if (verbose > 1) printf("Mapped %d sector%s.\n",sectors,sectors == 1 ? "" : "s"); if ((initrd = cfg_get_strg(cf_kernel,"initrd")) || (initrd = cfg_get_strg( cf_options,"initrd"))) { if (!modern_kernel) die("Kernel doesn't support initial RAM disks"); if (verbose > 0) { printf("Mapping RAM disk %s",initrd); show_link(initrd); printf("\n"); } fd = geo_open(&geo,initrd,O_RDONLY); if (fstat(fd,&st) < 0) die("fstat %s: %s",initrd,strerror(errno));#if 1 *(unsigned int *) descr->rd_size = st.st_size;#else descr->rd_size = (st.st_size + SECTOR_SIZE - 1)/SECTOR_SIZE;#endif map_begin_section(); map_add(&geo,0,(st.st_size+SECTOR_SIZE-1)/SECTOR_SIZE); sectors = map_end_section(&descr->initrd,0); if (verbose > 1) printf("RAM disk: %d sector%s.\n",sectors,sectors == 1 ? "" : "s"); if (hi_sectors + sectors > HIGH_SECTORS#ifndef LCF_INITRDLOW && !cfg_get_flag(cf_options,"large-memory")#endif ) { descr->flags |= FLAG_TOOBIG; if (!nowarn) fprintf(errstd, "Warning: The initial RAM disk is too big to fit between %s and\n" " the 15M-16M memory hole."#ifndef LCF_INITRDLOW# if 0 " If your BIOS supports memory moves above 16M,\n" " then you may specify \"large-memory\" in the configuration file\n" " (/etc/lilo.conf)."# else " It will be loaded in the highest memory as\n" " though the configuration file specified \"large-memory\" and it will\n" " be assumed that the BIOS supports memory moves above 16M."# endif#endif "\n", hi_sectors ? "the kernel" : "1M"); } geo_close(&geo); }}void boot_device(char *spec,char *range,IMAGE_DESCR *descr){ char *here; int start,secs; int sectors; if (verbose > 0) printf("Boot device: %s, range %s\n",spec,range); (void) geo_open(&geo,spec,O_NOACCESS); here = strchr(range,'-'); if (here) { *here++ = 0; start = to_number(range); if ((secs = to_number(here)-start+1) < 0) die("Invalid range"); } else { here = strchr(range,'+'); if (here) { *here++ = 0; start = to_number(range); secs = to_number(here); } else { start = to_number(range); secs = 1; } } map_add(&geo,start,secs); check_size(spec,SETUPSECS,sectors = map_end_section(&descr->start,60)); /* this is a crude hack ... ----------^^*/ geo_close(&geo); if (verbose > 1) printf("Mapped %d sector%s.\n",sectors,sectors == 1 ? "" : "s");}void do_map_drive(void){ const char *tmp; char *end; int from,to; tmp = cfg_get_strg(cf_other,"map-drive"); from = strtoul(tmp,&end,0); if (from > 0xff || *end) cfg_error("Invalid drive specification \"%s\"",tmp); cfg_init(cf_map_drive); (void) cfg_parse(cf_map_drive); tmp = cfg_get_strg(cf_map_drive,"to"); if (!tmp) cfg_error("TO is required"); to = strtoul(tmp,&end,0); if (to > 0xff || *end) cfg_error("Invalid drive specification \"%s\"",tmp); if (from || to) { /* 0 -> 0 is special */ int i; for (i = 0; i < curr_drv_map; i++) { if (drv_map[i] == ((to << 8) | from)) die("Mapping 0x%02x to 0x%02x already exists",from,to); if ((drv_map[i] & 0xff) == from) die("Ambiguous mapping 0x%02x to 0x%02x or 0x%02x",from, drv_map[i] >> 8,to); } if (curr_drv_map == DRVMAP_SIZE) cfg_error("Too many drive mappings (more than %d)",DRVMAP_SIZE); if (verbose > 1) printf(" Mapping BIOS drive 0x%02x to 0x%02x\n",from,to); drv_map[curr_drv_map++] = (to << 8) | from; } cfg_unset(cf_other,"map-drive");}/* * Derive the name of the MBR from the partition name * e.g. * /dev/scsi/host2/bus0/target1/lun0/part2 => disc * /dev/sd/c0b0t0u0p7 => c0b0t0u0 * /dev/sda11 => sda * * If table==0, do no check for primary partition; if table==1, check * that we started from a primary (1-4) partition. * * A NULL return indicates an error * */ char *boot_mbr(const char *boot, int table){#if 0 char *part, *npart, *endptr; int i, j, k; npart = stralloc(boot); part = strrchr(npart, '/'); if (!part++) die ("No '/' in partition/device name."); i = strlen(part); endptr = part + i - 1; /* j is the count of digits at the end of the name */ j = 0; while (isdigit(*endptr)) { j++; --endptr; } if (j==0 && !table) die ("Not a partition name; no digits at the end."); k = !table || (j==1 && endptr[1]>='1' && endptr[1]<='4'); /* test for devfs partNN */ if (strncmp(part, "part", 4)==0) { strcpy(part, "disc"); } /* test for ..NpNN */ else if (*endptr=='p' && isdigit(endptr[-1])) { *endptr = 0; /* truncate the pNN part */ } /* test for old /dev/hda3 or /dev/sda11 */ else if (endptr[-1]=='d' && endptr[-3]=='/' && (endptr[-2]=='h' || endptr[-2]=='s')#if 0 && strstr(npart, "/dev/")#endif ) { endptr[1] = 0; /* truncate the NN part */ } else k = 0;#else struct stat st; dev_t dev; DEVICE d; int mask, k; char *npart = NULL; k = 0; if (stat(boot,&st) < 0) die("stat %s: %s",boot,strerror(errno));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -