4 Copyright (C) 2001 Dell Computer Corporation <Matt_Domsch@dell.com>
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 #define _FILE_OFFSET_BITS 64
32 #include "scsi_ioctls.h"
34 #include "efibootmgr.h"
36 #define BLKSSZGET _IO(0x12,104) /* get block device sector size */
39 disk_info_from_fd(int fd,
41 unsigned int *controllernum,
42 unsigned int *disknum,
49 memset(&buf, 0, sizeof(struct stat));
55 if (!(S_ISBLK(buf.st_mode) || S_ISREG(buf.st_mode))) {
56 printf("Cannot stat non-block or non-regular file\n");
59 major = buf.st_dev >> 8;
60 minor = buf.st_dev && 0xFF;
62 /* IDE disks can have up to 64 partitions, or 6 bits worth,
63 * and have one bit for the disk number.
64 * This leaves an extra bit at the top.
67 *disknum = (minor >> 6) & 1;
68 *controllernum = (major - 3 + 0) + *disknum;
69 *interface_type = ata;
73 else if (major == 22) {
74 *disknum = (minor >> 6) & 1;
75 *controllernum = (major - 22 + 2) + *disknum;
76 *interface_type = ata;
80 else if (major >= 33 && major <= 34) {
81 *disknum = (minor >> 6) & 1;
82 *controllernum = (major - 33 + 4) + *disknum;
83 *interface_type = ata;
87 else if (major >= 56 && major <= 57) {
88 *disknum = (minor >> 6) & 1;
89 *controllernum = (major - 56 + 8) + *disknum;
90 *interface_type = ata;
94 else if (major >= 88 && major <= 91) {
95 *disknum = (minor >> 6) & 1;
96 *controllernum = (major - 88 + 12) + *disknum;
97 *interface_type = ata;
102 /* I2O disks can have up to 16 partitions, or 4 bits worth. */
103 if (major >= 80 && major <= 87) {
104 *interface_type = i2o;
105 *disknum = 16*(major-80) + (minor >> 4);
106 *part = (minor & 0xF);
110 /* SCSI disks can have up to 16 partitions, or 4 bits worth
111 * and have one bit for the disk number.
114 *interface_type = scsi;
115 *disknum = (minor >> 4);
116 *part = (minor & 0xF);
119 else if ( major >= 65 && major <= 71) {
120 *interface_type = scsi;
121 *disknum = 16*(major-64) + (minor >> 4);
122 *part = (minor & 0xF);
126 printf("Unknown interface type.\n");
131 disk_get_scsi_pci(int fd,
133 unsigned char *device,
134 unsigned char *function)
139 unsigned int b=0,d=0,f=0;
140 memset(&buf, 0, sizeof(buf));
141 rc = fstat(fd, &buf);
146 if (S_ISREG(buf.st_mode)) {
147 /* can't call ioctl() on this file and have it succeed.
148 * instead, need to open the block device
151 fprintf(stderr, "You must call this program with "
152 "a file name such as /dev/sda.\n");
156 rc = get_scsi_pci(usefd, slot_name);
158 perror("get_scsi_pci");
161 rc = sscanf(slot_name, "%x:%x.%x", &b,&d,&f);
163 printf("sscanf failed\n");
168 *function = f & 0xFF;
173 * The PCI interface treats multi-function devices as independent
174 * devices. The slot/function address of each device is encoded
175 * in a single byte as follows:
180 * pci bus 00 device 39 vid 8086 did 7111 channel 1
183 #define PCI_DEVFN(slot,func) ((((slot) & 0x1f) << 3) | ((func) & 0x07))
184 #define PCI_SLOT(devfn) (((devfn) >> 3) & 0x1f)
185 #define PCI_FUNC(devfn) ((devfn) & 0x07)
188 disk_get_ide_pci(int fd,
190 unsigned char *device,
191 unsigned char *function)
193 int num_scanned, procfd;
194 unsigned int b=0,d=0,disknum=0, controllernum=0;
195 unsigned char part=0;
196 char procname[80], infoline[80];
201 rc = disk_info_from_fd(fd, &interface_type, &controllernum,
206 sprintf(procname, "/proc/ide/ide%d/config", controllernum);
208 procfd = open(procname, O_RDONLY);
210 perror("opening /proc/ide/ide*/config");
213 read_count = read(procfd, infoline, sizeof(infoline)-1);
216 num_scanned = sscanf(infoline,
217 "pci bus %x device %x vid %*x did %*x channel %*x",
220 if (num_scanned == 2) {
222 *device = PCI_SLOT(d);
223 *function = PCI_FUNC(d);
231 /* this is a list of devices */
233 disk_get_md_parts(int fd)
242 unsigned char *device,
243 unsigned char *function)
245 int interface_type=interface_type_unknown;
246 unsigned int controllernum=0, disknum=0;
247 unsigned char part=0;
249 disk_info_from_fd(fd,
254 switch (interface_type) {
256 return disk_get_ide_pci(fd, bus, device, function);
259 return disk_get_scsi_pci(fd, bus, device, function);
272 disk_get_size(int fd, long *size)
274 return ioctl(fd, BLKGETSIZE, size);
278 * is_mbr_valid(): test MBR for validity
279 * @mbr: pointer to a legacy mbr structure
281 * Description: Returns 1 if MBR is valid, 0 otherwise.
282 * Validity depends on one thing:
283 * 1) MSDOS signature is in the last two bytes of the MBR
286 is_mbr_valid(legacy_mbr *mbr)
290 return (mbr->signature == MSDOS_MBR_SIGNATURE);
293 /************************************************************
294 * msdos_disk_get_extended partition_info()
296 * - open file descriptor fd
298 * Modifies: all these
301 * non-zero on failure
303 ************************************************************/
306 msdos_disk_get_extended_partition_info (int fd, legacy_mbr *mbr,
308 uint64_t *start, uint64_t *size)
310 /* Until I can handle these... */
311 fprintf(stderr, "Extended partition info not supported.\n");
315 /************************************************************
316 * msdos_disk_get_partition_info()
319 * - open file descriptor fd (for extended partitions)
320 * - start, size, signature, mbr_type, signature_type
321 * Modifies: all these
324 * non-zero on failure
326 ************************************************************/
329 msdos_disk_get_partition_info (int fd, legacy_mbr *mbr,
331 uint64_t *start, uint64_t *size,
333 uint8_t *mbr_type, uint8_t *signature_type)
341 if (!is_mbr_valid(mbr)) return 1;
344 *signature_type = 0x01;
346 if (!mbr->unique_mbr_signature && !opts.write_signature) {
348 printf("\n\n******************************************************\n");
349 printf("Warning! This MBR disk does not have a unique signature.\n");
350 printf("If this is not the first disk found by EFI, you may not be able\n");
351 printf("to boot from it without a unique signature.\n");
352 printf("Run efibootmgr with the -w flag to write a unique signature\n");
353 printf("to the disk.\n");
354 printf("******************************************************\n\n");
357 else if (opts.write_signature) {
359 /* MBR Signatures must be unique for the
361 to find the right disk to boot from */
363 rc = fstat(fd, &stat);
368 rc = gettimeofday(&tv, NULL);
370 perror("gettimeofday");
373 /* Write the device type to the signature.
374 This should be unique per disk per system */
375 mbr->unique_mbr_signature = tv.tv_usec << 16;
376 mbr->unique_mbr_signature |= stat.st_rdev & 0xFFFF;
378 /* Write it to the disk */
379 lseek(fd, 0, SEEK_SET);
380 write(fd, mbr, sizeof(*mbr));
383 *(uint32_t *)signature = mbr->unique_mbr_signature;
387 /* Extended partition */
388 return msdos_disk_get_extended_partition_info(fd, mbr, num,
394 disk_get_size(fd, &disk_size);
397 else if (num >= 1 && num <= 4) {
398 /* Primary partition */
399 *start = mbr->partition[num-1].starting_lba;
400 *size = mbr->partition[num-1].size_in_lba;
406 /************************************************************
409 * - filedes is an open file descriptor, suitable for reading
412 * sector size, or 512.
413 ************************************************************/
415 get_sector_size(int filedes)
417 int rc, sector_size = 512;
419 rc = ioctl(filedes, BLKSSZGET, §or_size);
426 * disk_get_partition_info()
427 * @fd - open file descriptor to disk
428 * @num - partition number (1 is first partition on the disk)
429 * @start - partition starting sector returned
430 * @size - partition size (in sectors) returned
431 * @signature - partition signature returned
432 * @mbr_type - partition type returned
433 * @signature_type - signature type returned
435 * Description: Finds partition table info for given partition on given disk.
436 * Both GPT and MSDOS partition tables are tested for.
437 * Returns 0 on success, non-zero on failure
440 disk_get_partition_info (int fd,
442 uint64_t *start, uint64_t *size,
444 uint8_t *mbr_type, uint8_t *signature_type)
449 int this_bytes_read = 0;
450 int gpt_invalid=0, mbr_invalid=0;
452 int sector_size = get_sector_size(fd);
454 if (sizeof(*mbr) != sector_size)
456 mbr_unaligned = malloc(sizeof(*mbr)+sector_size-1);
458 (((unsigned long)mbr_unaligned + sector_size - 1) &
459 ~(unsigned long)(sector_size-1));
460 memset(mbr, 0, sizeof(*mbr));
461 offset = lseek(fd, 0, SEEK_SET);
462 this_bytes_read = read(fd, mbr, sizeof(*mbr));
463 if (this_bytes_read < sizeof(*mbr)) {
467 gpt_invalid = gpt_disk_get_partition_info(fd, num,
473 mbr_invalid = msdos_disk_get_partition_info(fd, mbr, num,
490 main (int argc, char *argv[])
493 unsigned char bus=0,device=0,func=0;
494 if (argc <= 1) return 1;
495 fd = open(argv[1], O_RDONLY|O_DIRECT);
496 rc = disk_get_pci(fd, &bus, &device, &func);
498 printf("PCI %02x:%02x.%02x\n", bus, device, func);