Set up a new repo based on BOOTBOOT sources
This commit is contained in:
commit
5d58b46bbe
13 changed files with 3797 additions and 0 deletions
155
include/bootboot.h
Normal file
155
include/bootboot.h
Normal file
|
|
@ -0,0 +1,155 @@
|
||||||
|
/*
|
||||||
|
* bootboot.h
|
||||||
|
* https://gitlab.com/bztsrc/bootboot
|
||||||
|
*
|
||||||
|
* Copyright (C) 2017 - 2021 bzt (bztsrc@gitlab)
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person
|
||||||
|
* obtaining a copy of this software and associated documentation
|
||||||
|
* files (the "Software"), to deal in the Software without
|
||||||
|
* restriction, including without limitation the rights to use, copy,
|
||||||
|
* modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||||
|
* of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be
|
||||||
|
* included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||||
|
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||||
|
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
* DEALINGS IN THE SOFTWARE.
|
||||||
|
*
|
||||||
|
* This file is part of the BOOTBOOT Protocol package.
|
||||||
|
* @brief The BOOTBOOT structure
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _BOOTBOOT_H_
|
||||||
|
#define _BOOTBOOT_H_
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
#ifndef _MSC_VER
|
||||||
|
#define _pack __attribute__((packed))
|
||||||
|
#else
|
||||||
|
#define _pack
|
||||||
|
#pragma pack(push)
|
||||||
|
#pragma pack(1)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define BOOTBOOT_MAGIC "BOOT"
|
||||||
|
|
||||||
|
/* default virtual addresses for level 0 and 1 static loaders */
|
||||||
|
#define BOOTBOOT_MMIO 0xfffffffff8000000 /* memory mapped IO virtual address */
|
||||||
|
#define BOOTBOOT_FB 0xfffffffffc000000 /* frame buffer virtual address */
|
||||||
|
#define BOOTBOOT_INFO 0xffffffffffe00000 /* bootboot struct virtual address */
|
||||||
|
#define BOOTBOOT_ENV 0xffffffffffe01000 /* environment string virtual address */
|
||||||
|
#define BOOTBOOT_CORE 0xffffffffffe02000 /* core loadable segment start */
|
||||||
|
|
||||||
|
/* minimum protocol level:
|
||||||
|
* hardcoded kernel name, static kernel memory addresses */
|
||||||
|
#define PROTOCOL_MINIMAL 0
|
||||||
|
/* static protocol level:
|
||||||
|
* kernel name parsed from environment, static kernel memory addresses */
|
||||||
|
#define PROTOCOL_STATIC 1
|
||||||
|
/* dynamic protocol level:
|
||||||
|
* kernel name parsed, kernel memory addresses from ELF or PE symbols */
|
||||||
|
#define PROTOCOL_DYNAMIC 2
|
||||||
|
/* big-endian flag */
|
||||||
|
#define PROTOCOL_BIGENDIAN 0x80
|
||||||
|
|
||||||
|
/* loader types, just informational */
|
||||||
|
#define LOADER_BIOS (0<<2)
|
||||||
|
#define LOADER_UEFI (1<<2)
|
||||||
|
#define LOADER_RPI (2<<2)
|
||||||
|
#define LOADER_COREBOOT (3<<2)
|
||||||
|
|
||||||
|
/* framebuffer pixel format, only 32 bits supported */
|
||||||
|
#define FB_ARGB 0
|
||||||
|
#define FB_RGBA 1
|
||||||
|
#define FB_ABGR 2
|
||||||
|
#define FB_BGRA 3
|
||||||
|
|
||||||
|
/* mmap entry, type is stored in least significant tetrad (half byte) of size
|
||||||
|
* this means size described in 16 byte units (not a problem, most modern
|
||||||
|
* firmware report memory in pages, 4096 byte units anyway). */
|
||||||
|
typedef struct {
|
||||||
|
uint64_t ptr;
|
||||||
|
uint64_t size;
|
||||||
|
} _pack MMapEnt;
|
||||||
|
#define MMapEnt_Ptr(a) ((a)->ptr)
|
||||||
|
#define MMapEnt_Size(a) ((a)->size & 0xFFFFFFFFFFFFFFF0)
|
||||||
|
#define MMapEnt_Type(a) ((a)->size & 0xF)
|
||||||
|
#define MMapEnt_IsFree(a) (((a)->size&0xF)==1)
|
||||||
|
|
||||||
|
#define MMAP_USED 0 /* don't use. Reserved or unknown regions */
|
||||||
|
#define MMAP_FREE 1 /* usable memory */
|
||||||
|
#define MMAP_ACPI 2 /* acpi memory, volatile and non-volatile as well */
|
||||||
|
#define MMAP_MMIO 3 /* memory mapped IO region */
|
||||||
|
|
||||||
|
#define INITRD_MAXSIZE 16 /* Mb */
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
/* first 64 bytes is platform independent */
|
||||||
|
uint8_t magic[4]; /* 'BOOT' magic */
|
||||||
|
uint32_t size; /* length of bootboot structure, minimum 128 */
|
||||||
|
uint8_t protocol; /* 1, static addresses, see PROTOCOL_* and LOADER_* above */
|
||||||
|
uint8_t fb_type; /* framebuffer type, see FB_* above */
|
||||||
|
uint16_t numcores; /* number of processor cores */
|
||||||
|
uint16_t bspid; /* Bootsrap processor ID (Local APIC Id on x86_64) */
|
||||||
|
int16_t timezone; /* in minutes -1440..1440 */
|
||||||
|
uint8_t datetime[8]; /* in BCD yyyymmddhhiiss UTC (independent to timezone) */
|
||||||
|
uint64_t initrd_ptr; /* ramdisk image position and size */
|
||||||
|
uint64_t initrd_size;
|
||||||
|
uint64_t fb_ptr; /* framebuffer pointer and dimensions */
|
||||||
|
uint32_t fb_size;
|
||||||
|
uint32_t fb_width;
|
||||||
|
uint32_t fb_height;
|
||||||
|
uint32_t fb_scanline;
|
||||||
|
|
||||||
|
/* the rest (64 bytes) is platform specific */
|
||||||
|
union {
|
||||||
|
struct {
|
||||||
|
uint64_t acpi_ptr;
|
||||||
|
uint64_t smbi_ptr;
|
||||||
|
uint64_t efi_ptr;
|
||||||
|
uint64_t mp_ptr;
|
||||||
|
uint64_t unused0;
|
||||||
|
uint64_t unused1;
|
||||||
|
uint64_t unused2;
|
||||||
|
uint64_t unused3;
|
||||||
|
} x86_64;
|
||||||
|
struct {
|
||||||
|
uint64_t acpi_ptr;
|
||||||
|
uint64_t mmio_ptr;
|
||||||
|
uint64_t efi_ptr;
|
||||||
|
uint64_t unused0;
|
||||||
|
uint64_t unused1;
|
||||||
|
uint64_t unused2;
|
||||||
|
uint64_t unused3;
|
||||||
|
uint64_t unused4;
|
||||||
|
} aarch64;
|
||||||
|
} arch;
|
||||||
|
|
||||||
|
/* from 128th byte, MMapEnt[], more records may follow */
|
||||||
|
MMapEnt mmap;
|
||||||
|
/* use like this:
|
||||||
|
* MMapEnt *mmap_ent = &bootboot.mmap; mmap_ent++;
|
||||||
|
* until you reach bootboot->size, while(mmap_ent < bootboot + bootboot->size) */
|
||||||
|
} _pack BOOTBOOT;
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#pragma pack(pop)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
2
x86_64-efi/.gitignore
vendored
Normal file
2
x86_64-efi/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
*.o
|
||||||
|
!crt0-efi-x86_64.o
|
||||||
35
x86_64-efi/Makefile
Normal file
35
x86_64-efi/Makefile
Normal file
|
|
@ -0,0 +1,35 @@
|
||||||
|
ARCH = $(shell uname -m | sed s,i[3456789]86,ia32,)
|
||||||
|
GNUEFI_INCLUDES = -I/usr/include -I. -I/usr/include/efi -I/usr/include/efi/$(ARCH) -I/usr/include/efi/protocol -I../include
|
||||||
|
GNUEFI_CRT_OBJS = crt0-efi-$(ARCH).o
|
||||||
|
GNUEFI_LDS = elf_$(ARCH)_efi.lds
|
||||||
|
|
||||||
|
CC ?= gcc
|
||||||
|
LD ?= ld
|
||||||
|
OBJCOPY ?= objcopy
|
||||||
|
CFLAGS = -mno-red-zone -mno-mmx -mno-sse -O2 -fpic -pedantic -Wall -Wextra -Werror -fshort-wchar -fno-strict-aliasing -ffreestanding -fno-stack-protector -fno-stack-check -DCONFIG_$(ARCH) -DGNU_EFI_USE_MS_ABI --std=c11
|
||||||
|
|
||||||
|
LDFLAGS = -nostdlib
|
||||||
|
LDFLAGS += -shared -Bsymbolic -L. $(GNUEFI_CRT_OBJS)
|
||||||
|
|
||||||
|
TARGET = bootnetboot.efi
|
||||||
|
|
||||||
|
all: tinflate.o smp.o $(TARGET)
|
||||||
|
|
||||||
|
%.efi: %.so
|
||||||
|
@$(OBJCOPY) -j .text -j .sdata -j .data -j .dynamic -j .dynsym -j .rel -j .rela -j .rel.* -j .rela.* -j .reloc --target efi-app-$(ARCH) --subsystem=10 $^ $@
|
||||||
|
@printf "BOOTBOOT Loader do not " | dd conv=notrunc of=$(TARGET) bs=1 seek=78 1>/dev/null 2>/dev/null
|
||||||
|
@$(CC) $(GNUEFI_INCLUDES) -Wall -fshort-wchar efirom.c -o efirom $(LIBS)
|
||||||
|
@./efirom $(TARGET) bootnetboot.rom || true
|
||||||
|
|
||||||
|
%.so: %.o
|
||||||
|
@$(LD) $(LDFLAGS) tinflate.o smp.o $^ -o $@ -lefi -lgnuefi -T $(GNUEFI_LDS)
|
||||||
|
|
||||||
|
%.o: %.c
|
||||||
|
@$(CC) $(GNUEFI_INCLUDES) $(CFLAGS) -c $< -o $@
|
||||||
|
|
||||||
|
%.o: %.S
|
||||||
|
@$(CC) $(GNUEFI_INCLUDES) $(CFLAGS) -c $< -o $@
|
||||||
|
|
||||||
|
clean:
|
||||||
|
@rm bootboot.o $(TARGET) $(TARGET) bootnetboot.rom *.so *.efi efirom tinflate.o smp.o 2>/dev/null || true
|
||||||
|
|
||||||
2193
x86_64-efi/bootnetboot.c
Normal file
2193
x86_64-efi/bootnetboot.c
Normal file
File diff suppressed because it is too large
Load diff
BIN
x86_64-efi/crt0-efi-x86_64.o
Normal file
BIN
x86_64-efi/crt0-efi-x86_64.o
Normal file
Binary file not shown.
278
x86_64-efi/efirom.c
Normal file
278
x86_64-efi/efirom.c
Normal file
|
|
@ -0,0 +1,278 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2009 Michael Brown <mbrown@fensystems.co.uk>.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License as
|
||||||
|
* published by the Free Software Foundation; either version 2 of the
|
||||||
|
* License, or any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*
|
||||||
|
* modifications for gnuefi by bzt (bztsrc@gitlab)
|
||||||
|
*/
|
||||||
|
|
||||||
|
//#include <stdint.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <getopt.h>
|
||||||
|
#include <efi.h>
|
||||||
|
#include <efilink.h>
|
||||||
|
#include <pe.h>
|
||||||
|
#include <pci22.h>
|
||||||
|
|
||||||
|
#define eprintf(...) fprintf ( stderr, __VA_ARGS__ )
|
||||||
|
|
||||||
|
/** Command-line options */
|
||||||
|
struct options {
|
||||||
|
uint16_t vendor;
|
||||||
|
uint16_t device;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allocate memory
|
||||||
|
*
|
||||||
|
* @v len Length of memory to allocate
|
||||||
|
* @ret ptr Pointer to allocated memory
|
||||||
|
*/
|
||||||
|
static void * xmalloc ( size_t len ) {
|
||||||
|
void *ptr;
|
||||||
|
|
||||||
|
ptr = malloc ( len );
|
||||||
|
if ( ! ptr ) {
|
||||||
|
eprintf ( "Could not allocate %zd bytes\n", len );
|
||||||
|
exit ( 1 );
|
||||||
|
}
|
||||||
|
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get file size
|
||||||
|
*
|
||||||
|
* @v file File
|
||||||
|
* @v len File size
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
static size_t file_size ( FILE *file ) {
|
||||||
|
ssize_t len;
|
||||||
|
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* Read information from PE headers
|
||||||
|
*
|
||||||
|
* @v pe PE file
|
||||||
|
* @ret machine Machine type
|
||||||
|
* @ret subsystem EFI subsystem
|
||||||
|
*/
|
||||||
|
static void read_pe_info ( void *pe, uint16_t *machine,
|
||||||
|
uint16_t *subsystem ) {
|
||||||
|
IMAGE_DOS_HEADER *dos;
|
||||||
|
union {
|
||||||
|
IMAGE_NT_HEADERS nt64;
|
||||||
|
} *nt;
|
||||||
|
|
||||||
|
/* Locate NT header */
|
||||||
|
dos = pe;
|
||||||
|
nt = ( pe + dos->e_lfanew );
|
||||||
|
|
||||||
|
/* issue 4: TianoCore demands subsystem 10, so we must use EFI_APPLICATION
|
||||||
|
* in the PE header. Therefore we force EFI_ROM subsystem in this code here. */
|
||||||
|
if(nt->nt64.OptionalHeader.Subsystem == 10)
|
||||||
|
nt->nt64.OptionalHeader.Subsystem = 13;
|
||||||
|
|
||||||
|
/* Parse out PE information */
|
||||||
|
*machine = nt->nt64.FileHeader.Machine;
|
||||||
|
*subsystem = nt->nt64.OptionalHeader.Subsystem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert EFI image to ROM image
|
||||||
|
*
|
||||||
|
* @v pe EFI file
|
||||||
|
* @v rom ROM file
|
||||||
|
*/
|
||||||
|
static void make_efi_rom ( FILE *pe, FILE *rom, struct options *opts ) {
|
||||||
|
struct {
|
||||||
|
EFI_PCI_EXPANSION_ROM_HEADER rom;
|
||||||
|
PCI_DATA_STRUCTURE pci __attribute__ (( aligned ( 4 ) ));
|
||||||
|
uint8_t checksum;
|
||||||
|
} *headers;
|
||||||
|
struct stat pe_stat;
|
||||||
|
size_t pe_size;
|
||||||
|
size_t rom_size;
|
||||||
|
void *buf;
|
||||||
|
void *payload;
|
||||||
|
unsigned int i;
|
||||||
|
uint8_t checksum;
|
||||||
|
|
||||||
|
/* Determine PE file size */
|
||||||
|
if ( fstat ( fileno ( pe ), &pe_stat ) != 0 ) {
|
||||||
|
eprintf ( "Could not stat PE file: %s\n",
|
||||||
|
strerror ( errno ) );
|
||||||
|
exit ( 1 );
|
||||||
|
}
|
||||||
|
pe_size = pe_stat.st_size;
|
||||||
|
|
||||||
|
/* Determine ROM file size */
|
||||||
|
rom_size = ( ( pe_size + sizeof ( *headers ) + 511 ) & ~511 );
|
||||||
|
|
||||||
|
/* Allocate ROM buffer and read in PE file */
|
||||||
|
buf = xmalloc ( rom_size );
|
||||||
|
memset ( buf, 0, rom_size );
|
||||||
|
headers = buf;
|
||||||
|
payload = ( buf + sizeof ( *headers ) );
|
||||||
|
if ( fread ( payload, pe_size, 1, pe ) != 1 ) {
|
||||||
|
eprintf ( "Could not read PE file: %s\n",
|
||||||
|
strerror ( errno ) );
|
||||||
|
exit ( 1 );
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Construct ROM header */
|
||||||
|
headers->rom.Signature = PCI_EXPANSION_ROM_HEADER_SIGNATURE;
|
||||||
|
headers->rom.InitializationSize = ( rom_size / 512 );
|
||||||
|
headers->rom.EfiSignature = EFI_PCI_EXPANSION_ROM_HEADER_EFISIGNATURE;
|
||||||
|
read_pe_info ( payload, &headers->rom.EfiMachineType,
|
||||||
|
&headers->rom.EfiSubsystem );
|
||||||
|
headers->rom.EfiImageHeaderOffset = sizeof ( *headers );
|
||||||
|
headers->rom.PcirOffset =
|
||||||
|
offsetof ( typeof ( *headers ), pci );
|
||||||
|
headers->pci.Signature = PCI_DATA_STRUCTURE_SIGNATURE;
|
||||||
|
headers->pci.VendorId = opts->vendor ? opts->vendor : 0x8086;
|
||||||
|
headers->pci.DeviceId = opts->device ? opts->device : 0x100E;
|
||||||
|
headers->pci.Length = sizeof ( headers->pci );
|
||||||
|
headers->pci.ClassCode[0] = PCI_CLASS_NETWORK;
|
||||||
|
headers->pci.ImageLength = ( rom_size / 512 );
|
||||||
|
headers->pci.CodeType = 0x03; /* No constant in EFI headers? */
|
||||||
|
headers->pci.Indicator = 0x80; /* No constant in EFI headers? */
|
||||||
|
|
||||||
|
/* Fix image checksum */
|
||||||
|
for ( i = 0, checksum = 0 ; i < rom_size ; i++ )
|
||||||
|
checksum += *( ( uint8_t * ) buf + i );
|
||||||
|
headers->checksum -= checksum;
|
||||||
|
|
||||||
|
/* Write out ROM */
|
||||||
|
if ( fwrite ( buf, rom_size, 1, rom ) != 1 ) {
|
||||||
|
eprintf ( "Could not write ROM file: %s\n",
|
||||||
|
strerror ( errno ) );
|
||||||
|
exit ( 1 );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Print help
|
||||||
|
*
|
||||||
|
* @v program_name Program name
|
||||||
|
*/
|
||||||
|
static void print_help ( const char *program_name ) {
|
||||||
|
eprintf ( "Syntax: %s [--vendor=VVVV] [--device=DDDD] "
|
||||||
|
"infile outfile\n", program_name );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse command-line options
|
||||||
|
*
|
||||||
|
* @v argc Argument count
|
||||||
|
* @v argv Argument list
|
||||||
|
* @v opts Options structure to populate
|
||||||
|
*/
|
||||||
|
static int parse_options ( const int argc, char **argv,
|
||||||
|
struct options *opts ) {
|
||||||
|
char *end;
|
||||||
|
int c;
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
int option_index = 0;
|
||||||
|
static struct option long_options[] = {
|
||||||
|
{ "vendor", required_argument, NULL, 'v' },
|
||||||
|
{ "device", required_argument, NULL, 'd' },
|
||||||
|
{ "help", 0, NULL, 'h' },
|
||||||
|
{ 0, 0, 0, 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
if ( ( c = getopt_long ( argc, argv, "v:d:h",
|
||||||
|
long_options,
|
||||||
|
&option_index ) ) == -1 ) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch ( c ) {
|
||||||
|
case 'v':
|
||||||
|
opts->vendor = strtoul ( optarg, &end, 16 );
|
||||||
|
if ( *end ) {
|
||||||
|
eprintf ( "Invalid vendor \"%s\"\n", optarg );
|
||||||
|
exit ( 2 );
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'd':
|
||||||
|
opts->device = strtoul ( optarg, &end, 16 );
|
||||||
|
if ( *end ) {
|
||||||
|
eprintf ( "Invalid device \"%s\"\n", optarg );
|
||||||
|
exit ( 2 );
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'h':
|
||||||
|
print_help ( argv[0] );
|
||||||
|
exit ( 0 );
|
||||||
|
case '?':
|
||||||
|
default:
|
||||||
|
exit ( 2 );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return optind;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main ( int argc, char **argv ) {
|
||||||
|
struct options opts = {
|
||||||
|
};
|
||||||
|
unsigned int infile_index;
|
||||||
|
const char *infile_name;
|
||||||
|
const char *outfile_name;
|
||||||
|
FILE *infile;
|
||||||
|
FILE *outfile;
|
||||||
|
|
||||||
|
/* Parse command-line arguments */
|
||||||
|
infile_index = parse_options ( argc, argv, &opts );
|
||||||
|
if ( argc != ( infile_index + 2 ) ) {
|
||||||
|
print_help ( argv[0] );
|
||||||
|
exit ( 2 );
|
||||||
|
}
|
||||||
|
infile_name = argv[infile_index];
|
||||||
|
outfile_name = argv[infile_index + 1];
|
||||||
|
|
||||||
|
/* Open input and output files */
|
||||||
|
infile = fopen ( infile_name, "r" );
|
||||||
|
if ( ! infile ) {
|
||||||
|
eprintf ( "Could not open %s for reading: %s\n",
|
||||||
|
infile_name, strerror ( errno ) );
|
||||||
|
exit ( 1 );
|
||||||
|
}
|
||||||
|
outfile = fopen ( outfile_name, "w" );
|
||||||
|
if ( ! outfile ) {
|
||||||
|
eprintf ( "Could not open %s for writing: %s\n",
|
||||||
|
outfile_name, strerror ( errno ) );
|
||||||
|
exit ( 1 );
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Convert file */
|
||||||
|
make_efi_rom ( infile, outfile, &opts );
|
||||||
|
|
||||||
|
fclose ( outfile );
|
||||||
|
fclose ( infile );
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
74
x86_64-efi/elf_x86_64_efi.lds
Normal file
74
x86_64-efi/elf_x86_64_efi.lds
Normal file
|
|
@ -0,0 +1,74 @@
|
||||||
|
/* Same as elf_x86_64_fbsd_efi.lds, except for OUTPUT_FORMAT below - KEEP IN SYNC */
|
||||||
|
OUTPUT_FORMAT("elf64-x86-64", "elf64-x86-64", "elf64-x86-64")
|
||||||
|
OUTPUT_ARCH(i386:x86-64)
|
||||||
|
ENTRY(_start)
|
||||||
|
SECTIONS
|
||||||
|
{
|
||||||
|
. = 0;
|
||||||
|
ImageBase = .;
|
||||||
|
.hash : { *(.hash) } /* this MUST come first! */
|
||||||
|
. = ALIGN(4096);
|
||||||
|
.eh_frame :
|
||||||
|
{
|
||||||
|
*(.eh_frame)
|
||||||
|
}
|
||||||
|
. = ALIGN(4096);
|
||||||
|
.text :
|
||||||
|
{
|
||||||
|
_text = .;
|
||||||
|
*(.text)
|
||||||
|
*(.text.*)
|
||||||
|
*(.gnu.linkonce.t.*)
|
||||||
|
. = ALIGN(16);
|
||||||
|
}
|
||||||
|
_etext = .;
|
||||||
|
_text_size = . - _text;
|
||||||
|
. = ALIGN(4096);
|
||||||
|
.reloc :
|
||||||
|
{
|
||||||
|
*(.reloc)
|
||||||
|
}
|
||||||
|
. = ALIGN(4096);
|
||||||
|
.data :
|
||||||
|
{
|
||||||
|
_data = .;
|
||||||
|
*(.rodata*)
|
||||||
|
*(.got.plt)
|
||||||
|
*(.got)
|
||||||
|
*(.data*)
|
||||||
|
*(.sdata)
|
||||||
|
/* the EFI loader doesn't seem to like a .bss section, so we stick
|
||||||
|
it all into .data: */
|
||||||
|
*(.sbss)
|
||||||
|
*(.scommon)
|
||||||
|
*(.dynbss)
|
||||||
|
*(.bss)
|
||||||
|
*(COMMON)
|
||||||
|
*(.rel.local)
|
||||||
|
}
|
||||||
|
.note.gnu.build-id : { *(.note.gnu.build-id) }
|
||||||
|
|
||||||
|
_edata = .;
|
||||||
|
_data_size = . - _etext;
|
||||||
|
. = ALIGN(4096);
|
||||||
|
.dynamic : { *(.dynamic) }
|
||||||
|
. = ALIGN(4096);
|
||||||
|
.rela :
|
||||||
|
{
|
||||||
|
*(.rela.data*)
|
||||||
|
*(.rela.got)
|
||||||
|
*(.rela.stab)
|
||||||
|
}
|
||||||
|
. = ALIGN(4096);
|
||||||
|
.dynsym : { *(.dynsym) }
|
||||||
|
. = ALIGN(4096);
|
||||||
|
.dynstr : { *(.dynstr) }
|
||||||
|
. = ALIGN(4096);
|
||||||
|
.ignored.reloc :
|
||||||
|
{
|
||||||
|
*(.rela.reloc)
|
||||||
|
*(.eh_frame)
|
||||||
|
*(.note.GNU-stack)
|
||||||
|
}
|
||||||
|
.comment 0 : { *(.comment) }
|
||||||
|
}
|
||||||
356
x86_64-efi/fs.h
Normal file
356
x86_64-efi/fs.h
Normal file
|
|
@ -0,0 +1,356 @@
|
||||||
|
/*
|
||||||
|
* x86_64-efi/fs.h
|
||||||
|
*
|
||||||
|
* Copyright (C) 2017 - 2021 bzt (bztsrc@gitlab)
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person
|
||||||
|
* obtaining a copy of this software and associated documentation
|
||||||
|
* files (the "Software"), to deal in the Software without
|
||||||
|
* restriction, including without limitation the rights to use, copy,
|
||||||
|
* modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||||
|
* of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be
|
||||||
|
* included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||||
|
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||||
|
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
* DEALINGS IN THE SOFTWARE.
|
||||||
|
*
|
||||||
|
* This file is part of the BOOTBOOT Protocol package.
|
||||||
|
* @brief Filesystem drivers for initial ramdisk.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* FS/Z initrd (OS/Z's native file system)
|
||||||
|
*/
|
||||||
|
file_t fsz_initrd(unsigned char *initrd_p, char *kernel)
|
||||||
|
{
|
||||||
|
file_t ret = { NULL, 0 };
|
||||||
|
if(initrd_p==NULL || CompareMem(initrd_p + 512,"FS/Z",4) || kernel==NULL){
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
unsigned char passphrase[256],chk[32],iv[32];
|
||||||
|
unsigned int i,j,k,l,ss=1<<(initrd_p[518]+11);
|
||||||
|
unsigned char *ent, *in=(initrd_p+*((uint64_t*)(initrd_p+560))*ss);
|
||||||
|
SHA256_CTX ctx;
|
||||||
|
DBG(L" * FS/Z %s\n",a2u(kernel));
|
||||||
|
//decrypt initrd
|
||||||
|
while(*((uint32_t*)(initrd_p+520))!=0) {
|
||||||
|
Print(L" * Passphrase? ");
|
||||||
|
l=ReadLine(passphrase,sizeof(passphrase));
|
||||||
|
if(!l) {
|
||||||
|
Print(L"\n");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
if(*((uint32_t*)(initrd_p+520))!=crc32_calc((char*)passphrase,l)) {
|
||||||
|
Print(L"\rBOOTBOOT-ERROR: Bad passphrase\n");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
Print(L"\r * Decrypting...\r");
|
||||||
|
SHA256_Init(&ctx);
|
||||||
|
SHA256_Update(&ctx,passphrase,l);
|
||||||
|
SHA256_Update(&ctx,initrd_p+512,6);
|
||||||
|
SHA256_Final(chk,&ctx);
|
||||||
|
for(i=0;i<32;i++) initrd_p[i+680]^=chk[i];
|
||||||
|
SHA256_Init(&ctx);
|
||||||
|
SHA256_Update(&ctx,initrd_p+680,32);
|
||||||
|
SHA256_Final(iv,&ctx);
|
||||||
|
if(((initrd_p[519]>>4)&15)==1) {
|
||||||
|
// FSZ_SB_EALG_AESCBC
|
||||||
|
aes_init(iv);
|
||||||
|
for(k=ss,j=1;j<*((uint32_t*)(initrd_p+528));k+=ss,j++) {
|
||||||
|
aes_dec(initrd_p+k,ss);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// FSZ_SB_EALG_SHACBC
|
||||||
|
for(k=ss,j=1;j<*((uint32_t*)(initrd_p+528));j++) {
|
||||||
|
CopyMem(chk,iv,32);
|
||||||
|
for(i=0;i<ss;i++) {
|
||||||
|
if(i%32==0) {
|
||||||
|
SHA256_Init(&ctx);
|
||||||
|
SHA256_Update(&ctx,&chk,32);
|
||||||
|
SHA256_Update(&ctx,&j,4);
|
||||||
|
SHA256_Final(chk,&ctx);
|
||||||
|
}
|
||||||
|
initrd_p[k++]^=chk[i%32]^iv[i%32];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ZeroMem(initrd_p+680,32); *((uint32_t*)(initrd_p+520)) = 0;
|
||||||
|
*((uint32_t*)(initrd_p+1020))=crc32_calc((char *)initrd_p+512,508);
|
||||||
|
Print(L" \r");
|
||||||
|
}
|
||||||
|
// Get the inode
|
||||||
|
char *s,*e;
|
||||||
|
s=e=kernel;
|
||||||
|
i=0;
|
||||||
|
again:
|
||||||
|
while(*e!='/'&&*e!=0){e++;}
|
||||||
|
if(*e=='/'){e++;}
|
||||||
|
if(!CompareMem(in,"FSIN",4)){
|
||||||
|
//is it inlined?
|
||||||
|
if(!CompareMem(initrd_p[520]&1? in + 2048 : in + 1024,"FSDR",4)){
|
||||||
|
ent=(initrd_p[520]&1? in + 2048 : in + 1024);
|
||||||
|
} else if(!CompareMem(initrd_p+*((uint64_t*)(in+448))*ss,"FSDR",4)){
|
||||||
|
// go, get the sector pointed
|
||||||
|
ent=(initrd_p+*((uint64_t*)(in+448))*ss);
|
||||||
|
} else {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
//skip header
|
||||||
|
unsigned char *hdr=ent; ent+=128;
|
||||||
|
//iterate on directory entries
|
||||||
|
int j=*((uint64_t*)(hdr+16));
|
||||||
|
while(j-->0){
|
||||||
|
if(!CompareMem(ent + 16,s,e-s)) {
|
||||||
|
if(*e==0) {
|
||||||
|
i=*((uint64_t*)(ent+0));
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
s=e;
|
||||||
|
in=(initrd_p+*((uint64_t*)(ent+0))*ss);
|
||||||
|
goto again;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ent+=128;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
i=0;
|
||||||
|
}
|
||||||
|
if(i!=0) {
|
||||||
|
// fid -> inode ptr -> data ptr
|
||||||
|
unsigned char *in=(initrd_p+i*ss);
|
||||||
|
if(!CompareMem(in,"FSIN",4)){
|
||||||
|
ret.size=*((uint64_t*)(in+464));
|
||||||
|
if(*((uint64_t*)(in+448)) == i) {
|
||||||
|
if(!(in[488]&31)) {
|
||||||
|
// inline data
|
||||||
|
ret.ptr=(uint8_t*)(initrd_p+i*ss+(initrd_p[520]&1? 2048 : 1024));
|
||||||
|
} else {
|
||||||
|
// sector directory or list inlined
|
||||||
|
ret.ptr=(uint8_t*)(initrd_p + *((uint64_t*)(initrd_p[520]&1? in + 2048 : in + 1024))*ss);
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
if(*((uint64_t*)(in+448))) {
|
||||||
|
switch((in[488]&15) + (in[488]&16 ? 1 : 0)) {
|
||||||
|
case 0: // direct data
|
||||||
|
ret.ptr=(uint8_t*)(initrd_p + *((uint64_t*)(in+448)) * ss);
|
||||||
|
break;
|
||||||
|
case 1: // sector directory or list (only one level supported here, and no holes in files)
|
||||||
|
ret.ptr=(uint8_t*)(initrd_p + *((uint64_t*)(initrd_p + *((uint64_t*)(in+448))*ss)) * ss);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else ret.size=0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Minix3 file system
|
||||||
|
* directories only checked for their first block, and kernel must be defragmented
|
||||||
|
*/
|
||||||
|
file_t mfs_initrd(unsigned char *initrd_p, char *kernel)
|
||||||
|
{
|
||||||
|
UINT32 o, bs, ino_tbl;
|
||||||
|
UINT8 *ino, *d;
|
||||||
|
char *s = kernel, *e;
|
||||||
|
file_t ret = { NULL, 0 };
|
||||||
|
if(initrd_p[1048] != 'Z' || initrd_p[1049] != 'M') return ret;
|
||||||
|
DBG(L" * MFS %s\n",a2u(kernel));
|
||||||
|
bs = *((UINT16*)(initrd_p + 1052));
|
||||||
|
ino_tbl = (2 + *((UINT16*)(initrd_p + 1030)) + *((UINT16*)(initrd_p + 1032))) * bs;
|
||||||
|
ino = initrd_p + ino_tbl;
|
||||||
|
again:
|
||||||
|
for(e = s; *e && *e != '/'; e++);
|
||||||
|
d = initrd_p + *((UINT32*)(ino + 24)) * bs;
|
||||||
|
for(o = 0; o < *((UINT32*)(ino + 8)) && o < bs; o += 64, d += 64) {
|
||||||
|
if(*((UINT32*)d) && !CompareMem(s, d + 4, e - s) && !d[e - s]) {
|
||||||
|
ino = initrd_p + ino_tbl + (*((UINT32*)d) - 1) * 64;
|
||||||
|
d = initrd_p + *((UINT32*)(ino + 24)) * bs;
|
||||||
|
if(!*e) { ret.ptr = d; ret.size = *((UINT32*)(ino + 8)); return ret; }
|
||||||
|
s = e + 1; goto again;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* cpio archive
|
||||||
|
*/
|
||||||
|
file_t cpio_initrd(unsigned char *initrd_p, char *kernel)
|
||||||
|
{
|
||||||
|
unsigned char *ptr=initrd_p;
|
||||||
|
int k;
|
||||||
|
file_t ret = { NULL, 0 };
|
||||||
|
if(initrd_p==NULL || kernel==NULL ||
|
||||||
|
(CompareMem(initrd_p,"070701",6) && CompareMem(initrd_p,"070702",6) && CompareMem(initrd_p,"070707",6)))
|
||||||
|
return ret;
|
||||||
|
DBG(L" * cpio %s\n",a2u(kernel));
|
||||||
|
k=strlena(kernel);
|
||||||
|
// hpodc archive
|
||||||
|
while(!CompareMem(ptr,"070707",6)){
|
||||||
|
int ns=oct2bin(ptr+8*6+11,6);
|
||||||
|
int fs=oct2bin(ptr+8*6+11+6,11);
|
||||||
|
if(!CompareMem(ptr+9*6+2*11,kernel,k+1) ||
|
||||||
|
(ptr[9*6+2*11] == '.' && ptr[9*6+2*11+1] == '/' && !CompareMem(ptr+9*6+2*11+2,kernel,k+1))) {
|
||||||
|
ret.size=fs;
|
||||||
|
ret.ptr=(UINT8*)(ptr+9*6+2*11+ns);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
ptr+=(76+ns+fs);
|
||||||
|
}
|
||||||
|
// newc and crc archive
|
||||||
|
while(!CompareMem(ptr,"07070",5)){
|
||||||
|
int fs=hex2bin(ptr+8*6+6,8);
|
||||||
|
int ns=hex2bin(ptr+8*11+6,8);
|
||||||
|
if(!CompareMem(ptr+110,kernel,k+1) || (ptr[110] == '.' && ptr[111] == '/' && !CompareMem(ptr+112,kernel,k+1))) {
|
||||||
|
ret.size=fs;
|
||||||
|
ret.ptr=(UINT8*)(ptr+((110+ns+3)/4)*4);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
ptr+=((110+ns+3)/4)*4 + ((fs+3)/4)*4;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ustar tarball archive
|
||||||
|
*/
|
||||||
|
file_t tar_initrd(unsigned char *initrd_p, char *kernel)
|
||||||
|
{
|
||||||
|
unsigned char *ptr=initrd_p;
|
||||||
|
int k;
|
||||||
|
file_t ret = { NULL, 0 };
|
||||||
|
if(initrd_p==NULL || kernel==NULL || CompareMem(initrd_p+257,"ustar",5))
|
||||||
|
return ret;
|
||||||
|
DBG(L" * tar %s\n",a2u(kernel));
|
||||||
|
k=strlena(kernel);
|
||||||
|
while(!CompareMem(ptr+257,"ustar",5)){
|
||||||
|
int fs=oct2bin(ptr+0x7c,11);
|
||||||
|
if(!CompareMem(ptr,kernel,k+1) || (ptr[0] == '.' && ptr[1] == '/' && !CompareMem(ptr+2,kernel,k+1))) {
|
||||||
|
ret.size=fs;
|
||||||
|
ret.ptr=(UINT8*)(ptr+512);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
ptr+=(((fs+511)/512)+1)*512;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Simple File System
|
||||||
|
*/
|
||||||
|
file_t sfs_initrd(unsigned char *initrd_p, char *kernel)
|
||||||
|
{
|
||||||
|
unsigned char *ptr, *end;
|
||||||
|
int k,bs,ver;
|
||||||
|
file_t ret = { NULL, 0 };
|
||||||
|
if(initrd_p==NULL || kernel==NULL || (CompareMem(initrd_p+0x1AC,"SFS",3) && CompareMem(initrd_p+0x1A6,"SFS",3)))
|
||||||
|
return ret;
|
||||||
|
// 1.0 Brendan's version, 1.10 BenLunt's version
|
||||||
|
ver=!CompareMem(initrd_p+0x1A6,"SFS",3)?10:0;
|
||||||
|
bs=1<<(7+(UINT8)initrd_p[ver?0x1B6:0x1BC]);
|
||||||
|
end=initrd_p + *((UINT64 *)&initrd_p[ver?0x1AA:0x1B0]) * bs; // base + total_number_of_blocks * blocksize
|
||||||
|
// get index area
|
||||||
|
ptr=end - *((UINT64 *)&initrd_p[ver?0x19E:0x1A4]); // end - size of index area
|
||||||
|
// got a Starting Marker Entry?
|
||||||
|
if(ptr[0]!=2)
|
||||||
|
return ret;
|
||||||
|
DBG(L" * SFS 1.%d %s\n",ver,a2u(kernel));
|
||||||
|
k=strlena(kernel);
|
||||||
|
// iterate on index until we reach the end or Volume Identifier
|
||||||
|
while(ptr<end && ptr[0]!=0x01){
|
||||||
|
ptr+=64;
|
||||||
|
// file entry?
|
||||||
|
if(ptr[0]!=0x12)
|
||||||
|
continue;
|
||||||
|
// filename match?
|
||||||
|
if(!CompareMem(ptr+(ver?0x23:0x22),kernel,k+1)){
|
||||||
|
ret.size=*((UINTN*)&ptr[ver?0x1B:0x1A]); // file_length
|
||||||
|
ret.ptr=initrd_p + *((UINT64*)&ptr[ver?0x0B:0x0A]) * bs; // base + start_block * blocksize
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* James Molloy's initrd (for some reason it's popular among hobby OS developers)
|
||||||
|
* http://www.jamesmolloy.co.uk/tutorial_html
|
||||||
|
*/
|
||||||
|
file_t jamesm_initrd(unsigned char *initrd_p, char *kernel)
|
||||||
|
{
|
||||||
|
unsigned char *ptr=initrd_p+4;
|
||||||
|
int i,k,nf=*((int*)initrd_p);
|
||||||
|
file_t ret = { NULL, 0 };
|
||||||
|
// no real magic, so we assume initrd contains at least one file...
|
||||||
|
if(initrd_p==NULL || kernel==NULL || initrd_p[2]!=0 || initrd_p[3]!=0 || initrd_p[4]!=0xBF)
|
||||||
|
return ret;
|
||||||
|
DBG(L" * JamesM %s\n",a2u(kernel));
|
||||||
|
k=strlena(kernel);
|
||||||
|
for(i=0;i<nf && ptr[0]==0xBF;i++) {
|
||||||
|
if(!CompareMem(ptr+1,kernel,k+1)){
|
||||||
|
ret.ptr=*((uint32_t*)(ptr+65)) + initrd_p;
|
||||||
|
ret.size=*((uint32_t*)(ptr+69));
|
||||||
|
}
|
||||||
|
ptr+=73;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* EchFS
|
||||||
|
* http://github.com/echfs/echfs
|
||||||
|
*/
|
||||||
|
file_t ech_initrd(unsigned char *initrd_p, char *kernel)
|
||||||
|
{
|
||||||
|
UINT64 parent = 0xffffffffffffffffUL, n;
|
||||||
|
unsigned char *ptr;
|
||||||
|
char *end, *fn;
|
||||||
|
int k = 0;
|
||||||
|
file_t ret = { NULL, 0 };
|
||||||
|
if(initrd_p==NULL || kernel==NULL || CompareMem(initrd_p+4,"_ECH_FS_",8))
|
||||||
|
return ret;
|
||||||
|
DBG(L" * EchFS %s\n",a2u(kernel));
|
||||||
|
CopyMem(&k, initrd_p + 28, 4);
|
||||||
|
CopyMem(&n, initrd_p + 12, 8);
|
||||||
|
ptr = initrd_p + (((n * 8 + k - 1) / k) + 16) * k;
|
||||||
|
for(end = fn = kernel; *end && *end != '/'; end++);
|
||||||
|
while(*((UINT64*)ptr)) {
|
||||||
|
if(*((UINT64*)ptr) == parent && !CompareMem(ptr + 9, fn, end - fn) && !ptr[9 + end - fn]) {
|
||||||
|
parent = *((UINT64*)(ptr + 240));
|
||||||
|
if(!*end) {
|
||||||
|
ret.size=*((UINTN*)(ptr + 248));
|
||||||
|
ret.ptr=(UINT8*)(initrd_p + parent * k);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
end++;
|
||||||
|
for(fn = end; *end && *end != '/'; end++);
|
||||||
|
}
|
||||||
|
ptr += 256;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Static file system drivers registry
|
||||||
|
*/
|
||||||
|
file_t (*fsdrivers[]) (unsigned char *, char *) = {
|
||||||
|
fsz_initrd,
|
||||||
|
mfs_initrd,
|
||||||
|
cpio_initrd,
|
||||||
|
tar_initrd,
|
||||||
|
sfs_initrd,
|
||||||
|
jamesm_initrd,
|
||||||
|
ech_initrd,
|
||||||
|
NULL
|
||||||
|
};
|
||||||
BIN
x86_64-efi/libefi.a
Normal file
BIN
x86_64-efi/libefi.a
Normal file
Binary file not shown.
BIN
x86_64-efi/libgnuefi.a
Normal file
BIN
x86_64-efi/libgnuefi.a
Normal file
Binary file not shown.
112
x86_64-efi/smp.S
Normal file
112
x86_64-efi/smp.S
Normal file
|
|
@ -0,0 +1,112 @@
|
||||||
|
/*
|
||||||
|
* x86_64-efi/smp.S
|
||||||
|
*
|
||||||
|
* Copyright (C) 2017 - 2021 bzt (bztsrc@gitlab)
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person
|
||||||
|
* obtaining a copy of this software and associated documentation
|
||||||
|
* files (the "Software"), to deal in the Software without
|
||||||
|
* restriction, including without limitation the rights to use, copy,
|
||||||
|
* modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||||
|
* of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be
|
||||||
|
* included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||||
|
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||||
|
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
* DEALINGS IN THE SOFTWARE.
|
||||||
|
*
|
||||||
|
* This file is part of the BOOTBOOT Protocol package.
|
||||||
|
* @brief SMP initialization code.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
.globl ap_trampoline
|
||||||
|
.extern bootboot_startcode
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* things to do on the APs *
|
||||||
|
*****************************************************************************/
|
||||||
|
.balign 128
|
||||||
|
.code16
|
||||||
|
/* this code will be relocated to 0x8000 - 0x8100 */
|
||||||
|
ap_trampoline:
|
||||||
|
cli
|
||||||
|
cld
|
||||||
|
ljmp $0, $0x8040
|
||||||
|
.balign 16
|
||||||
|
// prot mode GDT
|
||||||
|
_L8010_GDT_table:
|
||||||
|
.long 0, 0
|
||||||
|
.long 0x0000FFFF, 0x00CF9A00 // flat code
|
||||||
|
.long 0x0000FFFF, 0x008F9200 // flat data
|
||||||
|
.long 0x00000068, 0x00CF8900 // tss, not used but required by VB's vt-x
|
||||||
|
_L8030_GDT_value:
|
||||||
|
.word _L8030_GDT_value - _L8010_GDT_table - 1
|
||||||
|
.long 0x8010
|
||||||
|
.long 0, 0
|
||||||
|
.balign 64
|
||||||
|
_L8040:
|
||||||
|
xorw %ax, %ax
|
||||||
|
movw %ax, %ds
|
||||||
|
lgdtl 0x8030
|
||||||
|
movl %cr0, %eax
|
||||||
|
orl $1, %eax
|
||||||
|
movl %eax, %cr0
|
||||||
|
ljmp $8, $0x8060
|
||||||
|
.balign 32
|
||||||
|
.code32
|
||||||
|
_L8060:
|
||||||
|
movw $16, %ax
|
||||||
|
movw %ax, %ds
|
||||||
|
movw %ax, %ss
|
||||||
|
movl $0x368, %eax // Set PAE, MCE, PGE; OSFXSR, OSXMMEXCPT (enable SSE)
|
||||||
|
movl %eax, %cr4
|
||||||
|
movl 0x80C0, %eax // let's hope it's in the first 4G...
|
||||||
|
movl %eax, %cr3
|
||||||
|
movl $0x0C0000080, %ecx // EFR MSR
|
||||||
|
rdmsr
|
||||||
|
orl $0x100, %eax // enable long mode
|
||||||
|
wrmsr
|
||||||
|
movl $0x0C0000011, %eax // clear EM, MP (enable SSE) and WP
|
||||||
|
movl %eax, %cr0
|
||||||
|
lgdtl 0x80E0
|
||||||
|
movl $0x80C8, %esp // we can't use "ljmp $8, $0x80A0", because we don't know cs
|
||||||
|
lret
|
||||||
|
.balign 32
|
||||||
|
.code64
|
||||||
|
_L80A0:
|
||||||
|
movl 0x80D0, %eax // load long mode segments
|
||||||
|
movw %ax, %ds
|
||||||
|
movw %ax, %es
|
||||||
|
movw %ax, %ss
|
||||||
|
movw %ax, %fs
|
||||||
|
movw %ax, %gs
|
||||||
|
// some linkers (GNU ld) generates bad relocation record for this
|
||||||
|
// jmp bootboot_startcode
|
||||||
|
movq 0x80D8, %rax
|
||||||
|
// in theory this could cause trouble, but it does not since all cores are executing the same
|
||||||
|
// code at this point, so it doesn't matter if one core is overwriting the same stack with the
|
||||||
|
// stack frame, because all are saving exactly the same stack frame to the same position
|
||||||
|
movl $0x8800, %esp
|
||||||
|
jmp *%rax
|
||||||
|
.balign 32
|
||||||
|
_L80C0_cr3_value:
|
||||||
|
.long 0, 0
|
||||||
|
.long 0x80A0
|
||||||
|
_L80CC_cs_value:
|
||||||
|
.long 0
|
||||||
|
_L80D0_ds_value:
|
||||||
|
.long 0, 0
|
||||||
|
_L80D8_bootboot_startcore:
|
||||||
|
.long 0, 0
|
||||||
|
_L80E0_gdt_value:
|
||||||
|
.long 0, 0, 0, 0
|
||||||
|
ap_trampoline_end:
|
||||||
117
x86_64-efi/tinf.h
Normal file
117
x86_64-efi/tinf.h
Normal file
|
|
@ -0,0 +1,117 @@
|
||||||
|
/*
|
||||||
|
* uzlib - tiny deflate/inflate library (deflate, gzip, zlib)
|
||||||
|
*
|
||||||
|
* Copyright (c) 2003 by Joergen Ibsen / Jibz
|
||||||
|
* All Rights Reserved
|
||||||
|
* http://www.ibsensoftware.com/
|
||||||
|
*
|
||||||
|
* Copyright (c) 2014-2016 by Paul Sokolovsky
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef TINF_H_INCLUDED
|
||||||
|
#define TINF_H_INCLUDED
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
/* calling convention */
|
||||||
|
#ifndef TINFCC
|
||||||
|
#ifdef __WATCOMC__
|
||||||
|
#define TINFCC __cdecl
|
||||||
|
#else
|
||||||
|
#define TINFCC
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* ok status, more data produced */
|
||||||
|
#define TINF_OK 0
|
||||||
|
/* end of compressed stream reached */
|
||||||
|
#define TINF_DONE 1
|
||||||
|
#define TINF_DATA_ERROR (-3)
|
||||||
|
#define TINF_CHKSUM_ERROR (-4)
|
||||||
|
#define TINF_DICT_ERROR (-5)
|
||||||
|
|
||||||
|
/* checksum types */
|
||||||
|
#define TINF_CHKSUM_NONE 0
|
||||||
|
#define TINF_CHKSUM_ADLER 1
|
||||||
|
#define TINF_CHKSUM_CRC 2
|
||||||
|
|
||||||
|
/* data structures */
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
unsigned short table[16]; /* table of code length counts */
|
||||||
|
unsigned short trans[288]; /* code -> symbol translation table */
|
||||||
|
} TINF_TREE;
|
||||||
|
|
||||||
|
struct TINF_DATA;
|
||||||
|
typedef struct TINF_DATA {
|
||||||
|
const unsigned char *source;
|
||||||
|
/* If source above is NULL, this function will be used to read
|
||||||
|
next byte from source stream */
|
||||||
|
unsigned char (*readSource)(struct TINF_DATA *data);
|
||||||
|
|
||||||
|
unsigned int tag;
|
||||||
|
unsigned int bitcount;
|
||||||
|
|
||||||
|
/* Buffer start */
|
||||||
|
unsigned char *destStart;
|
||||||
|
/* Buffer total size */
|
||||||
|
unsigned int destSize;
|
||||||
|
/* Current pointer in buffer */
|
||||||
|
unsigned char *dest;
|
||||||
|
/* Remaining bytes in buffer */
|
||||||
|
unsigned int destRemaining;
|
||||||
|
|
||||||
|
/* Accumulating checksum */
|
||||||
|
unsigned int checksum;
|
||||||
|
char checksum_type;
|
||||||
|
|
||||||
|
int btype;
|
||||||
|
int bfinal;
|
||||||
|
unsigned int curlen;
|
||||||
|
int lzOff;
|
||||||
|
unsigned char *dict_ring;
|
||||||
|
unsigned int dict_size;
|
||||||
|
unsigned int dict_idx;
|
||||||
|
|
||||||
|
TINF_TREE ltree; /* dynamic length/symbol tree */
|
||||||
|
TINF_TREE dtree; /* dynamic distance tree */
|
||||||
|
} TINF_DATA;
|
||||||
|
|
||||||
|
#define TINF_PUT(d, c) \
|
||||||
|
{ \
|
||||||
|
*d->dest++ = c; \
|
||||||
|
if (d->dict_ring) { d->dict_ring[d->dict_idx++] = c; if (d->dict_idx == d->dict_size) d->dict_idx = 0; } \
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char TINFCC uzlib_get_byte(TINF_DATA *d);
|
||||||
|
|
||||||
|
/* Decompression API */
|
||||||
|
|
||||||
|
void TINFCC uzlib_init(void);
|
||||||
|
void TINFCC uzlib_uncompress_init(TINF_DATA *d, void *dict, unsigned int dictLen);
|
||||||
|
int TINFCC uzlib_uncompress(TINF_DATA *d);
|
||||||
|
int TINFCC uzlib_uncompress_chksum(TINF_DATA *d);
|
||||||
|
|
||||||
|
int TINFCC uzlib_zlib_parse_header(TINF_DATA *d);
|
||||||
|
int TINFCC uzlib_gzip_parse_header(TINF_DATA *d);
|
||||||
|
|
||||||
|
/* Compression API */
|
||||||
|
|
||||||
|
void TINFCC uzlib_compress(void *data, const uint8_t *src, unsigned slen);
|
||||||
|
|
||||||
|
/* Checksum API */
|
||||||
|
|
||||||
|
/* prev_sum is previous value for incremental computation, 1 initially */
|
||||||
|
uint32_t TINFCC uzlib_adler32(const void *data, unsigned int length, uint32_t prev_sum);
|
||||||
|
/* crc is previous value for incremental computation, 0xffffffff initially */
|
||||||
|
uint32_t TINFCC uzlib_crc32(const void *data, unsigned int length, uint32_t crc);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
} /* extern "C" */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* TINF_H_INCLUDED */
|
||||||
475
x86_64-efi/tinflate.c
Normal file
475
x86_64-efi/tinflate.c
Normal file
|
|
@ -0,0 +1,475 @@
|
||||||
|
/*
|
||||||
|
* tinflate - tiny inflate
|
||||||
|
*
|
||||||
|
* Copyright (c) 2003 by Joergen Ibsen / Jibz
|
||||||
|
* All Rights Reserved
|
||||||
|
* http://www.ibsensoftware.com/
|
||||||
|
*
|
||||||
|
* Copyright (c) 2014-2016 by Paul Sokolovsky
|
||||||
|
*
|
||||||
|
* This software is provided 'as-is', without any express
|
||||||
|
* or implied warranty. In no event will the authors be
|
||||||
|
* held liable for any damages arising from the use of
|
||||||
|
* this software.
|
||||||
|
*
|
||||||
|
* Permission is granted to anyone to use this software
|
||||||
|
* for any purpose, including commercial applications,
|
||||||
|
* and to alter it and redistribute it freely, subject to
|
||||||
|
* the following restrictions:
|
||||||
|
*
|
||||||
|
* 1. The origin of this software must not be
|
||||||
|
* misrepresented; you must not claim that you
|
||||||
|
* wrote the original software. If you use this
|
||||||
|
* software in a product, an acknowledgment in
|
||||||
|
* the product documentation would be appreciated
|
||||||
|
* but is not required.
|
||||||
|
*
|
||||||
|
* 2. Altered source versions must be plainly marked
|
||||||
|
* as such, and must not be misrepresented as
|
||||||
|
* being the original software.
|
||||||
|
*
|
||||||
|
* 3. This notice may not be removed or altered from
|
||||||
|
* any source distribution.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "tinf.h"
|
||||||
|
|
||||||
|
uint32_t tinf_get_le_uint32(TINF_DATA *d);
|
||||||
|
uint32_t tinf_get_be_uint32(TINF_DATA *d);
|
||||||
|
|
||||||
|
/* --------------------------------------------------- *
|
||||||
|
* -- uninitialized global data (static structures) -- *
|
||||||
|
* --------------------------------------------------- */
|
||||||
|
|
||||||
|
#ifdef RUNTIME_BITS_TABLES
|
||||||
|
|
||||||
|
/* extra bits and base tables for length codes */
|
||||||
|
unsigned char length_bits[30];
|
||||||
|
unsigned short length_base[30];
|
||||||
|
|
||||||
|
/* extra bits and base tables for distance codes */
|
||||||
|
unsigned char dist_bits[30];
|
||||||
|
unsigned short dist_base[30];
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
const unsigned char length_bits[30] = {
|
||||||
|
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
|
||||||
|
};
|
||||||
|
const unsigned short length_base[30] = {
|
||||||
|
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
|
||||||
|
};
|
||||||
|
|
||||||
|
const unsigned char dist_bits[30] = {
|
||||||
|
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
|
||||||
|
};
|
||||||
|
const unsigned short dist_base[30] = {
|
||||||
|
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
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* special ordering of code length codes */
|
||||||
|
const unsigned char clcidx[] = {
|
||||||
|
16, 17, 18, 0, 8, 7, 9, 6,
|
||||||
|
10, 5, 11, 4, 12, 3, 13, 2,
|
||||||
|
14, 1, 15
|
||||||
|
};
|
||||||
|
|
||||||
|
/* ----------------------- *
|
||||||
|
* -- utility functions -- *
|
||||||
|
* ----------------------- */
|
||||||
|
|
||||||
|
#ifdef RUNTIME_BITS_TABLES
|
||||||
|
/* build extra bits and base tables */
|
||||||
|
static void tinf_build_bits_base(unsigned char *bits, unsigned short *base, int delta, int first)
|
||||||
|
{
|
||||||
|
int i, sum;
|
||||||
|
|
||||||
|
/* build bits table */
|
||||||
|
for (i = 0; i < delta; ++i) bits[i] = 0;
|
||||||
|
for (i = 0; i < 30 - delta; ++i) bits[i + delta] = i / delta;
|
||||||
|
|
||||||
|
/* build base table */
|
||||||
|
for (sum = first, i = 0; i < 30; ++i)
|
||||||
|
{
|
||||||
|
base[i] = sum;
|
||||||
|
sum += 1 << bits[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* build the fixed huffman trees */
|
||||||
|
static void tinf_build_fixed_trees(TINF_TREE *lt, TINF_TREE *dt)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* build fixed length tree */
|
||||||
|
for (i = 0; i < 7; ++i) lt->table[i] = 0;
|
||||||
|
|
||||||
|
lt->table[7] = 24;
|
||||||
|
lt->table[8] = 152;
|
||||||
|
lt->table[9] = 112;
|
||||||
|
|
||||||
|
for (i = 0; i < 24; ++i) lt->trans[i] = 256 + i;
|
||||||
|
for (i = 0; i < 144; ++i) lt->trans[24 + i] = i;
|
||||||
|
for (i = 0; i < 8; ++i) lt->trans[24 + 144 + i] = 280 + i;
|
||||||
|
for (i = 0; i < 112; ++i) lt->trans[24 + 144 + 8 + i] = 144 + i;
|
||||||
|
|
||||||
|
/* build fixed distance tree */
|
||||||
|
for (i = 0; i < 5; ++i) dt->table[i] = 0;
|
||||||
|
|
||||||
|
dt->table[5] = 32;
|
||||||
|
|
||||||
|
for (i = 0; i < 32; ++i) dt->trans[i] = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* given an array of code lengths, build a tree */
|
||||||
|
static void tinf_build_tree(TINF_TREE *t, const unsigned char *lengths, unsigned int num)
|
||||||
|
{
|
||||||
|
unsigned short offs[16];
|
||||||
|
unsigned int i, sum;
|
||||||
|
|
||||||
|
/* clear code length count table */
|
||||||
|
for (i = 0; i < 16; ++i) t->table[i] = 0;
|
||||||
|
|
||||||
|
/* scan symbol lengths, and sum code length counts */
|
||||||
|
for (i = 0; i < num; ++i) t->table[lengths[i]]++;
|
||||||
|
|
||||||
|
t->table[0] = 0;
|
||||||
|
|
||||||
|
/* compute offset table for distribution sort */
|
||||||
|
for (sum = 0, i = 0; i < 16; ++i)
|
||||||
|
{
|
||||||
|
offs[i] = sum;
|
||||||
|
sum += t->table[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* create code->symbol translation table (symbols sorted by code) */
|
||||||
|
for (i = 0; i < num; ++i)
|
||||||
|
{
|
||||||
|
if (lengths[i]) t->trans[offs[lengths[i]]++] = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ---------------------- *
|
||||||
|
* -- decode functions -- *
|
||||||
|
* ---------------------- */
|
||||||
|
|
||||||
|
unsigned char uzlib_get_byte(TINF_DATA *d)
|
||||||
|
{
|
||||||
|
if (d->source) {
|
||||||
|
return *d->source++;
|
||||||
|
}
|
||||||
|
return d->readSource(d);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t tinf_get_le_uint32(TINF_DATA *d)
|
||||||
|
{
|
||||||
|
uint32_t val = 0;
|
||||||
|
int i;
|
||||||
|
for (i = 4; i--;) {
|
||||||
|
val = val >> 8 | uzlib_get_byte(d) << 24;
|
||||||
|
}
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t tinf_get_be_uint32(TINF_DATA *d)
|
||||||
|
{
|
||||||
|
uint32_t val = 0;
|
||||||
|
int i;
|
||||||
|
for (i = 4; i--;) {
|
||||||
|
val = val << 8 | uzlib_get_byte(d);
|
||||||
|
}
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* get one bit from source stream */
|
||||||
|
static int tinf_getbit(TINF_DATA *d)
|
||||||
|
{
|
||||||
|
unsigned int bit;
|
||||||
|
|
||||||
|
/* check if tag is empty */
|
||||||
|
if (!d->bitcount--)
|
||||||
|
{
|
||||||
|
/* load next tag */
|
||||||
|
d->tag = uzlib_get_byte(d);
|
||||||
|
d->bitcount = 7;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* shift bit out of tag */
|
||||||
|
bit = d->tag & 0x01;
|
||||||
|
d->tag >>= 1;
|
||||||
|
|
||||||
|
return bit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* read a num bit value from a stream and add base */
|
||||||
|
static unsigned int tinf_read_bits(TINF_DATA *d, int num, int base)
|
||||||
|
{
|
||||||
|
unsigned int val = 0;
|
||||||
|
|
||||||
|
/* read num bits */
|
||||||
|
if (num)
|
||||||
|
{
|
||||||
|
unsigned int limit = 1 << (num);
|
||||||
|
unsigned int mask;
|
||||||
|
|
||||||
|
for (mask = 1; mask < limit; mask *= 2)
|
||||||
|
if (tinf_getbit(d)) val += mask;
|
||||||
|
}
|
||||||
|
|
||||||
|
return val + base;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* given a data stream and a tree, decode a symbol */
|
||||||
|
static int tinf_decode_symbol(TINF_DATA *d, TINF_TREE *t)
|
||||||
|
{
|
||||||
|
int sum = 0, cur = 0, len = 0;
|
||||||
|
|
||||||
|
/* get more bits while code value is above sum */
|
||||||
|
do {
|
||||||
|
|
||||||
|
cur = 2*cur + tinf_getbit(d);
|
||||||
|
|
||||||
|
++len;
|
||||||
|
|
||||||
|
sum += t->table[len];
|
||||||
|
cur -= t->table[len];
|
||||||
|
|
||||||
|
} while (cur >= 0);
|
||||||
|
|
||||||
|
return t->trans[sum + cur];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* given a data stream, decode dynamic trees from it */
|
||||||
|
static void tinf_decode_trees(TINF_DATA *d, TINF_TREE *lt, TINF_TREE *dt)
|
||||||
|
{
|
||||||
|
unsigned char lengths[288+32];
|
||||||
|
unsigned int hlit, hdist, hclen;
|
||||||
|
unsigned int i, num, length;
|
||||||
|
|
||||||
|
/* get 5 bits HLIT (257-286) */
|
||||||
|
hlit = tinf_read_bits(d, 5, 257);
|
||||||
|
|
||||||
|
/* get 5 bits HDIST (1-32) */
|
||||||
|
hdist = tinf_read_bits(d, 5, 1);
|
||||||
|
|
||||||
|
/* get 4 bits HCLEN (4-19) */
|
||||||
|
hclen = tinf_read_bits(d, 4, 4);
|
||||||
|
|
||||||
|
for (i = 0; i < 19; ++i) lengths[i] = 0;
|
||||||
|
|
||||||
|
/* read code lengths for code length alphabet */
|
||||||
|
for (i = 0; i < hclen; ++i)
|
||||||
|
{
|
||||||
|
/* get 3 bits code length (0-7) */
|
||||||
|
unsigned int clen = tinf_read_bits(d, 3, 0);
|
||||||
|
|
||||||
|
lengths[clcidx[i]] = clen;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* build code length tree, temporarily use length tree */
|
||||||
|
tinf_build_tree(lt, lengths, 19);
|
||||||
|
|
||||||
|
/* decode code lengths for the dynamic trees */
|
||||||
|
for (num = 0; num < hlit + hdist; )
|
||||||
|
{
|
||||||
|
int sym = tinf_decode_symbol(d, lt);
|
||||||
|
|
||||||
|
switch (sym)
|
||||||
|
{
|
||||||
|
case 16:
|
||||||
|
/* copy previous code length 3-6 times (read 2 bits) */
|
||||||
|
{
|
||||||
|
unsigned char prev = lengths[num - 1];
|
||||||
|
for (length = tinf_read_bits(d, 2, 3); length; --length)
|
||||||
|
{
|
||||||
|
lengths[num++] = prev;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 17:
|
||||||
|
/* repeat code length 0 for 3-10 times (read 3 bits) */
|
||||||
|
for (length = tinf_read_bits(d, 3, 3); length; --length)
|
||||||
|
{
|
||||||
|
lengths[num++] = 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 18:
|
||||||
|
/* repeat code length 0 for 11-138 times (read 7 bits) */
|
||||||
|
for (length = tinf_read_bits(d, 7, 11); length; --length)
|
||||||
|
{
|
||||||
|
lengths[num++] = 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
/* values 0-15 represent the actual code lengths */
|
||||||
|
lengths[num++] = sym;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* build dynamic trees */
|
||||||
|
tinf_build_tree(lt, lengths, hlit);
|
||||||
|
tinf_build_tree(dt, lengths + hlit, hdist);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ----------------------------- *
|
||||||
|
* -- block inflate functions -- *
|
||||||
|
* ----------------------------- */
|
||||||
|
|
||||||
|
/* given a stream and two trees, inflate a block of data */
|
||||||
|
static int tinf_inflate_block_data(TINF_DATA *d, TINF_TREE *lt, TINF_TREE *dt)
|
||||||
|
{
|
||||||
|
if (d->curlen == 0) {
|
||||||
|
unsigned int offs;
|
||||||
|
int dist;
|
||||||
|
int sym = tinf_decode_symbol(d, lt);
|
||||||
|
//printf("huff sym: %02x\n", sym);
|
||||||
|
|
||||||
|
/* literal byte */
|
||||||
|
if (sym < 256) {
|
||||||
|
TINF_PUT(d, sym);
|
||||||
|
return TINF_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* end of block */
|
||||||
|
if (sym == 256) {
|
||||||
|
return TINF_DONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* substring from sliding dictionary */
|
||||||
|
sym -= 257;
|
||||||
|
/* possibly get more bits from length code */
|
||||||
|
d->curlen = tinf_read_bits(d, length_bits[sym], length_base[sym]);
|
||||||
|
|
||||||
|
dist = tinf_decode_symbol(d, dt);
|
||||||
|
/* possibly get more bits from distance code */
|
||||||
|
offs = tinf_read_bits(d, dist_bits[dist], dist_base[dist]);
|
||||||
|
d->lzOff = -offs;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* copy next byte from dict substring */
|
||||||
|
d->dest[0] = d->dest[d->lzOff];
|
||||||
|
d->dest++;
|
||||||
|
d->curlen--;
|
||||||
|
return TINF_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* inflate an uncompressed block of data */
|
||||||
|
static int tinf_inflate_uncompressed_block(TINF_DATA *d)
|
||||||
|
{
|
||||||
|
if (d->curlen == 0) {
|
||||||
|
unsigned int length, invlength;
|
||||||
|
|
||||||
|
/* get length */
|
||||||
|
length = uzlib_get_byte(d) + 256 * uzlib_get_byte(d);
|
||||||
|
/* get one's complement of length */
|
||||||
|
invlength = uzlib_get_byte(d) + 256 * uzlib_get_byte(d);
|
||||||
|
/* check length */
|
||||||
|
if (length != (~invlength & 0x0000ffff)) return TINF_DATA_ERROR;
|
||||||
|
|
||||||
|
/* increment length to properly return TINF_DONE below, without
|
||||||
|
producing data at the same time */
|
||||||
|
d->curlen = length + 1;
|
||||||
|
|
||||||
|
/* make sure we start next block on a byte boundary */
|
||||||
|
d->bitcount = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (--d->curlen == 0) {
|
||||||
|
return TINF_DONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char c = uzlib_get_byte(d);
|
||||||
|
TINF_PUT(d, c);
|
||||||
|
return TINF_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ---------------------- *
|
||||||
|
* -- public functions -- *
|
||||||
|
* ---------------------- */
|
||||||
|
|
||||||
|
/* initialize global (static) data */
|
||||||
|
void uzlib_init(void)
|
||||||
|
{
|
||||||
|
#ifdef RUNTIME_BITS_TABLES
|
||||||
|
/* build extra bits and base tables */
|
||||||
|
tinf_build_bits_base(length_bits, length_base, 4, 3);
|
||||||
|
tinf_build_bits_base(dist_bits, dist_base, 2, 1);
|
||||||
|
|
||||||
|
/* fix a special case */
|
||||||
|
length_bits[28] = 0;
|
||||||
|
length_base[28] = 258;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/* inflate next byte of compressed stream */
|
||||||
|
int uzlib_uncompress(TINF_DATA *d)
|
||||||
|
{
|
||||||
|
do {
|
||||||
|
int res;
|
||||||
|
|
||||||
|
/* start a new block */
|
||||||
|
if (d->btype == -1) {
|
||||||
|
next_blk:
|
||||||
|
/* read final block flag */
|
||||||
|
d->bfinal = tinf_getbit(d);
|
||||||
|
/* read block type (2 bits) */
|
||||||
|
d->btype = tinf_read_bits(d, 2, 0);
|
||||||
|
|
||||||
|
//printf("Started new block: type=%d final=%d\n", d->btype, d->bfinal);
|
||||||
|
|
||||||
|
if (d->btype == 1) {
|
||||||
|
/* build fixed huffman trees */
|
||||||
|
tinf_build_fixed_trees(&d->ltree, &d->dtree);
|
||||||
|
} else if (d->btype == 2) {
|
||||||
|
/* decode trees from stream */
|
||||||
|
tinf_decode_trees(d, &d->ltree, &d->dtree);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* process current block */
|
||||||
|
switch (d->btype)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
/* decompress uncompressed block */
|
||||||
|
res = tinf_inflate_uncompressed_block(d);
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
case 2:
|
||||||
|
/* decompress block with fixed/dyanamic huffman trees */
|
||||||
|
/* trees were decoded previously, so it's the same routine for both */
|
||||||
|
res = tinf_inflate_block_data(d, &d->ltree, &d->dtree);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return TINF_DATA_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (res == TINF_DONE && !d->bfinal) {
|
||||||
|
/* the block has ended (without producing more data), but we
|
||||||
|
can't return without data, so start procesing next block */
|
||||||
|
goto next_blk;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (res != TINF_OK) {
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
} while (--d->destSize);
|
||||||
|
|
||||||
|
return TINF_OK;
|
||||||
|
}
|
||||||
Loading…
Add table
Reference in a new issue