Home | History | Annotate | Line # | Download | only in efiboot
      1  1.11   mlelstv /*	$NetBSD: efidisk.c,v 1.11 2024/01/06 21:26:43 mlelstv Exp $	*/
      2   1.1    nonaka 
      3   1.1    nonaka /*-
      4   1.1    nonaka  * Copyright (c) 2016 Kimihiro Nonaka <nonaka (at) netbsd.org>
      5   1.1    nonaka  * All rights reserved.
      6   1.1    nonaka  *
      7   1.1    nonaka  * Redistribution and use in source and binary forms, with or without
      8   1.1    nonaka  * modification, are permitted provided that the following conditions
      9   1.1    nonaka  * are met:
     10   1.1    nonaka  * 1. Redistributions of source code must retain the above copyright
     11   1.1    nonaka  *    notice, this list of conditions and the following disclaimer.
     12   1.1    nonaka  * 2. Redistributions in binary form must reproduce the above copyright
     13   1.1    nonaka  *    notice, this list of conditions and the following disclaimer in the
     14   1.1    nonaka  *    documentation and/or other materials provided with the distribution.
     15   1.1    nonaka  *
     16   1.1    nonaka  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     17   1.1    nonaka  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     18   1.1    nonaka  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     19   1.1    nonaka  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     20   1.1    nonaka  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     21   1.1    nonaka  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     22   1.1    nonaka  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     23   1.1    nonaka  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     24   1.1    nonaka  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     25   1.1    nonaka  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     26   1.1    nonaka  * SUCH DAMAGE.
     27   1.1    nonaka  */
     28   1.1    nonaka 
     29   1.2    nonaka #define FSTYPENAMES	/* for sys/disklabel.h */
     30   1.2    nonaka 
     31   1.1    nonaka #include "efiboot.h"
     32   1.1    nonaka 
     33   1.8      manu #include <sys/param.h>	/* for howmany, required by <dev/raidframe/raidframevar.h> */
     34   1.2    nonaka #include <sys/disklabel.h>
     35   1.8      manu #include <sys/disklabel_gpt.h>
     36   1.2    nonaka 
     37   1.2    nonaka #include "biosdisk.h"
     38   1.2    nonaka #include "biosdisk_ll.h"
     39   1.2    nonaka #include "devopen.h"
     40   1.1    nonaka #include "efidisk.h"
     41  1.11   mlelstv #include "bootinfo.h"
     42   1.1    nonaka 
     43   1.1    nonaka static struct efidiskinfo_lh efi_disklist;
     44   1.1    nonaka static int nefidisks;
     45  1.11   mlelstv static struct btinfo_biosgeom *bibg;
     46  1.11   mlelstv static size_t bibg_len;
     47   1.1    nonaka 
     48   1.8      manu #define MAXDEVNAME 39 /* "NAME=" + 34 char part_name */
     49   1.8      manu 
     50   1.8      manu #include <dev/raidframe/raidframevar.h>
     51   1.8      manu #define RF_COMPONENT_INFO_OFFSET   16384   /* from sys/dev/raidframe/rf_netbsdkintf.c */
     52   1.8      manu #define RF_COMPONENT_LABEL_VERSION     2   /* from <dev/raidframe/rf_raid.h> */
     53   1.8      manu 
     54   1.8      manu #define RAIDFRAME_NDEV 16 /* abitrary limit to 15 raidframe devices */
     55   1.8      manu struct efi_raidframe {
     56   1.8      manu        int last_unit;
     57   1.8      manu        int serial;
     58   1.8      manu        const struct efidiskinfo *edi;
     59   1.8      manu        int parent_part;
     60   1.8      manu        char parent_name[MAXDEVNAME + 1];
     61   1.8      manu        daddr_t offset;
     62   1.8      manu        daddr_t size;
     63   1.8      manu };
     64   1.8      manu 
     65   1.8      manu static void
     66   1.8      manu dealloc_biosdisk_part(struct biosdisk_partition *part, int nparts)
     67   1.8      manu {
     68   1.8      manu 	int i;
     69   1.8      manu 
     70   1.8      manu 	for (i = 0; i < nparts; i++) {
     71   1.8      manu 		if (part[i].part_name != NULL) {
     72   1.8      manu 			dealloc(part[i].part_name, BIOSDISK_PART_NAME_LEN);
     73   1.8      manu 			part[i].part_name = NULL;
     74   1.8      manu 		}
     75   1.8      manu 	}
     76  1.10  riastrad 
     77   1.8      manu 	dealloc(part, sizeof(*part) * nparts);
     78  1.10  riastrad 
     79   1.8      manu 	return;
     80   1.8      manu }
     81   1.8      manu 
     82   1.1    nonaka void
     83   1.1    nonaka efi_disk_probe(void)
     84   1.1    nonaka {
     85   1.1    nonaka 	EFI_STATUS status;
     86   1.1    nonaka 	UINTN i, nhandles;
     87   1.1    nonaka 	EFI_HANDLE *handles;
     88   1.1    nonaka 	EFI_BLOCK_IO *bio;
     89   1.1    nonaka 	EFI_BLOCK_IO_MEDIA *media;
     90   1.2    nonaka 	EFI_DEVICE_PATH *dp;
     91   1.1    nonaka 	struct efidiskinfo *edi;
     92   1.2    nonaka 	int dev, depth = -1;
     93   1.1    nonaka 
     94   1.1    nonaka 	TAILQ_INIT(&efi_disklist);
     95   1.1    nonaka 
     96   1.1    nonaka 	status = LibLocateHandle(ByProtocol, &BlockIoProtocol, NULL,
     97   1.1    nonaka 	    &nhandles, &handles);
     98   1.1    nonaka 	if (EFI_ERROR(status))
     99   1.7    nonaka 		return;
    100   1.1    nonaka 
    101   1.2    nonaka 	if (efi_bootdp != NULL)
    102   1.2    nonaka 		depth = efi_device_path_depth(efi_bootdp, MEDIA_DEVICE_PATH);
    103   1.2    nonaka 
    104   1.2    nonaka 	/*
    105   1.2    nonaka 	 * U-Boot incorrectly represents devices with a single
    106   1.2    nonaka 	 * MEDIA_DEVICE_PATH component.  In that case include that
    107   1.2    nonaka 	 * component into the matching, otherwise we'll blindly select
    108   1.2    nonaka 	 * the first device.
    109   1.2    nonaka 	 */
    110   1.2    nonaka 	if (depth == 0)
    111   1.2    nonaka 		depth = 1;
    112   1.2    nonaka 
    113   1.1    nonaka 	for (i = 0; i < nhandles; i++) {
    114   1.1    nonaka 		status = uefi_call_wrapper(BS->HandleProtocol, 3, handles[i],
    115   1.1    nonaka 		    &BlockIoProtocol, (void **)&bio);
    116   1.1    nonaka 		if (EFI_ERROR(status))
    117   1.7    nonaka 			continue;
    118   1.1    nonaka 
    119   1.1    nonaka 		media = bio->Media;
    120   1.1    nonaka 		if (media->LogicalPartition || !media->MediaPresent)
    121   1.1    nonaka 			continue;
    122   1.1    nonaka 
    123   1.1    nonaka 		edi = alloc(sizeof(struct efidiskinfo));
    124   1.1    nonaka 		memset(edi, 0, sizeof(*edi));
    125   1.2    nonaka 		edi->type = BIOSDISK_TYPE_HD;
    126   1.1    nonaka 		edi->bio = bio;
    127   1.1    nonaka 		edi->media_id = media->MediaId;
    128   1.1    nonaka 
    129   1.2    nonaka 		if (efi_bootdp != NULL && depth > 0) {
    130   1.2    nonaka 			status = uefi_call_wrapper(BS->HandleProtocol, 3,
    131   1.2    nonaka 			    handles[i], &DevicePathProtocol, (void **)&dp);
    132   1.2    nonaka 			if (EFI_ERROR(status))
    133   1.2    nonaka 				goto next;
    134   1.2    nonaka 			if (efi_device_path_ncmp(efi_bootdp, dp, depth) == 0) {
    135   1.2    nonaka 				edi->bootdev = true;
    136   1.2    nonaka 				TAILQ_INSERT_HEAD(&efi_disklist, edi,
    137   1.2    nonaka 				    list);
    138   1.2    nonaka 				continue;
    139   1.2    nonaka 			}
    140   1.2    nonaka 		}
    141   1.2    nonaka next:
    142   1.2    nonaka 		TAILQ_INSERT_TAIL(&efi_disklist, edi, list);
    143   1.2    nonaka 	}
    144   1.1    nonaka 
    145   1.2    nonaka 	FreePool(handles);
    146   1.1    nonaka 
    147   1.6    nonaka 	if (efi_bootdp_type == BOOT_DEVICE_TYPE_CD) {
    148   1.3    nonaka 		edi = TAILQ_FIRST(&efi_disklist);
    149   1.3    nonaka 		if (edi != NULL && edi->bootdev) {
    150   1.3    nonaka 			edi->type = BIOSDISK_TYPE_CD;
    151   1.3    nonaka 			TAILQ_REMOVE(&efi_disklist, edi, list);
    152   1.3    nonaka 			TAILQ_INSERT_TAIL(&efi_disklist, edi, list);
    153   1.1    nonaka 		}
    154   1.1    nonaka 	}
    155   1.1    nonaka 
    156   1.1    nonaka 	dev = 0x80;
    157   1.1    nonaka 	TAILQ_FOREACH(edi, &efi_disklist, list) {
    158   1.1    nonaka 		edi->dev = dev++;
    159   1.2    nonaka 		if (edi->type == BIOSDISK_TYPE_HD)
    160   1.2    nonaka 			nefidisks++;
    161   1.2    nonaka 		if (edi->bootdev)
    162   1.2    nonaka 			boot_biosdev = edi->dev;
    163   1.2    nonaka 	}
    164  1.11   mlelstv 
    165  1.11   mlelstv 	bibg_len = sizeof(*bibg) + nefidisks * sizeof(struct bi_biosgeom_entry);
    166  1.11   mlelstv 	bibg = alloc(bibg_len);
    167  1.11   mlelstv 	if (bibg == NULL)
    168  1.11   mlelstv 		return;
    169  1.11   mlelstv 
    170  1.11   mlelstv 	bibg->num = nefidisks;
    171  1.11   mlelstv 
    172  1.11   mlelstv 	i = 0;
    173  1.11   mlelstv 	TAILQ_FOREACH(edi, &efi_disklist, list) {
    174  1.11   mlelstv 		if (edi->type == BIOSDISK_TYPE_HD) {
    175  1.11   mlelstv 			memset(&bibg->disk[i], 0, sizeof(bibg->disk[i]));
    176  1.11   mlelstv 			bibg->disk[i].dev = edi->dev;
    177  1.11   mlelstv 			bibg->disk[i].flags = BI_GEOM_INVALID;
    178  1.11   mlelstv 		}
    179  1.11   mlelstv 		++i;
    180  1.11   mlelstv 	}
    181   1.2    nonaka }
    182   1.2    nonaka 
    183   1.8      manu static void
    184   1.8      manu efi_raidframe_probe(struct efi_raidframe *raidframe, int *raidframe_count,
    185   1.8      manu 		    const struct efidiskinfo *edi,
    186   1.8      manu 		    struct biosdisk_partition *part, int parent_part)
    187   1.8      manu 
    188   1.8      manu {
    189   1.8      manu 	int i = *raidframe_count;
    190   1.8      manu 	struct RF_ComponentLabel_s label;
    191   1.8      manu 
    192   1.8      manu 	if (i + 1 > RAIDFRAME_NDEV)
    193   1.8      manu 		return;
    194   1.8      manu 
    195   1.8      manu 	if (biosdisk_read_raidframe(edi->dev, part->offset, &label) != 0)
    196   1.8      manu 		return;
    197   1.8      manu 
    198   1.8      manu 	if (label.version != RF_COMPONENT_LABEL_VERSION)
    199   1.8      manu 		return;
    200   1.8      manu 
    201   1.8      manu 	raidframe[i].last_unit = label.last_unit;
    202   1.8      manu 	raidframe[i].serial = label.serial_number;
    203   1.8      manu 	raidframe[i].edi = edi;
    204   1.8      manu 	raidframe[i].parent_part = parent_part;
    205   1.8      manu 	if (part->part_name)
    206   1.8      manu 		strlcpy(raidframe[i].parent_name, part->part_name, MAXDEVNAME);
    207   1.8      manu 	else
    208   1.8      manu 		raidframe[i].parent_name[0] = '\0';
    209   1.8      manu 	raidframe[i].offset = part->offset;
    210   1.8      manu 	raidframe[i].size = label.__numBlocks;
    211   1.8      manu 
    212   1.8      manu 	(*raidframe_count)++;
    213   1.8      manu 
    214   1.8      manu 	return;
    215   1.8      manu }
    216   1.8      manu 
    217   1.2    nonaka void
    218   1.2    nonaka efi_disk_show(void)
    219   1.2    nonaka {
    220   1.2    nonaka 	const struct efidiskinfo *edi;
    221   1.8      manu 	struct efi_raidframe raidframe[RAIDFRAME_NDEV];
    222   1.8      manu 	int raidframe_count = 0;
    223   1.2    nonaka 	EFI_BLOCK_IO_MEDIA *media;
    224   1.2    nonaka 	struct biosdisk_partition *part;
    225   1.2    nonaka 	uint64_t size;
    226   1.8      manu 	int i, j, nparts;
    227   1.2    nonaka 	bool first;
    228   1.2    nonaka 
    229   1.2    nonaka 	TAILQ_FOREACH(edi, &efi_disklist, list) {
    230   1.2    nonaka 		media = edi->bio->Media;
    231   1.2    nonaka 		first = true;
    232   1.2    nonaka 		printf("disk ");
    233   1.2    nonaka 		switch (edi->type) {
    234   1.2    nonaka 		case BIOSDISK_TYPE_CD:
    235   1.2    nonaka 			printf("cd0");
    236   1.2    nonaka 			printf(" mediaId %u", media->MediaId);
    237   1.2    nonaka 			if (edi->media_id != media->MediaId)
    238   1.2    nonaka 				printf("(%u)", edi->media_id);
    239   1.2    nonaka 			printf("\n");
    240   1.2    nonaka 			printf("  cd0a\n");
    241   1.2    nonaka 			break;
    242   1.2    nonaka 		case BIOSDISK_TYPE_HD:
    243   1.2    nonaka 			printf("hd%d", edi->dev & 0x7f);
    244   1.2    nonaka 			printf(" mediaId %u", media->MediaId);
    245   1.2    nonaka 			if (edi->media_id != media->MediaId)
    246   1.2    nonaka 				printf("(%u)", edi->media_id);
    247   1.2    nonaka 			printf(" size ");
    248   1.2    nonaka 			size = (media->LastBlock + 1) * media->BlockSize;
    249   1.2    nonaka 			if (size >= (10ULL * 1024 * 1024 * 1024))
    250   1.2    nonaka 				printf("%"PRIu64" GB", size / (1024 * 1024 * 1024));
    251   1.2    nonaka 			else
    252   1.2    nonaka 				printf("%"PRIu64" MB", size / (1024 * 1024));
    253   1.2    nonaka 			printf("\n");
    254   1.2    nonaka 			break;
    255   1.2    nonaka 		}
    256   1.2    nonaka 		if (edi->type != BIOSDISK_TYPE_HD)
    257   1.2    nonaka 			continue;
    258   1.2    nonaka 
    259   1.8      manu 		if (biosdisk_readpartition(edi->dev, 0, 0, &part, &nparts))
    260   1.2    nonaka 			continue;
    261   1.2    nonaka 
    262   1.2    nonaka 		for (i = 0; i < nparts; i++) {
    263   1.2    nonaka 			if (part[i].size == 0)
    264   1.2    nonaka 				continue;
    265   1.2    nonaka 			if (part[i].fstype == FS_UNUSED)
    266   1.2    nonaka 				continue;
    267   1.8      manu 			if (part[i].fstype == FS_RAID) {
    268   1.8      manu 				efi_raidframe_probe(raidframe, &raidframe_count,
    269   1.8      manu 						    edi, &part[i], i);
    270   1.8      manu 			}
    271   1.2    nonaka 			if (first) {
    272   1.2    nonaka 				printf(" ");
    273   1.2    nonaka 				first = false;
    274   1.2    nonaka 			}
    275   1.9      manu 			if (part[i].part_name && part[i].part_name[0])
    276   1.8      manu 				printf(" NAME=%s(", part[i].part_name);
    277   1.8      manu 			else
    278   1.8      manu 				printf(" hd%d%c(", edi->dev & 0x7f, i + 'a');
    279   1.2    nonaka 			if (part[i].guid != NULL)
    280   1.2    nonaka 				printf("%s", part[i].guid->name);
    281   1.2    nonaka 			else if (part[i].fstype < FSMAXTYPES)
    282   1.2    nonaka 				printf("%s", fstypenames[part[i].fstype]);
    283   1.2    nonaka 			else
    284   1.2    nonaka 				printf("%d", part[i].fstype);
    285   1.2    nonaka 			printf(")");
    286   1.2    nonaka 		}
    287   1.2    nonaka 		if (!first)
    288   1.2    nonaka 			printf("\n");
    289   1.8      manu 		dealloc_biosdisk_part(part, nparts);
    290   1.8      manu 	}
    291   1.8      manu 
    292   1.8      manu 	for (i = 0; i < raidframe_count; i++) {
    293   1.8      manu 		size_t secsize = raidframe[i].edi->bio->Media->BlockSize;
    294   1.8      manu 		printf("raidframe raid%d serial %d in ",
    295   1.8      manu 		       raidframe[i].last_unit, raidframe[i].serial);
    296   1.8      manu 		if (raidframe[i].parent_name[0])
    297   1.8      manu 			printf("NAME=%s size ", raidframe[i].parent_name);
    298   1.8      manu 		else
    299   1.8      manu 			printf("hd%d%c size ",
    300   1.8      manu 			       raidframe[i].edi->dev & 0x7f,
    301   1.8      manu 			       raidframe[i].parent_part + 'a');
    302   1.8      manu 		if (raidframe[i].size >= (10ULL * 1024 * 1024 * 1024 / secsize))
    303   1.8      manu 			printf("%"PRIu64" GB",
    304   1.8      manu 			    raidframe[i].size / (1024 * 1024 * 1024 / secsize));
    305   1.8      manu 		else
    306   1.8      manu 			printf("%"PRIu64" MB",
    307   1.8      manu 			    raidframe[i].size / (1024 * 1024 / secsize));
    308   1.8      manu 		printf("\n");
    309   1.8      manu 
    310   1.8      manu 		if (biosdisk_readpartition(raidframe[i].edi->dev,
    311   1.8      manu 		    raidframe[i].offset + RF_PROTECTED_SECTORS,
    312   1.8      manu 		    raidframe[i].size,
    313   1.8      manu 		    &part, &nparts))
    314   1.8      manu 			continue;
    315  1.10  riastrad 
    316   1.8      manu 		first = 1;
    317   1.8      manu 		for (j = 0; j < nparts; j++) {
    318   1.8      manu 			bool bootme = part[j].attr & GPT_ENT_ATTR_BOOTME;
    319   1.8      manu 
    320   1.8      manu 			if (part[j].size == 0)
    321   1.8      manu 				continue;
    322   1.8      manu 			if (part[j].fstype == FS_UNUSED)
    323   1.8      manu 				continue;
    324   1.8      manu 			if (part[j].fstype == FS_RAID) /* raid in raid? */
    325   1.8      manu 				continue;
    326   1.8      manu 			if (first) {
    327   1.8      manu 				printf(" ");
    328   1.8      manu 				first = 0;
    329   1.8      manu 			}
    330   1.9      manu 			if (part[j].part_name && part[j].part_name[0])
    331   1.8      manu 				printf(" NAME=%s(", part[j].part_name);
    332   1.8      manu 			else
    333   1.8      manu 				printf(" raid%d%c(",
    334   1.8      manu 				       raidframe[i].last_unit, j + 'a');
    335   1.8      manu 			if (part[j].guid != NULL)
    336   1.8      manu 				printf("%s", part[j].guid->name);
    337   1.8      manu 			else if (part[j].fstype < FSMAXTYPES)
    338   1.8      manu 				printf("%s",
    339   1.8      manu 				  fstypenames[part[j].fstype]);
    340   1.8      manu 			else
    341   1.8      manu 				printf("%d", part[j].fstype);
    342   1.8      manu 			printf("%s)", bootme ? ", bootme" : "");
    343   1.8      manu 		}
    344   1.8      manu 
    345   1.8      manu 		if (first == 0)
    346   1.8      manu 			printf("\n");
    347   1.8      manu 
    348   1.8      manu 		dealloc_biosdisk_part(part, nparts);
    349   1.1    nonaka 	}
    350   1.1    nonaka }
    351   1.1    nonaka 
    352   1.1    nonaka const struct efidiskinfo *
    353   1.1    nonaka efidisk_getinfo(int dev)
    354   1.1    nonaka {
    355   1.1    nonaka 	const struct efidiskinfo *edi;
    356   1.1    nonaka 
    357   1.1    nonaka 	TAILQ_FOREACH(edi, &efi_disklist, list) {
    358   1.1    nonaka 		if (dev == edi->dev)
    359   1.1    nonaka 			return edi;
    360   1.1    nonaka 	}
    361   1.1    nonaka 	return NULL;
    362   1.1    nonaka }
    363   1.1    nonaka 
    364   1.1    nonaka /*
    365   1.1    nonaka  * Return the number of hard disk drives.
    366   1.1    nonaka  */
    367   1.1    nonaka int
    368   1.1    nonaka get_harddrives(void)
    369   1.1    nonaka {
    370   1.1    nonaka 	return nefidisks;
    371   1.1    nonaka }
    372   1.5    nonaka 
    373   1.5    nonaka int
    374   1.5    nonaka efidisk_get_efi_system_partition(int dev, int *partition)
    375   1.5    nonaka {
    376   1.5    nonaka 	extern const struct uuid GET_efi;
    377   1.5    nonaka 	const struct efidiskinfo *edi;
    378   1.5    nonaka 	struct biosdisk_partition *part;
    379   1.5    nonaka 	int i, nparts;
    380   1.5    nonaka 
    381   1.5    nonaka 	edi = efidisk_getinfo(dev);
    382   1.5    nonaka 	if (edi == NULL)
    383   1.5    nonaka 		return ENXIO;
    384   1.5    nonaka 
    385   1.5    nonaka 	if (edi->type != BIOSDISK_TYPE_HD)
    386   1.5    nonaka 		return ENOTSUP;
    387   1.5    nonaka 
    388   1.8      manu 	if (biosdisk_readpartition(edi->dev, 0, 0, &part, &nparts))
    389   1.5    nonaka 		return EIO;
    390   1.5    nonaka 
    391   1.5    nonaka 	for (i = 0; i < nparts; i++) {
    392   1.5    nonaka 		if (part[i].size == 0)
    393   1.5    nonaka 			continue;
    394   1.5    nonaka 		if (part[i].fstype == FS_UNUSED)
    395   1.5    nonaka 			continue;
    396   1.5    nonaka 		if (guid_is_equal(part[i].guid->guid, &GET_efi))
    397   1.5    nonaka 			break;
    398   1.5    nonaka 	}
    399   1.8      manu 	dealloc_biosdisk_part(part, nparts);
    400   1.5    nonaka 	if (i == nparts)
    401   1.5    nonaka 		return ENOENT;
    402   1.5    nonaka 
    403   1.5    nonaka 	*partition = i;
    404   1.5    nonaka 	return 0;
    405   1.5    nonaka }
    406  1.11   mlelstv 
    407  1.11   mlelstv void
    408  1.11   mlelstv efidisk_getbiosgeom()
    409  1.11   mlelstv {
    410  1.11   mlelstv 	BI_ADD(bibg, BTINFO_BIOSGEOM, bibg_len);
    411  1.11   mlelstv }
    412  1.11   mlelstv 
    413