[haiku-commits] haiku: hrev51183 - src/tools/anyboot build/jam/images

  • From: kallisti5@xxxxxxxxxxx
  • To: haiku-commits@xxxxxxxxxxxxx
  • Date: Fri, 26 May 2017 23:21:40 +0200 (CEST)

hrev51183 adds 1 changeset to branch 'master'
old head: 6af29d4f83018c47e1d2f2ff9d54fb198c0888a6
new head: 2f0ca6974e11d38fb66b83cd088bf1c4b55b0fa3
overview: 
http://cgit.haiku-os.org/haiku/log/?qt=range&q=2f0ca6974e11+%5E6af29d4f8301

----------------------------------------------------------------------------

2f0ca6974e11: anyboot: Add EFI partition support
  
  * Enables us to add an optional EFI filesystem
    to the anyboot image.
  * All existing anyboot behaviour is preserved.
  * We still need to figure out how to build bios
    and EFI loaders at the same time on x86.
  * The tiny "fake ISO" still needs el-torito
    alt-boot for the EFI loader to work when burned
    to a CD. This makes the EFI loader work when
    written to a hard disk / flash drive.

                          [ Alexander von Gluck IV <kallisti5@xxxxxxxxxxx> ]

----------------------------------------------------------------------------

Revision:    hrev51183
Commit:      2f0ca6974e11d38fb66b83cd088bf1c4b55b0fa3
URL:         http://cgit.haiku-os.org/haiku/commit/?id=2f0ca6974e11
Author:      Alexander von Gluck IV <kallisti5@xxxxxxxxxxx>
Date:        Fri May 26 21:13:44 2017 UTC

----------------------------------------------------------------------------

2 files changed, 196 insertions(+), 78 deletions(-)
build/jam/images/AnybootImage |   4 +-
src/tools/anyboot/anyboot.cpp | 270 +++++++++++++++++++++++++++-----------

----------------------------------------------------------------------------

diff --git a/build/jam/images/AnybootImage b/build/jam/images/AnybootImage
index 58d49f5..b1bdca7 100644
--- a/build/jam/images/AnybootImage
+++ b/build/jam/images/AnybootImage
@@ -12,11 +12,11 @@ rule BuildAnybootImage anybootImage : mbrPart : isoPart : 
imageFile {
        Depends $(anybootImage) : $(mbrPart) ;
        Depends $(anybootImage) : $(imageFile) ;
 
-       BuildAnybootImage1 $(anybootImage) : $(anyboot) $(isoPart) $(mbrPart) 
$(imageFile) ;
+       BuildAnybootImage1 $(anybootImage) : $(anyboot) $(mbrPart) $(isoPart) 
$(imageFile) ;
 }
 
 actions BuildAnybootImage1 {
-       $(2[1]) $(1) $(2[2]) $(2[3]) $(2[4])
+       $(2[1]) -b $(2[2]) $(2[3]) $(2[4]) $(1)
 }
 
 local baseMBR = base_mbr.bin ;
diff --git a/src/tools/anyboot/anyboot.cpp b/src/tools/anyboot/anyboot.cpp
index a768c21..bfc8813 100644
--- a/src/tools/anyboot/anyboot.cpp
+++ b/src/tools/anyboot/anyboot.cpp
@@ -1,10 +1,16 @@
 /*
  * Copyright 2010 Michael Lotz, mmlr@xxxxxxxx
+ * Copyright 2011-2017 Haiku, Inc. All rights reserved.
  * All rights reserved. Distributed under the terms of the MIT License.
+ *
+ * Authors:
+ *             Michael Lotz <mmlr@xxxxxxxx>
+ *             Alexander von Gluck IV <kallisti5@xxxxxxxxxxx>
  */
 
 
 #include <errno.h>
+#include <getopt.h>
 #include <fcntl.h>
 #include <unistd.h>
 #include <stdint.h>
@@ -13,32 +19,42 @@
 #include <string.h>
 #include <sys/stat.h>
 
+#define EXIT_FAILURE 1
+
+
+//#define DEBUG_ANYBOOT
+#ifdef DEBUG_ANYBOOT
+#   define TRACE(x...) printf("anyboot: " x)
+#else
+#   define TRACE(x...) ;
+#endif
+
+
 static uint8_t *sCopyBuffer = NULL;
 static size_t sCopyBufferSize = 2 * 1024 * 1024;
+static const size_t kBlockSize = 512;
 
 
-int
-copyLoop(int from, int to, off_t position)
-{
-       while (true) {
-               ssize_t copyLength = read(from, sCopyBuffer, sCopyBufferSize);
-               if (copyLength <= 0)
-                       return copyLength;
+// Haiku Anyboot Image:
+//   (MBR Table + Boot Sector)
+//   ISO (Small Haiku ISO9660)
+//   First Partition (Haiku OS Image, BFS)
+//   Second Partition (EFI Loader, FAT)
+//   Third Partition (EFI Mac, HFS) <not implemented>
 
-               ssize_t written = pwrite(to, sCopyBuffer, copyLength, position);
-               if (written != copyLength) {
-                       if (written < 0)
-                               return written;
-                       else
-                               return -1;
-               }
 
-               position += copyLength;
-       }
+static void
+print_usage(bool error)
+{
+       printf("\n");
+       printf("usage: anyboot [-b BIOS-Loader] [-e EFI-Filesystem] <isoFile> 
<imageFile> <outputFile>\n");
+       printf("       -b, --bios-loader <file>     Legacy BIOS bootloader\n");
+       printf("       -e, --efi-filesystem <file>  EFI filesystem\n");
+       exit(error ? EXIT_FAILURE : 0);
 }
 
 
-void
+static void
 checkError(bool failed, const char *message)
 {
        if (!failed)
@@ -50,7 +66,8 @@ checkError(bool failed, const char *message)
 }
 
 
-void
+#if 0
+static void
 chsAddressFor(uint32_t offset, uint8_t *address, uint32_t sectorsPerTrack,
        uint32_t headsPerCylinder)
 {
@@ -83,98 +100,199 @@ chsAddressFor(uint32_t offset, uint8_t *address, uint32_t 
sectorsPerTrack,
        address[1] |= (cylinders >> 2) & 0xc0;
        address[2] = cylinders;
 }
+#endif
+
+
+static void
+createPartition(int handle, int index, bool active, uint8_t type,
+       uint32_t offset, uint32_t size)
+{
+       uint8_t bootable = active ? 0x80 : 0x0;
+       uint8_t partition[16] = {
+               bootable,                               // bootable
+               0xff, 0xff, 0xff,               // CHS first block (default to 
LBA)
+               type,                                   // partition type
+               0xff, 0xff, 0xff,               // CHS last block (default to 
LBA)
+               0x00, 0x00, 0x00, 0x00, // imageOffset in blocks (written below)
+               0x00, 0x00, 0x00, 0x00  // imageSize in blocks (written below)
+       };
+
+       // fill in LBA values
+       uint32_t partitionOffset = (uint32_t)(offset / kBlockSize);
+       ((uint32_t *)partition)[2] = partitionOffset;
+       ((uint32_t *)partition)[3] = (uint32_t)(size / kBlockSize);
+
+       TRACE("%s: #%d %c bytes: %u-%u, sectors: %u-%u\n", __func__, index,
+               active ? 'b' : '-', offset, offset + size, partitionOffset,
+               partitionOffset + uint32_t(size / kBlockSize));
+#if 0
+       // while this should basically work, it makes the boot code needlessly
+       // use chs which has a high potential of failure due to the geometry
+       // being unknown beforehand (a fixed geometry would be used here).
+
+       uint32_t sectorsPerTrack = 63;
+       uint32_t headsPerCylinder = 255;
+
+       // fill in CHS values
+       chsAddressFor(partitionOffset, &partition[1], sectorsPerTrack,
+               headsPerCylinder);
+       chsAddressFor(partitionOffset + (uint32_t)(size / kBlockSize),
+               &partition[5], sectorsPerTrack, headsPerCylinder);
+#endif
+
+       ssize_t written = pwrite(handle, partition, 16, 512 - 2 - 16 * (4 - 
index));
+       checkError(written != 16, "failed to write partition entry");
+
+       if (active) {
+               // make it bootable
+               written = pwrite(handle, &partitionOffset, 4, offset + 512 - 2 
- 4);
+               checkError(written != 4, "failed to make image bootable");
+       }
+       return;
+}
+
+
+static int
+copyLoop(int from, int to, off_t position)
+{
+       while (true) {
+               ssize_t copyLength = read(from, sCopyBuffer, sCopyBufferSize);
+               if (copyLength <= 0)
+                       return copyLength;
+
+               ssize_t written = pwrite(to, sCopyBuffer, copyLength, position);
+               if (written != copyLength) {
+                       if (written < 0)
+                               return written;
+                       else
+                               return -1;
+               }
+
+               position += copyLength;
+       }
+}
 
 
 int
 main(int argc, char *argv[])
 {
-       if (argc < 5) {
-               printf("usage: %s <outputFile> <isoFile> <mbrFile> 
<imageFile>\n",
-                       argv[0]);
-               return 1;
+       const char *biosFile = NULL;
+       const char *efiFile = NULL;
+       const char *isoFile = NULL;
+       const char *imageFile = NULL;
+       const char *outputFile = NULL;
+
+       while (1) {
+               int c;
+               static struct option long_options[] = {
+                       {"bios-loader", required_argument, 0, 'b'},
+                       {"efi-loader", required_argument, 0, 'e'},
+                       {"help", no_argument, 0, 'h'},
+                       {0, 0, 0, 0}
+               };
+
+               opterr = 1; /* don't print errors */
+               c = getopt_long(argc, argv, "+hb:e:", long_options, NULL);
+
+               if (c == -1)
+                       break;
+
+               switch (c) {
+                       case 'h':
+                               print_usage(false);
+                               break;
+                       case 'b':
+                               biosFile = optarg;
+                               break;
+                       case 'e':
+                               efiFile = optarg;
+                               break;
+                       default:
+                               print_usage(true);
+               }
+       }
+
+       if ((argc - optind) != 3)
+               print_usage(true);
+
+       for (int index = optind; index < argc; index++) {
+               if (isoFile == NULL)
+                       isoFile = argv[index];
+               else if (imageFile == NULL)
+                       imageFile = argv[index];
+               else if (outputFile == NULL)
+                       outputFile = argv[index];
        }
 
        sCopyBuffer = (uint8_t *)malloc(sCopyBufferSize);
        checkError(sCopyBuffer == NULL, "no memory for copy buffer");
 
-       static const size_t kBlockSize = 512;
-
-       int outputFile = open(argv[1], O_WRONLY | O_TRUNC | O_CREAT,
+       int outputFileHandle = open(outputFile, O_WRONLY | O_TRUNC | O_CREAT,
                S_IRUSR | S_IWUSR);
-       checkError(outputFile < 0, "failed to open output file");
+       checkError(outputFileHandle < 0, "failed to open output file");
 
-       int isoFile = open(argv[2], O_RDONLY);
-       checkError(isoFile < 0, "failed to open ISO file");
+       int isoFileHandle = open(isoFile, O_RDONLY);
+       checkError(isoFileHandle < 0, "failed to open ISO file");
 
        struct stat stat;
-       int result = fstat(isoFile, &stat);
+       int result = fstat(isoFileHandle, &stat);
        checkError(result != 0, "failed to stat ISO file");
        off_t isoSize = stat.st_size;
 
-       int mbrFile = open(argv[3], O_RDONLY);
-       checkError(mbrFile < 0, "failed to open MBR file");
+       int biosFileHandle = -1;
+       if (biosFile != NULL) {
+               biosFileHandle = open(biosFile, O_RDONLY);
+               checkError(biosFileHandle < 0, "failed to open BIOS bootloader 
file");
+       }
 
-       int imageFile = open(argv[4], O_RDONLY);
-       checkError(imageFile < 0, "failed to open image file");
+       int efiFileHandle = -1;
+       off_t efiSize = 0;
+       if (efiFile != NULL) {
+               efiFileHandle = open(efiFile, O_RDONLY);
+               checkError(efiFileHandle < 0, "failed to open EFI bootloader 
file");
 
-       result = fstat(imageFile, &stat);
-       checkError(result != 0, "failed to stat image file");
+               result = fstat(efiFileHandle, &stat);
+               checkError(result != 0, "failed to stat EFI filesystem image");
+               efiSize = stat.st_size;
+       }
+
+       int imageFileHandle = open(imageFile, O_RDONLY);
+       checkError(imageFileHandle < 0, "failed to open image file");
 
+       result = fstat(imageFileHandle, &stat);
+       checkError(result != 0, "failed to stat image file");
        off_t imageSize = stat.st_size;
 
-       result = copyLoop(isoFile, outputFile, 0);
+       result = copyLoop(isoFileHandle, outputFileHandle, 0);
        checkError(result != 0, "failed to copy iso file to output");
 
        // isoSize rounded to the next full megabyte
        off_t alignment = 1 * 1024 * 1024 - 1;
        off_t imageOffset = (isoSize + alignment) & ~alignment;
 
-       result = copyLoop(imageFile, outputFile, imageOffset);
+       result = copyLoop(imageFileHandle, outputFileHandle, imageOffset);
        checkError(result != 0, "failed to copy image file to output");
 
-       result = copyLoop(mbrFile, outputFile, 0);
-       checkError(result != 0, "failed to copy mbr to output");
-
-       // construct the partition table
-       uint8_t partition[16] = {
-               0x80,                                   // active
-               0xff, 0xff, 0xff,               // CHS first block (default to 
LBA)
-               0xeb,                                   // partition type (BFS)
-               0xff, 0xff, 0xff,               // CHS last block (default to 
LBA)
-               0x00, 0x00, 0x00, 0x00, // imageOffset in blocks (written below)
-               0x00, 0x00, 0x00, 0x00  // imageSize in blocks (written below)
-       };
+       if (biosFileHandle >= 0) {
+               result = copyLoop(biosFileHandle, outputFileHandle, 0);
+               checkError(result != 0, "failed to copy BIOS bootloader to 
output");
+       }
 
+       // Haiku Image Partition
        alignment = kBlockSize - 1;
        imageSize = (imageSize + alignment) & ~alignment;
+       createPartition(outputFileHandle, 0, true, 0xeb, imageOffset, 
imageSize);
+
+       // Optional EFI Filesystem
+       if (efiFile != NULL) {
+               off_t efiOffset = (imageOffset + imageSize + alignment) & 
~alignment;
+               efiSize = (efiSize + alignment) & ~alignment;
+               result = copyLoop(efiFileHandle, outputFileHandle, efiOffset);
+               checkError(result != 0, "failed to copy EFI filesystem image to 
output");
+               createPartition(outputFileHandle, 1, false, 0xef, efiOffset, 
efiSize);
+       }
 
-       // fill in LBA values
-       uint32_t partitionOffset = (uint32_t)(imageOffset / kBlockSize);
-       ((uint32_t *)partition)[2] = partitionOffset;
-       ((uint32_t *)partition)[3] = (uint32_t)(imageSize / kBlockSize);
-
-#if 0
-       // while this should basically work, it makes the boot code needlessly
-       // use chs which has a high potential of failure due to the geometry
-       // being unknown beforehand (a fixed geometry would be used here).
-
-       uint32_t sectorsPerTrack = 63;
-       uint32_t headsPerCylinder = 255;
-
-       // fill in CHS values
-       chsAddressFor(partitionOffset, &partition[1], sectorsPerTrack,
-               headsPerCylinder);
-       chsAddressFor(partitionOffset + (uint32_t)(imageSize / kBlockSize),
-               &partition[5], sectorsPerTrack, headsPerCylinder);
-#endif
-
-       ssize_t written = pwrite(outputFile, partition, 16, 512 - 2 - 16 * 4);
-       checkError(written != 16, "failed to write partition entry");
-
-       // and make the image bootable
-       written = pwrite(outputFile, &partitionOffset, 4,
-               imageOffset + 512 - 2 - 4);
-       checkError(written != 4, "failed to make image bootable");
+       // TODO: MacEFI (HFS) maybe someday
 
        free(sCopyBuffer);
        return 0;


Other related posts: