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;