boot1.c revision 293460
1210284Sjmallett/*- 2215990Sjmallett * Copyright (c) 1998 Robert Nordier 3215990Sjmallett * All rights reserved. 4210284Sjmallett * Copyright (c) 2001 Robert Drehmel 5210284Sjmallett * All rights reserved. 6215990Sjmallett * Copyright (c) 2014 Nathan Whitehorn 7215990Sjmallett * All rights reserved. 8215990Sjmallett * 9210284Sjmallett * Redistribution and use in source and binary forms are freely 10215990Sjmallett * permitted provided that the above copyright notice and this 11215990Sjmallett * paragraph and the following disclaimer are duplicated in all 12210284Sjmallett * such forms. 13215990Sjmallett * 14215990Sjmallett * This software is provided "AS IS" and without any express or 15215990Sjmallett * implied warranties, including, without limitation, the implied 16215990Sjmallett * warranties of merchantability and fitness for a particular 17210284Sjmallett * purpose. 18215990Sjmallett */ 19215990Sjmallett 20215990Sjmallett#include <sys/cdefs.h> 21215990Sjmallett__FBSDID("$FreeBSD: head/sys/boot/efi/boot1/boot1.c 293460 2016-01-09 03:20:01Z smh $"); 22210284Sjmallett 23215990Sjmallett#include <sys/param.h> 24215990Sjmallett#include <sys/dirent.h> 25215990Sjmallett#include <machine/elf.h> 26215990Sjmallett#include <machine/stdarg.h> 27210284Sjmallett#include <stand.h> 28215990Sjmallett 29215990Sjmallett#include <efi.h> 30215990Sjmallett#include <eficonsctl.h> 31215990Sjmallett 32215990Sjmallett#define _PATH_LOADER "/boot/loader.efi" 33215990Sjmallett#define _PATH_KERNEL "/boot/kernel/kernel" 34215990Sjmallett 35215990Sjmallett#define BSIZEMAX 16384 36215990Sjmallett 37215990Sjmallettvoid panic(const char *fmt, ...) __dead2; 38215990Sjmallettvoid putchar(int c); 39210284Sjmallett 40210284Sjmallettstatic int domount(EFI_DEVICE_PATH *device, EFI_BLOCK_IO *blkio, int quiet); 41210284Sjmallettstatic void load(const char *fname); 42210284Sjmallett 43210284Sjmallettstatic EFI_SYSTEM_TABLE *systab; 44210284Sjmallettstatic EFI_HANDLE *image; 45210284Sjmallett 46215990Sjmallettstatic EFI_GUID BlockIoProtocolGUID = BLOCK_IO_PROTOCOL; 47210284Sjmallettstatic EFI_GUID DevicePathGUID = DEVICE_PATH_PROTOCOL; 48210284Sjmallettstatic EFI_GUID LoadedImageGUID = LOADED_IMAGE_PROTOCOL; 49210284Sjmallettstatic EFI_GUID ConsoleControlGUID = EFI_CONSOLE_CONTROL_PROTOCOL_GUID; 50210284Sjmallett 51210284Sjmallettstatic EFI_BLOCK_IO *bootdev; 52210284Sjmallettstatic EFI_DEVICE_PATH *bootdevpath; 53215990Sjmallettstatic EFI_HANDLE *bootdevhandle; 54215990Sjmallett 55215990SjmallettEFI_STATUS efi_main(EFI_HANDLE Ximage, EFI_SYSTEM_TABLE* Xsystab) 56215990Sjmallett{ 57215990Sjmallett EFI_HANDLE handles[128]; 58215990Sjmallett EFI_BLOCK_IO *blkio; 59210284Sjmallett UINTN i, nparts = sizeof(handles), cols, rows, max_dim, best_mode; 60210284Sjmallett EFI_STATUS status; 61210284Sjmallett EFI_DEVICE_PATH *devpath; 62210284Sjmallett EFI_BOOT_SERVICES *BS; 63210284Sjmallett EFI_CONSOLE_CONTROL_PROTOCOL *ConsoleControl = NULL; 64210284Sjmallett SIMPLE_TEXT_OUTPUT_INTERFACE *conout = NULL; 65210284Sjmallett char *path = _PATH_LOADER; 66210284Sjmallett 67210284Sjmallett systab = Xsystab; 68210284Sjmallett image = Ximage; 69210284Sjmallett 70210284Sjmallett BS = systab->BootServices; 71210284Sjmallett status = BS->LocateProtocol(&ConsoleControlGUID, NULL, 72210284Sjmallett (VOID **)&ConsoleControl); 73210284Sjmallett if (status == EFI_SUCCESS) 74210284Sjmallett (void)ConsoleControl->SetMode(ConsoleControl, 75210284Sjmallett EfiConsoleControlScreenText); 76210284Sjmallett /* 77210284Sjmallett * Reset the console and find the best text mode. 78210284Sjmallett */ 79210284Sjmallett conout = systab->ConOut; 80210284Sjmallett conout->Reset(conout, TRUE); 81210284Sjmallett max_dim = best_mode = 0; 82210284Sjmallett for (i = 0; ; i++) { 83210284Sjmallett status = conout->QueryMode(conout, i, &cols, &rows); 84210284Sjmallett if (EFI_ERROR(status)) 85210284Sjmallett break; 86210284Sjmallett if (cols * rows > max_dim) { 87210284Sjmallett max_dim = cols * rows; 88210284Sjmallett best_mode = i; 89210284Sjmallett } 90210284Sjmallett } 91210284Sjmallett if (max_dim > 0) 92210284Sjmallett conout->SetMode(conout, best_mode); 93210284Sjmallett conout->EnableCursor(conout, TRUE); 94210284Sjmallett conout->ClearScreen(conout); 95210284Sjmallett 96210284Sjmallett printf("\n" 97210284Sjmallett ">> FreeBSD EFI boot block\n"); 98215990Sjmallett printf(" Loader path: %s\n", path); 99210284Sjmallett 100210284Sjmallett status = systab->BootServices->LocateHandle(ByProtocol, 101210284Sjmallett &BlockIoProtocolGUID, NULL, &nparts, handles); 102210284Sjmallett nparts /= sizeof(handles[0]); 103210284Sjmallett 104210284Sjmallett for (i = 0; i < nparts; i++) { 105210284Sjmallett status = systab->BootServices->HandleProtocol(handles[i], 106210284Sjmallett &DevicePathGUID, (void **)&devpath); 107210284Sjmallett if (EFI_ERROR(status)) 108210284Sjmallett continue; 109210284Sjmallett 110210284Sjmallett while (!IsDevicePathEnd(NextDevicePathNode(devpath))) 111210284Sjmallett devpath = NextDevicePathNode(devpath); 112210284Sjmallett 113210284Sjmallett status = systab->BootServices->HandleProtocol(handles[i], 114210284Sjmallett &BlockIoProtocolGUID, (void **)&blkio); 115210284Sjmallett if (EFI_ERROR(status)) 116210284Sjmallett continue; 117210284Sjmallett 118210284Sjmallett if (!blkio->Media->LogicalPartition) 119210284Sjmallett continue; 120210284Sjmallett 121210284Sjmallett if (domount(devpath, blkio, 1) >= 0) 122210284Sjmallett break; 123210284Sjmallett } 124210284Sjmallett 125210284Sjmallett if (i == nparts) 126210284Sjmallett panic("No bootable partition found"); 127210284Sjmallett 128210284Sjmallett bootdevhandle = handles[i]; 129210284Sjmallett load(path); 130210284Sjmallett 131210284Sjmallett panic("Load failed"); 132210284Sjmallett 133210284Sjmallett return EFI_SUCCESS; 134210284Sjmallett} 135210284Sjmallett 136210284Sjmallettstatic int 137210284Sjmallettdskread(void *buf, u_int64_t lba, int nblk) 138210284Sjmallett{ 139210284Sjmallett EFI_STATUS status; 140210284Sjmallett int size; 141210284Sjmallett 142210284Sjmallett lba = lba / (bootdev->Media->BlockSize / DEV_BSIZE); 143210284Sjmallett size = nblk * DEV_BSIZE; 144210284Sjmallett status = bootdev->ReadBlocks(bootdev, bootdev->Media->MediaId, lba, 145210284Sjmallett size, buf); 146210284Sjmallett 147210284Sjmallett if (EFI_ERROR(status)) 148210284Sjmallett return (-1); 149210284Sjmallett 150210284Sjmallett return (0); 151215990Sjmallett} 152210284Sjmallett 153210284Sjmallett#include "ufsread.c" 154210284Sjmallett 155210284Sjmallettstatic ssize_t 156210284Sjmallettfsstat(ufs_ino_t inode) 157219694Sjmallett{ 158219694Sjmallett#ifndef UFS2_ONLY 159219694Sjmallett static struct ufs1_dinode dp1; 160219694Sjmallett ufs1_daddr_t addr1; 161219694Sjmallett#endif 162219694Sjmallett#ifndef UFS1_ONLY 163219694Sjmallett static struct ufs2_dinode dp2; 164219694Sjmallett#endif 165219694Sjmallett static struct fs fs; 166219694Sjmallett static ufs_ino_t inomap; 167219694Sjmallett char *blkbuf; 168219694Sjmallett void *indbuf; 169219694Sjmallett size_t n, nb, size, off, vboff; 170210284Sjmallett ufs_lbn_t lbn; 171210284Sjmallett ufs2_daddr_t addr2, vbaddr; 172210284Sjmallett static ufs2_daddr_t blkmap, indmap; 173210284Sjmallett u_int u; 174210284Sjmallett 175210284Sjmallett blkbuf = dmadat->blkbuf; 176210284Sjmallett indbuf = dmadat->indbuf; 177215990Sjmallett if (!dsk_meta) { 178215990Sjmallett inomap = 0; 179215990Sjmallett for (n = 0; sblock_try[n] != -1; n++) { 180215990Sjmallett if (dskread(dmadat->sbbuf, sblock_try[n] / DEV_BSIZE, 181215990Sjmallett SBLOCKSIZE / DEV_BSIZE)) 182215990Sjmallett return -1; 183215990Sjmallett memcpy(&fs, dmadat->sbbuf, sizeof(struct fs)); 184215990Sjmallett if (( 185215990Sjmallett#if defined(UFS1_ONLY) 186215990Sjmallett fs.fs_magic == FS_UFS1_MAGIC 187215990Sjmallett#elif defined(UFS2_ONLY) 188215990Sjmallett (fs.fs_magic == FS_UFS2_MAGIC && 189215990Sjmallett fs.fs_sblockloc == sblock_try[n]) 190215990Sjmallett#else 191210284Sjmallett fs.fs_magic == FS_UFS1_MAGIC || 192210284Sjmallett (fs.fs_magic == FS_UFS2_MAGIC && 193210284Sjmallett fs.fs_sblockloc == sblock_try[n]) 194210284Sjmallett#endif 195210284Sjmallett ) && 196215990Sjmallett fs.fs_bsize <= MAXBSIZE && 197215990Sjmallett fs.fs_bsize >= sizeof(struct fs)) 198215990Sjmallett break; 199210284Sjmallett } 200210284Sjmallett if (sblock_try[n] == -1) { 201210284Sjmallett printf("Not ufs\n"); 202210284Sjmallett return -1; 203210284Sjmallett } 204210284Sjmallett dsk_meta++; 205210284Sjmallett } else 206210284Sjmallett memcpy(&fs, dmadat->sbbuf, sizeof(struct fs)); 207210284Sjmallett if (!inode) 208210284Sjmallett return 0; 209210284Sjmallett if (inomap != inode) { 210210284Sjmallett n = IPERVBLK(&fs); 211210284Sjmallett if (dskread(blkbuf, INO_TO_VBA(&fs, n, inode), DBPERVBLK)) 212210284Sjmallett return -1; 213210284Sjmallett n = INO_TO_VBO(n, inode); 214210284Sjmallett#if defined(UFS1_ONLY) 215210284Sjmallett memcpy(&dp1, (struct ufs1_dinode *)blkbuf + n, 216210284Sjmallett sizeof(struct ufs1_dinode)); 217215990Sjmallett#elif defined(UFS2_ONLY) 218215990Sjmallett memcpy(&dp2, (struct ufs2_dinode *)blkbuf + n, 219215990Sjmallett sizeof(struct ufs2_dinode)); 220215990Sjmallett#else 221215990Sjmallett if (fs.fs_magic == FS_UFS1_MAGIC) 222215990Sjmallett memcpy(&dp1, (struct ufs1_dinode *)blkbuf + n, 223215990Sjmallett sizeof(struct ufs1_dinode)); 224215990Sjmallett else 225215990Sjmallett memcpy(&dp2, (struct ufs2_dinode *)blkbuf + n, 226215990Sjmallett sizeof(struct ufs2_dinode)); 227215990Sjmallett#endif 228215990Sjmallett inomap = inode; 229215990Sjmallett fs_off = 0; 230215990Sjmallett blkmap = indmap = 0; 231210284Sjmallett } 232215990Sjmallett size = DIP(di_size); 233215990Sjmallett n = size - fs_off; 234215990Sjmallett return (n); 235215990Sjmallett} 236215990Sjmallett 237215990Sjmallettstatic struct dmadat __dmadat; 238215990Sjmallett 239215990Sjmallettstatic int 240215990Sjmallettdomount(EFI_DEVICE_PATH *device, EFI_BLOCK_IO *blkio, int quiet) 241210284Sjmallett{ 242210284Sjmallett 243210284Sjmallett dmadat = &__dmadat; 244210284Sjmallett bootdev = blkio; 245210284Sjmallett bootdevpath = device; 246210284Sjmallett if (fsread(0, NULL, 0)) { 247210284Sjmallett if (!quiet) 248210284Sjmallett printf("domount: can't read superblock\n"); 249210284Sjmallett return (-1); 250210284Sjmallett } 251210284Sjmallett if (!quiet) 252210284Sjmallett printf("Succesfully mounted UFS filesystem\n"); 253210284Sjmallett return (0); 254210284Sjmallett} 255210284Sjmallett 256210284Sjmallettstatic void 257210284Sjmallettload(const char *fname) 258210284Sjmallett{ 259210284Sjmallett ufs_ino_t ino; 260210284Sjmallett EFI_STATUS status; 261210284Sjmallett EFI_HANDLE loaderhandle; 262210284Sjmallett EFI_LOADED_IMAGE *loaded_image; 263210284Sjmallett void *buffer; 264210284Sjmallett size_t bufsize; 265210284Sjmallett 266210284Sjmallett if ((ino = lookup(fname)) == 0) { 267210284Sjmallett printf("File %s not found\n", fname); 268210284Sjmallett return; 269210284Sjmallett } 270210284Sjmallett 271210284Sjmallett bufsize = fsstat(ino); 272210284Sjmallett status = systab->BootServices->AllocatePool(EfiLoaderData, 273210284Sjmallett bufsize, &buffer); 274210284Sjmallett fsread(ino, buffer, bufsize); 275210284Sjmallett 276210284Sjmallett /* XXX: For secure boot, we need our own loader here */ 277210284Sjmallett status = systab->BootServices->LoadImage(TRUE, image, bootdevpath, 278210284Sjmallett buffer, bufsize, &loaderhandle); 279210284Sjmallett if (EFI_ERROR(status)) 280210284Sjmallett printf("LoadImage failed with error %lu\n", 281210284Sjmallett EFI_ERROR_CODE(status)); 282210284Sjmallett 283210284Sjmallett status = systab->BootServices->HandleProtocol(loaderhandle, 284210284Sjmallett &LoadedImageGUID, (VOID**)&loaded_image); 285210284Sjmallett if (EFI_ERROR(status)) 286210284Sjmallett printf("HandleProtocol failed with error %lu\n", 287210284Sjmallett EFI_ERROR_CODE(status)); 288210284Sjmallett 289210284Sjmallett loaded_image->DeviceHandle = bootdevhandle; 290210284Sjmallett 291210284Sjmallett status = systab->BootServices->StartImage(loaderhandle, NULL, NULL); 292210284Sjmallett if (EFI_ERROR(status)) 293210284Sjmallett printf("StartImage failed with error %lu\n", 294210284Sjmallett EFI_ERROR_CODE(status)); 295210284Sjmallett} 296210284Sjmallett 297210284Sjmallettvoid 298210284Sjmallettpanic(const char *fmt, ...) 299210284Sjmallett{ 300210284Sjmallett va_list ap; 301210284Sjmallett 302210284Sjmallett printf("panic: "); 303210284Sjmallett va_start(ap, fmt); 304210284Sjmallett vprintf(fmt, ap); 305210284Sjmallett va_end(ap); 306215990Sjmallett printf("\n"); 307215990Sjmallett 308215990Sjmallett while (1) {} 309215990Sjmallett} 310210284Sjmallett 311210284Sjmallettvoid 312215990Sjmallettputchar(int c) 313210284Sjmallett{ 314210284Sjmallett CHAR16 buf[2]; 315210284Sjmallett 316210284Sjmallett if (c == '\n') { 317210284Sjmallett buf[0] = '\r'; 318210284Sjmallett buf[1] = 0; 319210284Sjmallett systab->ConOut->OutputString(systab->ConOut, buf); 320210284Sjmallett } 321210284Sjmallett buf[0] = c; 322210284Sjmallett buf[1] = 0; 323210284Sjmallett systab->ConOut->OutputString(systab->ConOut, buf); 324210284Sjmallett} 325210284Sjmallett