boot: Recover BIOS loader.

This commit is contained in:
K. Lange 2021-05-31 12:31:01 +09:00
parent 62e9138e5d
commit 074728b5ff
8 changed files with 437 additions and 1258 deletions

3
.gitignore vendored
View File

@ -26,3 +26,6 @@
/base/usr/bin/*
/base/usr/lib/*
/.make/
/cdrom
/fatbase
/image.iso

View File

@ -238,3 +238,30 @@ SOURCE_FILES += $(wildcard kuroko/src/*.c kuroko/src/*.h kuroko/src/*/*.c kuroko
SOURCE_FILES += $(wildcard $(BASE)/usr/include/*.h $(BASE)/usr/include/*/*.h $(BASE)/usr/include/*/*/*.h)
tags: $(SOURCE_FILES)
ctags -f tags $(SOURCE_FILES)
# Loader stuff, legacy CDs
fatbase/ramdisk.igz: ramdisk.igz
cp $< $@
fatbase/kernel: misaka-kernel
cp $< $@
strip $@
cdrom/fat.img: fatbase/ramdisk.igz fatbase/kernel util/mkdisk.sh | dirs
util/mkdisk.sh $@ fatbase
cdrom/boot.sys: boot/boot.o boot/cstuff.o boot/link.ld | dirs
${LD} -melf_i386 -T boot/link.ld -o $@ boot/boot.o boot/cstuff.o
boot/cstuff.o: boot/cstuff.c boot/*.h
${CC} -m32 -c -Os -fno-strict-aliasing -finline-functions -ffreestanding -mgeneral-regs-only -o $@ $<
boot/boot.o: boot/boot.S
${AS} --32 -o $@ $<
image.iso: cdrom/fat.img cdrom/boot.sys util/update-extents.py
xorriso -as mkisofs -R -J -c bootcat \
-b boot.sys -no-emul-boot -boot-load-size full \
-eltorito-alt-boot -e fat.img -no-emul-boot -isohybrid-gpt-basdat \
-o image.iso cdrom
python3 util/update-extents.py

View File

@ -1,99 +1,40 @@
#ifdef EFI_PLATFORM
# include <efi.h>
# include <efilib.h>
EFI_HANDLE ImageHandleIn;
#else
# include <stdint.h>
# include <stddef.h>
#endif
#include <stdint.h>
#include <stddef.h>
#define _BOOT_LOADER
#include "ata.h"
#include "text.h"
#include "util.h"
#ifndef EFI_PLATFORM
#include "atapi_imp.h"
#include "iso9660.h"
#endif
#include "elf.h"
#include "multiboot.h"
#include "kbd.h"
#include "options.h"
#include "inflate.h"
/* Basic text strings */
#define BASE_VERSION "ToaruOS Bootloader v2.1"
#ifdef EFI_PLATFORM
# if defined(__x86_64__)
# define VERSION_TEXT BASE_VERSION " (EFI, X64)"
# else
# define VERSION_TEXT BASE_VERSION " (EFI, IA32)"
# endif
#else
# define VERSION_TEXT BASE_VERSION " (BIOS)"
#endif
#define BASE_VERSION "ToaruOS Bootloader v3.0"
#define VERSION_TEXT BASE_VERSION " (BIOS)"
#define HELP_TEXT "Press <Enter> or select a menu option with \030/\031/\032/\033."
#define COPYRIGHT_TEXT "ToaruOS is free software under the NCSA license."
#define LINK_TEXT "https://toaruos.org - https://github.com/klange/toaruos"
/* Boot command line strings */
#define DEFAULT_ROOT_CMDLINE "root=/dev/ram0 root_type=tar "
#define DEFAULT_ROOT_CMDLINE "root=/dev/ram0 "
#define DEFAULT_GRAPHICAL_CMDLINE "start=live-session "
#define DEFAULT_SINGLE_CMDLINE "start=terminal\037-F "
#define DEFAULT_TEXT_CMDLINE "start=--vga "
#define DEFAULT_VID_CMDLINE "vid=auto,1440,900 "
#define DEFAULT_PRESET_VID_CMDLINE "vid=preset "
#define DEFAULT_NETINIT_CMDLINE "init=/dev/ram0 "
#define NETINIT_REMOTE_URL "args=http://toaruos.org/ramdisk-1.9.3.img "
#define MIGRATE_CMDLINE "migrate "
#define DEBUG_LOG_CMDLINE "logtoserial=warning "
#define DEBUG_SERIAL_CMDLINE "kdebug "
#define DEFAULT_HEADLESS_CMDLINE "start=--headless "
char * module_dir = "MOD";
char * kernel_path = "KERNEL.";
char * ramdisk_path = "RAMDISK.IGZ";
#ifdef EFI_PLATFORM
int _efi_do_mode_set = 0;
#endif
/* Module file names - need to be ordered. */
static char * modules[] = {
"ZERO.KO", // 0
"RANDOM.KO", // 1
"SERIAL.KO", // 2
"DEBUG_SH.KO", // 3
"PROCFS.KO", // 4
"TMPFS.KO", // 5
"ATA.KO", // 6
"EXT2.KO", // 7
"ISO9660.KO", // 8
"PS2KBD.KO", // 9
"PS2MOUSE.KO", // 10
"LFBVIDEO.KO", // 11
"VBOX.KO", // 12
"VMWARE.KO", // 13
"VIDSET.KO", // 14
"PACKETFS.KO", // 15
"SND.KO", // 16
"AC97.KO", // 17
"NET.KO", // 18
"PCNET.KO", // 19
"RTL.KO", // 20
"E1000.KO", // 21
"PCSPKR.KO", // 22
"PORTIO.KO", // 23
"TARFS.KO", // 24
0
};
/* Names of the available boot modes. */
static struct bootmode boot_mode_names[] = {
{1, "normal", "Normal Boot"},
#ifndef EFI_PLATFORM
{2, "vga", "VGA Text Mode"},
#endif
{3, "single", "Single-User Graphical Terminal"},
{4, "headless", "Headless"},
};
@ -101,40 +42,19 @@ static struct bootmode boot_mode_names[] = {
/* More bootloader implementation that depends on the module config */
#include "moremultiboot.h"
#ifdef EFI_PLATFORM
EFI_STATUS
EFIAPI
efi_main (EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable)
{
InitializeLib(ImageHandle, SystemTable);
ST = SystemTable;
ImageHandleIn = ImageHandle;
#else
extern char _bss_start[];
extern char _bss_end[];
int kmain() {
memset(&_bss_start,0,(uintptr_t)&_bss_end-(uintptr_t)&_bss_start);
#endif
BOOT_OPTION(_debug, 0, "Debug output",
"Enable debug output in the bootloader and enable the",
"serial debug log in the operating system itself.");
BOOT_OPTION(_legacy_ata, 0, "Legacy ATA driver",
"Enable the legacy ATA driver, which does not support",
"ATAPI or use DMA. May be necessary in some virtual machines.");
BOOT_OPTION(_normal_ata, 1, "DMA ATA driver",
"Enable the normal, DMA-capable ATA driver. This is the default.",
NULL);
BOOT_OPTION(_debug_shell, 1, "Debug shell",
"Enable the kernel debug shell. This can be accessed using",
"the `kdebug` application.");
BOOT_OPTION(_video, 1, "Video modules",
"Enable the video modules. These are needed to modeset",
"and provide a framebuffer for the UI.");
BOOT_OPTION(_nosmp, 1, "Disable SMP",
"SMP support is experimental and buggy.",
"");
BOOT_OPTION(_vbox, 1, "VirtualBox Guest Additions",
"Enable integration with VirtualBox, including",
@ -156,73 +76,21 @@ int kmain() {
"(Requires VMware driver) Enables support for",
"automatically setting display size in VMware");
BOOT_OPTION(_sound, 1, "Audio drivers",
"Enable the audio subsystem and AC'97 drivers.",
NULL);
BOOT_OPTION(_net, 1, "Network drivers",
"Enable the IPv4 network subsystem and various",
"network interface drivers.");
BOOT_OPTION(_migrate, 1, "Writable root",
"Migrates the ramdisk from tarball to an in-memory",
"temporary filesystem at boot. Needed for packages.");
BOOT_OPTION(_serialshell, 0, "Debug on serial",
"Start a kernel debug shell on the first",
"serial port.");
BOOT_OPTION(_netinit, 0, "Netinit (QEMU local)",
"Downloads a userspace filesystem from a local",
"HTTP server and extracts it at boot.");
BOOT_OPTION(_netinitr, 0, "Netinit (toaruos.org)",
"Downloads a userspace filesystem from a remote",
"HTTP server and extracts it at boot.");
#ifdef EFI_PLATFORM
BOOT_OPTION(_efilargest, 0, "Prefer largest mode.",
"When using EFI mode setting, use the largest mode.",
NULL);
BOOT_OPTION(_efi1024, 0, "Prefer 1024x768",
"If a 1024x768x32 mode is found, set that.",
NULL);
BOOT_OPTION(_efi1080p, 0, "Prefer 1080p",
"If a 1920x1080 mode is found, set that.",
NULL);
BOOT_OPTION(_efiask, 0, "Ask for input on each mode.",
"Displays a y/n prompt for each possible mode.",
NULL);
#endif
/* Loop over rendering the menu */
show_menu();
/* Build our command line. */
if (_netinit || _netinitr) {
strcat(cmdline, DEFAULT_NETINIT_CMDLINE);
ramdisk_path = "NETINIT.";
if (_netinitr) {
strcat(cmdline, NETINIT_REMOTE_URL);
}
} else {
strcat(cmdline, DEFAULT_ROOT_CMDLINE);
}
strcat(cmdline, DEFAULT_ROOT_CMDLINE);
if (_migrate) {
strcat(cmdline, MIGRATE_CMDLINE);
}
char * _video_command_line = DEFAULT_VID_CMDLINE;
#ifdef EFI_PLATFORM
_efi_do_mode_set = (_efilargest ? 1 : (_efi1024 ? 2 : (_efi1080p ? 3 : (_efiask ? 4 : 0))));
if (_efi_do_mode_set) {
_video_command_line = DEFAULT_PRESET_VID_CMDLINE;
}
#endif
if (boot_mode == 1) {
strcat(cmdline, DEFAULT_GRAPHICAL_CMDLINE);
@ -237,12 +105,11 @@ int kmain() {
}
if (_debug) {
strcat(cmdline, DEBUG_LOG_CMDLINE);
txt_debug = 1;
}
if (_serialshell) {
strcat(cmdline, DEBUG_SERIAL_CMDLINE);
if (!_vbox) {
strcat(cmdline, "novbox ");
}
if (_vbox && !_vboxrects) {
@ -257,45 +124,8 @@ int kmain() {
strcat(cmdline, "novmwareresset ");
}
/* Configure modules */
if (!_normal_ata) {
modules[6] = "NONE";
}
if (_legacy_ata) {
modules[6] = "ATAOLD.KO";
}
if (!_debug_shell) {
modules[3] = "NONE";
modules[14] = "NONE";
}
if (!_video) {
modules[11] = "NONE";
modules[12] = "NONE";
modules[13] = "NONE";
modules[14] = "NONE";
}
if (!_vmware) {
modules[13] = "NONE";
}
if (!_vbox) {
modules[12] = "NONE";
}
if (!_sound) {
modules[16] = "NONE";
modules[17] = "NONE";
}
if (!_net) {
modules[18] = "NONE";
modules[19] = "NONE";
modules[20] = "NONE";
modules[21] = "NONE";
if (_nosmp) {
strcat(cmdline, "nosmp ");
}
boot();

View File

@ -1,467 +0,0 @@
#include <stdint.h>
#include <stddef.h>
static uint8_t bit_buffer = 0;
static char buffer_size = 0;
static uint8_t * inputPtr = NULL;
static uint8_t * outputPtr = NULL;
static uint8_t read_byte(void);
static void _write(unsigned int sym);
/**
* Decoded Huffman table
*/
struct huff {
uint16_t counts[16]; /* Number of symbols of each length */
uint16_t symbols[288]; /* Ordered symbols */
};
/**
* Fixed Huffman code tables, generated later.
*/
struct huff fixed_lengths;
struct huff fixed_dists;
/**
* Read a little-endian short from the input.
*/
static uint16_t read_16le(void) {
uint16_t a, b;
a = read_byte();
b = read_byte();
return (a << 0) | (b << 8);
}
/**
* Read a single bit from the source.
* Fills the byte buffer with one byte when it runs out.
*/
static _Bool read_bit(void) {
/* When we run out of bits... */
if (buffer_size == 0) {
/* Refill from the next input byte */
bit_buffer = read_byte();
/* And restore bit buffer size to 8 bits */
buffer_size = 8;
}
/* Get the next available bit */
int out = bit_buffer & 1;
/* Shift the bit buffer forward */
bit_buffer >>= 1;
/* There is now one less bit available */
buffer_size--;
return out;
}
/**
* Read multible bits, in bit order, from the source.
*/
static uint32_t read_bits(unsigned int count) {
uint32_t out = 0;
for (unsigned int bit = 0; bit < count; bit++) {
/* Read one bit at a time, from least to most significant */
out |= (read_bit() << bit);
}
return out;
}
/**
* Build a Huffman table from an array of lengths.
*/
static void build_huffman(uint8_t * lengths, size_t size, struct huff * out) {
uint16_t offsets[16];
unsigned int count = 0;
/* Zero symbol counts */
for (unsigned int i = 0; i < 16; ++i) out->counts[i] = 0;
/* Count symbols */
for (unsigned int i = 0; i < size; ++i) out->counts[lengths[i]]++;
/* Special case... */
out->counts[0] = 0;
/* Figure out offsets */
for (unsigned int i = 0; i < 16; ++i) {
offsets[i] = count;
count += out->counts[i];
}
/* Build symbol ordering */
for (unsigned int i = 0; i < size; ++i) {
if (lengths[i]) out->symbols[offsets[lengths[i]]++] = i;
}
}
/**
* Build the fixed Huffman tables
*/
static void build_fixed(void) {
/* From 3.2.6:
* Lit Value Bits Codes
* --------- ---- -----
* 0 - 143 8 00110000 through
* 10111111
* 144 - 255 9 110010000 through
* 111111111
* 256 - 279 7 0000000 through
* 0010111
* 280 - 287 8 11000000 through
* 11000111
*/
uint8_t lengths[288];
for (int i = 0; i < 144; ++i) lengths[i] = 8;
for (int i = 144; i < 256; ++i) lengths[i] = 9;
for (int i = 256; i < 280; ++i) lengths[i] = 7;
for (int i = 280; i < 288; ++i) lengths[i] = 8;
build_huffman(lengths, 288, &fixed_lengths);
/* Continued from 3.2.6:
* Distance codes 0-31 are represented by (fixed-length) 5-bit
* codes, with possible additional bits as shown in the table
* shown in Paragraph 3.2.5, above. Note that distance codes 30-
* 31 will never actually occur in the compressed data.
*/
for (int i = 0; i < 30; ++i) lengths[i] = 5;
build_huffman(lengths, 30, &fixed_dists);
}
/**
* Decode a symbol from the source using a Huffman table.
*/
static int decode(struct huff * huff) {
int count = 0, cur = 0;
for (int i = 1; cur >= 0; i++) {
cur = (cur << 1) | read_bit(); /* Shift */
count += huff->counts[i];
cur -= huff->counts[i];
}
return huff->symbols[count + cur];
}
struct huff_ring {
size_t pointer;
uint8_t data[32768];
};
static struct huff_ring data = {0, {0}};
/**
* Emit one byte to the output, maintaining the ringbuffer.
* The ringbuffer ensures we can always look back 32K bytes
* while keeping output streaming.
*/
static void emit(unsigned char byte) {
data.data[data.pointer++] = byte;
data.pointer &= 0x7FFF;
_write(byte);
}
/**
* Look backwards in the output ring buffer.
*/
static void peek(unsigned int offset) {
data.data[data.pointer] = data.data[(data.pointer + 0x8000 - offset) & 0x7FFF];
_write(data.data[data.pointer++]);
data.pointer &= 0x7FFF;
}
/**
* Decompress a block of Huffman-encoded data.
*/
static int inflate(struct huff * huff_len, struct huff * huff_dist) {
/* These are the extra bits for lengths from the tables in section 3.2.5
* Extra Extra Extra
* Code Bits Length(s) Code Bits Lengths Code Bits Length(s)
* ---- ---- ------ ---- ---- ------- ---- ---- -------
* 257 0 3 267 1 15,16 277 4 67-82
* 258 0 4 268 1 17,18 278 4 83-98
* 259 0 5 269 2 19-22 279 4 99-114
* 260 0 6 270 2 23-26 280 4 115-130
* 261 0 7 271 2 27-30 281 5 131-162
* 262 0 8 272 2 31-34 282 5 163-194
* 263 0 9 273 3 35-42 283 5 195-226
* 264 0 10 274 3 43-50 284 5 227-257
* 265 1 11,12 275 3 51-58 285 0 258
* 266 1 13,14 276 3 59-66
*/
static const uint16_t lens[] = {
3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51,
59, 67, 83, 99, 115, 131, 163, 195, 227, 258
};
static const uint16_t lext[] = {
0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4,
4, 5, 5, 5, 5, 0
};
/* Extra bits for distances....
* Extra Extra Extra
* Code Bits Dist Code Bits Dist Code Bits Distance
* ---- ---- ---- ---- ---- ------ ---- ---- --------
* 0 0 1 10 4 33-48 20 9 1025-1536
* 1 0 2 11 4 49-64 21 9 1537-2048
* 2 0 3 12 5 65-96 22 10 2049-3072
* 3 0 4 13 5 97-128 23 10 3073-4096
* 4 1 5,6 14 6 129-192 24 11 4097-6144
* 5 1 7,8 15 6 193-256 25 11 6145-8192
* 6 2 9-12 16 7 257-384 26 12 8193-12288
* 7 2 13-16 17 7 385-512 27 12 12289-16384
* 8 3 17-24 18 8 513-768 28 13 16385-24576
* 9 3 25-32 19 8 769-1024 29 13 24577-32768
*/
static const uint16_t dists[] = {
1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385,
513, 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577
};
static const uint16_t dext[] = {
0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10,
10, 11, 11, 12, 12, 13, 13
};
while (1) {
unsigned int symbol = decode(huff_len);
if (symbol < 256) {
emit(symbol);
} else if (symbol == 256) {
/* "The literal/length symbol 256 (end of data), ..." */
break;
} else {
unsigned int length, distance, offset;
symbol -= 257;
length = read_bits(lext[symbol]) + lens[symbol];
distance = decode(huff_dist);
offset = read_bits(dext[distance]) + dists[distance];
for (unsigned int i = 0; i < length; ++i) {
peek(offset);
}
}
}
return 0;
}
/**
* Decode a dynamic Huffman block.
*/
static void decode_huffman(void) {
/* Ordering of code length codes:
* (HCLEN + 4) x 3 bits: code lengths for the code length
* alphabet given just above, in the order: ...
*/
static const uint8_t clens[] = {
16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15
};
unsigned int literals, distances, clengths;
uint8_t lengths[320] = {0};
literals = 257 + read_bits(5); /* 5 Bits: HLIT ... 257 */
distances = 1 + read_bits(5); /* 5 Bits: HDIST ... 1 */
clengths = 4 + read_bits(4); /* 4 Bits: HCLEN ... 4 */
/* (HCLEN + 4) x 3 bits... */
for (unsigned int i = 0; i < clengths; ++i) {
lengths[clens[i]] = read_bits(3);
}
struct huff codes;
build_huffman(lengths, 19, &codes);
/* Decode symbols:
* HLIT + 257 code lengths for the literal/length alphabet...
* HDIST + 1 code lengths for the distance alphabet...
*/
unsigned int count = 0;
while (count < literals + distances) {
int symbol = decode(&codes);
int rep = 0, length;
switch (symbol) {
case 16:
/* 16: Copy the previous code length 3-6 times */
rep = lengths[count-1];
length = read_bits(2) + 3; /* The next 2 bits indicate repeat length */
break;
case 17:
/* Repeat a code length of 0 for 3 - 10 times */
length = read_bits(3) + 3; /* 3 bits of length */
break;
case 18:
/* Repeat a code length of 0 for 11 - 138 times */
length = read_bits(7) + 11; /* 7 bits of length */
break;
default:
length = 1;
rep = symbol;
break;
}
while (length--) {
lengths[count++] = rep;
}
}
/* Build tables from lenghts decoded above */
struct huff huff_len;
build_huffman(lengths, literals, &huff_len);
struct huff huff_dist;
build_huffman(lengths + literals, distances, &huff_dist);
inflate(&huff_len, &huff_dist);
}
/**
* Decode an uncompressed block.
*/
static int uncompressed(void) {
/* Reset byte alignment */
bit_buffer = 0;
buffer_size = 0;
/* "The rest of the block consists of the following information:"
* 0 1 2 3 4...
* +---+---+---+---+================================+
* | LEN | NLEN |... LEN bytes of literal data...|
* +---+---+---+---+================================+
*/
uint16_t len = read_16le(); /* "the number of data bytes in the block" */
uint16_t nlen = read_16le(); /* "the one's complement of LEN */
/* Sanity check - does the ones-complement length actually match? */
if ((nlen & 0xFFFF) != (~len & 0xFFFF)) {
return 1;
}
/* Emit LEN bytes from the source to the output */
for (int i = 0; i < len; ++i) {
emit(read_byte());
}
return 0;
}
/**
* Decompress DEFLATE-compressed data.
*/
__attribute__((optimize("O2")))
__attribute__((hot))
int deflate_decompress(void) {
bit_buffer = 0;
buffer_size = 0;
build_fixed();
/* read compressed data */
while (1) {
/* Read bit */
int is_final = read_bit();
int type = read_bits(2);
switch (type) {
case 0x00: /* BTYPE=00 Non-compressed blocks */
uncompressed();
break;
case 0x01: /* BYTPE=01 Compressed with fixed Huffman codes */
inflate(&fixed_lengths, &fixed_dists);
break;
case 0x02: /* BTYPE=02 Compression with dynamic Huffman codes */
decode_huffman();
break;
case 0x03:
return 1;
default:
__builtin_unreachable();
break;
}
if (is_final) {
break;
}
}
return 0;
}
#define GZIP_FLAG_TEXT (1 << 0)
#define GZIP_FLAG_HCRC (1 << 1)
#define GZIP_FLAG_EXTR (1 << 2)
#define GZIP_FLAG_NAME (1 << 3)
#define GZIP_FLAG_COMM (1 << 4)
static unsigned int read_32le(void) {
unsigned int a, b, c, d;
a = read_byte();
b = read_byte();
c = read_byte();
d = read_byte();
return (d << 24) | (c << 16) | (b << 8) | (a << 0);
}
int gzip_decompress(void) {
/* Read gzip headers */
if (read_byte() != 0x1F) return 1;
if (read_byte() != 0x8B) return 1;
unsigned int cm = read_byte();
if (cm != 8) return 1;
unsigned int flags = read_byte();
/* Read mtime */
unsigned int mtime = read_32le();
(void)mtime;
/* Read extra flags */
unsigned int xflags = read_byte();
(void)xflags;
/* Read and discord OS flag */
unsigned int os = read_byte();
(void)os;
/* Extra bytes */
if (flags & GZIP_FLAG_EXTR) {
unsigned short size = read_16le();
for (unsigned int i = 0; i < size; ++i) read_byte();
}
if (flags & GZIP_FLAG_NAME) {
unsigned int c;
while ((c = read_byte()) != 0);
}
if (flags & GZIP_FLAG_COMM) {
unsigned int c;
while ((c = read_byte()) != 0);
}
unsigned int crc16 = 0;
if (flags & GZIP_FLAG_HCRC) {
crc16 = read_16le();
}
(void)crc16;
int status = deflate_decompress();
/* Read CRC and decompressed size from end of input */
unsigned int crc32 = read_32le();
unsigned int dsize = read_32le();
(void)crc32;
(void)dsize;
return status;
}

View File

@ -1,5 +1,5 @@
static mboot_mod_t modules_mboot[sizeof(modules)/sizeof(*modules)] = {
static mboot_mod_t modules_mboot[1] = {
{0,0,0,1}
};
@ -9,7 +9,7 @@ static struct multiboot multiboot_header = {
/* mem_upper; */ 0x640000,
/* boot_device; */ 0,
/* cmdline; */ 0,
/* mods_count; */ sizeof(modules)/sizeof(*modules),
/* mods_count; */ 1,
/* mods_addr; */ 0,
/* num; */ 0,
/* size; */ 0,
@ -60,13 +60,7 @@ static int strlen(char * s) {
return out;
}
#ifdef EFI_PLATFORM
static EFI_GUID efi_graphics_output_protocol_guid =
{0x9042a9de,0x23dc,0x4a38, {0x96,0xfb,0x7a,0xde,0xd0,0x80,0x51,0x6a}};
#define KERNEL_LOAD_START 0x1600000
#else
#define KERNEL_LOAD_START 0x300000
#endif
static void move_kernel(void) {
clear();
@ -95,14 +89,6 @@ static void move_kernel(void) {
print(" ");
print_hex(phdr->p_filesz);
print("\n");
#ifdef EFI_PLATFORM
EFI_PHYSICAL_ADDRESS addr = phdr->p_vaddr;
EFI_STATUS status = uefi_call_wrapper(ST->BootServices->AllocatePages, 3, AllocateAddress, EfiLoaderData, phdr->p_memsz / 4096 + 1, &addr);
if (EFI_ERROR(status)) {
print_("Failed to allocate memory to load kernel.\n");
while (1) {};
}
#endif
memcpy((uint8_t*)(uintptr_t)phdr->p_vaddr, (uint8_t*)KERNEL_LOAD_START + phdr->p_offset, phdr->p_filesz);
long r = phdr->p_filesz;
while (r < phdr->p_memsz) {
@ -113,201 +99,6 @@ static void move_kernel(void) {
}
print("Setting up memory map...\n");
#ifdef EFI_PLATFORM
mboot_memmap_t * mmap = (void*)KERNEL_LOAD_START;
memset((void*)KERNEL_LOAD_START, 0x00, 1024);
multiboot_header.mmap_addr = (uint32_t)(uintptr_t)mmap;
EFI_STATUS e;
UINTN mapSize = 0, mapKey, descriptorSize;
UINT32 descriptorVersion;
e = uefi_call_wrapper(ST->BootServices->GetMemoryMap, 5, &mapSize, NULL, &mapKey, &descriptorSize, NULL);
print_("Memory map size is "); print_hex_(mapSize); print_("\n");
EFI_MEMORY_DESCRIPTOR * efi_memory = (void*)(final_offset);
final_offset += mapSize;
while ((uintptr_t)final_offset & 0x3ff) final_offset++;
e = uefi_call_wrapper(ST->BootServices->GetMemoryMap, 5, &mapSize, efi_memory, &mapKey, &descriptorSize, NULL);
if (EFI_ERROR(e)) {
print_("EFI error.\n");
while (1) {};
}
uint64_t upper_mem = 0;
int descriptors = mapSize / descriptorSize;
for (int i = 0; i < descriptors; ++i) {
EFI_MEMORY_DESCRIPTOR * d = efi_memory;
mmap->size = sizeof(uint64_t) * 2 + sizeof(uint32_t);
mmap->base_addr = d->PhysicalStart;
mmap->length = d->NumberOfPages * 4096;
switch (d->Type) {
case EfiConventionalMemory:
case EfiLoaderCode:
case EfiLoaderData:
case EfiBootServicesCode:
case EfiBootServicesData:
case EfiRuntimeServicesCode:
case EfiRuntimeServicesData:
case EfiACPIReclaimMemory:
mmap->type = 1;
break;
case EfiReservedMemoryType:
case EfiUnusableMemory:
case EfiMemoryMappedIO:
case EfiMemoryMappedIOPortSpace:
case EfiPalCode:
case EfiACPIMemoryNVS:
default:
mmap->type = 2;
break;
}
if (mmap->type == 1 && mmap->base_addr >= 0x100000) {
upper_mem += mmap->length;
}
mmap = (mboot_memmap_t *) ((uintptr_t)mmap + mmap->size + sizeof(uint32_t));
efi_memory = (EFI_MEMORY_DESCRIPTOR *)((char *)efi_memory + descriptorSize);
}
multiboot_header.mmap_length = (uintptr_t)mmap - multiboot_header.mmap_addr;
multiboot_header.mem_lower = 1024;
multiboot_header.mem_upper = upper_mem / 1024;
/* Set up framebuffer */
if (_efi_do_mode_set) {
UINTN count;
EFI_HANDLE * handles;
EFI_GRAPHICS_OUTPUT_PROTOCOL * gfx;
EFI_STATUS status;
status = uefi_call_wrapper(ST->BootServices->LocateHandleBuffer,
5, ByProtocol, &efi_graphics_output_protocol_guid, NULL, &count, &handles);
if (EFI_ERROR(status)) {
print_("Error getting graphics device handle.\n");
while (1) {};
}
status = uefi_call_wrapper(ST->BootServices->HandleProtocol,
3, handles[0], &efi_graphics_output_protocol_guid, (void **)&gfx);
if (EFI_ERROR(status)) {
print_("Error getting graphics device.\n");
while (1) {};
}
#if 0
print_("Attempting to set a sane mode (32bit color, etc.)\n");
print_("There are 0x"); print_hex_(gfx->Mode->MaxMode); print_(" modes available.\n");
print_("This is mode 0x"); print_hex_(gfx->Mode->Mode); print_(".\n");
#endif
int biggest = gfx->Mode->Mode;
int big_width = 0;
int big_height = 0;
clear_();
for (int i = 0; i < gfx->Mode->MaxMode; ++i) {
EFI_STATUS status;
UINTN size;
EFI_GRAPHICS_OUTPUT_MODE_INFORMATION * info;
status = uefi_call_wrapper(gfx->QueryMode,
4, gfx, i, &size, &info);
if (EFI_ERROR(status)) {
print_("Error getting gfx mode 0x"); print_hex_(i); print_("\n");
} else {
print_("Mode "); print_int_(i); print_(" "); print_int_(info->HorizontalResolution);
print_("x"); print_int_(info->VerticalResolution); print_(" ");
print_int_(info->PixelFormat); print_("\n");
if (_efi_do_mode_set == 1) {
if (info->PixelFormat == 1 && info->HorizontalResolution >= big_width) {
biggest = i;
big_width = info->HorizontalResolution;
}
} else if (_efi_do_mode_set == 2) {
if (info->PixelFormat == 1 && info->HorizontalResolution == 1024 &&
info->VerticalResolution == 768) {
biggest = i;
break;
}
} else if (_efi_do_mode_set == 3) {
if (info->PixelFormat == 1 && info->HorizontalResolution == 1920 &&
info->VerticalResolution == 1080) {
biggest = i;
break;
}
} else if (_efi_do_mode_set == 4) {
while (1) {
print_("y/n? ");
int resp = read_scancode();
if (resp == 'y') {
print_("y\n");
biggest = i;
goto done_video;
} else if (resp == 'n') {
print_("n\n");
break;
}
print_("?\n");
}
}
}
}
done_video:
print_("Selected video mode was "); print_int_(biggest); print_("\n");
uefi_call_wrapper(gfx->SetMode, 2, gfx, biggest);
uint32_t high = gfx->Mode->FrameBufferBase >> 32;
uint32_t low = gfx->Mode->FrameBufferBase & 0xFFFFFFFF;
print_("Framebuffer address is 0x"); print_hex_(high); print_hex_(low); print_("\n");
if (high) {
clear_();
print_("Framebuffer is outside of 32-bit memory range.\n");
print_("EFI mode setting is not available - and graphics may not work in general.\n");
while (1) {};
}
multiboot_header.flags |= (1 << 12); /* Enable framebuffer flag */
multiboot_header.framebuffer_addr = low;
multiboot_header.framebuffer_width = gfx->Mode->Info->HorizontalResolution;
multiboot_header.framebuffer_height = gfx->Mode->Info->VerticalResolution;
multiboot_header.framebuffer_pitch = gfx->Mode->Info->PixelsPerScanLine * 4;
print_("Mode information passed to multiboot:\n");
print_(" Address: 0x"); print_hex_(multiboot_header.framebuffer_addr); print_("\n");
print_(" Width: "); print_int_(multiboot_header.framebuffer_width); print_("\n");
print_(" Height: "); print_int_(multiboot_header.framebuffer_height); print_("\n");
print_("\n");
}
memcpy(final_offset, cmdline, strlen(cmdline)+1);
multiboot_header.cmdline = (uintptr_t)final_offset;
final_offset += strlen(cmdline)+1;
memcpy(final_offset, VERSION_TEXT, strlen(VERSION_TEXT)+1);
multiboot_header.boot_loader_name = (uintptr_t)final_offset;
final_offset += strlen(VERSION_TEXT)+1;
while ((uintptr_t)final_offset & 0x3ff) final_offset++;
multiboot_header.mods_addr = (uintptr_t)final_offset;
memcpy(final_offset, &modules_mboot, sizeof(modules_mboot));
final_offset += sizeof(modules_mboot);
while ((uintptr_t)final_offset & 0x3ff) final_offset++;
memcpy(final_offset, &multiboot_header, sizeof(multiboot_header));
_ebx = (uintptr_t)final_offset;
print("Jumping to main, good luck.\n");
#else
print_hex(mmap_ent);
print("\n");
memset((void*)KERNEL_LOAD_START, 0x00, 1024);
@ -346,53 +137,11 @@ done_video:
multiboot_header.mem_upper = upper_mem / 1024;
_ebx = (unsigned int)&multiboot_header;
#endif
_eax = MULTIBOOT_EAX_MAGIC;
_xmain = entry;
#ifdef EFI_PLATFORM
//print_("\nExiting boot services and jumping to ");
//print_hex_(_xmain);
//print_(" with mboot_mag=");
//print_hex_(_eax);
//print_(" and mboot_ptr=");
//print_hex_(_ebx);
//print_("...\n");
print_("Jumping...\n");
#if defined(__x86_64__)
//print_("&_xmain = "); print_hex_(((uintptr_t)&_xmain) >> 32); print_hex_((uint32_t)(uintptr_t)&_xmain); print_("\n");
#endif
if (1) {
EFI_STATUS e;
UINTN mapSize = 0, mapKey, descriptorSize;
UINT32 descriptorVersion;
uefi_call_wrapper(ST->BootServices->GetMemoryMap, 5, &mapSize, NULL, &mapKey, &descriptorSize, NULL);
e = uefi_call_wrapper(ST->BootServices->ExitBootServices, 2, ImageHandleIn, mapKey);
if (e != EFI_SUCCESS) {
print_("Exit services failed. \n");
print_hex_(e);
while (1) {};
}
}
#endif
#if defined(__x86_64__)
uint64_t foobar = ((uint32_t)(uintptr_t)&do_the_nasty) | (0x10L << 32L);
uint32_t * foo = (uint32_t *)0x7c00;
foo[0] = _eax;
foo[1] = _ebx;
foo[2] = _xmain;
__asm__ __volatile__ (
"push %0\n"
"retf\n"
: : "g"(foobar));
#else
uint32_t foo[3];
foo[0] = _eax;
foo[1] = _ebx;
@ -410,49 +159,8 @@ done_video:
"mov %2,%%ebx \n"
"jmp *%0" : : "g"(foo[2]), "g"(foo[0]), "g"(foo[1]) : "eax", "ebx"
);
#endif
}
#if defined(__x86_64__)
__asm__ (
"do_the_nasty:\n"
"cli\n"
//"mov 0x08, %ax\n"
//"mov %ax, %ds\n"
//"mov %ax, %es\n"
//"mov %ax, %fs\n"
//"mov %ax, %gs\n"
//"mov %ax, %ss\n"
".code32\n"
"mov %cr0, %eax\n"
"and $0x7FFeFFFF, %eax\n"
"mov %eax, %cr0\n"
// Paging is disabled
"mov $0xc0000080, %ecx\n"
"rdmsr\n"
"and $0xfffffeff, %eax\n"
"wrmsr\n"
"mov $0x640, %eax\n"
"mov %eax, %cr4\n"
"mov 0x7c00, %eax\n"
"mov 0x7c04, %ebx\n"
"mov 0x7c08, %ecx\n"
"jmp *%ecx\n"
"target: jmp target\n"
".code64\n"
);
#endif
__attribute__((always_inline))
static inline uint8_t read_byte(void) {
return *inputPtr++;
}
__attribute__((always_inline))
static inline void _write(unsigned int sym) {
*outputPtr++ = sym;
}
#ifndef EFI_PLATFORM
static void do_it(struct ata_device * _device) {
device = _device;
if (device->atapi_sector_size != 2048) {
@ -482,89 +190,45 @@ done:
print_hex(dir_entry->extent_length_LSB); print("\n");
long offset = 0;
for (int i = dir_entry->extent_start_LSB; i < dir_entry->extent_start_LSB + dir_entry->extent_length_LSB / 2048 + 1; ++i, offset += 2048) {
ata_device_read_sector_atapi(device, i, (uint8_t *)KERNEL_LOAD_START + offset);
}
while (offset % 4096) offset++;
restore_root();
if (navigate(module_dir)) {
memcpy(mod_dir, dir_entry, sizeof(iso_9660_directory_entry_t));
print("Scanning modules...\n");
char ** c = modules;
int j = 0;
while (*c) {
print("load "); print(*c); print("\n");
if (!navigate(*c)) {
print("Failed to locate module! [");
print(*c);
multiboot_header.mods_count--;
print("]\n");
} else {
modules_mboot[j].mod_start = KERNEL_LOAD_START + offset;
modules_mboot[j].mod_end = KERNEL_LOAD_START + offset + dir_entry->extent_length_LSB;
for (int i = dir_entry->extent_start_LSB; i < dir_entry->extent_start_LSB + dir_entry->extent_length_LSB / 2048 + 1; ++i, offset += 2048) {
ata_device_read_sector_atapi(device, i, (uint8_t *)KERNEL_LOAD_START + offset);
}
while (offset % 4096) offset++;
j++;
}
c++;
restore_mod();
}
print("Done.\n");
restore_root();
if (navigate(ramdisk_path)) {
//clear_();
ramdisk_off = KERNEL_LOAD_START + offset;
print_("Loading ramdisk");
int i = dir_entry->extent_start_LSB;
int sectors = dir_entry->extent_length_LSB / 2048 + 1;
size_t off = 0;
#define RAMDISK_OFFSET 0x5000000
print_("Loading ramdisk");
if (navigate(ramdisk_path)) {
ramdisk_off = KERNEL_LOAD_START + offset;
ramdisk_len = dir_entry->extent_length_LSB;
modules_mboot[0].mod_start = ramdisk_off;
modules_mboot[0].mod_end = ramdisk_off + ramdisk_len;
int i = dir_entry->extent_start_LSB;
int sectors = dir_entry->extent_length_LSB / 2048 + 1;
#define SECTORS 512
while (sectors >= SECTORS) {
print_(".");
ata_device_read_sectors_atapi(device, i, (uint8_t *)RAMDISK_OFFSET + off, SECTORS);
while (sectors >= SECTORS) {
print_(".");
ata_device_read_sectors_atapi(device, i, (uint8_t *)KERNEL_LOAD_START + offset, SECTORS);
sectors -= SECTORS;
off += 2048 * SECTORS;
i += SECTORS;
}
if (sectors > 0) {
print_("!");
ata_device_read_sectors_atapi(device, i, (uint8_t *)RAMDISK_OFFSET + off, sectors);
off += 2048 * sectors;
}
inputPtr = (uint8_t*)RAMDISK_OFFSET;
outputPtr = (uint8_t*)ramdisk_off;
print_("\nDecompressing ramdisk... ");
if (gzip_decompress()) {
print_("Failed?\n");
}
ramdisk_len = (uint32_t)outputPtr - ramdisk_off;
modules_mboot[multiboot_header.mods_count-1].mod_start = ramdisk_off;
modules_mboot[multiboot_header.mods_count-1].mod_end = ramdisk_off + ramdisk_len;
final_offset = (outputPtr) + ((uintptr_t)outputPtr) % 4096;
set_attr(0x07);
print("Done.\n");
move_kernel();
sectors -= SECTORS;
offset += 2048 * SECTORS;
i += SECTORS;
}
if (sectors > 0) {
print_("!");
ata_device_read_sectors_atapi(device, i, (uint8_t *)KERNEL_LOAD_START + offset, sectors);
offset += 2048 * sectors;
}
print_("\n");
final_offset = (uint8_t *)KERNEL_LOAD_START + offset;
set_attr(0x07);
move_kernel();
} else {
print("No mod directory?\n");
print_("... failed to locate ramdisk.\n");
}
} else {
print("boo\n");
print("... failed to locate kernel.\n");
}
return;
}
#endif
struct fw_cfg_file {
uint32_t size;
@ -602,11 +266,6 @@ void show_menu(void) {
bytes[i] = inportb(0x511);
}
swap_bytes(&count, 4);
#if 0
print_("there are ");
print_hex_(count);
print_(" entries\n");
#endif
unsigned int bootmode_size = 0;
int bootmode_index = -1;
@ -622,10 +281,6 @@ void show_menu(void) {
bootmode_size = file.size;
bootmode_index = file.select;
}
#if 0
print_("selector "); print_hex_(file.select); print_(" is "); print_hex_(file.size); print_(" bytes\n");
print_("and its name is: "); print_(file.name); print_("\n");
#endif
}
if (bootmode_index != -1) {
@ -647,7 +302,6 @@ void show_menu(void) {
}
#endif
/* Determine number of options */
sel_max = 0;
while (boot_options[sel_max].value) {
@ -655,7 +309,6 @@ void show_menu(void) {
}
sel_max += BASE_SEL + 1;
#ifndef EFI_PLATFORM
outportb(0x3D4, 14);
outportb(0x3D5, 0xFF);
outportb(0x3D4, 15);
@ -666,7 +319,6 @@ void show_menu(void) {
char b = inportb(0x3C1);
b &= ~8;
outportb(0x3c0, b);
#endif
clear_();
@ -753,232 +405,10 @@ void show_menu(void) {
boot_mode = boot_mode_names[i].index;
break;
}
#if 0
} else {
print_hex_(s);
#endif
}
} while (1);
}
#ifdef EFI_PLATFORM
/* EFI boot uses simple filesystem driver */
static EFI_GUID efi_simple_file_system_protocol_guid =
{0x0964e5b22,0x6459,0x11d2,0x8e,0x39,0x00,0xa0,0xc9,0x69,0x72,0x3b};
static EFI_GUID efi_loaded_image_protocol_guid =
{0x5B1B31A1,0x9562,0x11d2, {0x8E,0x3F,0x00,0xA0,0xC9,0x69,0x72,0x3B}};
static char space[4096];
static void boot(void) {
UINTN count;
EFI_HANDLE * handles;
EFI_LOADED_IMAGE * loaded_image;
EFI_FILE_IO_INTERFACE *efi_simple_filesystem;
EFI_FILE *root;
EFI_STATUS status;
uefi_call_wrapper(ST->BootServices->SetWatchdogTimer, 4, 0, 0, 0, NULL);
clear_();
status = uefi_call_wrapper(ST->BootServices->HandleProtocol,
3, ImageHandleIn, &efi_loaded_image_protocol_guid,
(void **)&loaded_image);
if (EFI_ERROR(status)) {
print_("Could not obtain loaded_image_protocol\n");
while (1) {};
}
print("Found loaded image...\n");
status = uefi_call_wrapper(ST->BootServices->HandleProtocol,
3, loaded_image->DeviceHandle, &efi_simple_file_system_protocol_guid,
(void **)&efi_simple_filesystem);
if (EFI_ERROR(status)) {
print_("Could not obtain simple_file_system_protocol.\n");
while (1) {};
}
status = uefi_call_wrapper(efi_simple_filesystem->OpenVolume,
2, efi_simple_filesystem, &root);
if (EFI_ERROR(status)) {
print_("Could not open volume.\n");
while (1) {};
}
EFI_FILE * file;
CHAR16 kernel_name[16] = {0};
{
char * c = kernel_path;
char * ascii = c;
int i = 0;
while (*ascii) {
kernel_name[i] = *ascii;
i++;
ascii++;
}
if (kernel_name[i-1] == L'.') {
kernel_name[i-1] = 0;
}
}
/* Load kernel */
status = uefi_call_wrapper(root->Open,
5, root, &file, kernel_name, EFI_FILE_MODE_READ, 0);
if (EFI_ERROR(status)) {
print_("Error opening kernel.\n");
while (1) {};
}
{
EFI_PHYSICAL_ADDRESS addr = KERNEL_LOAD_START;
EFI_ALLOCATE_TYPE type = AllocateAddress;
EFI_MEMORY_TYPE memtype = EfiLoaderData;
UINTN pages = 8192;
EFI_STATUS status = 0;
status = uefi_call_wrapper(ST->BootServices->AllocatePages, 4, type, memtype, pages, &addr);
if (EFI_ERROR(status)) {
print_("Could not allocate space to load boot payloads: ");
print_hex_(status);
print_(" ");
print_hex_(addr);
while (1) {};
}
}
unsigned int offset = 0;
UINTN bytes = 134217728;
status = uefi_call_wrapper(file->Read,
3, file, &bytes, (void *)KERNEL_LOAD_START);
if (EFI_ERROR(status)) {
print_("Error loading kernel.\n");
while (1) {};
}
print("Read "); print_hex(bytes); print(" bytes\n");
offset += bytes;
while (offset % 4096) offset++;
print("Reading modules...\n");
char ** c = modules;
int j = 0;
while (*c) {
if (strcmp(*c, "NONE")) {
/* Try to load module */
CHAR16 name[16] = {0};
name[0] = L'm';
name[1] = L'o';
name[2] = L'd';
name[3] = L'\\';
char * ascii = *c;
int i = 0;
while (*ascii) {
name[i+4] = (*ascii >= 'A' && *ascii <= 'Z') ? (*ascii - 'A' + 'a') : *ascii;
name[i+5] = 0;
i++;
ascii++;
}
for (int i = 0; name[i]; ++i) {
char c[] = {name[i], 0};
print(c);
}
print("\n");
bytes = 2097152;
_try_module_again:
status = uefi_call_wrapper(root->Open,
5, root, &file, name, EFI_FILE_MODE_READ, 0);
if (!EFI_ERROR(status)) {
status = uefi_call_wrapper(file->Read,
3, file, &bytes, (void *)(KERNEL_LOAD_START + (uintptr_t)offset));
if (!EFI_ERROR(status)) {
print("Loaded "); print(*c); print("\n");
modules_mboot[j].mod_start = KERNEL_LOAD_START + offset;
modules_mboot[j].mod_end = KERNEL_LOAD_START + offset + bytes;
j++;
offset += bytes;
while (offset % 4096) offset++;
}
} else {
print_("Error opening "); print_(*c); print_(" "); print_hex_(status); print_("\n");
while (1) { };
}
} else {
multiboot_header.mods_count--;
}
c++;
}
print_("Loading ramdisk...\n");
{
char * c = ramdisk_path;
CHAR16 name[16] = {0};
char * ascii = c;
int i = 0;
while (*ascii) {
name[i] = *ascii;
i++;
ascii++;
}
if (name[i-1] == L'.') {
name[i-1] == 0;
}
bytes = 134217728;
status = uefi_call_wrapper(root->Open,
5, root, &file, name, EFI_FILE_MODE_READ, 0);
if (!EFI_ERROR(status)) {
uintptr_t RAMDISK_OFFSET;
{
EFI_PHYSICAL_ADDRESS addr;
EFI_STATUS status = uefi_call_wrapper(ST->BootServices->AllocatePages, 4, AllocateAnyPages, EfiLoaderData, 4096, &addr);
if (EFI_ERROR(status)) {
print_("Failed to allocate space for ramdisk.\n");
while (1) {};
}
print_("Placing ramdisk at ");
print_hex_(addr >> 32);
print_hex_(addr & 0xFFFFFFFF);
print_("\n");
RAMDISK_OFFSET = addr;
}
status = uefi_call_wrapper(file->Read,
3, file, &bytes, (void*)RAMDISK_OFFSET);
if (!EFI_ERROR(status)) {
print_("Read "); print_hex_(bytes); print_(" bytes.\n");
inputPtr = (uint8_t*)RAMDISK_OFFSET;
outputPtr = (uint8_t*)KERNEL_LOAD_START + offset;
print_("Decompressing ramdisk... ");
if (gzip_decompress()) {
print_("Failed?\n");
}
print_("Loaded "); print_(c); print_("\n");
modules_mboot[multiboot_header.mods_count-1].mod_start = KERNEL_LOAD_START + offset;
modules_mboot[multiboot_header.mods_count-1].mod_end = (uintptr_t)outputPtr;
final_offset = (uint8_t *)outputPtr;
while ((uintptr_t)final_offset & 0xfff) final_offset++;
} else {
print_("Failed to read ramdisk\n");
}
} else {
print_("Error opening "); print_(c); print_("\n");
}
}
move_kernel();
}
#else
/* BIOS boot uses native ATAPI drivers, need to find boot drive. */
static void boot(void) {
@ -1009,4 +439,3 @@ static void boot(void) {
while (1);
}
#endif

View File

@ -14,6 +14,7 @@
#define MULTIBOOT_FLAG_LOADER 0x200
#define MULTIBOOT_FLAG_APM 0x400
#define MULTIBOOT_FLAG_VBE 0x800
#define MULTIBOOT_FLAG_FB 0x1000
struct multiboot
{
@ -37,17 +38,16 @@ struct multiboot
uint32_t apm_table;
uint32_t vbe_control_info;
uint32_t vbe_mode_info;
uint32_t vbe_mode;
uint32_t vbe_interface_seg;
uint32_t vbe_interface_off;
uint32_t vbe_interface_len;
uint32_t framebuffer_addr;
uint16_t vbe_mode;
uint16_t vbe_interface_seg;
uint16_t vbe_interface_off;
uint16_t vbe_interface_len;
uint64_t framebuffer_addr;
uint32_t framebuffer_pitch;
uint32_t framebuffer_width;
uint32_t framebuffer_height;
uint8_t framebuffer_bpp;
uint8_t framebuffer_type;
/* Palette stuff goes here but we don't use it */
uint8_t framebuffer_bpp;
uint8_t framebuffer_type;
} __attribute__ ((packed));
typedef struct {

54
util/mkdisk.sh Executable file
View File

@ -0,0 +1,54 @@
#!/bin/bash
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
OUT=$1
IN=$2
OUTDIR=`dirname $1`
# Calculate required space
SPACE_REQ=$(du -sb "$DIR/../fatbase" | cut -f 1)
let "SIZE = ($SPACE_REQ / 1000000)"
# Minimum size
if [ $SIZE -lt 14 ]; then
SIZE=14
fi
# Use more sectors-per-cluster for larger disk sizes
if [ $SIZE -gt 128 ]; then
SPC=4
else
SPC=1
fi
# Create empty FAT image
rm -f $OUT
mkdir -p cdrom
fallocate -l ${SIZE}M $OUT || dd if=/dev/zero bs=1M count=${SIZE} of=$OUT
mkfs.fat -s $SPC -S 2048 $OUT
#echo "Turning $IN into $OUT"
# Add files
for i in $(find $IN)
do
if [[ $i == $IN ]]; then
continue
fi
OUT_FILE=`echo $i | sed s"/^$IN/$OUTDIR/"`
IN_FILE=`echo $i | sed s"/^$IN//"`
#echo $IN_FILE $OUT_FILE
if [ -d "$i" ]; then
mmd -i $OUT $IN_FILE
mkdir -p $OUT_FILE
else
mcopy -i $OUT $i '::'$IN_FILE
touch $OUT_FILE
fi
done
rm -f cdrom/efi/boot/bootia32.efi # Otherwise virtualbox may erroneously try to load from this
rm -f cdrom/efi/boot/bootx64.efi # Same

303
util/update-extents.py Executable file
View File

@ -0,0 +1,303 @@
#!/usr/bin/env python3
import array
import struct
def read_struct(fmt,buf,offset):
out, = struct.unpack_from(fmt,buf,offset)
return out, offset + struct.calcsize(fmt)
class ISO(object):
def __init__(self, path):
with open(path, 'rb') as f:
tmp = f.read()
self.data = array.array('b', tmp)
self.sector_size = 2048
o = 0x10 * self.sector_size
self.type, o = read_struct('B',self.data,o)
self.id, o = read_struct('5s',self.data,o)
self.version, o = read_struct('B',self.data,o)
_unused0, o = read_struct('B',self.data,o)
self.system_id, o = read_struct('32s',self.data,o)
self.volume_id, o = read_struct('32s',self.data,o)
_unused1, o = read_struct('8s',self.data,o)
self.volume_space_lsb, o = read_struct('<I',self.data,o)
self.volume_space_msb, o = read_struct('>I',self.data,o)
_unused2, o = read_struct('32s',self.data,o)
self.volume_set_lsb, o = read_struct('<H',self.data,o)
self.volume_set_msb, o = read_struct('>H',self.data,o)
self.volume_seq_lsb, o = read_struct('<H',self.data,o)
self.volume_seq_msb, o = read_struct('>H',self.data,o)
self.logical_block_size_lsb, o = read_struct('<H',self.data,o)
self.logical_block_size_msb, o = read_struct('>H',self.data,o)
self.path_table_size_lsb, o = read_struct('<I',self.data,o)
self.path_table_size_msb, o = read_struct('>I',self.data,o)
self.path_table_lsb, o = read_struct('<I',self.data,o)
self.optional_path_table_lsb, o = read_struct('<I',self.data,o)
self.path_table_msb, o = read_struct('>I',self.data,o)
self.optional_path_table_msb, o = read_struct('>I',self.data,o)
_offset = o
self.root_dir_entry, o = read_struct('34s',self.data,o)
self.root = ISOFile(self,_offset)
self._cache = {}
def get_file(self, path):
if path == '/':
return self.root
else:
if path in self._cache:
return self._cache[path]
units = path.split('/')
units = units[1:] # remove root
me = self.root
for i in units:
next_file = me.find(i)
if not next_file:
me = None
break
else:
me = next_file
self._cache[path] = me
return me
class ISOFile(object):
def __init__(self, iso, offset):
self.iso = iso
self.offset = offset
o = offset
self.length, o = read_struct('B', self.iso.data, o)
if not self.length:
return
self.ext_length, o = read_struct('B', self.iso.data, o)
self.extent_start_lsb, o = read_struct('<I',self.iso.data, o)
self.extent_start_msb, o = read_struct('>I',self.iso.data, o)
self.extent_length_lsb, o = read_struct('<I',self.iso.data, o)
self.extent_length_msb, o = read_struct('>I',self.iso.data, o)
self.date_data, o = read_struct('7s', self.iso.data, o)
self.flags, o = read_struct('b', self.iso.data, o)
self.interleave_units, o = read_struct('b', self.iso.data, o)
self.interleave_gap, o = read_struct('b', self.iso.data, o)
self.volume_seq_lsb, o = read_struct('<H',self.iso.data, o)
self.volume_seq_msb, o = read_struct('>H',self.iso.data, o)
self.name_len, o = read_struct('b', self.iso.data, o)
self.name, o = read_struct('{}s'.format(self.name_len), self.iso.data, o)
self.name = self.name.decode('ascii')
def write_extents(self):
struct.pack_into('<I', self.iso.data, self.offset + 2, self.extent_start_lsb)
struct.pack_into('>I', self.iso.data, self.offset + 6, self.extent_start_lsb)
struct.pack_into('<I', self.iso.data, self.offset + 10, self.extent_length_lsb)
struct.pack_into('>I', self.iso.data, self.offset + 14, self.extent_length_lsb)
def readable_name(self):
if not ';' in self.name:
return self.name.lower()
else:
tmp, _ = self.name.split(';')
return tmp.lower()
def list(self):
sectors = self.iso.data[self.extent_start_lsb * self.iso.sector_size: self.extent_start_lsb * self.iso.sector_size+ 3 * self.iso.sector_size]
offset = 0
while 1:
f = ISOFile(self.iso, self.extent_start_lsb * self.iso.sector_size + offset)
yield f
offset += f.length
if not f.length:
break
def find(self, name):
sectors = self.iso.data[self.extent_start_lsb * self.iso.sector_size: self.extent_start_lsb * self.iso.sector_size+ 3 * self.iso.sector_size]
offset = 0
if '.' in name and len(name.split('.')[0]) > 8:
a, b = name.split('.')
name = a[:8] + '.' + b
if '-' in name:
name = name.replace('-','_')
while 1:
f = ISOFile(self.iso, self.extent_start_lsb * self.iso.sector_size + offset)
if not f.length:
if offset < self.extent_length_lsb:
offset += 1
continue
else:
break
if ';' in f.name:
tmp, _ = f.name.split(';')
if tmp.endswith('.'):
tmp = tmp[:-1]
if tmp.lower() == name.lower():
return f
elif f.name.lower() == name.lower():
return f
offset += f.length
return None
class FAT(object):
def __init__(self, iso, offset):
self.iso = iso
self.offset = offset
self.bytespersector, _ = read_struct('H', self.iso.data, offset + 11)
self.sectorspercluster, _ = read_struct('B', self.iso.data, offset + 13)
self.reservedsectors, _ = read_struct('H', self.iso.data, offset + 14)
self.numberoffats, _ = read_struct('B', self.iso.data, offset + 16)
self.numberofdirs, _ = read_struct('H', self.iso.data, offset + 17)
self.fatsize, _ = read_struct('H', self.iso.data, offset + 22)
self.root_dir_sectors = (self.numberofdirs * 32 + (self.bytespersector - 1)) // self.bytespersector
self.first_data_sector = self.reservedsectors + (self.numberoffats * self.fatsize) + self.root_dir_sectors
self.root_sector= self.first_data_sector - self.root_dir_sectors
self.root = FATDirectory(self, self.offset + self.root_sector * self.bytespersector)
def get_offset(self, cluster):
return self.offset + ((cluster - 2) * self.sectorspercluster + self.first_data_sector) * self.bytespersector
def get_file(self, path):
units = path.split('/')
units = units[1:]
me = self.root
out = None
for i in units:
for fatfile in me.list():
if fatfile.readable_name() == i:
me = fatfile.to_dir()
out = fatfile
break
else:
return None
return out
class FATDirectory(object):
def __init__(self, fat, offset):
self.fat = fat
self.offset = offset
def list(self):
o = self.offset
while 1:
out = FATFile(self.fat, o)
if out.name != '\0\0\0\0\0\0\0\0':
yield out
else:
break
o += out.size
class FATFile(object):
def __init__(self, fat, offset):
self.fat = fat
self.offset = offset
self.magic_long = None
self.size = 0
self.long_name = ''
o = self.offset
self.actual_offset = o
self.attrib, _ = read_struct('B',self.fat.iso.data,o+11)
while (self.attrib & 0x0F) == 0x0F:
# Long file name entry
tmp = read_struct('10s',self.fat.iso.data,o+1)[0]
tmp += read_struct('12s',self.fat.iso.data,o+14)[0]
tmp += read_struct('4s',self.fat.iso.data,o+28)[0]
tmp = "".join([chr(x) for x in tmp[::2] if x != '\xFF']).strip('\x00')
self.long_name = tmp + self.long_name
self.size += 32
o = self.offset + self.size
self.actual_offset = o
self.attrib, _ = read_struct('B',self.fat.iso.data,o+11)
o = self.offset + self.size
self.name, o = read_struct('8s',self.fat.iso.data,o)
self.ext, o = read_struct('3s',self.fat.iso.data,o)
self.attrib, o = read_struct('B',self.fat.iso.data,o)
self.userattrib, o = read_struct('B',self.fat.iso.data,o)
self.undelete, o = read_struct('b',self.fat.iso.data,o)
self.createtime, o = read_struct('H',self.fat.iso.data,o)
self.createdate, o = read_struct('H',self.fat.iso.data,o)
self.accessdate, o = read_struct('H',self.fat.iso.data,o)
self.clusterhi, o = read_struct('H',self.fat.iso.data,o)
self.modifiedti, o = read_struct('H',self.fat.iso.data,o)
self.modifiedda, o = read_struct('H',self.fat.iso.data,o)
self.clusterlow, o = read_struct('H',self.fat.iso.data,o)
self.filesize, o = read_struct('I',self.fat.iso.data,o)
self.name = self.name.decode('ascii')
self.ext = self.ext.decode('ascii')
self.size += 32
self.cluster = (self.clusterhi << 16) + self.clusterlow
def is_dir(self):
return bool(self.attrib & 0x10)
def is_long(self):
return bool((self.attrib & 0x0F) == 0x0F)
def to_dir(self):
return FATDirectory(self.fat, self.fat.get_offset(self.cluster))
def get_offset(self):
return self.fat.get_offset(self.cluster)
def readable_name(self):
if self.long_name:
return self.long_name
if self.ext.strip():
return (self.name.strip() + '.' + self.ext.strip()).lower()
else:
return self.name.strip().lower()
image = ISO('image.iso')
fat = image.root.find('FAT.IMG')
fatfs = FAT(image, fat.extent_start_lsb * image.sector_size)
def process(fatfile, path):
if fatfile.is_long():
return
if fatfile.readable_name() == '.':
return
if fatfile.readable_name() == '..':
return
if fatfile.is_dir():
for i in fatfile.to_dir().list():
process(i, path + fatfile.readable_name() + '/')
else:
cdfile = image.get_file(path + fatfile.readable_name())
if not cdfile:
if fatfile.readable_name() != 'bootia32.efi' and fatfile.readable_name() != 'bootx64.efi':
print("Warning:", fatfile.readable_name(), "not found in ISO")
else:
cdfile.extent_start_lsb = fatfile.get_offset() // 2048
cdfile.extent_length_lsb = fatfile.filesize
cdfile.write_extents()
for i in fatfs.root.list():
process(i,'/')
with open('image.iso','wb') as f:
f.write(image.data)