📄 probe.c
字号:
/* probe.c -- BIOS probes *//*Copyright 1999-2002 John Coffman.All rights reserved.Licensed under the terms contained in the file 'COPYING' in the source directory.*//*#define DEBUG*/#define VIDEO 1#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 <linux/unistd.h>#include "common.h"#include "device.h"#include "geometry.h"#include "partition.h"#include "bsect.h"#include "bdata.h"#include "probe.h"/*#include "lrmi.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[4*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; */ } s;} buf;static int buf_valid = 0;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_bitmap(char *file);static void do_geom_all(void);static void do_table(char *part);#if VIDEOstatic void do_video(void);#endifstatic char dev[] = "<device>";extern CHANGE_RULE *change_rules; /* defined in partition.c */#if 0 /* def LCF_ALL_PARTITIONS */#define LLSECTORSIZE ((long long)SECTOR_SIZE) _syscall5(int, _llseek, uint, fd, ulong, hi, ulong, lo, loff_t *, res, uint, wh); int _llseek(unsigned int fd, unsigned long offset_high, unsigned long offset_low, loff_t * result, unsigned int whence); loff_t llseek(unsigned int fd, loff_t offs, unsigned int whence) { loff_t res; return _llseek(fd, offs>>32, offs, &res, whence) < 0 ? (loff_t)(-1) : res; }#endifstaticstruct Probes { char *cmd; void (*prc)(); char *str; char *help; } list[] = {{ "help", do_help, NULL, "Print list of -T(ell) options" },{ "bitmap=",do_bitmap,"<file>", "Display .bmp file X,Y/color/timer information"},{ "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."},#if VIDEO{ "video", do_video, NULL, "Graphic mode information" },#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";/* load the low memory bios data area *//* 0 = no error, !0 = error on get */static int fetch(void){ int fd; int got, get; int at = 0, seek = PROBESEG*16; if (buf_valid) return 0; if ((fd=open("/dev/mem", O_RDONLY)) < 0) return 1;#if 0 while (at<seek) { get = seek - at > sizeof(buf.b) ? sizeof(buf.b) : seek - at; got = read(fd, &buf.b, get); if (got != get) return 1; at += got; }#else at = lseek(fd, seek, SEEK_SET); if (at != seek) return 1;#endif get = sizeof(buf.b); if (read(fd, &buf.b, get) != get) return 1; close(fd); if (strncmp(buf.s.signature, PROBE_SIGNATURE,4)) return 2;/* got = buf.s.version; */ /* quiet GCC */ if (buf.s.version < 3 || buf.s.version > (short)(PROBE_VERSION)) return 3; got = buf.s.length; if (got > sizeof(buf.b) || got < sizeof(buf.s)) return 4; if (*(long*)buf.s.checksum != crc32((char*)&buf.s + 4, got-4, CRC_POLY1)) return 5; buf_valid = 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.s) ); 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; if((i=fetch())) { printf("No drive geometry information is available.\n\n"); exit(0); }#ifdef DEBUG printf("get_geom: drive = 0x%02X\n", drive); fflush(stdout);#endif if (drive >= 0 && drive < buf.s.mflp) { fd = (floppy_t*)&buf.b[buf.s.floppy] + drive; hd = (hard_t*)fd; } else if (drive == 0x80) { hdp[drive-0x80] = hd = (hard_t*)&buf.b[buf.s.hard]; } else if (drive >= 0x81 && drive < 0x80+buf.s.mhrd) { if (drive > buf.s.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; geom->n_sect = hd->fn08.cx & 0x3F; geom->n_head = ((hd->fn08.dx>>8)&0xFF)+1; geom->n_cyl = (((hd->fn08.cx>>8)&0xFF)|((hd->fn08.cx&0xC0)<<2))+1; geom->n_disks = hd->fn08.dx & 0xFF; geom->pt = NULL; if (drive < 4) return 0; pt_base = NULL; if (buf.s.disk) { pt_base = (struct partition *)&buf.b[buf.s.partitions]; } if (pt_base && drive <= (int)buf.s.disk) {#if 0 geom->pt = &pt_base[(drive&15)*4];#else void *p = (void*)pt_base; int i = buf.s.version >= 4 ? 8 : 0; p += (drive & 15) * (PART_TABLE_SIZE + i) + i; geom->pt = (struct partition *)p; if (i) geom->serial_no = *(int*)(p-6);#endif }#ifdef DEBUG printf("get_geom: PT->%08X S/N=%08X\n", (int)geom->pt, geom->serial_no);#endif /* regs.eax = 0x4100; check EDD extensions present */ /* regs.edx = drive; */ /* regs.ebx = 0x55AA; */#ifdef DEBUG printf("get_geom: int13, fn=41\n"); fflush(stdout);#endif if ((hd->fn41.flags&1)==0 && (hd->fn41.bx)==(unsigned short)0xAA55) { geom->EDD_flags = hd->fn41.cx; geom->EDD_rev = hd->fn41.ah; } if ((geom->EDD_flags) & EDD_SUBSET) { edd_t *dp; dp = (edd_t*)hdp[drive-0x80 + 1];#ifdef DEBUG printf("get_geom: EDD dp = %08X\n", (int)dp); fflush(stdout);#endif /* update the pointer to the next drive */ hdp[drive-0x80 + 1] = (void*)dp + sizeof(edd_t); /* regs.eax = 0x4800; */ /* regs.edx = drive; */ #ifdef DEBUG printf("get_geom: int13, fn=48\n"); fflush(stdout);#endif if ((dp->info) & EDD_PARAM_GEOM_VALID) { if ((geom->n_sect != dp->sectors || geom->n_head != dp->heads) && !nowarn && !(warned[drive-0x80]&1) ) { fprintf(errstd,"Warning: Int 0x13 function 8 and function 0x48 return different\n" "head/sector geometries for BIOS drive 0x%02X\n", drive); show_geom("fn 08", geom->n_cyl, geom->n_head, geom->n_sect); show_geom("fn 48", dp->cylinders, dp->heads, dp->sectors); warned[drive-0x80] |= 1; }/* prefer to return the fn 8 geometry */#if 0 geom->n_cyl = dp->cylinders; geom->n_head = dp->heads; geom->n_sect = dp->sectors;#endif if (dp->total_sectors > geom->n_total_blocks) geom->n_total_blocks = dp->total_sectors; } } return 0;}/* get the conventional memory size in Kb */static int get_conv_mem(void){ if(fetch()) { printf("No memory information is available.\n\n"); exit(0); } return (int)buf.s.v.mem;}/* print the conventional memory size */static void do_ebda(void){ int m, n, init; static char EBDA[]="Extended BIOS Data Area (EBDA)"; m = get_conv_mem(); if (m==640) printf(" no %s\n", EBDA); else printf(" %s = %dK\n", EBDA, 640-m); printf(" Conventional Memory = %dK 0x%06X\n", m, m<<10); m <<= 10; m -= 0x200;#ifndef LCF_BUILTIN n = m - (MAX_SECONDARY+4+MAX_DESCR_SECS)*SECTOR_SIZE;#else n = (select_loader()->size + SECTOR_SIZE - 1) / SECTOR_SIZE; n = m - (n+4+MAX_DESCR_SECS)*SECTOR_SIZE;#endif init = (n - (MAX_SETUPSECS+1)*SECTOR_SIZE)>>4; if (init > DEF_INITSEG) init = DEF_INITSEG;#if 0 if (!(verbose>0)) return;#else printf("\n");#endif printf(" The First stage loader boots at: 0x%08X (0000:%04X)\n", FIRSTSEG<<4, FIRSTSEG<<4); printf(" The Second stage loader runs at: 0x%08X (%04X:%04X)\n", n, n>>4, n&15); printf(" The kernel cmdline is passed at: 0x%08X (%04X:%04X)\n", m, init, m-(init<<4));}/* print the CHS geometry information for the specified disk */static void print_geom(int dr, struct disk_geom geom){ char ch_ser[12] = { 0 }; if (geom.serial_no) sprintf(ch_ser, "%08X", geom.serial_no); printf(" bios=0x%02x, cylinders=%d, heads=%d, sectors=%d\t%s\n", dr, geom.n_cyl, geom.n_head, geom.n_sect, ch_ser); if (geom.EDD_flags & EDD_PACKET) printf("\tEDD packet calls allowed\n");}/* print disk drive geometry for all drives */static void do_geom_all(void){ int d, hd, dr;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -