Got it to run on the test laptop
This commit is contained in:
parent
8dbeccbe75
commit
98da895f18
9 changed files with 1234 additions and 3 deletions
5
Makefile
5
Makefile
|
|
@ -6,6 +6,7 @@ OBJS=\
|
|||
src/pxe.o \
|
||||
src/std.o \
|
||||
src/main.o \
|
||||
src/tinflate.o \
|
||||
# end of object list
|
||||
|
||||
.PHONY: all clean
|
||||
|
|
@ -23,10 +24,12 @@ boot.bin: boot.elf
|
|||
wc -c $@
|
||||
|
||||
boot.elf: $(OBJS) src/nbp.ld
|
||||
$(LD) $(LDFLAGS) -T src/nbp.ld -o $@ $(OBJS)
|
||||
$(CC) -m32 -fno-pic -fno-pie -T src/nbp.ld -o $@ $(OBJS) -ffreestanding -nostdlib
|
||||
|
||||
%.o: %.S
|
||||
$(CC) $(CFLAGS) -c -o $@ $(@:.o=.S) $(CPPFLAGS)
|
||||
|
||||
%.o: %.c
|
||||
$(CC) $(CFLAGS) -O0 -c -o $@ $(@:.o=.c) $(CPPFLAGS)
|
||||
|
||||
# TODO header dependencies
|
||||
|
|
|
|||
|
|
@ -5,4 +5,4 @@ LD = ld
|
|||
|
||||
CFLAGS = -no-pie -fno-pic -fno-stack-protector -nostdinc -ffreestanding -m32
|
||||
CPPFLAGS = -I3rdparty/include
|
||||
LDFLAGS = -m elf_i386
|
||||
LDFLAGS = -m elf_i386 -fno-pic
|
||||
|
|
|
|||
20
eth-dnsmasq.conf
Normal file
20
eth-dnsmasq.conf
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
#listen-address=10.0.0.1
|
||||
#bind-dynamic
|
||||
#bind-interfaces
|
||||
#except-interface=lo
|
||||
interface=enp6s0f3u1
|
||||
|
||||
dhcp-range=10.0.0.2,10.0.0.100,255.255.255.0,6h
|
||||
dhcp-boot=/boot.bin
|
||||
#dhcp-option=66,"10.0.0.1"
|
||||
#dhcp-option=67,"/boot.bin"
|
||||
#dhcp-option=67,"/pxelinux.0"
|
||||
|
||||
log-async
|
||||
|
||||
# Disable DNS server
|
||||
port=0
|
||||
|
||||
enable-tftp
|
||||
tftp-root=/home/thomas/karlos/fernlader2/serve
|
||||
|
||||
364
src/fs.h
Normal file
364
src/fs.h
Normal file
|
|
@ -0,0 +1,364 @@
|
|||
/*
|
||||
* x86_64-cb/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.
|
||||
*
|
||||
*/
|
||||
|
||||
#if 0
|
||||
/**
|
||||
* 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 || memcmp(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;
|
||||
PRINTFS("FS/Z",kernel);
|
||||
//decrypt initrd
|
||||
if(*((uint32_t*)(initrd_p+520))!=0 && (initrd_p[519]&&0xF0)!=0) {
|
||||
printf("BOOTBOOT-PANIC: Unsupported cipher\n");
|
||||
return ret;
|
||||
}
|
||||
while(*((uint32_t*)(initrd_p+520))!=0) {
|
||||
printf(" * Passphrase? ");
|
||||
l=ReadLine(passphrase,sizeof(passphrase));
|
||||
if(!l) {
|
||||
printf("\n");
|
||||
return ret;
|
||||
}
|
||||
if(*((uint32_t*)(initrd_p+520))!=crc32_calc((char*)passphrase,l)) {
|
||||
printf("\rBOOTBOOT-ERROR: Bad passphrase\n");
|
||||
continue;
|
||||
}
|
||||
printf("\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);
|
||||
// FSZ_SB_EALG_SHACBC
|
||||
for(k=ss,j=1;j<*((uint32_t*)(initrd_p+528));j++) {
|
||||
memcpy(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];
|
||||
}
|
||||
}
|
||||
memset(initrd_p+680,0,32); *((uint32_t*)(initrd_p+520)) = 0;
|
||||
*((uint32_t*)(initrd_p+1020))=crc32_calc((char *)initrd_p+512,508);
|
||||
printf(" \r");
|
||||
}
|
||||
// Get the inode
|
||||
char *s,*e;
|
||||
s=e=kernel;
|
||||
i=0;
|
||||
again:
|
||||
while(*e!='/'&&*e!=0){e++;}
|
||||
if(*e=='/'){e++;}
|
||||
if(!memcmp(in,"FSIN",4)){
|
||||
//is it inlined?
|
||||
if(!memcmp(initrd_p[520]&1? in + 2048 : in + 1024,"FSDR",4)){
|
||||
ent=(initrd_p[520]&1? in + 2048 : in + 1024);
|
||||
} else if(!memcmp(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(!memcmp(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(!memcmp(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;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* 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_t o, bs, ino_tbl;
|
||||
uint8_t *ino, *d;
|
||||
char *s = kernel, *e;
|
||||
file_t ret = { NULL, 0 };
|
||||
if(initrd_p[1048] != 'Z' || initrd_p[1049] != 'M') return ret;
|
||||
PRINTFS("MFS",kernel);
|
||||
bs = *((uint16_t*)(initrd_p + 1052));
|
||||
ino_tbl = (2 + *((uint16_t*)(initrd_p + 1030)) + *((uint16_t*)(initrd_p + 1032))) * bs;
|
||||
ino = initrd_p + ino_tbl;
|
||||
again:
|
||||
for(e = s; *e && *e != '/'; e++);
|
||||
d = initrd_p + *((uint32_t*)(ino + 24)) * bs;
|
||||
for(o = 0; o < *((uint32_t*)(ino + 8)) && o < bs; o += 64, d += 64) {
|
||||
if(*((uint32_t*)d) && !memcmp(s, d + 4, e - s) && !d[e - s]) {
|
||||
ino = initrd_p + ino_tbl + (*((uint32_t*)d) - 1) * 64;
|
||||
d = initrd_p + *((uint32_t*)(ino + 24)) * bs;
|
||||
if(!*e) { ret.ptr = d; ret.size = *((uint32_t*)(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 ||
|
||||
(memcmp(initrd_p,"070701",6) && memcmp(initrd_p,"070702",6) && memcmp(initrd_p,"070707",6)))
|
||||
return ret;
|
||||
PRINTFS("cpio",kernel);
|
||||
k=strlen(kernel);
|
||||
// hpodc archive
|
||||
while(!memcmp(ptr,"070707",6)){
|
||||
int ns=octbin(ptr+8*6+11,6);
|
||||
int fs=octbin(ptr+8*6+11+6,11);
|
||||
if(!memcmp(ptr+9*6+2*11,kernel,k+1) ||
|
||||
(ptr[9*6+2*11] == '.' && ptr[9*6+2*11+1] == '/' && !memcmp(ptr+9*6+2*11+2,kernel,k+1))) {
|
||||
ret.size=fs;
|
||||
ret.ptr=(uint8_t*)(ptr+9*6+2*11+ns);
|
||||
return ret;
|
||||
}
|
||||
ptr+=(76+ns+fs);
|
||||
}
|
||||
// newc and crc archive
|
||||
while(!memcmp(ptr,"07070",5)){
|
||||
int fs=hexbin(ptr+8*6+6,8);
|
||||
int ns=hexbin(ptr+8*11+6,8);
|
||||
if(!memcmp(ptr+110,kernel,k+1) || (ptr[110] == '.' && ptr[111] == '/' && !memcmp(ptr+112,kernel,k+1))) {
|
||||
ret.size=fs;
|
||||
ret.ptr=(uint8_t*)(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 || memcmp(initrd_p+257,"ustar",5))
|
||||
return ret;
|
||||
PRINTFS("tar",kernel);
|
||||
k=strlen(kernel);
|
||||
while(!memcmp(ptr+257,"ustar",5)){
|
||||
int fs=octbin(ptr+0x7c,11);
|
||||
if(!memcmp(ptr,kernel,k+1) || (ptr[0] == '.' && ptr[1] == '/' && !memcmp(ptr+2,kernel,k+1))) {
|
||||
ret.size=fs;
|
||||
ret.ptr=(uint8_t*)(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 || (memcmp(initrd_p+0x1AC,"SFS",3) && memcmp(initrd_p+0x1A6,"SFS",3)))
|
||||
return ret;
|
||||
// 1.0 Brendan's version, 1.10 BenLunt's version
|
||||
ver=!memcmp(initrd_p+0x1A6,"SFS",3)?10:0;
|
||||
bs=1<<(7+(uint8_t)initrd_p[ver?0x1B6:0x1BC]);
|
||||
end=initrd_p + *((uint64_t *)&initrd_p[ver?0x1AA:0x1B0]) * bs; // base + total_number_of_blocks * blocksize
|
||||
// get index area
|
||||
ptr=end - *((uint64_t *)&initrd_p[ver?0x19E:0x1A4]); // end - size of index area
|
||||
// got a Starting Marker Entry?
|
||||
if(ptr[0]!=2)
|
||||
return ret;
|
||||
if (ver) {
|
||||
PRINTFS("SFS 1.10",kernel);
|
||||
} else {
|
||||
PRINTFS("SFS 1.0",kernel);
|
||||
}
|
||||
k=strlen(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(!memcmp(ptr+(ver?0x23:0x22),kernel,k+1)){
|
||||
ret.size=*((uint64_t*)&ptr[ver?0x1B:0x1A]); // file_length
|
||||
ret.ptr=initrd_p + *((uint64_t*)&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;
|
||||
PRINTFS("JamesM",kernel);
|
||||
k=strlen(kernel);
|
||||
for(i=0;i<nf && ptr[0]==0xBF;i++) {
|
||||
if(!memcmp(ptr+1,kernel,k+1)){
|
||||
ret.ptr=*((uint32_t*)(ptr+65)) + initrd_p;
|
||||
ret.size=*((uint32_t*)(ptr+69));
|
||||
}
|
||||
ptr+=73;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if 0
|
||||
/**
|
||||
* EchFS
|
||||
* http://github.com/echfs/echfs
|
||||
*/
|
||||
file_t ech_initrd(unsigned char *initrd_p, char *kernel)
|
||||
{
|
||||
uint64_t parent = 0xffffffffffffffffUL, n;
|
||||
unsigned char *ptr;
|
||||
char *end, *fn;
|
||||
int k = 0;
|
||||
file_t ret = { NULL, 0 };
|
||||
if(initrd_p==NULL || kernel==NULL || memcmp(initrd_p+4,"_ECH_FS_",8))
|
||||
return ret;
|
||||
PRINTFS("EchFS",kernel);
|
||||
memcpy(&k, initrd_p + 28, 4);
|
||||
memcpy(&n, initrd_p + 12, 8);
|
||||
ptr = initrd_p + (((n * 8 + k - 1) / k) + 16) * k;
|
||||
for(end = fn = kernel; *end && *end != '/'; end++);
|
||||
while(*((uint64_t*)ptr)) {
|
||||
if(*((uint64_t*)ptr) == parent && !memcmp(ptr + 9, fn, end - fn) && !ptr[9 + end - fn]) {
|
||||
parent = *((uint64_t*)(ptr + 240));
|
||||
if(!*end) {
|
||||
ret.size=*((uint64_t*)(ptr + 248));
|
||||
ret.ptr=(uint8_t*)(initrd_p + parent * k);
|
||||
break;
|
||||
}
|
||||
end++;
|
||||
for(fn = end; *end && *end != '/'; end++);
|
||||
}
|
||||
ptr += 256;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Static file system drivers registry
|
||||
*/
|
||||
file_t (*fsdrivers[]) (unsigned char *, char *) = {
|
||||
#if 0
|
||||
fsz_initrd,
|
||||
#endif
|
||||
mfs_initrd,
|
||||
cpio_initrd,
|
||||
tar_initrd,
|
||||
sfs_initrd,
|
||||
jamesm_initrd,
|
||||
#if 0
|
||||
ech_initrd,
|
||||
#endif
|
||||
NULL
|
||||
};
|
||||
49
src/main.c
49
src/main.c
|
|
@ -205,6 +205,55 @@ typedef struct __attribute__((packed)) s_PXENV_TFTP_OPEN {
|
|||
uint16_t packet_size;
|
||||
} t_PXENV_TFTP_OPEN;
|
||||
|
||||
/**
|
||||
* return type for fs drivers
|
||||
*/
|
||||
typedef struct {
|
||||
uint8_t *ptr;
|
||||
uint32_t size;
|
||||
} file_t;
|
||||
|
||||
/**
|
||||
* convert ascii octal number to binary number
|
||||
*/
|
||||
int octbin(unsigned char *str,int size)
|
||||
{
|
||||
int s=0;
|
||||
unsigned char *c=str;
|
||||
while(size-->0){
|
||||
s*=8;
|
||||
s+=*c-'0';
|
||||
c++;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
/**
|
||||
* convert ascii hex number to binary number
|
||||
*/
|
||||
int hexbin(unsigned char *str, int size)
|
||||
{
|
||||
int v=0;
|
||||
while(size-->0){
|
||||
v <<= 4;
|
||||
if(*str>='0' && *str<='9')
|
||||
v += (int)((unsigned char)(*str)-'0');
|
||||
else if(*str >= 'A' && *str <= 'F')
|
||||
v += (int)((unsigned char)(*str)-'A'+10);
|
||||
str++;
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
#define PRINTFS(fsname,kernel) do {\
|
||||
debug_write(fsname);\
|
||||
debug_write(" ");\
|
||||
debug_write(kernel);\
|
||||
debug_write("\r\n");\
|
||||
} while (0)
|
||||
|
||||
#include "fs.h"
|
||||
|
||||
void
|
||||
main()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ _start: cli
|
|||
|
||||
// initialize our own BSS section
|
||||
mov $_bss_start, %di
|
||||
mov $_bss_end, %cx
|
||||
mov $_bss_end, %ecx
|
||||
sub %di, %cx
|
||||
xor %al, %al
|
||||
rep stosb
|
||||
|
|
|
|||
203
src/smp.S
Normal file
203
src/smp.S
Normal file
|
|
@ -0,0 +1,203 @@
|
|||
/*
|
||||
* x86_64-cb/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 and long mode initialization code.
|
||||
*
|
||||
*/
|
||||
|
||||
.globl ap_trampoline
|
||||
.globl bsp_init
|
||||
.globl bsp64_init
|
||||
.extern lapic_ids
|
||||
.extern lapic_addr
|
||||
.extern initstack
|
||||
|
||||
.text
|
||||
|
||||
/*****************************************************************************
|
||||
* things to do on the APs *
|
||||
*****************************************************************************/
|
||||
.balign 128
|
||||
.code16
|
||||
/* this code will be relocated to 0x1000 - 0x1100 */
|
||||
ap_trampoline:
|
||||
cli
|
||||
cld
|
||||
ljmp $0, $0x1040
|
||||
.balign 16
|
||||
// prot mode GDT
|
||||
_L1010_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
|
||||
_L1030_GDT_value:
|
||||
.word _L1030_GDT_value - _L1010_GDT_table - 1
|
||||
.long 0x1010
|
||||
.long 0, 0
|
||||
.balign 64
|
||||
_L1040:
|
||||
xorw %ax, %ax
|
||||
movw %ax, %ds
|
||||
lgdtl 0x1030
|
||||
movl %cr0, %eax
|
||||
orl $1, %eax
|
||||
movl %eax, %cr0
|
||||
ljmp $8, $0x1060
|
||||
.balign 32
|
||||
.code32
|
||||
_L1060:
|
||||
movw $16, %ax
|
||||
movw %ax, %ds
|
||||
incb 0x1011
|
||||
// spinlock until BSP finishes
|
||||
1: pause
|
||||
cmpb $0, 0x1010
|
||||
jz 1b
|
||||
// jump back to non-relocated code segment
|
||||
ljmp $8, $longmode_init
|
||||
.balign 128
|
||||
ap_trampoline_end:
|
||||
|
||||
// long mode GDT (here it is aligned and out of execution flow)
|
||||
GDT_table:
|
||||
.long 0, 0
|
||||
.long 0x0000FFFF, 0x00209800 // flat code, ring 0
|
||||
.long 0x0000FFFF, 0x00809200 // flat data
|
||||
.long 0x00000068, 0x00008900 // tss, required by vt-x
|
||||
.long 0, 0
|
||||
GDT_value:
|
||||
.word GDT_value - GDT_table - 1
|
||||
.long GDT_table, 0, 0
|
||||
.word 0
|
||||
.balign 8
|
||||
stack64:
|
||||
.long bootboot_startcore
|
||||
.long 0
|
||||
.quad 8
|
||||
|
||||
/*****************************************************************************
|
||||
* things to do on BSP *
|
||||
*****************************************************************************/
|
||||
/* these are 32 bit encoded instructions */
|
||||
bsp_init:
|
||||
cli
|
||||
cld
|
||||
movb $0xFF, %al // disable PIC
|
||||
outb %al, $0x21
|
||||
outb %al, $0xA1
|
||||
inb $0x70, %al // disable NMI
|
||||
orb $0x80, %al
|
||||
outb %al, $0x70
|
||||
incb 0x1010 // release AP spin lock
|
||||
// fall into long mode initialization code
|
||||
|
||||
/*****************************************************************************
|
||||
* common code for all cores, enable long mode and start kernel *
|
||||
*****************************************************************************/
|
||||
longmode_init:
|
||||
// enable lapic and find our lapic id
|
||||
movl lapic_addr, %edi
|
||||
or %edi, %edi
|
||||
jz 1f
|
||||
addl $0xF0, %edi
|
||||
movl (%edi), %eax
|
||||
or $0x1, %ah
|
||||
movl %eax, (%edi)
|
||||
subl $0xD0, %edi
|
||||
movl (%edi), %edi
|
||||
shrl $24, %edi
|
||||
1: // do not clobber di
|
||||
|
||||
movl $0x368, %eax // Set PAE, MCE, PGE; OSFXSR, OSXMMEXCPT (enable SSE)
|
||||
movl %eax, %cr4
|
||||
movl $0x4000, %eax
|
||||
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
|
||||
lgdt GDT_value
|
||||
ljmp $8, $bootboot_startcore
|
||||
|
||||
.code64
|
||||
/* similar code to above, but these are 64 bit encoded, only needed on BSP if coreboot is compiled for x86_64 */
|
||||
bsp64_init:
|
||||
// do not clobber di
|
||||
cli
|
||||
cld
|
||||
movb $0xFF, %al // disable PIC
|
||||
outb %al, $0x21
|
||||
outb %al, $0xA1
|
||||
inb $0x70, %al // disable NMI
|
||||
orb $0x80, %al
|
||||
outb %al, $0x70
|
||||
incb 0x1010 // release AP spin lock
|
||||
|
||||
xorq %rax, %rax
|
||||
movl $0xC0000011, %eax // enable SSE
|
||||
movq %rax, %cr0
|
||||
movq %cr4, %rax
|
||||
orw $3 << 8, %ax
|
||||
mov %rax, %cr4
|
||||
movl $0x4000, %eax // set up paging
|
||||
movq %rax, %cr3
|
||||
xorq %rax, %rax
|
||||
movl $GDT_value, %eax
|
||||
lgdt (%rax)
|
||||
movl $stack64, %eax // reload CS, that's tricky in long mode because ljmp doesn't work
|
||||
movq %rax, %rsp
|
||||
lretq
|
||||
|
||||
/* IN: di = apic id of current core */
|
||||
bootboot_startcore:
|
||||
movl $0x10, %eax // load long mode segments
|
||||
movw %ax, %ds
|
||||
movw %ax, %es
|
||||
movw %ax, %ss
|
||||
movw %ax, %fs
|
||||
movw %ax, %gs
|
||||
movzwq %di, %rbx
|
||||
shll $1, %ebx // ebx = lapic id * 2
|
||||
addl $lapic_ids, %ebx
|
||||
xorq %rax, %rax
|
||||
movw (%rbx), %ax // ax = word[lapic_ids + lapic id * 2]
|
||||
movl $initstack, %ebx
|
||||
movl (%rbx), %ebx
|
||||
movzwq %ax, %rdi
|
||||
mulq %rbx // 1k stack for each core
|
||||
|
||||
// set stack and call _start() in sys/core
|
||||
xorq %rsp, %rsp // sp = core_num * -initstack
|
||||
subq %rax, %rsp
|
||||
xorq %rsi, %rsi
|
||||
movl $entrypoint, %esi // GAS does not allow "jmp qword[entrypoint]"
|
||||
lodsq
|
||||
jmp *%rax
|
||||
hlt
|
||||
117
src/tinf.h
Normal file
117
src/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 "std.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
src/tinflate.c
Normal file
475
src/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