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