"Fossies" - the Fresh Open Source Software Archive

Member "xorriso-1.5.4/libisofs/make_isohybrid_mbr.c" (30 Jan 2021, 25418 Bytes) of package /linux/misc/xorriso-1.5.4.pl02.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "make_isohybrid_mbr.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 1.5.2_vs_1.5.4.

    1 /*
    2  * Copyright (c) 2002 - 2008 H. Peter Anvin
    3  * Copyright (c) 2008 - 2015 Thomas Schmitt
    4  * with special credits to Matthew Garrett for isohybrid with GPT and APM
    5  *
    6  * This file is part of the libisofs project; you can redistribute it and/or
    7  * modify it under the terms of the GNU General Public License version 2
    8  * or later as published by the Free Software Foundation.
    9  * See COPYING file for details.
   10  */
   11 
   12 #ifdef HAVE_CONFIG_H
   13 #include "../config.h"
   14 #endif
   15 
   16 #include <ctype.h>
   17 
   18 #ifdef HAVE_STDINT_H
   19 #include <stdint.h>
   20 #else
   21 #ifdef HAVE_INTTYPES_H
   22 #include <inttypes.h>
   23 #endif
   24 #endif
   25 
   26 #include <sys/types.h>
   27 #include <stdlib.h>
   28 #include <stdio.h>
   29 #include <unistd.h>
   30 #include <string.h>
   31 #include <errno.h>
   32 
   33 /* for gettimeofday() */
   34 #include <sys/time.h>
   35 
   36 #include "filesrc.h"
   37 #include "ecma119.h"
   38 #include "eltorito.h"
   39 #include "system_area.h"
   40 #include "image.h"
   41 #include "messages.h"
   42 
   43 
   44 /* This code stems from syslinux-3.72/utils/isohybrid, a perl script
   45 under GPL which is Copyright 2002-2008 H. Peter Anvin.
   46 
   47 Line numbers in comments refer to the lines of that script.
   48 It has been analyzed and re-written in C language 2008 by Thomas Schmitt,
   49 and is now under the licenses to which H.Peter Anvin agreed:
   50 
   51  http://syslinux.zytor.com/archives/2008-November/011105.html
   52  Date: Mon, 10 Nov 2008 08:36:46 -0800
   53  From: H. Peter Anvin <hpa@zytor.com>
   54  I hereby give permission for this code, translated to the C language, to
   55  be released under either the LGPL or the MIT/ISC/2-clause BSD licenses
   56  or both, at your option.
   57  Sincerely, H. Peter Anvin
   58 
   59 In the context of GNU xorriso, this code is under GPLv3+ derived from LGPL.
   60 In the context of libisofs this code derives its matching free software
   61 license from above stem licenses, typically from LGPL.
   62 In case its generosity is needed, here is the 2-clause BSD license:
   63 
   64 make_isohybrid_mbr.c is copyright 2002-2008 H. Peter Anvin
   65                               and 2008-2015 Thomas Schmitt
   66 
   67 1. Redistributions of source code must retain the above copyright notice,
   68    this list of conditions and the following disclaimer.
   69 2. Redistributions in binary form must reproduce the above copyright notice,
   70    this list of conditions and the following disclaimer in the documentation
   71    and/or other materials provided with the distribution.
   72 THIS SOFTWARE IS PROVIDED `AS IS' AND ANY EXPRESS OR IMPLIED WARRANTIES,
   73 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
   74 AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
   75 THE PROVIDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   76 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
   77 PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
   78 OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
   79 WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
   80 OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
   81 ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   82 
   83 */
   84 
   85 
   86 /* A helper function. One could replace it by one or two macros. */
   87 static int lsb_to_buf(char **wpt, uint32_t value, int bits, int flag)
   88 {
   89     int b;
   90 
   91     for (b = 0; b < bits; b += 8)
   92         *((unsigned char *) ((*wpt)++)) = (value >> b) & 0xff;
   93     return (1);
   94 }
   95 
   96 
   97 /* ====================================================================== */
   98 /*                          Deprecated Function                           */
   99 /* ====================================================================== */
  100 
  101 /*
  102  * Create a MBR for an isohybrid enabled ISOLINUX boot image.
  103  *
  104  * It is assumed that the caller has verified the readiness of the boot image
  105  * by checking for 0xfb 0xc0 0x78 0x70 at bytes 0x40 to 0x43 of isolinux.bin.
  106  *
  107  * @param bin_lba    The predicted LBA of isolinux.bin within the emerging ISO.
  108  * @param img_blocks The predicted number of 2048 byte blocks in the ISO.
  109  *                   It will get rounded up to full MBs and that many blocks
  110  *                   must really be written as ISO 9660 image.
  111  * @param mbr        A buffer of at least 512 bytes to take the result which is
  112  *                   to be written as the very beginning of the ISO.
  113  * @param flag    unused yet, submit 0
  114  * @return  <0 = fatal, 0 = failed , 1 = ok , 2 = ok with size warning
  115  */
  116 int make_isohybrid_mbr(int bin_lba, int *img_blocks, char *mbr, int flag)
  117 {
  118     /* According to H. Peter Anvin this binary code stems from
  119      syslinux-3.72/mbr/isohdpfx.S
  120      */
  121     static int mbr_code_size = 271;
  122     static unsigned char mbr_code[271] = { 0xfa, 0x31, 0xc0, 0x8e, 0xd8, 0x8e,
  123             0xd0, 0xbc, 0x00, 0x7c, 0x89, 0xe6, 0x06, 0x57, 0x52, 0x8e, 0xc0,
  124             0xfb, 0xfc, 0xbf, 0x00, 0x06, 0xb9, 0x00, 0x01, 0xf3, 0xa5, 0xea,
  125             0x20, 0x06, 0x00, 0x00, 0x52, 0xb4, 0x41, 0xbb, 0xaa, 0x55, 0x31,
  126             0xc9, 0x30, 0xf6, 0xf9, 0xcd, 0x13, 0x72, 0x14, 0x81, 0xfb, 0x55,
  127             0xaa, 0x75, 0x0e, 0x83, 0xe1, 0x01, 0x74, 0x09, 0x66, 0xc7, 0x06,
  128             0xb4, 0x06, 0xb4, 0x42, 0xeb, 0x15, 0x5a, 0x51, 0xb4, 0x08, 0xcd,
  129             0x13, 0x83, 0xe1, 0x3f, 0x51, 0x0f, 0xb6, 0xc6,
  130 
  131             0x40, 0x50, 0xf7, 0xe1, 0x52, 0x50, 0xbb, 0x00, 0x7c, 0xb9, 0x04,
  132             0x00, 0x66, 0xa1, 0xb0, 0x07, 0xe8, 0x40, 0x00, 0x72, 0x74, 0x66,
  133             0x40, 0x80, 0xc7, 0x02, 0xe2, 0xf4, 0x66, 0x81, 0x3e, 0x40, 0x7c,
  134             0xfb, 0xc0, 0x78, 0x70, 0x75, 0x07, 0xfa, 0xbc, 0xf4, 0x7b, 0xe9,
  135             0xc6, 0x75, 0xe8, 0x79, 0x00, 0x69, 0x73, 0x6f, 0x6c, 0x69, 0x6e,
  136             0x75, 0x78, 0x2e, 0x62, 0x69, 0x6e, 0x20, 0x6d, 0x69, 0x73, 0x73,
  137             0x69, 0x6e, 0x67, 0x20, 0x6f, 0x72, 0x20, 0x63, 0x6f, 0x72, 0x72,
  138             0x75, 0x70, 0x74,
  139 
  140             0x2e, 0x0d, 0x0a, 0x66, 0x60, 0x66, 0x31, 0xd2, 0x66, 0x52, 0x66,
  141             0x50, 0x06, 0x53, 0x6a, 0x01, 0x6a, 0x10, 0x89, 0xe6, 0x66, 0xf7,
  142             0x36, 0xf0, 0x7b, 0xc0, 0xe4, 0x06, 0x88, 0xe1, 0x88, 0xc5, 0x92,
  143             0xf6, 0x36, 0xf6, 0x7b, 0x88, 0xc6, 0x08, 0xe1, 0x41, 0xb8, 0x01,
  144             0x02, 0x8a, 0x16, 0xfa, 0x7b, 0xcd, 0x13, 0x8d, 0x64, 0x10, 0x66,
  145             0x61, 0xc3, 0xe8, 0x1e, 0x00, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74,
  146             0x69, 0x6e, 0x67, 0x20, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x20,
  147             0x6c, 0x6f, 0x61,
  148 
  149             0x64, 0x20, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x2e, 0x0d, 0x0a, 0x5e,
  150             0xac, 0xb4, 0x0e, 0x8a, 0x3e, 0x62, 0x04, 0xb3, 0x07, 0xcd, 0x10,
  151             0x3c, 0x0a, 0x75, 0xf1, 0xcd, 0x18, 0xf4, 0xeb, 0xfd };
  152 
  153     static int h = 64, s = 32;
  154 
  155     int i, id;
  156     char *wpt;
  157     off_t imgsize, cylsize, frac, padding, c, cc;
  158 
  159     /* For generating a weak random number */
  160     struct timeval tv;
  161 
  162     if (bin_lba < 0 || bin_lba >= (1 << 29))
  163         return (0); /* 1 TB limit of signed 32 bit addressing of 512 byte blocks */
  164 
  165     /*
  166      84: Gets size of image in bytes.
  167      89:
  168      */
  169     imgsize = ((off_t) *img_blocks) * (off_t) 2048;
  170 
  171     /*
  172      90: Computes $padding, size of padded image and number $c of
  173      pseudo-cylinders ($h and $s are constants set in line 24).
  174      102: $cc is $c curbed to 1024.
  175      */
  176     cylsize = h * s * 512;
  177     frac = imgsize % cylsize;
  178     padding = (frac > 0 ? cylsize - frac : 0);
  179     imgsize += padding;
  180     *img_blocks = imgsize / (off_t) 2048;
  181     c = imgsize / cylsize;
  182     if (c > 1024) {
  183         cc = 1024;
  184     } else
  185         cc = c;
  186 
  187     /*
  188      107: Brings the hex-encoded bytes from the file __END__ into
  189      113: the MBR buffer. (This function holds them in mbr_code[].)
  190      */
  191     for (i = 0; i < mbr_code_size; i++)
  192         mbr[i] = mbr_code[i];
  193 
  194     /*
  195      118: Pads up to 432
  196      */
  197     for (i = mbr_code_size; i < 432; i++)
  198         mbr[i] = 0;
  199 
  200     /* From here on use write cursor wpt */
  201     wpt = mbr + 432;
  202 
  203     /*
  204      120: Converts LBA of isolinux.bin to blocksize 512 and writes
  205      to buffer. Appends 4 zero bytes.
  206      */
  207     lsb_to_buf(&wpt, bin_lba * 4, 32, 0);
  208     lsb_to_buf(&wpt, 0, 32, 0);
  209 
  210     /*
  211      121: I do not understand where $id should eventually come
  212      from. An environment variable ?
  213      125: Whatever, i use some 32-bit random value with no crypto strength.
  214      */
  215     gettimeofday(&tv, NULL);
  216     id = 0xffffffff & (tv.tv_sec ^ (tv.tv_usec * 2000));
  217 
  218     /*
  219      126: Adds 4 id bytes and 2 zero bytes.
  220      */
  221     lsb_to_buf(&wpt, id, 32, 0);
  222     lsb_to_buf(&wpt, 0, 16, 0);
  223 
  224     /*
  225      129: Composes 16 byte record from the parameters determined
  226      147: so far. Appends it to buffer and add 48 zero bytes.
  227      */
  228     /* There are 4 "partition slots". Only the first is non-zero here.
  229      In the perl script, the fields are set in variables and then
  230      written to buffer. I omit the variables.
  231      */
  232     /* 0x80 */
  233     lsb_to_buf(&wpt, 0x80, 8, 0);
  234     /* bhead */
  235     lsb_to_buf(&wpt, 0, 8, 0);
  236     /* bsect */
  237     lsb_to_buf(&wpt, 1, 8, 0);
  238     /* bcyl */
  239     lsb_to_buf(&wpt, 0, 8, 0);
  240     /* fstype */
  241     lsb_to_buf(&wpt, 0x83, 8, 0);
  242     /* ehead */
  243     lsb_to_buf(&wpt, h - 1, 8, 0);
  244     /* esect */
  245     lsb_to_buf(&wpt, s + (((cc - 1) & 0x300) >> 2), 8, 0);
  246     /* ecyl */
  247     lsb_to_buf(&wpt, (cc - 1) & 0xff, 8, 0);
  248     /* 0 */
  249     lsb_to_buf(&wpt, 0, 32, 0);
  250     /* psize */
  251     lsb_to_buf(&wpt, c * h * s, 32, 0);
  252 
  253     /* Fill the other three slots with zeros */
  254     for (i = 0; i < 3 * 4; i++)
  255         lsb_to_buf(&wpt, 0, 32, 0);
  256 
  257     /*
  258      148: Appends bytes 0x55 , 0xAA.
  259      */
  260     lsb_to_buf(&wpt, 0x55, 8, 0);
  261     lsb_to_buf(&wpt, 0xaa, 8, 0);
  262 
  263     return (1);
  264 }
  265 
  266 
  267 /* ====================================================================== */
  268 /*                          The New MBR Producer                          */
  269 /* ====================================================================== */
  270 
  271 /* The new MBR producer for isohybrid is a slightly generalized version of
  272    the deprecated function make_isohybrid_mbr(). It complies to the urge
  273    of H.Peter Anvin not to hardcode MBR templates but rather to read a
  274    file from the Syslinux tree, and to patch it as was done with the old
  275    MBR producer.
  276 
  277    The old algorithm was clarified publicly by the following mail.
  278    Changes towards the old algorithm:
  279    - 512-byte LBA of boot image is extended to 64 bit (we stay with 32)
  280    - check for a magic number is now gone
  281 
  282    The new implementation tries to use similar terms as the mail in order
  283    to facilitate its future discussion with Syslinux developers.
  284 
  285 From hpa@zytor.com Thu Apr  1 08:32:52 2010
  286 Date: Wed, 31 Mar 2010 14:53:51 -0700
  287 From: H. Peter Anvin <hpa@zytor.com>
  288 To: For discussion of Syslinux and tftp-hpa <syslinux@zytor.com>
  289 Cc: Thomas Schmitt <scdbackup@gmx.net>
  290 Subject: Re: [syslinux] port syslinux isohybrid perl script to C
  291 
  292 [...]
  293 
  294 [me:]
  295 > Currently i lack of blob and prescriptions.
  296 
  297 The blobs are available in the Syslinux build tree under the names:
  298 
  299 mbr/isohdp[fp]x*.bin
  300 
  301 The default probably should be mbr/isohdppx.bin, but it's ultimately up
  302 to the user.
  303 
  304 User definable parameters:
  305 
  306 -> MBR ID       (default random 32-bit number,
  307              or preserved from previous instance)
  308 -> Sector count     (default 32, range 1-63)
  309 -> Head count       (default 64, range 1-256)
  310 -> Partition offset (default 0, range 0-64)
  311 -> Partition number (default 1, range 1-4)
  312 -> Filesystem type  (default 0x17, range 1-255)
  313 
  314 Note: the filesystem type is largely arbitrary, in theory it can be any
  315 value other than 0x00, 0x05, 0x0f, 0x85, 0xee, or 0xef.  0x17 ("Windows
  316 IFS Hidden") seems safeish, some people believe 0x83 (Linux) is better.
  317 
  318 Here is the prescriptions for how to install it:
  319 
  320 All numbers are littleendian.  "word" means 16 bits, "dword" means 32
  321 bits, "qword" means 64 bits.
  322 
  323 Common subroutine LBA_to_CHS():
  324     s = (lba % sector_count) + 1
  325     t = (lba / sector_count)
  326     h = (t % head_count)
  327     c = (t / head_count)
  328 
  329     if (c >= 1024):
  330         c = 1023
  331         h = head_count
  332         s = sector_count
  333 
  334     s = s | ((c & 0x300) >> 2)
  335     c = c & 0xff
  336 
  337     write byte h
  338     write byte s
  339     write byte c
  340 
  341 Main:
  342     Pad image_size to a multiple of sector_count*head_count
  343     Use the input file unmodified for bytes 0..431
  344     write qword boot_lba        # Offset 432
  345     write dword mbr_id      # Offset 440
  346     write word 0            # Offset 444
  347 
  348     # Offset 446
  349     For each partition entry 1..4:
  350         if this_partition != partition_number:
  351             write 16 zero bytes
  352         else:
  353             write byte 0x80
  354             write LBA_to_CHS(partition_offset)
  355             write byte filesystem_type
  356             write LBA_to_CHS(image_size-1)
  357             write dword partition_offset
  358             write dword image_size
  359 
  360     # Offset 510
  361     write word 0xaa55
  362 
  363     Use the input file unmodified for bytes 512..32767
  364     (pad with zero as necessary)
  365 
  366 [...]
  367 
  368     -hpa
  369 */
  370 
  371 
  372 /* The new stuff about GPT and APM which was learned from Matthew Garret
  373    and isohybrid.c is described in doc/boot_sectord.txt chapter
  374     "SYSLINUX isohybrid for MBR, UEFI and x86-Mac"
  375 */
  376 
  377 
  378 static
  379 int lba512chs_to_buf(char **wpt, off_t lba, int head_count, int sector_count)
  380 {
  381     int s, t, h, c;
  382 
  383     s = (lba % sector_count) + 1;
  384     t = (lba / sector_count);
  385     h = (t % head_count);
  386     c = (t / head_count);
  387     if (c >= 1024) {
  388         c = 1023;
  389         h = head_count; /* >>> not -1 ? Limits head_count to 255 */
  390         s = sector_count;
  391     }
  392     s = s | ((c & 0x300) >> 2);
  393     c = c & 0xff;
  394     (*((unsigned char **) wpt))[0] = h;
  395     (*((unsigned char **) wpt))[1] = s;
  396     (*((unsigned char **) wpt))[2] = c;
  397     (*wpt)+= 3;
  398     return(1); 
  399 }
  400 
  401 
  402 /* Find out whether GPT and APM are desired
  403    flag bit0 = register APM and GPT requests in Ecma119Image
  404         bit1 = do not asses and register APM
  405         bit2 = do not register overall GPT partition
  406 */
  407 int assess_isohybrid_gpt_apm(Ecma119Image *t, int *gpt_count, int gpt_idx[128],
  408                              int *apm_count, int flag)
  409 {
  410     int i, ilx_opts, j, ret, num_img;
  411     uint32_t block_count;
  412     uint64_t start_block;
  413     uint8_t gpt_name[72];
  414     static uint8_t zero_uuid[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
  415     static uint8_t basic_data_uuid[16] = {
  416         0xa2, 0xa0, 0xd0, 0xeb, 0xe5, 0xb9, 0x33, 0x44,
  417         0x87, 0xc0, 0x68, 0xb6, 0xb7, 0x26, 0x99, 0xc7
  418     };
  419     static uint8_t hfs_uuid[16] = {
  420         0x00, 0x53, 0x46, 0x48, 0x00, 0x00, 0xaa, 0x11,
  421         0xaa, 0x11, 0x00, 0x30, 0x65, 0x43, 0xec, 0xac
  422     };
  423     uint8_t *uuid;
  424     static uint64_t gpt_flags = (((uint64_t) 1) << 60) | 1;
  425 
  426     *gpt_count = 0;
  427     *apm_count = 0;
  428 
  429     if (t->catalog != NULL)
  430         num_img = t->catalog->num_bootimages;
  431     else
  432         num_img = 0;
  433     for (i = 0; i < num_img; i++) {
  434         ilx_opts = t->catalog->bootimages[i]->isolinux_options;
  435         if ((((ilx_opts >> 2) & 63) == 1 || ((ilx_opts >> 2) & 63) == 2) &&
  436            !(t->boot_appended_idx[i] >= 0 && t->opts->appended_as_gpt)) {
  437             if (*gpt_count < 128)
  438                 gpt_idx[*gpt_count] = i;
  439             (*gpt_count)++;
  440             if ((flag & 1) &&
  441                 (t->bootsrc[i] != NULL || t->boot_appended_idx[i] >= 0)) {
  442                 /* Register GPT entry */
  443                 memset(gpt_name, 0, 72);
  444                 sprintf((char *) gpt_name, "ISOHybrid%d", *gpt_count);
  445                 iso_ascii_utf_16le(gpt_name);
  446                 if (((ilx_opts >> 2) & 63) == 2)
  447                     uuid = hfs_uuid;
  448                 else
  449                     uuid = basic_data_uuid;
  450                 if (t->boot_appended_idx[i] >= 0) {
  451                     block_count = t->appended_part_size[
  452                                                       t->boot_appended_idx[i]];
  453                     start_block = ((uint64_t) t->appended_part_start[
  454                                                  t->boot_appended_idx[i]]) * 4;
  455                 } else {
  456                     block_count = 0;
  457                     for (j = 0; j < t->bootsrc[i]->nsections; j++)
  458                         block_count += t->bootsrc[i]->sections[j].size / 2048;
  459                     start_block = ((uint64_t) t->bootsrc[i]->sections[0].block)
  460                                   * 4;
  461                 }
  462                 ret = iso_quick_gpt_entry(
  463                             t->gpt_req, &(t->gpt_req_count),
  464                             start_block, ((uint64_t) block_count) * 4,
  465                             uuid, zero_uuid, gpt_flags, (uint8_t *) gpt_name);
  466                 if (ret < 0)
  467                     return ret;
  468             }
  469         }
  470         if ((ilx_opts & 256) && !(flag & 2)) {
  471             (*apm_count)++;
  472             if ((flag & 1) &&
  473                 (t->bootsrc[i] != NULL || t->boot_appended_idx[i] >= 0)) {
  474                 /* Register APM entry */
  475                 if (t->boot_appended_idx[i] >= 0) {
  476                     block_count = t->appended_part_size[
  477                                                       t->boot_appended_idx[i]];
  478                     start_block = t->appended_part_start[
  479                                                       t->boot_appended_idx[i]];
  480                 } else {
  481                     block_count = 0;
  482                     for (j = 0; j < t->bootsrc[i]->nsections; j++)
  483                         block_count += t->bootsrc[i]->sections[j].size / 2048;
  484                     start_block = t->bootsrc[i]->sections[0].block;
  485                 }
  486                 ret = iso_quick_apm_entry(t->apm_req, &(t->apm_req_count),
  487                                           (uint32_t) start_block,
  488                                           block_count, "EFI", "Apple_HFS");
  489                 if (ret < 0)
  490                     return ret;
  491                 /* Prevent gap filling */
  492                 t->apm_req_flags |= 2;
  493                 t->opts->apm_block_size = 2048;
  494             }
  495         }
  496     }
  497     if (*gpt_count > 0 && !(flag & 4)) {
  498         (*gpt_count)++;
  499         if (*gpt_count < 128)
  500             gpt_idx[*gpt_count] = -1;
  501     }
  502     if ((flag & 1) && *gpt_count > 0 && !(flag & 4)) {
  503         /* Register overall GPT partition */
  504         memset(gpt_name, 0, 72);
  505         sprintf((char *) gpt_name, "ISOHybrid");
  506         iso_ascii_utf_16le(gpt_name);
  507         /* Let it be open ended. iso_write_gpt() will truncate it as needed. */
  508         block_count = 0xffffffff;
  509         ret = iso_quick_gpt_entry(t->gpt_req, &(t->gpt_req_count),
  510                                   (uint64_t) t->opts->partition_offset * 4,
  511                                   ((uint64_t) block_count) * 4,
  512                                   basic_data_uuid, zero_uuid, gpt_flags,
  513                                   (uint8_t *) gpt_name);
  514         if (ret < 0)
  515             return ret;
  516         /* Remove ban on GPT overlapping */
  517         t->gpt_req_flags |= 1;
  518     }
  519     return ISO_SUCCESS;
  520 }
  521 
  522 
  523 /* Insert APM head into MBR */
  524 static int insert_apm_head(uint8_t *buf, int apm_count)
  525 {
  526     int i;
  527     static uint8_t apm_mbr_start[32] = {
  528         0x33, 0xed, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
  529         0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
  530         0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
  531         0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90
  532     };
  533     static uint8_t apm_head[32] = {
  534         0x45, 0x52, 0x08, 0x00, 0x00, 0x00, 0x90, 0x90,
  535         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  536         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  537         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
  538     };
  539 
  540     if (apm_count) {
  541         for (i = 0; i < 32; i++)
  542             if(buf[i] != apm_mbr_start[i])
  543         break;
  544         if (i < 32) {
  545             /* Maybe it is already patched by apm_head ? */
  546             for (i = 0; i < 32; i++)
  547                 if(buf[i] != apm_head[i])
  548             break;
  549         }
  550         if (i < 32) {
  551             iso_msgs_submit(0,
  552                "MBR template file seems not prepared for Apple Partition Map.",
  553                0, "FAILURE", 0);
  554             return ISO_ISOLINUX_CANT_PATCH;
  555         }
  556         for (i = 0; i < 32; i++)
  557             buf[i] = apm_head[i];
  558     }
  559     return ISO_SUCCESS;
  560 }
  561 
  562 
  563 /* Describe GPT boot images as MBR partitions */
  564 static int gpt_images_as_mbr_partitions(Ecma119Image *t, char *wpt,
  565                                         int gpt_idx[128], int *gpt_cursor)
  566 {
  567     int ilx_opts, skip = 0;
  568     off_t hd_blocks;
  569     static uint8_t dummy_chs[3] = {
  570         0xfe, 0xff, 0xff, 
  571     };
  572 
  573     if (gpt_idx[*gpt_cursor] < 0)
  574         skip = 1;
  575     else if (t->bootsrc[gpt_idx[*gpt_cursor]] == NULL)
  576         skip = 1;
  577     if (skip) {
  578         (*gpt_cursor)++;
  579         return 2;
  580     }
  581 
  582     wpt[0] = 0;
  583     memcpy(wpt + 1, dummy_chs, 3);
  584     ilx_opts = t->catalog->bootimages[gpt_idx[*gpt_cursor]]->isolinux_options;
  585     if (((ilx_opts >> 2) & 63) == 2)
  586         wpt[4] = 0x00; /* HFS gets marked as "Empty" */
  587     else
  588         ((unsigned char *) wpt)[4] = 0xef; /* "EFI (FAT-12/16)" */
  589 
  590     memcpy(wpt + 5, dummy_chs, 3);
  591 
  592     /* Start LBA (in 512 blocks) */
  593     wpt += 8;
  594     lsb_to_buf(&wpt, t->bootsrc[gpt_idx[*gpt_cursor]]->sections[0].block * 4,
  595                32, 0);
  596 
  597     /* Number of blocks */
  598     hd_blocks = t->bootsrc[gpt_idx[*gpt_cursor]]->sections[0].size;
  599     hd_blocks = hd_blocks / 512 + !!(hd_blocks % 512);
  600     lsb_to_buf(&wpt, (int) hd_blocks, 32, 0);
  601 
  602     (*gpt_cursor)++;
  603     return ISO_SUCCESS;
  604 }
  605 
  606 
  607 /* For generating a weak random number */
  608 static uint32_t iso_make_mbr_id(Ecma119Image *t, int flag)
  609 {
  610     uint32_t id;
  611     struct timeval tv;
  612 
  613     if(t->opts->vol_uuid[0]) {
  614         id = iso_crc32_gpt((unsigned char *) t->opts->vol_uuid, 16, 0);
  615     } else if(t->opts->vol_modification_time > 0) {
  616         id = iso_crc32_gpt((unsigned char *) &(t->opts->vol_modification_time),
  617                            sizeof(time_t), 0);
  618     } else {
  619         gettimeofday(&tv, NULL);
  620         id = 0xffffffff & (tv.tv_sec ^ (tv.tv_usec * 2000));
  621     }
  622     return id;
  623 }
  624 
  625 
  626 /*
  627  * @param flag  bit0= make own random MBR Id from current time
  628  *                    >>> or from overridden modification time
  629  *              bit1= create protective MBR as of UEFI/GPT specs
  630  */
  631 int make_isolinux_mbr(uint32_t *img_blocks, Ecma119Image *t,
  632                       int part_offset, int part_number, int fs_type,
  633                       uint8_t *buf, int flag)
  634 {
  635     uint32_t id, part, nominal_part_size;
  636     off_t hd_img_blocks, hd_boot_lba;
  637     char *wpt;
  638     uint32_t boot_lba;
  639     int head_count, sector_count, ret;
  640     int gpt_count = 0, gpt_idx[128], apm_count = 0, gpt_cursor, i;
  641 
  642     if (t->bootsrc[0] == NULL)
  643         return iso_msg_submit(t->image->id, ISO_BOOT_IMAGE_NOT_VALID, 0,
  644       "Cannot refer by isohybrid MBR to data outside of ISO 9660 filesystem.");
  645 
  646     for (i = 0; i < 128; i++)
  647         gpt_idx[i] = -1;
  648 
  649     if (flag & 2) {
  650         part_number = 1;
  651         part_offset = 1;
  652     }
  653 
  654     hd_img_blocks = ((off_t) *img_blocks) * (off_t) 4 -
  655                     t->post_iso_part_pad / 512;
  656 
  657     boot_lba = t->bootsrc[0]->sections[0].block;
  658     head_count = t->partition_heads_per_cyl;
  659     sector_count = t->partition_secs_per_head;
  660 
  661     ret = assess_isohybrid_gpt_apm(t, &gpt_count, gpt_idx, &apm_count, 0);
  662     if (ret < 0)
  663         return ret;
  664 
  665     /* The rest of APM has already been written by iso_write_apm().
  666        But the isohybrid APM head differs from the hfsplus_writer APM head.
  667     */
  668     ret = insert_apm_head(buf, apm_count);
  669     if (ret < 0)
  670         return ret;
  671 
  672     /* Padding of image_size to a multiple of sector_count*head_count
  673        happens already at compute time and is implemented by
  674        an appropriate increase of Ecma119Image->tail_blocks.
  675     */
  676 
  677     wpt = (char *) buf + 432;
  678 
  679     /* write qword boot_lba            # Offset 432
  680     */
  681     hd_boot_lba = ((off_t) boot_lba) * (off_t) 4;
  682     lsb_to_buf(&wpt, hd_boot_lba & 0xffffffff, 32, 0);
  683     lsb_to_buf(&wpt, hd_boot_lba >> 32, 32, 0);
  684 
  685     /* write dword mbr_id              # Offset 440 
  686        (here some 32-bit random value with no crypto strength)
  687     */
  688     if (flag & 1) {
  689         id = iso_make_mbr_id(t, 0);
  690         lsb_to_buf(&wpt, id, 32, 0);
  691     } else {
  692         wpt+= 4;
  693     }
  694 
  695     /* write word 0                    # Offset 444
  696     */
  697     lsb_to_buf(&wpt, 0, 16, 0);
  698 
  699     /* # Offset 446
  700     */
  701     gpt_cursor= 0;
  702     for (part = 1 ; part <= 4; part++) {
  703         if ((int) part != part_number) {
  704             /* if this_partition != partition_number: write 16 zero bytes
  705                (this is now overridden by the eventual desire to announce
  706                 EFI and HFS boot images.)
  707             */
  708             memset(wpt, 0, 16);
  709 
  710             if (gpt_cursor < gpt_count) {
  711                 ret = gpt_images_as_mbr_partitions(t, wpt, gpt_idx,
  712                                                    &gpt_cursor);
  713                 if (ret < 0)
  714                     return ret;
  715             }
  716             wpt+= 16;
  717     continue;
  718         }
  719         /* write byte 0x80 if bootable
  720            write LBA_to_CHS(partition_offset)
  721            write byte filesystem_type
  722            write LBA_to_CHS(image_size-1)
  723            write dword partition_offset
  724            write dword image_size
  725         */
  726         if (flag & 2)
  727             lsb_to_buf(&wpt, 0x00, 8, 0);
  728         else
  729             lsb_to_buf(&wpt, 0x80, 8, 0);
  730         lba512chs_to_buf(&wpt, part_offset, head_count, sector_count);
  731         lsb_to_buf(&wpt, fs_type, 8, 0);
  732         lba512chs_to_buf(&wpt, hd_img_blocks - 1, head_count, sector_count);
  733         lsb_to_buf(&wpt, part_offset, 32, 0);
  734         if (hd_img_blocks - (off_t) part_offset > (off_t) 0xffffffff)
  735             nominal_part_size = 0xffffffff;
  736         else
  737             nominal_part_size = hd_img_blocks - (off_t) part_offset;
  738         lsb_to_buf(&wpt, nominal_part_size, 32, 0);
  739     }
  740 
  741     /*  write word 0xaa55            # Offset 510
  742     */
  743     lsb_to_buf(&wpt, 0xaa55, 16, 0);
  744 
  745     return(1);
  746 }
  747 
  748