Changeset View
Standalone View
sys/boot/efi/boot1/boot1.c
/*- | /*- | ||||
* Copyright (c) 1998 Robert Nordier | * Copyright (c) 1998 Robert Nordier | ||||
* All rights reserved. | * All rights reserved. | ||||
* Copyright (c) 2001 Robert Drehmel | * Copyright (c) 2001 Robert Drehmel | ||||
* All rights reserved. | * All rights reserved. | ||||
* Copyright (c) 2014 Nathan Whitehorn | * Copyright (c) 2014 Nathan Whitehorn | ||||
* All rights reserved. | * All rights reserved. | ||||
* Copyright (c) 2014 Eric McCorkle | |||||
* All rights reverved. | |||||
* | * | ||||
* Redistribution and use in source and binary forms are freely | * Redistribution and use in source and binary forms are freely | ||||
* permitted provided that the above copyright notice and this | * permitted provided that the above copyright notice and this | ||||
* paragraph and the following disclaimer are duplicated in all | * paragraph and the following disclaimer are duplicated in all | ||||
* such forms. | * such forms. | ||||
* | * | ||||
* This software is provided "AS IS" and without any express or | * This software is provided "AS IS" and without any express or | ||||
* implied warranties, including, without limitation, the implied | * implied warranties, including, without limitation, the implied | ||||
* warranties of merchantability and fitness for a particular | * warranties of merchantability and fitness for a particular | ||||
* purpose. | * purpose. | ||||
*/ | */ | ||||
#include <sys/cdefs.h> | #include <sys/cdefs.h> | ||||
__FBSDID("$FreeBSD$"); | __FBSDID("$FreeBSD$"); | ||||
#include <sys/param.h> | #include <sys/param.h> | ||||
#include <sys/dirent.h> | |||||
#include <machine/elf.h> | #include <machine/elf.h> | ||||
#include <machine/stdarg.h> | #include <machine/stdarg.h> | ||||
#include <efi.h> | #include <efi.h> | ||||
#include <eficonsctl.h> | #include <eficonsctl.h> | ||||
#include "boot_module.h" | |||||
#define _PATH_LOADER "/boot/loader.efi" | #define _PATH_LOADER "/boot/loader.efi" | ||||
#define _PATH_KERNEL "/boot/kernel/kernel" | #define _PATH_KERNEL "/boot/kernel/kernel" | ||||
#define BSIZEMAX 16384 | #define BSIZEMAX 16384 | ||||
typedef int putc_func_t(char c, void *arg); | typedef int putc_func_t(char c, void *arg); | ||||
struct sp_data { | struct sp_data { | ||||
char *sp_buf; | char *sp_buf; | ||||
u_int sp_len; | u_int sp_len; | ||||
u_int sp_size; | u_int sp_size; | ||||
}; | }; | ||||
static const char digits[] = "0123456789abcdef"; | static const boot_module_t* const boot_modules[] = | ||||
{ | |||||
#ifdef ZFS_EFI_BOOT | |||||
&zfs_module, | |||||
#endif | |||||
#ifdef UFS_EFI_BOOT | |||||
&ufs_module | |||||
#endif | |||||
}; | |||||
static void panic(const char *fmt, ...) __dead2; | #define NUM_BOOT_MODULES (sizeof(boot_modules) / sizeof(boot_module_t*)) | ||||
static int printf(const char *fmt, ...); | |||||
static int putchar(char c, void *arg); | |||||
static int vprintf(const char *fmt, va_list ap); | |||||
static int vsnprintf(char *str, size_t sz, const char *fmt, va_list ap); | |||||
static const char digits[] = "0123456789abcdef"; | |||||
static int __printf(const char *fmt, putc_func_t *putc, void *arg, va_list ap); | static int __printf(const char *fmt, putc_func_t *putc, void *arg, va_list ap); | ||||
static int __putc(char c, void *arg); | static int __putc(char c, void *arg); | ||||
static int __puts(const char *s, putc_func_t *putc, void *arg); | static int __puts(const char *s, putc_func_t *putc, void *arg); | ||||
static int __sputc(char c, void *arg); | static int __sputc(char c, void *arg); | ||||
static char *__uitoa(char *buf, u_int val, int base); | static char *__uitoa(char *buf, u_int val, int base); | ||||
static char *__ultoa(char *buf, u_long val, int base); | static char *__ultoa(char *buf, u_long val, int base); | ||||
static int domount(EFI_DEVICE_PATH *device, EFI_BLOCK_IO *blkio, int quiet); | static int domount(EFI_DEVICE_PATH *device, EFI_BLOCK_IO *blkio, int quiet); | ||||
static void load(const char *fname); | static void load(const char *fname); | ||||
static EFI_SYSTEM_TABLE *systab; | static EFI_SYSTEM_TABLE *systab; | ||||
static EFI_HANDLE *image; | static EFI_HANDLE *image; | ||||
static void | |||||
bcopy(const void *src, void *dst, size_t len) | void* Malloc(size_t len, const char* file, int line) | ||||
delphij: There are many style(9) violations in the following section, please consider fixing them before… | |||||
{ | { | ||||
void* out; | |||||
if (systab->BootServices->AllocatePool(EfiLoaderData, | |||||
len, &out) != | |||||
EFI_SUCCESS) { | |||||
printf("Can't allocate memory pool\n"); | |||||
return NULL; | |||||
} | |||||
return out; | |||||
} | |||||
Not Done Inline ActionsReturn values should be enclosed in parentheses, i.e. return (out); (and similar for other return statements). andrew: Return values should be enclosed in parentheses, i.e. `return (out);` (and similar for other… | |||||
char* strcpy(char* dst, const char* src) { | |||||
for(int i = 0; src[i]; i++) | |||||
dst[i] = src[i]; | |||||
return dst; | |||||
} | |||||
char* strchr(const char* s, int c) { | |||||
for(int i = 0; s[i]; i++) | |||||
delphijUnsubmitted Done Inline ActionsCan we just use the libc version of strchr instead of introducing yet another new strchr implementation? delphij: Can we just use the libc version of strchr instead of introducing yet another new strchr… | |||||
eric_metricspace.netAuthorUnsubmitted Not Done Inline ActionsThe issue here is that this is EFI ABI code. Therefore, it has to be compiled with a different set of compiler flags. I don't think linking against libc will actually work because of that. eric_metricspace.net: The issue here is that this is EFI ABI code. Therefore, it has to be compiled with a different… | |||||
Not Done Inline ActionsNo, I mean perhaps we can either add ${SRCTOP}/lib/libc/string/strcpy.c or #include it? delphij: No, I mean perhaps we can either add ${SRCTOP}/lib/libc/string/strcpy.c or #include it? | |||||
if (s[i] == c) | |||||
return (char*)(s + i); | |||||
return NULL; | |||||
} | |||||
int strncmp(const char *a, const char *b, size_t len) | |||||
{ | |||||
for (int i = 0; i < len; i++) | |||||
delphijUnsubmitted Done Inline ActionsSame here. delphij: Same here. | |||||
if(a[i] == '\0' && b[i] == '\0') { | |||||
return 0; | |||||
} else if(a[i] < b[i]) { | |||||
return -1; | |||||
} else if(a[i] > b[i]) { | |||||
return 1; | |||||
} | |||||
return 0; | |||||
} | |||||
char* strdup(const char* s) { | |||||
int len; | |||||
for(len = 1; s[len]; len++); | |||||
delphijUnsubmitted Done Inline ActionsCan we make this a strlen()? delphij: Can we make this a strlen()? | |||||
char* out = malloc(len); | |||||
for(int i = 0; i < len; i++) | |||||
out[i] = s[i]; | |||||
return out; | |||||
} | |||||
Done Inline ActionsThis looks like it is not doing what it is supposed to do. If it passed a string that does where the first byte is not 0 it would loop forever... alvisen_gmail.com: This looks like it is not doing what it is supposed to do. If it passed a string that does… | |||||
int bcmp(const void *a, const void *b, size_t len) | |||||
delphijUnsubmitted Done Inline ActionsSince there is an alias for this (memcmp), I would suggest just use memcmp and remove this one. delphij: Since there is an alias for this (memcmp), I would suggest just use memcmp and remove this one. | |||||
Not Done Inline ActionsThe existence of bcmp is required by either the ZFS or UFS code. In general, the functions here are required by the filesystem code, and because of the aforementioned ABI issue, we can't just link against stdlib eric_metricspace.net: The existence of bcmp is required by either the ZFS or UFS code. In general, the functions… | |||||
{ | |||||
const char *sa = a; | |||||
const char *sb = b; | |||||
for (int i = 0; i < len; i++) | |||||
if(sa[i] != sb[i]) | |||||
return 1; | |||||
return 0; | |||||
} | |||||
int memcmp(const void *a, const void *b, size_t len) | |||||
{ | |||||
return bcmp(a, b, len); | |||||
} | |||||
void bcopy(const void *src, void *dst, size_t len) | |||||
{ | |||||
const char *s = src; | const char *s = src; | ||||
char *d = dst; | char *d = dst; | ||||
while (len-- != 0) | while (len-- != 0) | ||||
*d++ = *s++; | *d++ = *s++; | ||||
} | } | ||||
static void | void* memcpy(void *dst, const void *src, size_t len) | ||||
memcpy(void *dst, const void *src, size_t len) | |||||
{ | { | ||||
bcopy(src, dst, len); | bcopy(src, dst, len); | ||||
return dst; | |||||
} | } | ||||
static void | |||||
bzero(void *b, size_t len) | void* memset(void *b, int val, size_t len) | ||||
{ | { | ||||
char *p = b; | char *p = b; | ||||
while (len-- != 0) | while (len-- != 0) | ||||
*p++ = 0; | *p++ = val; | ||||
return b; | |||||
} | } | ||||
static int | int strcmp(const char *s1, const char *s2) | ||||
strcmp(const char *s1, const char *s2) | |||||
{ | { | ||||
for (; *s1 == *s2 && *s1; s1++, s2++) | for (; *s1 == *s2 && *s1; s1++, s2++) | ||||
Not Done Inline ActionsMissing a space, i.e. this should be void *. andrew: Missing a space, i.e. this should be `void *`. | |||||
; | ; | ||||
return ((u_char)*s1 - (u_char)*s2); | return ((u_char)*s1 - (u_char)*s2); | ||||
} | } | ||||
int putchr(char c, void *arg) | |||||
{ | |||||
CHAR16 buf[2]; | |||||
if (c == '\n') { | |||||
buf[0] = '\r'; | |||||
buf[1] = 0; | |||||
systab->ConOut->OutputString(systab->ConOut, buf); | |||||
} | |||||
buf[0] = c; | |||||
buf[1] = 0; | |||||
systab->ConOut->OutputString(systab->ConOut, buf); | |||||
return (1); | |||||
} | |||||
static EFI_GUID BlockIoProtocolGUID = BLOCK_IO_PROTOCOL; | static EFI_GUID BlockIoProtocolGUID = BLOCK_IO_PROTOCOL; | ||||
static EFI_GUID DevicePathGUID = DEVICE_PATH_PROTOCOL; | static EFI_GUID DevicePathGUID = DEVICE_PATH_PROTOCOL; | ||||
static EFI_GUID LoadedImageGUID = LOADED_IMAGE_PROTOCOL; | |||||
static EFI_GUID ConsoleControlGUID = EFI_CONSOLE_CONTROL_PROTOCOL_GUID; | static EFI_GUID ConsoleControlGUID = EFI_CONSOLE_CONTROL_PROTOCOL_GUID; | ||||
static EFI_GUID LoadedImageGUID = LOADED_IMAGE_PROTOCOL; | |||||
static EFI_BLOCK_IO *bootdev; | #define MAX_DEVS 128 | ||||
static EFI_DEVICE_PATH *bootdevpath; | |||||
static EFI_HANDLE *bootdevhandle; | |||||
delphijUnsubmitted Done Inline ActionsI'd suggest some comment here describing that try_load would not return if load is succeeded. delphij: I'd suggest some comment here describing that try_load would not return if load is succeeded. | |||||
EFI_STATUS efi_main(EFI_HANDLE Ximage, EFI_SYSTEM_TABLE* Xsystab) | void try_load(const boot_module_t* const mod, | ||||
const dev_info_t devs[], | |||||
size_t ndevs) | |||||
{ | { | ||||
EFI_HANDLE handles[128]; | int idx; | ||||
size_t bufsize; | |||||
void* const buffer = mod->load(devs, ndevs, _PATH_LOADER, &idx, &bufsize); | |||||
EFI_HANDLE loaderhandle; | |||||
EFI_LOADED_IMAGE *loaded_image; | |||||
if (NULL == buffer) { | |||||
delphijUnsubmitted Done Inline ActionsPlease use buffer == NULL. Modern compilers already have the ability to detect this kind of mistakes and doing so doesn't buy us much. delphij: Please use buffer == NULL. Modern compilers already have the ability to detect this kind of… | |||||
printf("Could not load file\n"); | |||||
return; | |||||
} | |||||
//printf("Loaded file %s, image at %p\n" | |||||
// "Attempting to load as bootable image...", | |||||
// _PATH_LOADER, image); | |||||
emasteUnsubmitted Done Inline ActionsWe'll want to clean these up -- either delete them if there's no value any longer, or make a DPRINTF macro or such. emaste: We'll want to clean these up -- either delete them if there's no value any longer, or make a… | |||||
if (systab->BootServices->LoadImage(TRUE, image, devs[idx].devpath, | |||||
buffer, bufsize, &loaderhandle) != | |||||
EFI_SUCCESS) { | |||||
//printf("failed\n"); | |||||
return; | |||||
} | |||||
//printf("success\n" | |||||
// "Preparing to execute image..."); | |||||
if (systab->BootServices->HandleProtocol(loaderhandle, | |||||
&LoadedImageGUID, | |||||
(VOID**)&loaded_image) != | |||||
EFI_SUCCESS) { | |||||
//printf("failed\n"); | |||||
return; | |||||
} | |||||
//printf("success\n"); | |||||
loaded_image->DeviceHandle = devs[idx].devhandle; | |||||
//printf("Image prepared, attempting to execute\n"); | |||||
// XXX Set up command args first | |||||
if (systab->BootServices->StartImage(loaderhandle, NULL, NULL) != | |||||
EFI_SUCCESS) { | |||||
Not Done Inline ActionsThe second line should be indented 1 tab and 4 spaces. The EFI_SUCCESS) can then be moved to the same line. andrew: The second line should be indented 1 tab and 4 spaces. The `EFI_SUCCESS)` can then be moved to… | |||||
//printf("Failed to execute loader\n"); | |||||
return; | |||||
} | |||||
//printf("Shouldn't be here!\n"); | |||||
} | |||||
void efi_main(EFI_HANDLE Ximage, EFI_SYSTEM_TABLE* Xsystab) | |||||
Not Done Inline ActionsDitto andrew: Ditto | |||||
{ | |||||
EFI_HANDLE handles[MAX_DEVS]; | |||||
dev_info_t module_devs[NUM_BOOT_MODULES][MAX_DEVS]; | |||||
size_t dev_offsets[NUM_BOOT_MODULES]; | |||||
EFI_BLOCK_IO *blkio; | EFI_BLOCK_IO *blkio; | ||||
UINTN i, nparts = sizeof(handles), cols, rows, max_dim, best_mode; | UINTN nparts = sizeof(handles); | ||||
EFI_STATUS status; | EFI_STATUS status; | ||||
EFI_DEVICE_PATH *devpath; | EFI_DEVICE_PATH *devpath; | ||||
EFI_BOOT_SERVICES *BS; | EFI_BOOT_SERVICES *BS; | ||||
EFI_CONSOLE_CONTROL_PROTOCOL *ConsoleControl = NULL; | EFI_CONSOLE_CONTROL_PROTOCOL *ConsoleControl = NULL; | ||||
SIMPLE_TEXT_OUTPUT_INTERFACE *conout = NULL; | SIMPLE_TEXT_OUTPUT_INTERFACE *conout = NULL; | ||||
char *path = _PATH_LOADER; | |||||
// Basic initialization | |||||
systab = Xsystab; | systab = Xsystab; | ||||
image = Ximage; | image = Ximage; | ||||
for(int i = 0; i < NUM_BOOT_MODULES; i++) | |||||
emasteUnsubmitted Done Inline Actionsstyle(9) does not want variable declarations in for loops emaste: style(9) does not want variable declarations in for loops | |||||
{ | |||||
dev_offsets[i] = 0; | |||||
delphijUnsubmitted Done Inline ActionsPlease change this to memset(). delphij: Please change this to memset(). | |||||
} | |||||
// Set up the console, so printf works. | |||||
emasteUnsubmitted Done Inline Actionsstyle(9) wants /* */ comments emaste: style(9) wants `/* */` comments | |||||
BS = systab->BootServices; | BS = systab->BootServices; | ||||
status = BS->LocateProtocol(&ConsoleControlGUID, NULL, | status = BS->LocateProtocol(&ConsoleControlGUID, NULL, | ||||
(VOID **)&ConsoleControl); | (VOID **)&ConsoleControl); | ||||
if (status == EFI_SUCCESS) | if (status == EFI_SUCCESS) | ||||
(void)ConsoleControl->SetMode(ConsoleControl, | (void)ConsoleControl->SetMode(ConsoleControl, | ||||
EfiConsoleControlScreenText); | EfiConsoleControlScreenText); | ||||
/* | /* | ||||
* Reset the console and find the best text mode. | * Reset the console and find the best text mode. | ||||
*/ | */ | ||||
UINTN max_dim; | |||||
UINTN best_mode; | |||||
UINTN cols; | |||||
UINTN rows; | |||||
conout = systab->ConOut; | conout = systab->ConOut; | ||||
conout->Reset(conout, TRUE); | conout->Reset(conout, TRUE); | ||||
max_dim = best_mode = 0; | max_dim = best_mode = 0; | ||||
for (i = 0; ; i++) { | for (int i = 0; ; i++) { | ||||
status = conout->QueryMode(conout, i, | status = conout->QueryMode(conout, i, | ||||
&cols, &rows); | &cols, &rows); | ||||
if (EFI_ERROR(status)) | if (EFI_ERROR(status)) | ||||
break; | break; | ||||
if (cols * rows > max_dim) { | if (cols * rows > max_dim) { | ||||
max_dim = cols * rows; | max_dim = cols * rows; | ||||
best_mode = i; | best_mode = i; | ||||
} | } | ||||
} | } | ||||
if (max_dim > 0) | if (max_dim > 0) | ||||
conout->SetMode(conout, best_mode); | conout->SetMode(conout, best_mode); | ||||
conout->EnableCursor(conout, TRUE); | conout->EnableCursor(conout, TRUE); | ||||
conout->ClearScreen(conout); | conout->ClearScreen(conout); | ||||
printf("\n" | printf("\n" | ||||
">> FreeBSD EFI boot block\n"); | ">> FreeBSD ZFS-enabled EFI boot block\n"); | ||||
emasteUnsubmitted Done Inline ActionsThe printf should be conditionalized on UFS/ZFS being enabled, or more likely just leave it -- especially if there's per-module printfs below. emaste: The printf should be conditionalized on UFS/ZFS being enabled, or more likely just leave it… | |||||
printf(" Loader path: %s\n", path); | printf(" Loader path: %s\n\n", _PATH_LOADER); | ||||
printf(" Initializing modules:"); | |||||
for(int i = 0; i < NUM_BOOT_MODULES; i++) | |||||
{ | |||||
if (NULL != boot_modules[i]) | |||||
{ | |||||
avgUnsubmitted Done Inline ActionsHere and at several other places the opening brace is placed on a new line. This violates FreeBSD style and is inconsistent with the nearby code. avg: Here and at several other places the opening brace is placed on a new line. This violates… | |||||
printf(" %s", boot_modules[i]->name); | |||||
boot_modules[i]->init(image, systab, BS); | |||||
} | |||||
} | |||||
putchr('\n', NULL); | |||||
// Get all the device handles | |||||
status = systab->BootServices->LocateHandle(ByProtocol, | status = systab->BootServices->LocateHandle(ByProtocol, | ||||
&BlockIoProtocolGUID, NULL, &nparts, handles); | &BlockIoProtocolGUID, NULL, &nparts, handles); | ||||
nparts /= sizeof(handles[0]); | nparts /= sizeof(handles[0]); | ||||
//printf(" Scanning %lu device handles\n", nparts); | |||||
for (i = 0; i < nparts; i++) { | // Scan all partitions, probing with all modules. | ||||
for (int i = 0; i < nparts; i++) { | |||||
dev_info_t devinfo; | |||||
// Figure out if we're dealing with an actual partition | |||||
status = systab->BootServices->HandleProtocol(handles[i], | status = systab->BootServices->HandleProtocol(handles[i], | ||||
&DevicePathGUID, (void **)&devpath); | &DevicePathGUID, (void **)&devpath); | ||||
if (EFI_ERROR(status)) | if (EFI_ERROR(status)) { | ||||
//printf(" Not a device path protocol\n"); | |||||
continue; | continue; | ||||
} | |||||
while (!IsDevicePathEnd(NextDevicePathNode(devpath))) | while (!IsDevicePathEnd(NextDevicePathNode(devpath))) { | ||||
//printf(" Advancing to next device\n"); | |||||
devpath = NextDevicePathNode(devpath); | devpath = NextDevicePathNode(devpath); | ||||
} | |||||
status = systab->BootServices->HandleProtocol(handles[i], | status = systab->BootServices->HandleProtocol(handles[i], | ||||
&BlockIoProtocolGUID, (void **)&blkio); | &BlockIoProtocolGUID, (void **)&blkio); | ||||
if (EFI_ERROR(status)) | if (EFI_ERROR(status)) { | ||||
//printf(" Not a block device\n"); | |||||
continue; | continue; | ||||
} | |||||
if (!blkio->Media->LogicalPartition) | if (!blkio->Media->LogicalPartition) { | ||||
//printf(" Logical partition\n"); | |||||
continue; | continue; | ||||
if (domount(devpath, blkio, 1) >= 0) | |||||
break; | |||||
} | } | ||||
if (i == nparts) | // Setup devinfo | ||||
panic("No bootable partition found"); | devinfo.dev = blkio; | ||||
devinfo.devpath = devpath; | |||||
devinfo.devhandle = handles[i]; | |||||
devinfo.devdata = NULL; | |||||
bootdevhandle = handles[i]; | // Run through each module, see if it can load this partition | ||||
load(path); | for (int j = 0; j < NUM_BOOT_MODULES; j++ ) | ||||
panic("Load failed"); | |||||
return EFI_SUCCESS; | |||||
} | |||||
static int | |||||
dskread(void *buf, u_int64_t lba, int nblk) | |||||
{ | { | ||||
EFI_STATUS status; | if (NULL != boot_modules[j] && | ||||
int size; | boot_modules[j]->probe(&devinfo)) | ||||
lba = lba / (bootdev->Media->BlockSize / DEV_BSIZE); | |||||
size = nblk * DEV_BSIZE; | |||||
status = bootdev->ReadBlocks(bootdev, bootdev->Media->MediaId, lba, | |||||
size, buf); | |||||
if (EFI_ERROR(status)) | |||||
return (-1); | |||||
return (0); | |||||
} | |||||
#include "ufsread.c" | |||||
static ssize_t | |||||
fsstat(ufs_ino_t inode) | |||||
{ | { | ||||
#ifndef UFS2_ONLY | // If it can, save it to the device list for | ||||
static struct ufs1_dinode dp1; | // that module | ||||
ufs1_daddr_t addr1; | module_devs[j][dev_offsets[j]++] = devinfo; | ||||
#endif | |||||
#ifndef UFS1_ONLY | |||||
static struct ufs2_dinode dp2; | |||||
#endif | |||||
static struct fs fs; | |||||
static ufs_ino_t inomap; | |||||
char *blkbuf; | |||||
void *indbuf; | |||||
size_t n, nb, size, off, vboff; | |||||
ufs_lbn_t lbn; | |||||
ufs2_daddr_t addr2, vbaddr; | |||||
static ufs2_daddr_t blkmap, indmap; | |||||
u_int u; | |||||
blkbuf = dmadat->blkbuf; | |||||
indbuf = dmadat->indbuf; | |||||
if (!dsk_meta) { | |||||
inomap = 0; | |||||
for (n = 0; sblock_try[n] != -1; n++) { | |||||
if (dskread(dmadat->sbbuf, sblock_try[n] / DEV_BSIZE, | |||||
SBLOCKSIZE / DEV_BSIZE)) | |||||
return -1; | |||||
memcpy(&fs, dmadat->sbbuf, sizeof(struct fs)); | |||||
if (( | |||||
#if defined(UFS1_ONLY) | |||||
fs.fs_magic == FS_UFS1_MAGIC | |||||
#elif defined(UFS2_ONLY) | |||||
(fs.fs_magic == FS_UFS2_MAGIC && | |||||
fs.fs_sblockloc == sblock_try[n]) | |||||
#else | |||||
fs.fs_magic == FS_UFS1_MAGIC || | |||||
(fs.fs_magic == FS_UFS2_MAGIC && | |||||
fs.fs_sblockloc == sblock_try[n]) | |||||
#endif | |||||
) && | |||||
fs.fs_bsize <= MAXBSIZE && | |||||
fs.fs_bsize >= sizeof(struct fs)) | |||||
break; | |||||
} | } | ||||
if (sblock_try[n] == -1) { | |||||
printf("Not ufs\n"); | |||||
return -1; | |||||
} | } | ||||
dsk_meta++; | |||||
} else | |||||
memcpy(&fs, dmadat->sbbuf, sizeof(struct fs)); | |||||
if (!inode) | |||||
return 0; | |||||
if (inomap != inode) { | |||||
n = IPERVBLK(&fs); | |||||
if (dskread(blkbuf, INO_TO_VBA(&fs, n, inode), DBPERVBLK)) | |||||
return -1; | |||||
n = INO_TO_VBO(n, inode); | |||||
#if defined(UFS1_ONLY) | |||||
memcpy(&dp1, (struct ufs1_dinode *)blkbuf + n, | |||||
sizeof(struct ufs1_dinode)); | |||||
#elif defined(UFS2_ONLY) | |||||
memcpy(&dp2, (struct ufs2_dinode *)blkbuf + n, | |||||
sizeof(struct ufs2_dinode)); | |||||
#else | |||||
if (fs.fs_magic == FS_UFS1_MAGIC) | |||||
memcpy(&dp1, (struct ufs1_dinode *)blkbuf + n, | |||||
sizeof(struct ufs1_dinode)); | |||||
else | |||||
memcpy(&dp2, (struct ufs2_dinode *)blkbuf + n, | |||||
sizeof(struct ufs2_dinode)); | |||||
#endif | |||||
inomap = inode; | |||||
fs_off = 0; | |||||
blkmap = indmap = 0; | |||||
} | } | ||||
size = DIP(di_size); | |||||
n = size - fs_off; | |||||
return (n); | |||||
} | |||||
static struct dmadat __dmadat; | // Select a partition to boot. We do this by trying each | ||||
// module in order. | |||||
static int | for (int i = 0; i < NUM_BOOT_MODULES; i++) | ||||
domount(EFI_DEVICE_PATH *device, EFI_BLOCK_IO *blkio, int quiet) | |||||
{ | { | ||||
if (NULL != boot_modules[i]) | |||||
dmadat = &__dmadat; | { | ||||
bootdev = blkio; | //printf(" Trying to load from %lu %s partitions\n", | ||||
bootdevpath = device; | // dev_offsets[i], boot_modules[i]->name); | ||||
if (fsread(0, NULL, 0)) { | try_load(boot_modules[i], module_devs[i], | ||||
if (!quiet) | dev_offsets[i]); | ||||
printf("domount: can't read superblock\n"); | //printf(" Failed\n"); | ||||
return (-1); | |||||
} | } | ||||
if (!quiet) | |||||
printf("Succesfully mounted UFS filesystem\n"); | |||||
return (0); | |||||
} | } | ||||
static void | // If we get here, we're out of luck... | ||||
load(const char *fname) | panic("No bootable partitions found!"); | ||||
{ | |||||
ufs_ino_t ino; | |||||
EFI_STATUS status; | |||||
EFI_HANDLE loaderhandle; | |||||
EFI_LOADED_IMAGE *loaded_image; | |||||
void *buffer; | |||||
size_t bufsize; | |||||
if ((ino = lookup(fname)) == 0) { | |||||
printf("File %s not found\n", fname); | |||||
return; | |||||
} | } | ||||
bufsize = fsstat(ino); | void panic(const char *fmt, ...) | ||||
status = systab->BootServices->AllocatePool(EfiLoaderData, | |||||
bufsize, &buffer); | |||||
fsread(ino, buffer, bufsize); | |||||
/* XXX: For secure boot, we need our own loader here */ | |||||
status = systab->BootServices->LoadImage(TRUE, image, bootdevpath, | |||||
buffer, bufsize, &loaderhandle); | |||||
if (EFI_ERROR(status)) | |||||
printf("LoadImage failed with error %lx\n", status); | |||||
status = systab->BootServices->HandleProtocol(loaderhandle, | |||||
&LoadedImageGUID, (VOID**)&loaded_image); | |||||
if (EFI_ERROR(status)) | |||||
printf("HandleProtocol failed with error %lx\n", status); | |||||
loaded_image->DeviceHandle = bootdevhandle; | |||||
status = systab->BootServices->StartImage(loaderhandle, NULL, NULL); | |||||
if (EFI_ERROR(status)) | |||||
printf("StartImage failed with error %lx\n", status); | |||||
} | |||||
static void | |||||
panic(const char *fmt, ...) | |||||
{ | { | ||||
char buf[128]; | char buf[128]; | ||||
va_list ap; | va_list ap; | ||||
va_start(ap, fmt); | va_start(ap, fmt); | ||||
vsnprintf(buf, sizeof buf, fmt, ap); | vsnprintf(buf, sizeof buf, fmt, ap); | ||||
printf("panic: %s\n", buf); | printf("panic: %s\n", buf); | ||||
va_end(ap); | va_end(ap); | ||||
while (1) {} | while (1) {} | ||||
} | } | ||||
static int | int printf(const char *fmt, ...) | ||||
printf(const char *fmt, ...) | |||||
{ | { | ||||
va_list ap; | va_list ap; | ||||
int ret; | int ret; | ||||
/* Don't annoy the user as we probe for partitions */ | |||||
if (strcmp(fmt,"Not ufs\n") == 0) | |||||
return 0; | |||||
va_start(ap, fmt); | va_start(ap, fmt); | ||||
ret = vprintf(fmt, ap); | ret = __printf(fmt, putchr, 0, ap); | ||||
va_end(ap); | va_end(ap); | ||||
return (ret); | return (ret); | ||||
} | } | ||||
static int | void vprintf(const char *fmt, va_list ap) | ||||
putchar(char c, void *arg) | |||||
{ | { | ||||
CHAR16 buf[2]; | __printf(fmt, putchr, 0, ap); | ||||
if (c == '\n') { | |||||
buf[0] = '\r'; | |||||
buf[1] = 0; | |||||
systab->ConOut->OutputString(systab->ConOut, buf); | |||||
} | } | ||||
buf[0] = c; | |||||
buf[1] = 0; | |||||
systab->ConOut->OutputString(systab->ConOut, buf); | |||||
return (1); | |||||
} | |||||
static int | int vsnprintf(char *str, size_t sz, const char *fmt, va_list ap) | ||||
vprintf(const char *fmt, va_list ap) | |||||
{ | |||||
int ret; | |||||
ret = __printf(fmt, putchar, 0, ap); | |||||
return (ret); | |||||
} | |||||
static int | |||||
vsnprintf(char *str, size_t sz, const char *fmt, va_list ap) | |||||
{ | { | ||||
struct sp_data sp; | struct sp_data sp; | ||||
int ret; | int ret; | ||||
sp.sp_buf = str; | sp.sp_buf = str; | ||||
sp.sp_len = 0; | sp.sp_len = 0; | ||||
sp.sp_size = sz; | sp.sp_size = sz; | ||||
ret = __printf(fmt, __sputc, &sp, ap); | ret = __printf(fmt, __sputc, &sp, ap); | ||||
▲ Show 20 Lines • Show All 162 Lines • Show Last 20 Lines |
There are many style(9) violations in the following section, please consider fixing them before committing.