boot1.c revision 293724
1/*- 2 * Copyright (c) 1998 Robert Nordier 3 * All rights reserved. 4 * Copyright (c) 2001 Robert Drehmel 5 * All rights reserved. 6 * Copyright (c) 2014 Nathan Whitehorn 7 * All rights reserved. 8 * 9 * Redistribution and use in source and binary forms are freely 10 * permitted provided that the above copyright notice and this 11 * paragraph and the following disclaimer are duplicated in all 12 * such forms. 13 * 14 * This software is provided "AS IS" and without any express or 15 * implied warranties, including, without limitation, the implied 16 * warranties of merchantability and fitness for a particular 17 * purpose. 18 */ 19 20#include <sys/cdefs.h> 21__FBSDID("$FreeBSD: head/sys/boot/efi/boot1/boot1.c 293724 2016-01-12 02:17:39Z smh $"); 22 23#include <sys/param.h> 24#include <sys/dirent.h> 25#include <machine/elf.h> 26#include <machine/stdarg.h> 27#include <stand.h> 28 29#include <efi.h> 30#include <eficonsctl.h> 31 32#define _PATH_LOADER "/boot/loader.efi" 33#define _PATH_KERNEL "/boot/kernel/kernel" 34 35#define BSIZEMAX 16384 36 37void panic(const char *fmt, ...) __dead2; 38void putchar(int c); 39EFI_STATUS efi_main(EFI_HANDLE Ximage, EFI_SYSTEM_TABLE* Xsystab); 40 41static int domount(EFI_DEVICE_PATH *device, EFI_BLOCK_IO *blkio, int quiet); 42static void load(const char *fname); 43 44static EFI_SYSTEM_TABLE *systab; 45static EFI_HANDLE *image; 46 47static EFI_GUID BlockIoProtocolGUID = BLOCK_IO_PROTOCOL; 48static EFI_GUID DevicePathGUID = DEVICE_PATH_PROTOCOL; 49static EFI_GUID LoadedImageGUID = LOADED_IMAGE_PROTOCOL; 50static EFI_GUID ConsoleControlGUID = EFI_CONSOLE_CONTROL_PROTOCOL_GUID; 51 52static EFI_BLOCK_IO *bootdev; 53static EFI_DEVICE_PATH *bootdevpath; 54static EFI_HANDLE *bootdevhandle; 55 56EFI_STATUS efi_main(EFI_HANDLE Ximage, EFI_SYSTEM_TABLE* Xsystab) 57{ 58 EFI_HANDLE handles[128]; 59 EFI_BLOCK_IO *blkio; 60 UINTN i, nparts = sizeof(handles), cols, rows, max_dim, best_mode; 61 EFI_STATUS status; 62 EFI_DEVICE_PATH *devpath; 63 EFI_BOOT_SERVICES *BS; 64 EFI_CONSOLE_CONTROL_PROTOCOL *ConsoleControl = NULL; 65 SIMPLE_TEXT_OUTPUT_INTERFACE *conout = NULL; 66 const char *path = _PATH_LOADER; 67 68 systab = Xsystab; 69 image = Ximage; 70 71 BS = systab->BootServices; 72 status = BS->LocateProtocol(&ConsoleControlGUID, NULL, 73 (VOID **)&ConsoleControl); 74 if (status == EFI_SUCCESS) 75 (void)ConsoleControl->SetMode(ConsoleControl, 76 EfiConsoleControlScreenText); 77 /* 78 * Reset the console and find the best text mode. 79 */ 80 conout = systab->ConOut; 81 conout->Reset(conout, TRUE); 82 max_dim = best_mode = 0; 83 for (i = 0; ; i++) { 84 status = conout->QueryMode(conout, i, &cols, &rows); 85 if (EFI_ERROR(status)) 86 break; 87 if (cols * rows > max_dim) { 88 max_dim = cols * rows; 89 best_mode = i; 90 } 91 } 92 if (max_dim > 0) 93 conout->SetMode(conout, best_mode); 94 conout->EnableCursor(conout, TRUE); 95 conout->ClearScreen(conout); 96 97 printf("\n" 98 ">> FreeBSD EFI boot block\n"); 99 printf(" Loader path: %s\n", path); 100 101 status = systab->BootServices->LocateHandle(ByProtocol, 102 &BlockIoProtocolGUID, NULL, &nparts, handles); 103 nparts /= sizeof(handles[0]); 104 105 for (i = 0; i < nparts; i++) { 106 status = systab->BootServices->HandleProtocol(handles[i], 107 &DevicePathGUID, (void **)&devpath); 108 if (EFI_ERROR(status)) 109 continue; 110 111 while (!IsDevicePathEnd(NextDevicePathNode(devpath))) 112 devpath = NextDevicePathNode(devpath); 113 114 status = systab->BootServices->HandleProtocol(handles[i], 115 &BlockIoProtocolGUID, (void **)&blkio); 116 if (EFI_ERROR(status)) 117 continue; 118 119 if (!blkio->Media->LogicalPartition) 120 continue; 121 122 if (domount(devpath, blkio, 1) >= 0) 123 break; 124 } 125 126 if (i == nparts) 127 panic("No bootable partition found"); 128 129 bootdevhandle = handles[i]; 130 load(path); 131 132 panic("Load failed"); 133 134 return EFI_SUCCESS; 135} 136 137static int 138dskread(void *buf, u_int64_t lba, int nblk) 139{ 140 EFI_STATUS status; 141 int size; 142 143 lba = lba / (bootdev->Media->BlockSize / DEV_BSIZE); 144 size = nblk * DEV_BSIZE; 145 status = bootdev->ReadBlocks(bootdev, bootdev->Media->MediaId, lba, 146 size, buf); 147 148 if (EFI_ERROR(status)) 149 return (-1); 150 151 return (0); 152} 153 154#include "ufsread.c" 155 156static ssize_t 157fsstat(ufs_ino_t inode) 158{ 159#ifndef UFS2_ONLY 160 static struct ufs1_dinode dp1; 161#endif 162#ifndef UFS1_ONLY 163 static struct ufs2_dinode dp2; 164#endif 165 static struct fs fs; 166 static ufs_ino_t inomap; 167 char *blkbuf; 168 void *indbuf; 169 size_t n, size; 170 static ufs2_daddr_t blkmap, indmap; 171 172 blkbuf = dmadat->blkbuf; 173 indbuf = dmadat->indbuf; 174 if (!dsk_meta) { 175 inomap = 0; 176 for (n = 0; sblock_try[n] != -1; n++) { 177 if (dskread(dmadat->sbbuf, sblock_try[n] / DEV_BSIZE, 178 SBLOCKSIZE / DEV_BSIZE)) 179 return -1; 180 memcpy(&fs, dmadat->sbbuf, sizeof(struct fs)); 181 if (( 182#if defined(UFS1_ONLY) 183 fs.fs_magic == FS_UFS1_MAGIC 184#elif defined(UFS2_ONLY) 185 (fs.fs_magic == FS_UFS2_MAGIC && 186 fs.fs_sblockloc == sblock_try[n]) 187#else 188 fs.fs_magic == FS_UFS1_MAGIC || 189 (fs.fs_magic == FS_UFS2_MAGIC && 190 fs.fs_sblockloc == sblock_try[n]) 191#endif 192 ) && 193 fs.fs_bsize <= MAXBSIZE && 194 fs.fs_bsize >= (int32_t)sizeof(struct fs)) 195 break; 196 } 197 if (sblock_try[n] == -1) { 198 return -1; 199 } 200 dsk_meta++; 201 } else 202 memcpy(&fs, dmadat->sbbuf, sizeof(struct fs)); 203 if (!inode) 204 return 0; 205 if (inomap != inode) { 206 n = IPERVBLK(&fs); 207 if (dskread(blkbuf, INO_TO_VBA(&fs, n, inode), DBPERVBLK)) 208 return -1; 209 n = INO_TO_VBO(n, inode); 210#if defined(UFS1_ONLY) 211 memcpy(&dp1, (struct ufs1_dinode *)blkbuf + n, 212 sizeof(struct ufs1_dinode)); 213#elif defined(UFS2_ONLY) 214 memcpy(&dp2, (struct ufs2_dinode *)blkbuf + n, 215 sizeof(struct ufs2_dinode)); 216#else 217 if (fs.fs_magic == FS_UFS1_MAGIC) 218 memcpy(&dp1, (struct ufs1_dinode *)(void *)blkbuf + n, 219 sizeof(struct ufs1_dinode)); 220 else 221 memcpy(&dp2, (struct ufs2_dinode *)(void *)blkbuf + n, 222 sizeof(struct ufs2_dinode)); 223#endif 224 inomap = inode; 225 fs_off = 0; 226 blkmap = indmap = 0; 227 } 228 size = DIP(di_size); 229 n = size - fs_off; 230 return (n); 231} 232 233static struct dmadat __dmadat; 234 235static int 236domount(EFI_DEVICE_PATH *device, EFI_BLOCK_IO *blkio, int quiet) 237{ 238 239 dmadat = &__dmadat; 240 bootdev = blkio; 241 bootdevpath = device; 242 if (fsread(0, NULL, 0)) { 243 if (!quiet) 244 printf("domount: can't read superblock\n"); 245 return (-1); 246 } 247 if (!quiet) 248 printf("Succesfully mounted UFS filesystem\n"); 249 return (0); 250} 251 252static void 253load(const char *fname) 254{ 255 ufs_ino_t ino; 256 EFI_STATUS status; 257 EFI_HANDLE loaderhandle; 258 EFI_LOADED_IMAGE *loaded_image; 259 void *buffer; 260 size_t bufsize; 261 262 if ((ino = lookup(fname)) == 0) { 263 printf("File %s not found\n", fname); 264 return; 265 } 266 267 bufsize = fsstat(ino); 268 status = systab->BootServices->AllocatePool(EfiLoaderData, 269 bufsize, &buffer); 270 fsread(ino, buffer, bufsize); 271 272 /* XXX: For secure boot, we need our own loader here */ 273 status = systab->BootServices->LoadImage(TRUE, image, bootdevpath, 274 buffer, bufsize, &loaderhandle); 275 if (EFI_ERROR(status)) 276 printf("LoadImage failed with error %lu\n", 277 EFI_ERROR_CODE(status)); 278 279 status = systab->BootServices->HandleProtocol(loaderhandle, 280 &LoadedImageGUID, (VOID**)&loaded_image); 281 if (EFI_ERROR(status)) 282 printf("HandleProtocol failed with error %lu\n", 283 EFI_ERROR_CODE(status)); 284 285 loaded_image->DeviceHandle = bootdevhandle; 286 287 status = systab->BootServices->StartImage(loaderhandle, NULL, NULL); 288 if (EFI_ERROR(status)) 289 printf("StartImage failed with error %lu\n", 290 EFI_ERROR_CODE(status)); 291} 292 293void 294panic(const char *fmt, ...) 295{ 296 va_list ap; 297 298 printf("panic: "); 299 va_start(ap, fmt); 300 vprintf(fmt, ap); 301 va_end(ap); 302 printf("\n"); 303 304 while (1) {} 305} 306 307void 308putchar(int c) 309{ 310 CHAR16 buf[2]; 311 312 if (c == '\n') { 313 buf[0] = '\r'; 314 buf[1] = 0; 315 systab->ConOut->OutputString(systab->ConOut, buf); 316 } 317 buf[0] = c; 318 buf[1] = 0; 319 systab->ConOut->OutputString(systab->ConOut, buf); 320} 321