SECURITY: Add SECURITY file
[grub.git] / grub-core / fs / cbfs.c
blob581215ef1886e7eba6713bd215ce695ae173341a
1 /* cbfs.c - cbfs and tar filesystem. */
2 /*
3 * GRUB -- GRand Unified Bootloader
4 * Copyright (C) 2007,2008,2009,2013 Free Software Foundation, Inc.
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 #include <grub/misc.h>
21 #include <grub/disk.h>
22 #include <grub/archelp.h>
24 #include <grub/file.h>
25 #include <grub/mm.h>
26 #include <grub/dl.h>
27 #include <grub/i18n.h>
28 #include <grub/cbfs_core.h>
30 GRUB_MOD_LICENSE ("GPLv3+");
33 struct grub_archelp_data
35 grub_disk_t disk;
36 grub_off_t hofs, next_hofs;
37 grub_off_t dofs;
38 grub_off_t size;
39 grub_off_t cbfs_start;
40 grub_off_t cbfs_end;
41 grub_off_t cbfs_align;
44 static grub_err_t
45 grub_cbfs_find_file (struct grub_archelp_data *data, char **name,
46 grub_int32_t *mtime,
47 grub_uint32_t *mode)
49 grub_size_t offset;
50 for (;;
51 data->dofs = data->hofs + offset,
52 data->next_hofs = ALIGN_UP (data->dofs + data->size, data->cbfs_align))
54 struct cbfs_file hd;
55 grub_size_t namesize;
57 data->hofs = data->next_hofs;
59 if (data->hofs >= data->cbfs_end)
61 *mode = GRUB_ARCHELP_ATTR_END;
62 return GRUB_ERR_NONE;
65 if (grub_disk_read (data->disk, 0, data->hofs, sizeof (hd), &hd))
66 return grub_errno;
68 if (grub_memcmp (hd.magic, CBFS_FILE_MAGIC, sizeof (hd.magic)) != 0)
70 *mode = GRUB_ARCHELP_ATTR_END;
71 return GRUB_ERR_NONE;
73 data->size = grub_be_to_cpu32 (hd.len);
74 (void) mtime;
75 offset = grub_be_to_cpu32 (hd.offset);
77 *mode = GRUB_ARCHELP_ATTR_FILE | GRUB_ARCHELP_ATTR_NOTIME;
79 namesize = offset;
80 if (namesize >= sizeof (hd))
81 namesize -= sizeof (hd);
82 if (namesize == 0)
83 continue;
84 *name = grub_malloc (namesize + 1);
85 if (*name == NULL)
86 return grub_errno;
88 if (grub_disk_read (data->disk, 0, data->hofs + sizeof (hd),
89 namesize, *name))
91 grub_free (*name);
92 return grub_errno;
95 if ((*name)[0] == '\0')
97 grub_free (*name);
98 *name = NULL;
99 continue;
102 (*name)[namesize] = 0;
104 data->dofs = data->hofs + offset;
105 data->next_hofs = ALIGN_UP (data->dofs + data->size, data->cbfs_align);
106 return GRUB_ERR_NONE;
110 static void
111 grub_cbfs_rewind (struct grub_archelp_data *data)
113 data->next_hofs = data->cbfs_start;
116 static struct grub_archelp_ops arcops =
118 .find_file = grub_cbfs_find_file,
119 .rewind = grub_cbfs_rewind
122 static int
123 validate_head (struct cbfs_header *head)
125 return (head->magic == grub_cpu_to_be32_compile_time (CBFS_HEADER_MAGIC)
126 && (head->version
127 == grub_cpu_to_be32_compile_time (CBFS_HEADER_VERSION1)
128 || head->version
129 == grub_cpu_to_be32_compile_time (CBFS_HEADER_VERSION2))
130 && (grub_be_to_cpu32 (head->bootblocksize)
131 < grub_be_to_cpu32 (head->romsize))
132 && (grub_be_to_cpu32 (head->offset)
133 < grub_be_to_cpu32 (head->romsize))
134 && (grub_be_to_cpu32 (head->offset)
135 + grub_be_to_cpu32 (head->bootblocksize)
136 < grub_be_to_cpu32 (head->romsize))
137 && head->align != 0
138 && (head->align & (head->align - 1)) == 0
139 && head->romsize != 0);
142 static struct grub_archelp_data *
143 grub_cbfs_mount (grub_disk_t disk)
145 struct cbfs_file hd;
146 struct grub_archelp_data *data = NULL;
147 grub_uint32_t ptr;
148 grub_off_t header_off;
149 struct cbfs_header head;
151 if (grub_disk_native_sectors (disk) == GRUB_DISK_SIZE_UNKNOWN)
152 goto fail;
154 if (grub_disk_read (disk, grub_disk_native_sectors (disk) - 1,
155 GRUB_DISK_SECTOR_SIZE - sizeof (ptr),
156 sizeof (ptr), &ptr))
157 goto fail;
159 ptr = grub_cpu_to_le32 (ptr);
160 header_off = (grub_disk_native_sectors (disk) << GRUB_DISK_SECTOR_BITS)
161 + (grub_int32_t) ptr;
163 if (grub_disk_read (disk, 0, header_off,
164 sizeof (head), &head))
165 goto fail;
167 if (!validate_head (&head))
168 goto fail;
170 data = (struct grub_archelp_data *) grub_zalloc (sizeof (*data));
171 if (!data)
172 goto fail;
174 data->cbfs_start = (grub_disk_native_sectors (disk) << GRUB_DISK_SECTOR_BITS)
175 - (grub_be_to_cpu32 (head.romsize) - grub_be_to_cpu32 (head.offset));
176 data->cbfs_end = (grub_disk_native_sectors (disk) << GRUB_DISK_SECTOR_BITS)
177 - grub_be_to_cpu32 (head.bootblocksize);
178 data->cbfs_align = grub_be_to_cpu32 (head.align);
180 if (data->cbfs_start >= (grub_disk_native_sectors (disk) << GRUB_DISK_SECTOR_BITS))
181 goto fail;
182 if (data->cbfs_end > (grub_disk_native_sectors (disk) << GRUB_DISK_SECTOR_BITS))
183 data->cbfs_end = (grub_disk_native_sectors (disk) << GRUB_DISK_SECTOR_BITS);
185 data->next_hofs = data->cbfs_start;
187 if (grub_disk_read (disk, 0, data->cbfs_start, sizeof (hd), &hd))
188 goto fail;
190 if (grub_memcmp (hd.magic, CBFS_FILE_MAGIC, sizeof (CBFS_FILE_MAGIC) - 1))
191 goto fail;
193 data->disk = disk;
195 return data;
197 fail:
198 grub_free (data);
199 grub_error (GRUB_ERR_BAD_FS, "not a cbfs filesystem");
200 return 0;
203 static grub_err_t
204 grub_cbfs_dir (grub_device_t device, const char *path_in,
205 grub_fs_dir_hook_t hook, void *hook_data)
207 struct grub_archelp_data *data;
208 grub_err_t err;
210 data = grub_cbfs_mount (device->disk);
211 if (!data)
212 return grub_errno;
214 err = grub_archelp_dir (data, &arcops,
215 path_in, hook, hook_data);
217 grub_free (data);
219 return err;
222 static grub_err_t
223 grub_cbfs_open (grub_file_t file, const char *name_in)
225 struct grub_archelp_data *data;
226 grub_err_t err;
228 data = grub_cbfs_mount (file->device->disk);
229 if (!data)
230 return grub_errno;
232 err = grub_archelp_open (data, &arcops, name_in);
233 if (err)
235 grub_free (data);
237 else
239 file->data = data;
240 file->size = data->size;
242 return err;
245 static grub_ssize_t
246 grub_cbfs_read (grub_file_t file, char *buf, grub_size_t len)
248 struct grub_archelp_data *data;
249 grub_ssize_t ret;
251 data = file->data;
252 data->disk->read_hook = file->read_hook;
253 data->disk->read_hook_data = file->read_hook_data;
255 ret = (grub_disk_read (data->disk, 0, data->dofs + file->offset,
256 len, buf)) ? -1 : (grub_ssize_t) len;
257 data->disk->read_hook = 0;
259 return ret;
262 static grub_err_t
263 grub_cbfs_close (grub_file_t file)
265 struct grub_archelp_data *data;
267 data = file->data;
268 grub_free (data);
270 return grub_errno;
273 #if (defined (__i386__) || defined (__x86_64__)) && !defined (GRUB_UTIL) \
274 && !defined (GRUB_MACHINE_EMU) && !defined (GRUB_MACHINE_XEN)
276 static char *cbfsdisk_addr;
277 static grub_off_t cbfsdisk_size = 0;
279 static int
280 grub_cbfsdisk_iterate (grub_disk_dev_iterate_hook_t hook, void *hook_data,
281 grub_disk_pull_t pull)
283 if (pull != GRUB_DISK_PULL_NONE)
284 return 0;
286 return hook ("cbfsdisk", hook_data);
289 static grub_err_t
290 grub_cbfsdisk_open (const char *name, grub_disk_t disk)
292 if (grub_strcmp (name, "cbfsdisk"))
293 return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "not a cbfsdisk");
295 disk->total_sectors = cbfsdisk_size / GRUB_DISK_SECTOR_SIZE;
296 disk->max_agglomerate = GRUB_DISK_MAX_MAX_AGGLOMERATE;
297 disk->id = 0;
299 return GRUB_ERR_NONE;
302 static void
303 grub_cbfsdisk_close (grub_disk_t disk __attribute((unused)))
307 static grub_err_t
308 grub_cbfsdisk_read (grub_disk_t disk __attribute((unused)),
309 grub_disk_addr_t sector,
310 grub_size_t size, char *buf)
312 grub_memcpy (buf, cbfsdisk_addr + (sector << GRUB_DISK_SECTOR_BITS),
313 size << GRUB_DISK_SECTOR_BITS);
314 return 0;
317 static grub_err_t
318 grub_cbfsdisk_write (grub_disk_t disk __attribute__ ((unused)),
319 grub_disk_addr_t sector __attribute__ ((unused)),
320 grub_size_t size __attribute__ ((unused)),
321 const char *buf __attribute__ ((unused)))
323 return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
324 "rom flashing isn't implemented yet");
327 static struct grub_disk_dev grub_cbfsdisk_dev =
329 .name = "cbfsdisk",
330 .id = GRUB_DISK_DEVICE_CBFSDISK_ID,
331 .disk_iterate = grub_cbfsdisk_iterate,
332 .disk_open = grub_cbfsdisk_open,
333 .disk_close = grub_cbfsdisk_close,
334 .disk_read = grub_cbfsdisk_read,
335 .disk_write = grub_cbfsdisk_write,
336 .next = 0
339 static void
340 init_cbfsdisk (void)
342 grub_uint32_t ptr;
343 struct cbfs_header *head;
345 ptr = *(grub_uint32_t *) 0xfffffffc;
346 head = (struct cbfs_header *) (grub_addr_t) ptr;
347 grub_dprintf ("cbfs", "head=%p\n", head);
349 /* coreboot current supports only ROMs <= 16 MiB. Bigger ROMs will
350 have problems as RCBA is 18 MiB below end of 32-bit typically,
351 so either memory map would have to be rearranged or we'd need to support
352 reading ROMs through controller directly.
354 if (ptr < 0xff000000
355 || 0xffffffff - ptr < (grub_uint32_t) sizeof (*head) + 0xf
356 || !validate_head (head))
357 return;
359 cbfsdisk_size = ALIGN_UP (grub_be_to_cpu32 (head->romsize),
360 GRUB_DISK_SECTOR_SIZE);
361 cbfsdisk_addr = (void *) (grub_addr_t) (0x100000000ULL - cbfsdisk_size);
363 grub_disk_dev_register (&grub_cbfsdisk_dev);
366 static void
367 fini_cbfsdisk (void)
369 if (! cbfsdisk_size)
370 return;
371 grub_disk_dev_unregister (&grub_cbfsdisk_dev);
374 #endif
376 static struct grub_fs grub_cbfs_fs = {
377 .name = "cbfs",
378 .fs_dir = grub_cbfs_dir,
379 .fs_open = grub_cbfs_open,
380 .fs_read = grub_cbfs_read,
381 .fs_close = grub_cbfs_close,
382 #ifdef GRUB_UTIL
383 .reserved_first_sector = 0,
384 .blocklist_install = 0,
385 #endif
388 GRUB_MOD_INIT (cbfs)
390 #if (defined (__i386__) || defined (__x86_64__)) && !defined (GRUB_UTIL) && !defined (GRUB_MACHINE_EMU) && !defined (GRUB_MACHINE_XEN)
391 init_cbfsdisk ();
392 #endif
393 grub_fs_register (&grub_cbfs_fs);
396 GRUB_MOD_FINI (cbfs)
398 grub_fs_unregister (&grub_cbfs_fs);
399 #if (defined (__i386__) || defined (__x86_64__)) && !defined (GRUB_UTIL) && !defined (GRUB_MACHINE_EMU) && !defined (GRUB_MACHINE_XEN)
400 fini_cbfsdisk ();
401 #endif