📄 probe.c
字号:
/* probe.c -- BIOS probes *//*Copyright 1999-2004 John Coffman.All rights reserved.Licensed under the terms contained in the file 'COPYING' in the source directory.*//*#define DEBUG*/#define BITMAP 0 /* change to 1 when do_bitmap is filled in */#define VOLID 1 /* change to 1 when do_volid is filled in */#define _GNU_SOURCE#include <stdlib.h>#include <unistd.h>#include <stdio.h>#include <string.h>#include <ctype.h>#include <fcntl.h>#include <errno.h>#include <sys/stat.h>#include <sys/types.h>#include "lilo.h"#include "common.h"#include "device.h"#include "geometry.h"#include "partition.h"#include "bsect.h"#include "bdata.h"#include "probe.h"#ifdef LCF_BDATA#if BD_MAX_FLOPPY > 4#error "too many floppies in bdata.h"#endif#if BD_MAX_HARD > 16#error "too many hard disks in bdata.h"#endif#if BD_GET_VIDEO > 3#error "video get level set too high in bdata.h"#endif#endifstatic union Buf { unsigned char b[5*SECTOR_SIZE]; struct { short checksum[2]; /* prevent alignment on *4 boundary */ char signature[4]; short version; short length; unsigned char disk; /* device code of last good disk */ unsigned char vid, mflp, mhrd; short floppy; /* byte offset to floppy data */ short hard; /* byte offset to hard disk data */ short partitions; /* byte offset to partition info */ video_t v; floppy_t f[4]; hard_t d;/* edd_t edd; */ } s4; struct { short checksum[2]; /* prevent alignment on *4 boundary */ char signature[4]; short version; short length; unsigned char disk; /* device code of last good disk */ unsigned char vid, mflp, mhrd; short floppy; /* byte offset to floppy data */ short hard; /* byte offset to hard disk data */ short partitions; /* byte offset to partition info *//* version 5 additions */ short equipment; /* byte offset to the equipment information */ short video; /* byte offset to the video information */ } s5;} buf;static equip_t *eq;static video_t1 *v1;static video_t2 *v2;static video_t25 *v25; /* extension for PROBE_VERSION 5 */static video_t3 *v3;static int video_36_bug;static int buf_valid = -1;static hard_t *hdp[16+1] = /* pointers to all the hard disks */ { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL };static char warned[16];static void do_ebda(void);static void do_cr_pr(void);static void do_help(void);static void do_geom(char *bios);static void do_geom_all(void);static void do_table(char *part);static void do_video(void);static void do_bios(void);#if BITMAPstatic void do_bitmap(char *file);#endif#if VOLIDstatic void do_volid(void);#endifstatic char dev[] = "<device>";extern CHANGE_RULE *change_rules; /* defined in partition.c */staticstruct Probes { char *cmd; void (*prc)(); char *str; char *help; } list[] = {{ "help", do_help, NULL, "Print list of -T(ell) options" },{ "bios", do_bios, NULL, "State of DL as passed to boot loader" },#if BITMAP{ "bitmap=",do_bitmap,"<file>", "Display .bmp file X,Y/color/timer information"},#endif{ "ChRul", do_cr_pr, NULL, "List partition change-rules" },{ "EBDA", do_ebda, NULL, "Extended BIOS Data Area information" },{ "geom=", do_geom, "<bios>", "Geometry CHS data for BIOS code 0x80, etc." },{ "geom" , do_geom_all, NULL, "Geometry for all BIOS drives" },{ "table=", do_table, dev, "Partition table information for /dev/hda, etc."},{ "video", do_video, NULL, "Graphic mode information" },#if VOLID{ "vol-ID", do_volid, NULL, "Volume ID check for uniqueness"},#endif{ NULL, NULL, NULL, NULL} };static struct partitions { char *name; unsigned char type; unsigned char hide; } ptab [] = { /* Not complete, by any means */ { "DOS12", PART_DOS12, HIDDEN_OFF }, { "DOS16_small", PART_DOS16_SMALL, HIDDEN_OFF }, { "DOS16_big", PART_DOS16_BIG, HIDDEN_OFF }, { "NTFS or OS2_HPFS", PART_NTFS, HIDDEN_OFF }, /* same as HPFS; keep these two together *//* { "HPFS", PART_HPFS, HIDDEN_OFF }, */ /* same as NTFS */ { "FAT32", PART_FAT32, HIDDEN_OFF }, { "FAT32_lba", PART_FAT32_LBA, HIDDEN_OFF }, { "FAT16_lba", PART_FAT16_LBA, HIDDEN_OFF }, { "OS/2 BootMgr", PART_OS2_BOOTMGR, 0 }, { "DOS extended", PART_DOS_EXTD, 0 }, { "WIN extended", PART_WIN_EXTD_LBA, 0 }, { "Linux ext'd", PART_LINUX_EXTD, 0 }, { "Linux Swap", PART_LINUX_SWAP, 0 }, { "Linux Native", PART_LINUX_NATIVE, 0 }, { "Minix", PART_LINUX_MINIX, 0 }, { "Linux RAID", 0xfd, 0 }, { NULL, 0, 0 } };static char phead[] = "\t\t Type Boot Start End Sector #sectors";static int dirty = -1; /* buffer is unread *//* load the low memory bios data area *//* 0 = no error, !0 = error on get */int fetch(void){ int fd; int got, get; int at = 0, seek = PROBESEG*16; if (buf_valid>=0) return buf_valid; if ((fd=open("/dev/mem", O_RDONLY)) < 0) return buf_valid=1; at = lseek(fd, seek, SEEK_SET); if (at != seek) return buf_valid=1; get = sizeof(buf.b); if (read(fd, &buf.b, get) != get) return buf_valid=1; close(fd); dirty = 0; /* buffer is unmodified */ if (strncmp(buf.s5.signature, PROBE_SIGNATURE,4)) return buf_valid=2;/* got = buf.s5.version; */ /* quiet GCC */ if (buf.s5.version < 3 || buf.s5.version > (short)(PROBE_VERSION)) return buf_valid=3; got = buf.s5.length; if (got > sizeof(buf.b) || got < sizeof(buf.s4)) return buf_valid=4; if (*(int*)buf.s5.checksum != crc32((char*)&buf.s5 + 4, got-4, CRC_POLY1)) return buf_valid=5; if (buf.s5.version == 4) { eq = (void*)&buf.s4.v.equipment; v1 = (void*)&buf.s4.v.vid0F; if (buf.s4.vid > 1) v2 = (void*)&buf.s4.v.vid12; if (buf.s4.vid > 2) v3 = (void*)&buf.s4.v.vid4F00; } if (buf.s5.version >= 5) { eq = (void*)&buf.b[buf.s5.equipment]; v1 = (void*)&buf.b[buf.s5.video]; if (buf.s5.vid > 1) { v2 = (void*)v1 + sizeof(*v1); v25 = (void*)v2 + sizeof(*v2); } if (buf.s5.vid > 2) v3 = (void*)v25 + sizeof(*v25); }#if BETA_TEST if (verbose>=5) printf("fetch: good return\n");#endif return buf_valid=0;}int purge(void){ int i, fd; int seek = PROBESEG*16; if (verbose>=6) printf("purge: called\n");#if 0 if (verbose>=6) {fetch(); dirty=1;} /* test of checksumming */#endif if (dirty <= 0) return 0; /* nothing to purge */ if ((i=fetch())) return i; /* return error from fetch */ i = buf.s5.length; *(int*)buf.s5.checksum = crc32((char*)&buf.s5 + 4, i-4, CRC_POLY1); if ((fd=open("/dev/mem", O_WRONLY)) < 0) pdie("purge: can't open /dev/mem"); if (lseek(fd, seek, SEEK_SET) != seek) pdie("purge: "); i = sizeof(buf.b); if (write(fd, &buf.b, i) != i) pdie("purge: "); close(fd); if (verbose>=6) printf("purge: successful write\n"); return dirty = 0; /* buffer is unmodified */}static int notice(int needed){ int f = fetch(); if (f || buf.s5.version < needed) { printf( f==1 ? "Only 'root' may do this.\n\n" :#if 0 "This information request requires that you previously booted your system\n" "using LILO version %s or later. These versions of the LILO boot\n" "loader provide the BIOS data check information in low memory. A boot floppy\n" "constructed with 'mkrescue' may help.\n\n",#endif "The information you requested is not available.\n\n" "Booting your system with LILO version %s or later would provide the re-\n" "quested information as part of the BIOS data check. Please install a more\n" "recent version of LILO on your hard disk, or create a bootable rescue floppy\n" "with the 'mkrescue' command.\n\n", needed==4 ? "22.0" : needed==5 ? "22.5.1" : needed==6 ? "22.5.7" : S(VERSION_MAJOR) "." S(VERSION_MINOR) VERSION_EDIT ); return 1; } return 0;}/* print out the help page for -T flag */static void do_help(void){ struct Probes *pr; printf("usage:"); for (pr=list; pr->cmd; pr++) { printf("\tlilo -T %s%s\t%s\n", pr->cmd, pr->str ? pr->str : " ", pr->help); }#ifdef DEBUG printf(" In some cases, the '-v' flag will produce more output.\n"); printf("sizeof(video_t) = %d sizeof(floppy_t) = %d sizeof(hard_t) = %d\n" "sizeof(edd_t) = %d sizeof(buf.s) = %d\n", sizeof(video_t), sizeof(floppy_t), sizeof(hard_t), sizeof(edd_t), sizeof(buf.s5) ); printf("fetch returns %d\n", fetch()); #endif}/* diagnostic output */static void show_geom(char *who, int cyl, int head, int sect){ fprintf(errstd, " %s: %d cylinders, %d heads, %d sectors\n", who, cyl, head, sect);}/* get the old BIOS disk geometry */static int get_geom(unsigned int drive, struct disk_geom *geom){ hard_t *hd; floppy_t *fd; int i; struct partition *pt_base; unsigned int total;#if 0 if((i=fetch())) { printf("No drive geometry information is available.\n\n"); exit(0); }#else if (notice(4)) exit(0);#endif#ifdef DEBUG printf("get_geom: drive = 0x%02X\n", drive); fflush(stdout);#endif if (drive >= 0 && drive < buf.s5.mflp) { fd = (floppy_t*)&buf.b[buf.s5.floppy] + drive; hd = (hard_t*)fd; } else if (drive == 0x80) { hdp[drive-0x80] = hd = (hard_t*)&buf.b[buf.s5.hard]; } else if (drive >= 0x81 && drive < 0x80+buf.s5.mhrd) { if (drive > buf.s5.disk) return 1; if (!hdp[drive-0x80]) { i = get_geom(drive-1, geom);#ifdef DEBUG printf("get_geom recursive return = %d AH=0x%02X\n", i, i-1); fflush(stdout);#endif if (i) return i; } hd = hdp[drive-0x80]; } else return 1;#ifdef DEBUG printf("get_geom: hd = %08X\n", (int)hd); fflush(stdout);#endif memset(geom, 0, sizeof(*geom)); if (drive >= 0x80) hdp[drive-0x80 + 1] = (void*)hd + sizeof(hard_t); /* simplest increment, but may be wrong */ /* regs.eax = 0x1500; check drive type */ /* regs.edx = drive; */#ifdef DEBUG printf("get_geom: int13, fn=15\n"); fflush(stdout);#endif if (hd->fn15.flags & 1) return 1; /* carry was set */ geom->type = hd->fn15.ah; if (geom->type == 0) return 1; if (geom->type == 3) geom->n_total_blocks = ((int)hd->fn15.cx << 16) + hd->fn15.dx; /* regs.eax = 0x0800; */ /* regs.edx = drive; */ #ifdef DEBUG printf("get_geom: int13, fn=08\n"); fflush(stdout);#endif if (hd->fn08.flags&1 || hd->fn08.ah || hd->fn08.cx==0) return 1 + hd->fn08.ah; i = geom->n_sect = hd->fn08.cx & 0x3F; i *= geom->n_head = ((hd->fn08.dx>>8)&0xFF)+1; i *= geom->n_cyl = (((hd->fn08.cx>>8)&0xFF)|((hd->fn08.cx&0xC0)<<2))+1; if (i > geom->n_total_blocks) geom->n_total_blocks = i; geom->n_disks = hd->fn08.dx & 0xFF; geom->pt = NULL; if (drive < 4) return 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -