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