1 /* cbfs.c - cbfs and tar filesystem. */
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>
27 #include <grub/i18n.h>
28 #include <grub/cbfs_core.h>
30 GRUB_MOD_LICENSE ("GPLv3+");
33 struct grub_archelp_data
36 grub_off_t hofs
, next_hofs
;
39 grub_off_t cbfs_start
;
41 grub_off_t cbfs_align
;
45 grub_cbfs_find_file (struct grub_archelp_data
*data
, char **name
,
51 data
->dofs
= data
->hofs
+ offset
,
52 data
->next_hofs
= ALIGN_UP (data
->dofs
+ data
->size
, data
->cbfs_align
))
57 data
->hofs
= data
->next_hofs
;
59 if (data
->hofs
>= data
->cbfs_end
)
61 *mode
= GRUB_ARCHELP_ATTR_END
;
65 if (grub_disk_read (data
->disk
, 0, data
->hofs
, sizeof (hd
), &hd
))
68 if (grub_memcmp (hd
.magic
, CBFS_FILE_MAGIC
, sizeof (hd
.magic
)) != 0)
70 *mode
= GRUB_ARCHELP_ATTR_END
;
73 data
->size
= grub_be_to_cpu32 (hd
.len
);
75 offset
= grub_be_to_cpu32 (hd
.offset
);
77 *mode
= GRUB_ARCHELP_ATTR_FILE
| GRUB_ARCHELP_ATTR_NOTIME
;
80 if (namesize
>= sizeof (hd
))
81 namesize
-= sizeof (hd
);
84 *name
= grub_malloc (namesize
+ 1);
88 if (grub_disk_read (data
->disk
, 0, data
->hofs
+ sizeof (hd
),
95 if ((*name
)[0] == '\0')
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
;
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
123 validate_head (struct cbfs_header
*head
)
125 return (head
->magic
== grub_cpu_to_be32_compile_time (CBFS_HEADER_MAGIC
)
127 == grub_cpu_to_be32_compile_time (CBFS_HEADER_VERSION1
)
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
))
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
)
146 struct grub_archelp_data
*data
= NULL
;
148 grub_off_t header_off
;
149 struct cbfs_header head
;
151 if (grub_disk_get_size (disk
) == GRUB_DISK_SIZE_UNKNOWN
)
154 if (grub_disk_read (disk
, grub_disk_get_size (disk
) - 1,
155 GRUB_DISK_SECTOR_SIZE
- sizeof (ptr
),
159 ptr
= grub_cpu_to_le32 (ptr
);
160 header_off
= (grub_disk_get_size (disk
) << GRUB_DISK_SECTOR_BITS
)
161 + (grub_int32_t
) ptr
;
163 if (grub_disk_read (disk
, 0, header_off
,
164 sizeof (head
), &head
))
167 if (!validate_head (&head
))
170 data
= (struct grub_archelp_data
*) grub_zalloc (sizeof (*data
));
174 data
->cbfs_start
= (grub_disk_get_size (disk
) << GRUB_DISK_SECTOR_BITS
)
175 - (grub_be_to_cpu32 (head
.romsize
) - grub_be_to_cpu32 (head
.offset
));
176 data
->cbfs_end
= (grub_disk_get_size (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_get_size (disk
) << GRUB_DISK_SECTOR_BITS
))
182 if (data
->cbfs_end
> (grub_disk_get_size (disk
) << GRUB_DISK_SECTOR_BITS
))
183 data
->cbfs_end
= (grub_disk_get_size (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
))
190 if (grub_memcmp (hd
.magic
, CBFS_FILE_MAGIC
, sizeof (CBFS_FILE_MAGIC
) - 1))
199 grub_error (GRUB_ERR_BAD_FS
, "not a cbfs filesystem");
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
;
210 data
= grub_cbfs_mount (device
->disk
);
214 err
= grub_archelp_dir (data
, &arcops
,
215 path_in
, hook
, hook_data
);
223 grub_cbfs_open (grub_file_t file
, const char *name_in
)
225 struct grub_archelp_data
*data
;
228 data
= grub_cbfs_mount (file
->device
->disk
);
232 err
= grub_archelp_open (data
, &arcops
, name_in
);
240 file
->size
= data
->size
;
246 grub_cbfs_read (grub_file_t file
, char *buf
, grub_size_t len
)
248 struct grub_archelp_data
*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;
263 grub_cbfs_close (grub_file_t file
)
265 struct grub_archelp_data
*data
;
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;
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
)
286 return hook ("cbfsdisk", hook_data
);
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
;
299 return GRUB_ERR_NONE
;
303 grub_cbfsdisk_close (grub_disk_t disk
__attribute((unused
)))
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
);
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
=
330 .id
= GRUB_DISK_DEVICE_CBFSDISK_ID
,
331 .iterate
= grub_cbfsdisk_iterate
,
332 .open
= grub_cbfsdisk_open
,
333 .close
= grub_cbfsdisk_close
,
334 .read
= grub_cbfsdisk_read
,
335 .write
= grub_cbfsdisk_write
,
343 struct cbfs_header
*head
;
345 ptr
= *(grub_uint32_t
*) 0xfffffffc;
346 head
= (struct cbfs_header
*) (grub_addr_t
) ptr
;
348 if (!validate_head (head
))
351 cbfsdisk_size
= ALIGN_UP (grub_be_to_cpu32 (head
->romsize
),
352 GRUB_DISK_SECTOR_SIZE
);
353 cbfsdisk_addr
= (void *) (grub_addr_t
) (0x100000000ULL
- cbfsdisk_size
);
355 grub_disk_dev_register (&grub_cbfsdisk_dev
);
363 grub_disk_dev_unregister (&grub_cbfsdisk_dev
);
368 static struct grub_fs grub_cbfs_fs
= {
370 .dir
= grub_cbfs_dir
,
371 .open
= grub_cbfs_open
,
372 .read
= grub_cbfs_read
,
373 .close
= grub_cbfs_close
,
375 .reserved_first_sector
= 0,
376 .blocklist_install
= 0,
382 #if (defined (__i386__) || defined (__x86_64__)) && !defined (GRUB_UTIL) && !defined (GRUB_MACHINE_EMU) && !defined (GRUB_MACHINE_XEN)
385 grub_fs_register (&grub_cbfs_fs
);
390 grub_fs_unregister (&grub_cbfs_fs
);
391 #if (defined (__i386__) || defined (__x86_64__)) && !defined (GRUB_UTIL) && !defined (GRUB_MACHINE_EMU) && !defined (GRUB_MACHINE_XEN)