Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/stand/efi/boot1/ufs_module.c
34860 views
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
* Copyright (c) 2015 Eric McCorkle
9
* All rights reverved.
10
*
11
* Redistribution and use in source and binary forms, with or without
12
* modification, are permitted provided that the following conditions
13
* are met:
14
* 1. Redistributions of source code must retain the above copyright
15
* notice, this list of conditions and the following disclaimer.
16
* 2. Redistributions in binary form must reproduce the above copyright
17
* notice, this list of conditions and the following disclaimer in the
18
* documentation and/or other materials provided with the distribution.
19
*
20
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30
* SUCH DAMAGE.
31
*/
32
33
#include <stdarg.h>
34
#include <stdbool.h>
35
36
#include <sys/param.h>
37
#include <sys/disk/bsd.h>
38
#include <efi.h>
39
40
#include "boot_module.h"
41
42
#define BSD_LABEL_BUFFER 8192
43
#define BSD_LABEL_OFFSET DEV_BSIZE
44
45
static dev_info_t *devinfo;
46
static dev_info_t *devices;
47
48
static int
49
dskread(void *buf, uint64_t lba, int nblk)
50
{
51
int size;
52
EFI_STATUS status;
53
54
lba += devinfo->partoff;
55
lba = lba / (devinfo->dev->Media->BlockSize / DEV_BSIZE);
56
size = nblk * DEV_BSIZE;
57
58
status = devinfo->dev->ReadBlocks(devinfo->dev,
59
devinfo->dev->Media->MediaId, lba, size, buf);
60
61
if (status != EFI_SUCCESS) {
62
DPRINTF("dskread: failed dev: %p, id: %u, lba: %ju, size: %d, "
63
"status: %lu\n", devinfo->dev,
64
devinfo->dev->Media->MediaId, (uintmax_t)lba, size,
65
EFI_ERROR_CODE(status));
66
return (-1);
67
}
68
69
return (0);
70
}
71
72
#include "ufsread.c"
73
74
static struct dmadat __dmadat __aligned(512);
75
static char ufs_buffer[BSD_LABEL_BUFFER] __aligned(512);
76
77
static int
78
init_dev(dev_info_t* dev)
79
{
80
struct disklabel *dl;
81
uint64_t bs;
82
int ok;
83
84
devinfo = dev;
85
dmadat = &__dmadat;
86
87
/*
88
* First try offset 0. This is the typical GPT case where we have no
89
* further partitioning (as well as the degenerate MBR case where
90
* the bsdlabel has a 0 offset).
91
*/
92
devinfo->partoff = 0;
93
ok = fsread(0, NULL, 0);
94
if (ok >= 0)
95
return (ok);
96
97
/*
98
* Next, we look for a bsdlabel. This is technically located in sector
99
* 1. For 4k sectors, this offset is 4096, for 512b sectors it's
100
* 512. However, we have to fall back to 512 here because we create
101
* images that assume 512 byte blocks, but these can be put on devices
102
* who have 4k (or other) block sizes. If there's a crazy block size, we
103
* skip the 'at one sector' and go stright to checking at 512 bytes.
104
* There are other offsets that are historic, but we don't probe those
105
* since they were never used for MBR disks on FreeBSD on systems that
106
* could boot UEFI. UEFI is little endian only, as are BSD labels. We
107
* will retry fsread(0) only if there's a label found with a non-zero
108
* offset.
109
*/
110
if (dskread(ufs_buffer, 0, BSD_LABEL_BUFFER / DEV_BSIZE) != 0)
111
return (-1);
112
dl = NULL;
113
bs = devinfo->dev->Media->BlockSize;
114
if (bs != 0 && bs <= BSD_LABEL_BUFFER / 2)
115
dl = (struct disklabel *)&ufs_buffer[bs];
116
if (dl == NULL || dl->d_magic != BSD_MAGIC || dl->d_magic2 != BSD_MAGIC)
117
dl = (struct disklabel *)&ufs_buffer[BSD_LABEL_OFFSET];
118
if (dl->d_magic != BSD_MAGIC || dl->d_magic2 != BSD_MAGIC ||
119
dl->d_partitions[0].p_offset == 0)
120
return (-1);
121
devinfo->partoff = dl->d_partitions[0].p_offset;
122
return (fsread(0, NULL, 0));
123
}
124
125
static EFI_STATUS
126
probe(dev_info_t* dev)
127
{
128
129
if (init_dev(dev) < 0)
130
return (EFI_UNSUPPORTED);
131
132
add_device(&devices, dev);
133
134
return (EFI_SUCCESS);
135
}
136
137
static EFI_STATUS
138
load(const char *filepath, dev_info_t *dev, void **bufp, size_t *bufsize)
139
{
140
ufs_ino_t ino;
141
size_t size;
142
ssize_t read;
143
void *buf;
144
145
#ifdef EFI_DEBUG
146
{
147
CHAR16 *text = efi_devpath_name(dev->devpath);
148
DPRINTF("UFS Loading '%s' from %S\n", filepath, text);
149
efi_free_devpath_name(text);
150
}
151
#endif
152
if (init_dev(dev) < 0) {
153
DPRINTF("Failed to init device\n");
154
return (EFI_UNSUPPORTED);
155
}
156
157
if ((ino = lookup(filepath)) == 0) {
158
DPRINTF("Failed to lookup '%s' (file not found?)\n", filepath);
159
return (EFI_NOT_FOUND);
160
}
161
162
if (fsread_size(ino, NULL, 0, &size) < 0 || size <= 0) {
163
printf("Failed to read size of '%s' ino: %d\n", filepath, ino);
164
return (EFI_INVALID_PARAMETER);
165
}
166
167
buf = malloc(size);
168
if (buf == NULL) {
169
printf("Failed to allocate read buffer %zu for '%s'\n",
170
size, filepath);
171
return (EFI_OUT_OF_RESOURCES);
172
}
173
174
read = fsread(ino, buf, size);
175
if ((size_t)read != size) {
176
printf("Failed to read '%s' (%zd != %zu)\n", filepath, read,
177
size);
178
free(buf);
179
return (EFI_INVALID_PARAMETER);
180
}
181
182
DPRINTF("Load complete\n");
183
184
*bufp = buf;
185
*bufsize = size;
186
187
return (EFI_SUCCESS);
188
}
189
190
static void
191
status(void)
192
{
193
int i;
194
dev_info_t *dev;
195
196
for (dev = devices, i = 0; dev != NULL; dev = dev->next, i++)
197
;
198
199
printf("%s found ", ufs_module.name);
200
switch (i) {
201
case 0:
202
printf("no partitions\n");
203
break;
204
case 1:
205
printf("%d partition\n", i);
206
break;
207
default:
208
printf("%d partitions\n", i);
209
}
210
}
211
212
static dev_info_t *
213
_devices(void)
214
{
215
216
return (devices);
217
}
218
219
const boot_module_t ufs_module =
220
{
221
.name = "UFS",
222
.probe = probe,
223
.load = load,
224
.status = status,
225
.devices = _devices
226
};
227
228