89b50f6b4d
Fix EFI boot support when presented with multiple valid boot partitions across multiple devices. It now prefers to boot from partitions that are present on the underlying device that the boot1 image was loaded from. This means that it will boot from the partitions on device the user chose from EFI boot menu in preference to those on other devices. Also fixed is the recovery from a failed attempt to boot, from a seemingly valid partition, by continuing to trying all other available partitions no matter what the error. boot1 now use * to signify a partition what was accepted from the preferred device and + otherwise. Finally some error messages where improved and DPRINTF's with slowed boot to aid debugging. ZFS will still be preferred over UFS when both are available on the boot device. Reviewed by: imp MFC after: 1 week Sponsored by: Multiplay Differential Revision: https://reviews.freebsd.org/D5108
181 lines
4.1 KiB
C
181 lines
4.1 KiB
C
/*-
|
|
* Copyright (c) 1998 Robert Nordier
|
|
* All rights reserved.
|
|
* Copyright (c) 2001 Robert Drehmel
|
|
* All rights reserved.
|
|
* Copyright (c) 2014 Nathan Whitehorn
|
|
* All rights reserved.
|
|
* Copyright (c) 2015 Eric McCorkle
|
|
* All rights reverved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
* SUCH DAMAGE.
|
|
*
|
|
* $FreeBSD$
|
|
*/
|
|
|
|
#include <stdarg.h>
|
|
#include <stdbool.h>
|
|
#include <sys/cdefs.h>
|
|
#include <sys/param.h>
|
|
#include <efi.h>
|
|
|
|
#include "boot_module.h"
|
|
|
|
static dev_info_t *devinfo;
|
|
static dev_info_t *devices;
|
|
|
|
static int
|
|
dskread(void *buf, u_int64_t lba, int nblk)
|
|
{
|
|
int size;
|
|
EFI_STATUS status;
|
|
|
|
lba = lba / (devinfo->dev->Media->BlockSize / DEV_BSIZE);
|
|
size = nblk * DEV_BSIZE;
|
|
|
|
status = devinfo->dev->ReadBlocks(devinfo->dev,
|
|
devinfo->dev->Media->MediaId, lba, size, buf);
|
|
|
|
if (status != EFI_SUCCESS) {
|
|
DPRINTF("dskread: failed dev: %p, id: %u, lba: %lu, size: %d, "
|
|
"status: %lu\n", devinfo->dev,
|
|
devinfo->dev->Media->MediaId, lba, size,
|
|
EFI_ERROR_CODE(status));
|
|
return (-1);
|
|
}
|
|
|
|
return (0);
|
|
}
|
|
|
|
#include "ufsread.c"
|
|
|
|
static struct dmadat __dmadat;
|
|
|
|
static int
|
|
init_dev(dev_info_t* dev)
|
|
{
|
|
|
|
devinfo = dev;
|
|
dmadat = &__dmadat;
|
|
|
|
return fsread(0, NULL, 0);
|
|
}
|
|
|
|
static EFI_STATUS
|
|
probe(dev_info_t* dev)
|
|
{
|
|
|
|
if (init_dev(dev) < 0)
|
|
return (EFI_UNSUPPORTED);
|
|
|
|
add_device(&devices, dev);
|
|
|
|
return (EFI_SUCCESS);
|
|
}
|
|
|
|
static EFI_STATUS
|
|
load(const char *filepath, dev_info_t *dev, void **bufp, size_t *bufsize)
|
|
{
|
|
ufs_ino_t ino;
|
|
EFI_STATUS status;
|
|
size_t size;
|
|
ssize_t read;
|
|
void *buf;
|
|
|
|
DPRINTF("Loading '%s' from %s\n", filepath, devpath_str(dev->devpath));
|
|
|
|
if (init_dev(dev) < 0) {
|
|
DPRINTF("Failed to init device\n");
|
|
return (EFI_UNSUPPORTED);
|
|
}
|
|
|
|
if ((ino = lookup(filepath)) == 0) {
|
|
DPRINTF("Failed to lookup '%s' (file not found?)\n", filepath);
|
|
return (EFI_NOT_FOUND);
|
|
}
|
|
|
|
if (fsread_size(ino, NULL, 0, &size) < 0 || size <= 0) {
|
|
printf("Failed to read size of '%s' ino: %d\n", filepath, ino);
|
|
return (EFI_INVALID_PARAMETER);
|
|
}
|
|
|
|
if ((status = bs->AllocatePool(EfiLoaderData, size, &buf)) !=
|
|
EFI_SUCCESS) {
|
|
printf("Failed to allocate read buffer %zu for '%s' (%lu)\n",
|
|
size, filepath, EFI_ERROR_CODE(status));
|
|
return (status);
|
|
}
|
|
|
|
read = fsread(ino, buf, size);
|
|
if ((size_t)read != size) {
|
|
printf("Failed to read '%s' (%zd != %zu)\n", filepath, read,
|
|
size);
|
|
(void)bs->FreePool(buf);
|
|
return (EFI_INVALID_PARAMETER);
|
|
}
|
|
|
|
DPRINTF("Load complete\n");
|
|
|
|
*bufp = buf;
|
|
*bufsize = size;
|
|
|
|
return (EFI_SUCCESS);
|
|
}
|
|
|
|
static void
|
|
status()
|
|
{
|
|
int i;
|
|
dev_info_t *dev;
|
|
|
|
for (dev = devices, i = 0; dev != NULL; dev = dev->next, i++)
|
|
;
|
|
|
|
printf("%s found ", ufs_module.name);
|
|
switch (i) {
|
|
case 0:
|
|
printf("no partitions\n");
|
|
break;
|
|
case 1:
|
|
printf("%d partition\n", i);
|
|
break;
|
|
default:
|
|
printf("%d partitions\n", i);
|
|
}
|
|
}
|
|
|
|
static dev_info_t *
|
|
_devices()
|
|
{
|
|
|
|
return (devices);
|
|
}
|
|
|
|
const boot_module_t ufs_module =
|
|
{
|
|
.name = "UFS",
|
|
.probe = probe,
|
|
.load = load,
|
|
.status = status,
|
|
.devices = _devices
|
|
};
|