1 /*
2  * Copyright (c) 2008 Vreixo Formoso
3  * Copyright (c) 2012 - 2019 Thomas Schmitt
4  *
5  * This file is part of the libisofs project; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License version 2
7  * or later as published by the Free Software Foundation.
8  * See COPYING file for details.
9  */
10 
11 /*
12  * Functions for dealing with the system area, this is, the first 16 blocks
13  * of the image.
14  *
15  * At this time, this is only used for hybrid boot images with isolinux.
16  */
17 
18 #ifndef SYSTEM_AREA_H_
19 #define SYSTEM_AREA_H_
20 
21 #include "ecma119.h"
22 
23 /*
24  * Create a MBR for an isohybrid enabled ISOLINUX boot image.
25  *
26  * It is assumed that the caller has verified the readiness of the boot image
27  * by checking for 0xfb 0xc0 0x78 0x70 at bytes 0x40 to 0x43 of isolinux.bin.
28  *
29  * @param bin_lba    The predicted LBA of isolinux.bin within the emerging ISO.
30  * @param img_blocks The predicted number of 2048 byte blocks in the ISO.
31  *                   It will get rounded up to full MBs and that many blocks
32  *                   must really be written as ISO 9660 image.
33  * @param mbr        A buffer of at least 512 bytes to take the result which is
34  *                   to be written as the very beginning of the ISO.
35  * @param flag    unused yet, submit 0
36  * @return  <0 = fatal, 0 = failed , 1 = ok , 2 = ok with size warning
37  */
38 int make_isohybrid_mbr(int bin_lba, int *img_blocks, char *mbr, int flag);
39 
40 /**
41  * Write the system area for the given image to the given buffer.
42  *
43  * @param buf
44  *      A buffer with at least 32 K allocated
45  * @param flag
46  *      bit0= t->opts->ms_block is not counted in t->total_size
47  * @return
48  *      1 if success, < 0 on error
49  */
50 int iso_write_system_area(Ecma119Image *t, uint8_t *buf, int flag);
51 
52 /**
53  * Adjust t->tail_blocks to the eventual alignment needs of isohybrid booting.
54  */
55 int iso_align_isohybrid(Ecma119Image *t, int flag);
56 
57 
58 /**
59  * Read the necessary ELF information from the first MIPS boot file.
60  * See doc/boot_sectors.txt "DEC Boot Block" for "MIPS Little Endian".
61  */
62 int iso_read_mipsel_elf(Ecma119Image *t, int flag);
63 
64 
65 /* Compute size and position of appended partitions.
66 */
67 int iso_compute_append_partitions(Ecma119Image *t, int flag);
68 
69 
70 /* The parameter struct for production of a single MBR partition entry.
71    See also the description of MBR in doc/boot_sectors.txt.
72    No sorting by start sector and gap filling is done before the System Area
73    gets written. But the entries may get assigned to a desired slot number
74    in the table.
75    Requested entries with block_count == 0 get expanded to the start of
76    the next requested entry resp. to image end, if no entry follows.
77    start_block of a following entry must be at least a high as the sum of
78    start_block and block_count of the previous entry.
79    Empty requested entries will be represented as 16 bytes of 0.
80 */
81 struct iso_mbr_partition_request {
82 
83     /* Always given in blocks of 512 bytes */
84     uint64_t start_block;
85 
86     /* A block count of 0 means that the partition reaches up to the start of
87        the next one.
88     */
89     uint64_t block_count;
90 
91     /* Partition type */
92     uint8_t type_byte;
93 
94     /* 0x80 = bootable */
95     uint8_t status_byte;
96 
97     /* If >= 1 && <= 4 : The partition slot number in MBR.
98        If more than one partition desires the same slot, then an error
99        ISO_BOOT_MBR_COLLISION occurs at registration time.
100        Use iso_mbr_entry_slot_is_free() to detect this in advance.
101        If desired_slot is 0, then the partition entry is put into the
102        lowest MBR slot that is not occupied by an entry with desired_slot > 0
103        or by an entry that was registered before this entry.
104     */
105     int desired_slot;
106 
107 };
108 
109 /* Copies the content of req and registers it in t.mbr_req[].
110    I.e. after the call the submitted storage of req can be disposed or re-used.
111    Submit 0 as value flag.
112 */
113 int iso_register_mbr_entry(struct iso_mbr_partition_request **req_array,
114                            int *mbr_req_count,
115                            struct iso_mbr_partition_request *req, int flag);
116 
117 /* Convenience frontend for iso_register_mbr_entry().
118    name and type are 0-terminated strings, which may get silently truncated.
119 */
120 int iso_quick_mbr_entry(struct iso_mbr_partition_request **req_array,
121                         int *mbr_req_count,
122                         uint64_t start_block, uint64_t block_count,
123                         uint8_t type_byte, uint8_t status_byte,
124                         int desired_slot);
125 
126 /* Peek in advance whether a desired slot number is already occupied by a
127    registered MBR entry.
128    Parameter slot may be between 0 and 4. 0 always returns "free".
129    Return value is 0 if occupied, 1 if free, and -1 if the slot number is
130    out of range.
131 */
132 int iso_mbr_entry_slot_is_free(struct iso_mbr_partition_request **req_array,
133                                int mbr_req_count, int slot);
134 
135 
136 /* The parameter struct for production of a single Apple Partition Map entry.
137    See also the partial APM description in doc/boot_sectors.txt.
138    The list of entries is stored e.g. in Ecma119Image.apm_req, .apm_req_count.
139    The size of a block can be chosen by setting Ecma119Image.apm_block_size.
140    If an entry has start_block <=1, then its block_count will be adjusted
141    to the final size of the partition map.
142    If no such entry is requested, then it will be prepended automatically
143    with name "Apple" and type "Apple_partition_map".
144    The requested entries will get sorted and gaps will be filled by more
145    entries.
146 */
147 struct iso_apm_partition_request {
148 
149     /* Given in blocks of 2 KiB unless (Ecma119Image.apm_req_flags & 4).
150        Written to the ISO image according to Ecma119Image.apm_block_size.
151     */
152     uint64_t start_block;
153     uint64_t block_count;
154 
155     /* All 32 bytes get copied to the system area.
156        Take care to pad up short strings by 0.
157     */
158     uint8_t name[32];
159     uint8_t type[32];
160 
161     /* Status of the request object itself:
162        bit0= this is an automatically placed filler partition
163     */
164     uint32_t req_status;
165 };
166 
167 /* Copies the content of req and registers it in t.apm_req[].
168    I.e. after the call the submitted storage of req can be disposed or re-used.
169    Submit 0 as value flag.
170 */
171 int iso_register_apm_entry(struct iso_apm_partition_request **req_array,
172                            int *apm_req_count,
173                            struct iso_apm_partition_request *req, int flag);
174 
175 /* Convenience frontend for iso_register_apm_entry().
176    name and type are 0-terminated strings, which may get silently truncated.
177 */
178 int iso_quick_apm_entry(struct iso_apm_partition_request **req_array,
179                         int *apm_req_count,
180                         uint32_t start_block, uint32_t block_count,
181                         char *name, char *type);
182 
183 /* These two pseudo-random generators produce byte strings which will
184    surely not duplicate in the first 256 calls. If more calls are necessary
185    in the same process, then one must wait until the output of
186    gettimeofday(2) changes.
187    It is advised to obtain them as late as possible, so that Ecma119Image *t
188    can distinguish itself from other image production setups which might be
189    run on other machines with the same process number at the same time.
190 */
191 
192 /* Produces a GPT disk or partition GUID.
193    Pseudo-random by iso_generate_gpt_guid() if t->gpt_uuid_counter is 0.
194    Else derived reproducibly by counter number from t->gpt_uuid_base.
195 */
196 void iso_gpt_uuid(Ecma119Image *t, uint8_t uuid[16]);
197 
198 /* Mark a given byte string as UUID version 4, RFC 4122.
199 */
200 void iso_mark_guid_version_4(uint8_t *u);
201 
202 /* The parameter struct for production of a single GPT entry.
203    See also the partial GPT description in doc/boot_sectors.txt.
204    The list of entries is stored in Ecma119Image.gpt_req.
205    The GPT header block at byte 0x200 will get produced automatically.
206    The requested entries will get sorted and gaps will be filled by more
207    entries. Overlapping partitions are allowed only if
208    (Ecma119Image.gpt_req_flags & 1).
209    The block_count will be truncated to the image size before the GPT backup.
210 
211    The GPT entries will be stored after the Apple Partition Map, if such
212    gets generated too. Both partition descriptions must fit into the 32 KiB
213    of the ISO 9660 System Area.
214    GPT can be combined with APM only if (Ecma119Image.apm_block_size > 512).
215    Otherwise, block 1 of APM and GPT header block would collide.
216    So Ecma119Image.apm_block_size is set automatically to 2048 if at least
217    one GPT entry is requested. (One could try 1024 ...).
218 */
219 struct iso_gpt_partition_request {
220 
221     /* Always given in blocks of 512 bytes.
222     */
223     uint64_t start_block;
224     uint64_t block_count;
225 
226     /* The registered GUID which defines the partition type */
227     uint8_t type_guid[16];
228 
229     /* An individual GUID which shall be unique to the partition.
230        If the caller submits 0...0 then a (weak) random uuid will be generated.
231     */
232     uint8_t partition_guid[16];
233 
234     /* bit0= "System Partition" Do not alter,
235        bit2= Legacy BIOS bootable (MBR partition type 0x80)
236        bit60= read-only
237     */
238     uint64_t flags;
239 
240     /* Fill with text encoded as UTF-16LE.
241        All 72 bytes get copied to the system area.
242        Take care to pad up short strings by 0.
243     */
244     uint8_t name[72];
245 
246     /* Only if read from imported image: Table index of partition (first = 1)
247     */
248     uint32_t idx;
249 
250     /* Status of the request object itself:
251        bit0= this is an automatically placed filler partition
252     */
253     uint32_t req_status;
254 };
255 
256 /* Copies the content of req and registers it in t.gpt_req[].
257    I.e. after the call the submitted storage of req can be disposed or re-used.
258    Submit 0 as value flag.
259 */
260 int iso_register_gpt_entry(struct iso_gpt_partition_request **req_array,
261                            int *gpt_req_count,
262                            struct iso_gpt_partition_request *req, int flag);
263 
264 /* Convenience frontend for iso_register_gpt_entry().
265    name has to be already encoded as UTF-16LE.
266 */
267 int iso_quick_gpt_entry(struct iso_gpt_partition_request **req_array,
268                         int *gpt_req_count,
269                         uint64_t start_block, uint64_t block_count,
270                         uint8_t type_guid[16], uint8_t partition_guid[16],
271                         uint64_t flags, uint8_t name[72]);
272 
273 /* Deletes the partition requests for gap filling in GPT and APM.
274    Purpose is to get the request list clean again after a multi-session
275    emulation superblock was created and handed to the application.
276 */
277 void iso_delete_gpt_apm_fillers(Ecma119Image *target, int flag);
278 
279 /* Internal helper that will be used by system_area.c and make_isohybrid_mbr.c
280 */
281 int iso_write_gpt_header_block(Ecma119Image *t, uint32_t img_blocks,
282                                uint8_t *buf, uint32_t max_entries,
283                                uint32_t part_start, uint32_t p_arr_crc);
284 
285 /* The description of a loaded MIPS Big Endian Volume Directory Entry
286 */
287 struct iso_mips_voldir_entry {
288     char name[9];
289     uint32_t boot_block;
290     uint32_t boot_bytes;
291 };
292 
293 /* The description of a loaded SUN Disk Label partition */
294 struct iso_sun_disk_label_entry {
295     int idx;
296     uint16_t id_tag;
297     uint16_t permissions;
298     uint32_t start_cyl;
299     uint32_t num_blocks;
300 };
301 
302 /* Creates the Partition Prepend writer.
303 */
304 int partprepend_writer_create(Ecma119Image *target);
305 
306 /* Creates the Inline Partition Append Writer
307 */
308 int partappend_writer_create(Ecma119Image *target);
309 
310 /* Creates the GPT backup tail writer.
311 */
312 int gpt_tail_writer_create(Ecma119Image *target);
313 
314 /* Not for execution but only to identify the writer by
315     ( writer->write_vol_desc == gpt_tail_writer_write_vol_desc )
316 */
317 int gpt_tail_writer_write_vol_desc(IsoImageWriter *writer);
318 
319 
320 /* Only for up to 36 characters ISO-8859-1 (or ASCII) input */
321 void iso_ascii_utf_16le(uint8_t gap_name[72]);
322 
323 
324 /* Parameters of MBR patching for GRUB2
325    Might later become variables in Ecma119Image
326 */
327 #define Libisofs_grub2_mbr_patch_poS    0x1b0
328 #define Libisofs_grub2_mbr_patch_offsT      4
329 
330 /* Parameters of SUN Disk Label patching for GRUB2
331    See API iso_image_set_sparc_core().
332 */
333 #define Libisofs_grub2_sparc_patch_adr_poS    0x228
334 #define Libisofs_grub2_sparc_patch_size_poS   0x230
335 
336 
337 /* Put appended partitions into the writer range
338 */
339 #define Libisofs_appended_partitions_inlinE yes
340 #ifdef Libisofs_appended_partitions_inlinE
341 /* For padding after appended partitions (and also after backup GPT)
342 */
343 #define Libisofs_part_align_writeR yes
344 #endif
345 
346 #endif /* SYSTEM_AREA_H_ */
347