Set up a new repo based on BOOTBOOT sources

This commit is contained in:
Thomas Oltmann 2025-03-15 18:48:09 +01:00
commit 5d58b46bbe
13 changed files with 3797 additions and 0 deletions

155
include/bootboot.h Normal file
View 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
View file

@ -0,0 +1,2 @@
*.o
!crt0-efi-x86_64.o

35
x86_64-efi/Makefile Normal file
View 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

File diff suppressed because it is too large Load diff

Binary file not shown.

278
x86_64-efi/efirom.c Normal file
View 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;
}

View 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
View 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

Binary file not shown.

BIN
x86_64-efi/libgnuefi.a Normal file

Binary file not shown.

112
x86_64-efi/smp.S Normal file
View 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
View 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
View 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;
}