boot1.c revision 294981
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 294981 2016-01-28 12:11:42Z 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>> FreeBSD EFI boot block\n"); 98 printf(" Loader path: %s\n", path); 99 100 status = systab->BootServices->LocateHandle(ByProtocol, 101 &BlockIoProtocolGUID, NULL, &nparts, handles); 102 nparts /= sizeof(handles[0]); 103 104 for (i = 0; i < nparts; i++) { 105 status = systab->BootServices->HandleProtocol(handles[i], 106 &DevicePathGUID, (void **)&devpath); 107 if (EFI_ERROR(status)) 108 continue; 109 110 while (!IsDevicePathEnd(NextDevicePathNode(devpath))) 111 devpath = NextDevicePathNode(devpath); 112 113 status = systab->BootServices->HandleProtocol(handles[i], 114 &BlockIoProtocolGUID, (void **)&blkio); 115 if (EFI_ERROR(status)) 116 continue; 117 118 if (!blkio->Media->LogicalPartition) 119 continue; 120 121 if (domount(devpath, blkio, 1) >= 0) 122 break; 123 } 124 125 if (i == nparts) 126 panic("No bootable partition found"); 127 128 bootdevhandle = handles[i]; 129 load(path); 130 131 panic("Load failed"); 132 133 return EFI_SUCCESS; 134} 135 136static int 137dskread(void *buf, u_int64_t lba, int nblk) 138{ 139 EFI_STATUS status; 140 int size; 141 142 lba = lba / (bootdev->Media->BlockSize / DEV_BSIZE); 143 size = nblk * DEV_BSIZE; 144 status = bootdev->ReadBlocks(bootdev, bootdev->Media->MediaId, lba, 145 size, buf); 146 147 if (EFI_ERROR(status)) 148 return (-1); 149 150 return (0); 151} 152 153#include "ufsread.c" 154 155static ssize_t 156fsstat(ufs_ino_t inode) 157{ 158#ifndef UFS2_ONLY 159 static struct ufs1_dinode dp1; 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, size; 169 static ufs2_daddr_t blkmap, indmap; 170 171 blkbuf = dmadat->blkbuf; 172 indbuf = dmadat->indbuf; 173 if (!dsk_meta) { 174 inomap = 0; 175 for (n = 0; sblock_try[n] != -1; n++) { 176 if (dskread(dmadat->sbbuf, sblock_try[n] / DEV_BSIZE, 177 SBLOCKSIZE / DEV_BSIZE)) 178 return -1; 179 memcpy(&fs, dmadat->sbbuf, sizeof(struct fs)); 180 if (( 181#if defined(UFS1_ONLY) 182 fs.fs_magic == FS_UFS1_MAGIC 183#elif defined(UFS2_ONLY) 184 (fs.fs_magic == FS_UFS2_MAGIC && 185 fs.fs_sblockloc == sblock_try[n]) 186#else 187 fs.fs_magic == FS_UFS1_MAGIC || 188 (fs.fs_magic == FS_UFS2_MAGIC && 189 fs.fs_sblockloc == sblock_try[n]) 190#endif 191 ) && 192 fs.fs_bsize <= MAXBSIZE && 193 fs.fs_bsize >= (int32_t)sizeof(struct fs)) 194 break; 195 } 196 if (sblock_try[n] == -1) { 197 return -1; 198 } 199 dsk_meta++; 200 } else 201 memcpy(&fs, dmadat->sbbuf, sizeof(struct fs)); 202 if (!inode) 203 return 0; 204 if (inomap != inode) { 205 n = IPERVBLK(&fs); 206 if (dskread(blkbuf, INO_TO_VBA(&fs, n, inode), DBPERVBLK)) 207 return -1; 208 n = INO_TO_VBO(n, inode); 209#if defined(UFS1_ONLY) 210 memcpy(&dp1, (struct ufs1_dinode *)blkbuf + n, 211 sizeof(struct ufs1_dinode)); 212#elif defined(UFS2_ONLY) 213 memcpy(&dp2, (struct ufs2_dinode *)blkbuf + n, 214 sizeof(struct ufs2_dinode)); 215#else 216 if (fs.fs_magic == FS_UFS1_MAGIC) 217 memcpy(&dp1, (struct ufs1_dinode *)(void *)blkbuf + n, 218 sizeof(struct ufs1_dinode)); 219 else 220 memcpy(&dp2, (struct ufs2_dinode *)(void *)blkbuf + n, 221 sizeof(struct ufs2_dinode)); 222#endif 223 inomap = inode; 224 fs_off = 0; 225 blkmap = indmap = 0; 226 } 227 size = DIP(di_size); 228 n = size - fs_off; 229 return (n); 230} 231 232static struct dmadat __dmadat; 233 234static int 235domount(EFI_DEVICE_PATH *device, EFI_BLOCK_IO *blkio, int quiet) 236{ 237 238 dmadat = &__dmadat; 239 bootdev = blkio; 240 bootdevpath = device; 241 if (fsread(0, NULL, 0)) { 242 if (!quiet) 243 printf("domount: can't read superblock\n"); 244 return (-1); 245 } 246 if (!quiet) 247 printf("Succesfully mounted UFS filesystem\n"); 248 return (0); 249} 250 251static void 252load(const char *fname) 253{ 254 ufs_ino_t ino; 255 EFI_STATUS status; 256 EFI_HANDLE loaderhandle; 257 EFI_LOADED_IMAGE *loaded_image; 258 void *buffer; 259 size_t bufsize; 260 261 if ((ino = lookup(fname)) == 0) { 262 printf("File %s not found\n", fname); 263 return; 264 } 265 266 bufsize = fsstat(ino); 267 status = systab->BootServices->AllocatePool(EfiLoaderData, 268 bufsize, &buffer); 269 fsread(ino, buffer, bufsize); 270 271 /* XXX: For secure boot, we need our own loader here */ 272 status = systab->BootServices->LoadImage(TRUE, image, bootdevpath, 273 buffer, bufsize, &loaderhandle); 274 if (EFI_ERROR(status)) 275 printf("LoadImage failed with error %lu\n", 276 EFI_ERROR_CODE(status)); 277 278 status = systab->BootServices->HandleProtocol(loaderhandle, 279 &LoadedImageGUID, (VOID**)&loaded_image); 280 if (EFI_ERROR(status)) 281 printf("HandleProtocol failed with error %lu\n", 282 EFI_ERROR_CODE(status)); 283 284 loaded_image->DeviceHandle = bootdevhandle; 285 286 status = systab->BootServices->StartImage(loaderhandle, NULL, NULL); 287 if (EFI_ERROR(status)) 288 printf("StartImage failed with error %lu\n", 289 EFI_ERROR_CODE(status)); 290} 291 292void 293panic(const char *fmt, ...) 294{ 295 va_list ap; 296 297 printf("panic: "); 298 va_start(ap, fmt); 299 vprintf(fmt, ap); 300 va_end(ap); 301 printf("\n"); 302 303 while (1) {} 304} 305 306void 307putchar(int c) 308{ 309 CHAR16 buf[2]; 310 311 if (c == '\n') { 312 buf[0] = '\r'; 313 buf[1] = 0; 314 systab->ConOut->OutputString(systab->ConOut, buf); 315 } 316 buf[0] = c; 317 buf[1] = 0; 318 systab->ConOut->OutputString(systab->ConOut, buf); 319} 320