1
0
Fork 0
mirror of https://gitlab.com/bztsrc/bootboot.git synced 2023-02-13 20:54:32 -05:00

Additional BPs

This commit is contained in:
bzt 2020-12-30 20:34:42 +01:00
commit d7d2aff8e7
6 changed files with 4222 additions and 0 deletions

25
Makefile Normal file
View file

@ -0,0 +1,25 @@
all: bootboot.bin bootboot.sym refresh
bootboot.bin: bootboot.asm
@echo " src x86_64-bios (MultiBoot / BIOS)"
@cat bootboot.asm | grep -v "^public" | grep -v "format ELF64" >bb.asm
@fasm bb.asm bootboot.bin >/dev/null
@rm bb.asm
bootboot.sym: bootboot.asm
@echo " sym bootboot.sym"
@fasm bootboot.asm bootboot.elf >/dev/null
@nm bootboot.elf | sort | sed 's/\ A\ /\ /g' > bootboot.sym
@printf "fffffffff8000000 mmio\nfffffffffc000000 fb\nffffffffffe00000 bootboot\nffffffffffe01000 environment\nffffffffffe02000 _start\n" >>bootboot.sym
@rm bootboot.elf
disk-x86.img: disk-x86.img.gz
@gzip -d -k disk-x86.img.gz
refresh: bootboot.bin disk-x86.img
@echo " dd bootboot.bin to disk-x86.img"
@dd if=bootboot.bin of=disk-x86.img bs=1 seek=120832 conv=notrunc 2>/dev/null
clean:
@rm bootboot.bin bootboot.sym disk-x86.img >/dev/null 2>/dev/null || true

2916
bootboot.asm Normal file

File diff suppressed because it is too large Load diff

125
bootboot.inc Normal file
View file

@ -0,0 +1,125 @@
;*
;* x86_64-bios/bootboot.inc
;*
;* Copyright (C) 2017 - 2020 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
;*
; ------ !!! WARNING: MUST MATCH ../bootboot.h !!! ------
bootboot = 8000h
; this define is in the 18th line of bootboot.h
bootboot_MAGIC equ 'BOOT'
; minimum protocol level:
; hardcoded kernel name, static kernel memory addresses
PROTOCOL_MINIMAL equ 0
; static protocol level:
; kernel name parsed from environment, static kernel memory addresses
PROTOCOL_STATIC equ 1
; dynamic protocol level:
; kernel name parsed from environment, kernel memory addresses parsed from ELF symbols
PROTOCOL_DYNAMIC equ 2
; big-endian flag
PROTOCOL_BIGENDIAN equ 080h
; loader types, just informational
LOADER_BIOS equ 0
LOADER_UEFI equ 4
LOADER_RPI equ 8
LOADER_COREBOOT equ 16
; framebuffer pixel format, only 32 bits supported
FB_ARGB equ 0
FB_RGBA equ 1
FB_ABGR equ 2
FB_BGRA equ 3
; mmap entry, type is stored in least significant tetrad of size
virtual at 0
mmap_ent.ptr: dq 0
mmap_ent.size: dq 0
end virtual
; we don't have entry field macros for asm
; realsize = size & 0xFFFFFFFFFFF0
; type = size & 0xF
MMAP_USED equ 0
MMAP_FREE equ 1
MMAP_ACPI equ 2
MMAP_MMIO equ 3
INITRD_MAXSIZE equ 16 ; Mb
virtual at bootboot
; first 64 bytes is platform independent
bootboot.magic: dd 0
bootboot.size: dd 0
bootboot.protocol: db 1
bootboot.fb_type: db 0
bootboot.numcores: dw 0
bootboot.bspid: dw 0
bootboot.timezone: dw 0
bootboot.datetime: dq 0
bootboot.initrd_ptr: dq 0
bootboot.initrd_size: dq 0
bootboot.fb_ptr: dq 0
bootboot.fb_size: dd 0
bootboot.fb_width: dd 0
bootboot.fb_height: dd 0
bootboot.fb_scanline: dd 0
; the rest (64 bytes) is platform specific
; x86_64
bootboot.acpi_ptr: dq 0
bootboot.smbi_ptr: dq 0
bootboot.efi_ptr: dq 0
bootboot.mp_ptr: dq 0
bootboot.unused: dq 0,0,0,0
bootboot.mmap:
end virtual

BIN
disk-x86.img.gz Normal file

Binary file not shown.

656
fs.inc Normal file
View file

@ -0,0 +1,656 @@
;*
;* x86_64-bios/fs.inc
;*
;* Copyright (C) 2017 - 2020 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.
;*
;*********************************************************************
;* File System Drivers *
;*********************************************************************
USE32
fsdrivers:
dw fsz_initrd
dw cpio_initrd
dw tar_initrd
dw sfs_initrd
dw jamesm_initrd
dw 0
; ----------- FS/Z ----------
; Find the kernel on initrd (only supports 4096 logical sector sizes)
; IN: esi: initrd pointer, ecx: initrd end, edi: kernel filename
; OUT: On Success
; esi: pointer to the first byte, ecx: size in bytes
; On Error
; ecx: 0
fsz_initrd:
mov ebx, ecx
xor ecx, ecx
; FS/Z superblock
cmp dword [esi+512], 'FS/Z' ; FSZ_SuperBlock.magic
jne .nolib
; encrypted initrd?
cmp dword [esi+708], 0 ; FSZ_SuperBlock.enchash
jz .noenc
mov al, byte [esi+518] ; FSZ_SuperBlock.flags
shr al, 2
and al, 7
or al, al
jz @f
prot_realmode
real_print loader.name
real_print panic
mov esi, nocipher
call real_printfunc
real_protmode
jmp .err
@@: push edi
prot_realmode
.passagain: real_print passphrase
; get passphrase from user
mov di, pass
mov byte [di], 0
.getchar: call real_getchar
cmp al, 27 ; Esc
jne @f
real_print clrdecrypt
jmp .err
@@: cmp al, 8 ; Backspace
jne @f
cmp di, pass
je .getchar
mov byte [di], 0
dec di
jmp .getchar
@@: cmp al, 13 ; Enter
je .gotpass
cmp al, 10
je .gotpass
cmp al, ' '
jb .getchar
cmp di, pass+255
jge .getchar
mov word [di], ax
inc di
jmp .getchar
.gotpass: push esi
real_protmode
mov esi, pass
mov ecx, edi
sub ecx, esi
mov dword [pl], ecx
call crc32_calc
prot_realmode
pop esi
cmp dword [esi+708], edx
je .passok
real_print badpass
jmp .passagain
.passok: real_print decrypting
real_protmode
; decrypt initrd
call sha_init
mov ecx, dword [pl]
mov ebx, pass
call sha_upd
mov ecx, 6
mov ebx, esi
add ebx, 512 ; FSZ_SuperBlock.magic
call sha_upd
mov edi, chk
call sha_final
mov edi, esi
add edi, 680 ; FSZ_SuperBlock.encrypt
mov cl, 28
xor ebx, ebx
@@: mov al, byte [edi]
xor byte [chk+ebx], al
xor eax, eax
stosb
inc ebx
dec cl
jnz @b
stosd
call sha_init
mov ecx, 28
mov ebx, chk
call sha_upd
mov edi, iv
call sha_final
mov eax, dword [esi+528] ; FSZ_SuperBlock.numsec
mov dword [pl], eax
xor eax, eax
inc eax
mov dword [_i], eax ; skip first sector
mov ebx, esi
add ebx, 4096
push esi
.decrypt: mov esi, iv
mov edi, chk
xor ecx, ecx
mov cl, 32/4
repnz movsd
mov cx, 4096
.nextblk: mov al, bl
and al, 31
jnz @f
push ebx
push ecx
call sha_init
mov ecx, 32
mov ebx, chk
call sha_upd
mov ecx, 4
mov ebx, _i
call sha_upd
mov edi, chk
call sha_final
pop ecx
pop ebx
mov edx, edi
@@: mov al, byte [edx]
xor byte [ebx], al
mov al, byte [edx+32]
xor byte [ebx], al
inc ebx
inc edx
dec cx
jnz .nextblk
inc dword [_i]
mov eax, dword [_i]
cmp eax, dword [pl]
jne .decrypt
mov esi, dword [esp]
add esi, 512
mov ecx, 508
call crc32_calc
pop esi
mov dword [esi+1020], edx ; FSZ_SuperBlock.chksum
; clear console message
prot_realmode
real_print clrdecrypt
real_protmode
pop edi
; get root dir inode
.noenc: mov dword [_i], 1024
mov al, byte [esi+518] ; FSZ_SuperBlock.flags
bt ax, 0 ; FSZ_FLAG_BIGINODE?
jnc @f
mov dword [_i], 2048
@@: mov eax, dword [esi+560] ; FSZ_SuperBlock.rootdirfid
shl eax, 12
add esi, eax
cmp dword [esi], 'FSIN'
je @f
.nolib: mov esi, nolib
.err: xor ecx, ecx
ret
.nocore: mov esi, nocore
jmp .err
@@: ; it has inlined data?
.again: mov eax, dword [esi+448] ; FSZ_Inode.sec
add esi, dword[_i] ; FSZ_Inode.[big|small].inlinedata
cmp dword [esi], 'FSDR'
je .srchdir
; no, locate the data
mov ecx, dword [esi]
shl eax, 12
mov esi, dword [bootboot.initrd_ptr]
add esi, eax
cmp dword [esi], 'FSDR'
je .srchdir
; inlined sector directory or list?
shl ecx, 12
mov esi, dword [bootboot.initrd_ptr]
add esi, ecx
cmp dword [esi], 'FSDR'
jne .nolib
.srchdir: ; find sys/
mov ecx, dword [esi+16] ; FSZ_DirEntHeader.numentries
mov eax, dword [edi]
@@: add esi, 128 ; directories than
cmp dword [esi+17], eax
je @f
dec ecx
jnz @b
jmp .nolib
; found, get it's inode
@@:
mov eax, dword [esi]
shl eax, 12
mov esi, dword [bootboot.initrd_ptr]
add esi, eax
cmp dword [esi], 'FSIN'
jne .nolib
;this is not bullet proof
add edi, 4
cmp byte [edi+3], '/'
je .again
; it has inlined data?
mov eax, dword [esi+448] ; FSZ_Inode.sec
add esi, dword[_i] ; FSZ_Inode.[big|small].inlinedata
cmp dword [esi], 'FSDR'
je .srchcore
; no, locate the data
mov ecx, dword [esi]
shl eax, 12
mov esi, dword [bootboot.initrd_ptr]
add esi, eax
cmp dword [esi], 'FSDR'
je .srchdir
; inlined sector directory or list?
shl ecx, 12
mov esi, dword [bootboot.initrd_ptr]
add esi, ecx
cmp dword [esi], 'FSDR'
jne .nolib
.srchcore: ; find filename
mov ecx, dword [esi+16] ; FSZ_DirEntHeader.numentries
;filename, 8 characters supported
mov eax, dword [edi]
mov edx, dword [edi+4]
@@: add esi, 128
cmp dword [esi+21], edx
jne .not
cmp dword [esi+17], eax
je @f
.not: dec ecx
jnz @b
jmp .nocore
; found, get it's inode
@@: mov eax, dword [esi]
shl eax, 12
mov esi, dword [bootboot.initrd_ptr]
add esi, eax
cmp dword [esi], 'FSIN'
jne .nocore
; get data
mov eax, dword [esi+448] ; FSZ_Inode.sec
mov ecx, dword [esi+464] ; FSZ_Inode.size
mov bl, byte [esi+488] ; FSZ_Inode.flags
; inline
cmp bl, 0FFh ; FSZ_IN_FLAG_INLINE
jne @f
add esi, dword[_i] ; FSZ_Inode.[big|small].inlinedata
ret
; direct data block
@@: or bl, bl ; FSZ_IN_FLAG_DIRECT
je .load
; inlined sector directory or sector list
@@: cmp bl, 07Fh ; FSZ_IN_FLAG_SDINLINE
je @f
cmp bl, 080h ; FSZ_IN_FLAG_SECLIST
je @f
cmp bl, 1 ; FSZ_IN_FLAG_SD
jne .nocore
shl eax, 12
mov esi, dword [bootboot.initrd_ptr]
add esi, eax
mov eax, dword [esi] ; first FSZ_SectorList.sec
jmp .load
@@: add esi, dword[_i] ; FSZ_Inode.[big|small].inlinedata
; sector directory at esi, file size in ecx
mov eax, dword [esi] ; first FSZ_SectorList.sec
.load: shl eax, 12
mov esi, dword [bootboot.initrd_ptr]
add esi, eax
ret
; ----------- cpio ----------
; Find the kernel on initrd
; IN: esi: initrd pointer, ecx: initrd end, edi: kernel filename
; OUT: On Success
; esi: pointer to the first byte, ecx: size in bytes
; On Error
; ecx: 0
cpio_initrd:
; upper bound
mov ebx, ecx
xor ecx, ecx
; strlen(kernel)
mov eax, edi
or eax, eax
jz .err
cmp byte [eax], 0
jz .err
xor ecx, ecx
@@: inc ecx
inc eax
cmp byte [eax], 0
jnz @b
mov dword [.ks], ecx
; while(ptr.magic=='070707' && ptr<limit)
.next: cmp esi, ebx
jae .err
mov eax, '0707'
cmp dword [esi], eax ; cpio magic
jne .err
cmp word [esi+4], ax ; hpodc
je @f
cmp word [esi+4], '01' ; newc
je .newc
cmp word [esi+4], '02' ; crc
je .newc
.err: xor ecx, ecx
ret
@@: mov eax, esi ; filename len
add eax, 8*6+11
mov ecx, 6
call prot_oct2bin
mov dword [.ns], eax
mov eax, esi ; filesize
add eax, 8*6+11+6
mov ecx, 11
call prot_oct2bin
mov dword [.fs], eax
push esi ; name equals?
push edi
add esi, 9*6+2*11
mov ecx, dword [.ks]
cmp word [esi], './'
jne .notcurdir
add esi, 2
sub ecx, 2
.notcurdir: repz cmpsb
pop edi
pop esi
jz @f
add esi, 76 ; no skip this record
add esi, dword [.ns] ; and check the next one
add esi, dword [.fs]
jmp .next
@@: add esi, 76 ; found! esi=data
add esi, dword [.ns]
mov ecx, dword [.fs] ; ecx=size
ret
.newc: mov edx, esi ; filename len
add esi, 8*11+6
mov ecx, 8
call prot_hex2bin
mov dword [.ns], eax
mov esi, edx ; filesize
add esi, 8*6+6
mov ecx, 8
call prot_hex2bin
mov dword [.fs], eax
mov esi, edx
push esi ; name equals?
push edi
add esi, 110
mov ecx, dword [.ks]
cmp word [esi], './'
jne .notcudir
add esi, 2
sub ecx, 2
.notcudir: repz cmpsb
pop edi
pop esi
jz @f
mov eax, 113 ; no skip this record
add eax, dword [.ns] ; and check the next one
and al, 0FCh
add esi, eax
mov eax, dword [.fs]
add eax, 3
and al, 0FCh
add esi, eax
cmp dword [esi], '0707' ; cpio magic
jne .err
jmp .newc
@@: mov eax, 113 ; found! esi=data
add eax, dword [.ns]
and al, 0FCh
add esi, eax
mov ecx, dword [.fs] ; ecx=size
ret
.ks: dd 0
.ns: dd 0
.fs: dd 0
; ----------- tar ----------
; Find the kernel on initrd
; IN: esi: initrd pointer, ecx: initrd end, edi: kernel filename
; OUT: On Success
; esi: pointer to the first byte, ecx: size in bytes
; On Error
; ecx: 0
tar_initrd:
; upper bound
mov ebx, ecx
xor ecx, ecx
; strlen(kernel)
mov eax, edi
or eax, eax
jz .err
cmp byte [eax], 0
jz .err
xor ecx, ecx
@@: inc ecx
inc eax
cmp byte [eax], 0
jnz @b
mov dword [.ks], ecx
; while(ptr.magic=='ustar' && ptr<limit)
.next: cmp esi, ebx
jae .err
cmp dword [esi+257], 'usta' ; tar magic
jne .err
cmp byte [esi+261], 'r' ; tar magic
je @f
.err: xor ecx, ecx
ret
@@: mov eax, esi ; filesize
add eax, 07ch
mov ecx, 11
call prot_oct2bin
mov dword [.fs], eax
push esi ; name equals?
push edi
mov ecx, dword [.ks]
cmp word [esi], './'
jne .notcurdir
add esi, 2
sub ecx, 2
.notcurdir: repz cmpsb
pop edi
pop esi
jz @f
add esi, 512 ; no skip this record
mov eax, dword [.fs] ; and check the next one
add eax, 511
shr eax, 9
shl eax, 9
add esi, eax
jmp .next
@@: add esi, 512 ; found! esi=data
mov ecx, dword [.fs] ; ecx=size
ret
.ks: dd 0
.fs: dd 0
; ----------- SFS ----------
; Find the kernel on Stupid File System
; IN: esi: initrd pointer, ecx: initrd end, edi: kernel filename
; OUT: On Success
; esi: pointer to the first byte, ecx: size in bytes
; On Error
; ecx: 0
sfs_initrd:
; check magic
; 1.0, Brendan's version
mov byte [.ver], 0
cmp word [esi+01ACh], 'SF'
jne @f
cmp byte [esi+01AEh], 'S'
je .ok
; 1.1, BenLunt's version
@@: cmp word [esi+01A6h], 'SF'
jne .err
cmp byte [esi+01A8h], 'S'
jne .err
inc byte [.ver]
; upper bound
.ok: mov ebx, ecx
xor ecx, ecx
; strlen(kernel)
mov eax, edi
or eax, eax
jz .err
cmp byte [eax], 0
jz .err
xor ecx, ecx
@@: inc ecx
inc eax
cmp byte [eax], 0
jnz @b
mov dword [.ks], ecx
; get block size
xor eax, eax
inc eax
xor ecx, ecx
mov cl, byte [esi+01BCh]
cmp byte [.ver], 0
jz @f
mov cl, byte [esi+01B6h]
@@: add cl, 7
shl eax, cl
mov dword [.bs], ecx
; get index area, base + totalblocks*blocksize - indexsize
xor edx, edx
mov eax, dword [esi+01B0h] ; total number of blocks
cmp byte [.ver], 0
jz @f
mov eax, dword [esi+01AAh] ; total number of blocks
@@: mul ecx
add eax, esi
mov ebx, eax
mov edx, dword [esi+01A4h] ; size of index area
cmp byte [.ver], 0
jz @f
mov edx, dword [esi+019Eh] ; size of index area
@@: sub eax, edx
mov edx, esi
mov esi, eax
cmp byte [esi], 02h ; got Starting Marker Entry?
jne .err
; iterate on index until we reach end or Volume Identifier
.nextindex: cmp esi, ebx
jae .err
cmp byte [esi], 01h
je .err
add esi, 64
cmp byte [esi], 12h ; file entry?
jne .nextindex
push esi ; name equals?
push edi
mov ecx, dword [.ks]
add esi, 022h
add esi, dword [.ver]
repz cmpsb
pop edi
pop esi
jnz .nextindex
mov ebx, esi
mov eax, dword [esi+0Ah] ; start_block
cmp byte [.ver], 0
jz @f
mov eax, dword [esi+0Bh] ; start_block
@@: mov esi, edx
xor edx, edx
mov ecx, dword [.bs]
mul ecx ; * blocksize
add esi, eax ; base +
; found! esi=data, ecx=size
mov ecx, dword [ebx+01Ah] ; file_length
cmp byte [.ver], 0
jz @f
mov ecx, dword [ebx+01Bh] ; file_length
@@: ret
.err: xor ecx, ecx
ret
.ks: dd 0
.bs: dd 0
.ver: dd 0
; ----------- JamesMolloy's ----------
; Find the kernel on initrd
; IN: esi: initrd pointer, ecx: initrd end, edi: kernel filename
; OUT: On Success
; esi: pointer to the first byte, ecx: size in bytes
; On Error
; ecx: 0
jamesm_initrd:
; no real magic, so we assume initrd contains at least one file...
cmp word [esi+2], 0
jne .err
cmp byte [esi+4], 0BFh
jne .err
; upper bound
xor ecx, ecx
; strlen(kernel)
mov eax, edi
or eax, eax
jz .err
cmp byte [eax], 0
jz .err
xor ecx, ecx
@@: inc ecx
inc eax
cmp byte [eax], 0
jnz @b
mov dword [.ks], ecx
mov ebx, esi
; edx=*(int*)initrd_p
lodsd
mov edx, eax
; for(i=0;i<nf && ptr[0]==0xBF;i++)
@@: lodsb
cmp al, 0BFh
jne .err
push esi ; name equals?
push edi
mov ecx, dword [.ks]
repz cmpsb
pop edi
pop esi
jz @f
add esi, 72
dec dx
jnz @b
.err: xor ecx, ecx
ret
@@: mov ecx, dword [esi+68]
mov esi, dword [esi+64]
add esi, ebx
ret
.ks: dd 0

500
tinf.inc Normal file
View file

@ -0,0 +1,500 @@
;*
;* x86_64-bios/tinf.inc
;*
;* Copyright (C) 2017 - 2020 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 Tiny inflate, ported after tinflate.c by bzt
;*
;IN:
; esi: gzipped initrd (without gzip header)
; edi: output buffer (guaranteed to be big enough)
; ecx: output buffer size
tinf_uncompress:
push ecx
push edi
mov edi, tinf_bss_start
mov ecx, tinf_bss_end-tinf_bss_start+1
xor al, al
repnz stosb
pop edi
pop ecx
mov dword [d_end], ecx
add dword [d_end], edi
.again:
; start a new block
cmp byte [d_btype], 255
jne .notst
; read final block flag
.next_blk: call tinf_getbit
mov byte [d_bfinal], al
; read block type
xor ebx, ebx
mov cl, 2
call tinf_read_bits
mov byte [d_btype], al
; build fixed huffman trees
cmp al, 1
jne @f
call tinf_build_fixed_trees
xor al, al
; decode trees from stream
@@: cmp al, 2
jne @f
call tinf_decode_trees
@@:
.notst:
; process current block
cmp byte [d_btype], 0
jnz @f
; decompress uncompressed block
call tinf_inflate_uncompressed_block
JMP .procend
@@: cmp byte [d_btype], 1
je @f
cmp byte [d_btype], 2
jne tinf_err
; decompress block with fixed/dyanamic huffman trees
; trees were decoded previously, so it's the same routine for both
@@: call tinf_inflate_block_data
.procend: cmp al, 1
jne @f
cmp byte [d_bfinal], 0
; the block has ended (without producing more data), but we
; can't return without data, so start procesing next block
jz .next_blk
ret
@@: or al, al
jnz tinf_err
cmp edi, dword [d_end]
jbe .again
ret
; build the fixed huffman trees
tinf_build_fixed_trees:
push edi
xor ecx, ecx
xor eax, eax
; build fixed length tree
mov cl, 7
mov edi, d_ltree_table
repnz stosb
mov al, 24
stosb
mov al, 152
stosb
mov al, 112
stosb
mov edi, d_ltree_trans
mov cl, 24
mov ax, 256
@@: stosw
inc ax
dec cl
jnz @b
mov cl, 144
xor ax, ax
@@: stosw
inc ax
dec cl
jnz @b
mov cl, 8
mov ax, 280
@@: stosw
inc ax
dec cl
jnz @b
mov cl, 112
mov ax, 144
@@: stosw
inc ax
dec cl
jnz @b
; build fixed distance tree
mov cl, 5
mov edi, d_dtree_table
xor al, al
repnz stosb
mov al, 32
stosb
mov edi, d_dtree_trans
mov cl, 32
xor ax, ax
@@: stosw
inc ax
dec cl
jnz @b
pop edi
ret
;IN:
; ebp: TINF_TREE
; ebx: lengths
; ecx: num
tinf_build_tree:
push edi
xor eax, eax
; clear code length count table
mov edi, ebp
stosd ; for(i=0;i<16;i++) table[i]=0;
stosd
stosd
stosd
; scan symbol lengths, and sum code length counts
push ebx
push ecx
@@: mov al, byte [ebx] ;lengths[i]
inc ebx
inc byte [ebp+eax] ;table[lengths[i]]++
dec cx
jnz @b
mov byte [ebp], 0
; compute offset table for distribution sort
mov cl, 16
xor edx, edx ;i
xor ebx, ebx ;sum
xor eax, eax
@@: mov word [offs+2*edx], bx
mov al, byte [ebp+edx]
add ebx, eax
inc edx
dec cl
jnz @b
pop ecx
pop ebx ;lengths
; create code->symbol translation table (symbols sorted by code)
xor eax, eax ;i
@@: cmp byte [ebx], 0
jz .null
xor edx, edx
mov dl, byte [ebx] ;lengths[i]
inc word [offs+2*edx]
mov dx, word [offs+2*edx]
dec dx
mov word [ebp+2*edx+16], ax
.null: inc ebx
inc eax
dec cx
jnz @b
pop edi
ret
tinf_decode_trees:
mov word [num], 0
; get 5 bits HLIT (257-286)
xor ecx, ecx
mov cl, 5
mov ebx, 257
call tinf_read_bits
mov word [hlit], ax
mov word [num], ax
; get 5 bits HDIST (1-32)
mov cl, 5
xor ebx, ebx
inc ebx
call tinf_read_bits
mov word [hdist], ax
add word [num], ax
; get 4 bits HCLEN (4-19)
mov cl, 4
mov ebx, ecx
call tinf_read_bits
mov word [hclen], ax
push edi
mov cl, 19
mov edi, lengths
xor ax, ax
repnz stosw
pop edi
; read code lengths for code length alphabet
mov edx, clcidx
; get 3 bits code length (0-7)
@@: mov cx, 3
xor ebx, ebx
call tinf_read_bits
xor ebx, ebx
mov bl, byte [edx] ;clcidx[i]
mov byte[ebx+lengths], al
inc edx
dec word [hclen]
jnz @b
; build code length tree, temporarily use length tree
mov ebp, d_ltree
mov ebx, lengths
xor ecx, ecx
mov cl, 19
call tinf_build_tree
; decode code lengths for the dynamic trees
mov edx, lengths
.decode: mov ebp, d_ltree
call tinf_decode_symbol
xor ebx, ebx
cmp al, 16
jne .not16
; copy previous code length 3-6 times (read 2 bits)
mov cl, 2
mov bl, 3
call tinf_read_bits
mov cx, ax
mov al, byte [edx-1] ;lengths[num-1]
@@: mov byte [edx], al
inc edx
dec word [num]
dec cl
jnz @b
jmp .next
.not16: cmp al, 17
jne .not17
; repeat code length 0 for 3-10 times (read 3 bits)
mov cl, 3
mov bl, cl
call tinf_read_bits
mov cx, ax
@@: mov byte [edx], 0
inc edx
dec word [num]
dec cl
jnz @b
jmp .next
.not17: cmp al, 18
jne .not18
; repeat code length 0 for 11-138 times (read 7 bits)
mov cl, 7
mov bl, 11
call tinf_read_bits
mov cx, ax
@@: mov byte [edx], 0
inc edx
dec word [num]
dec cl
jnz @b
jmp .next
.not18: ; values 0-15 represent the actual code lengths
mov byte [edx], al
inc edx
dec word [num]
.next: cmp word [num], 0
jnz .decode
; build dynamic trees
mov ebp, d_ltree
mov ebx, lengths
xor ecx, ecx
mov cx, word [hlit]
call tinf_build_tree
mov ebp, d_dtree
mov ebx, lengths
xor ecx, ecx
mov cx, word [hlit]
add ebx, ecx
mov cx, word [hdist]
call tinf_build_tree
ret
;OUT:
; al: status
tinf_inflate_block_data:
cmp word [d_curlen], 0
jne .notnull
mov ebp, d_ltree
call tinf_decode_symbol
; literal byte
cmp ax, 256
jae @f
stosb
xor al, al
ret
@@: cmp ax, 256
jne @f
; end of block
mov al, 1
ret
@@: ; substring from sliding dictionary
sub eax, 257
; possibly get more bits from length code
xor ecx, ecx
mov cl, byte [length_bits+eax]
xor ebx, ebx
mov bx, word [length_base+2*eax]
call tinf_read_bits
mov word [d_curlen], ax
; possibly get more bits from distance code
mov ebp, d_dtree
call tinf_decode_symbol
xor ecx, ecx
mov cl, byte [dist_bits+eax]
xor ebx, ebx
mov bx, word [dists_base+2*eax]
call tinf_read_bits
cmp dword [d_dict_ring], 0
neg eax
mov dword [d_lzOff], eax
.notnull: mov eax, edi
add eax, dword [d_lzOff]
mov al, byte [eax]
stosb
@@: dec word [d_curlen]
xor al, al
ret
;OUT:
; al: status
tinf_inflate_uncompressed_block:
cmp word [d_curlen], 0
jne @f
; get length
lodsw
; get one's complement of length
add esi, 2
; increment length to properly return TINF_DONE below, without
; producing data at the same time
mov word [d_curlen], ax
inc word [d_curlen]
; make sure we start next block on a byte boundary
mov byte [d_bitcount], 0
@@: dec byte [d_curlen]
cmp byte [d_curlen], 0
jnz @f
mov al, 1
ret
@@: movsb
xor al, al
ret
;OUT:
; al,zeroflag bit
tinf_getbit:
mov al, byte [d_bitcount]
or al, al
jnz @f
lodsb
mov byte [d_tag], al
mov byte [d_bitcount], 8
@@: dec byte [d_bitcount]
xor ax, ax
shr byte [d_tag], 1
adc ax, 0
ret
;IN:
; ebx: base
; cl: num
;OUT:
; eax: bits
tinf_read_bits:
push edx
or cl, cl
jz .end
xor eax, eax
xor edx, edx
inc dl
.next: call tinf_getbit
jz @f
add ebx, edx
@@: shl edx, 1
dec cl
jnz .next
.end: pop edx
mov eax, ebx
ret
;IN:
; ebp: TINF_TREE
;OUT:
; eax: trans
tinf_decode_symbol:
push edx
xor eax, eax
xor ebx, ebx ;cur
xor ecx, ecx ;len
xor edx, edx ;sum
; get more bits while code value is above sum
@@: shl ebx, 1
call tinf_getbit
add ebx, eax
inc ecx
mov al, byte [ebp+ecx]
add edx, eax
sub ebx, eax
jns @b
add edx, ebx
mov ax, word [ebp+2*edx+16]
mov ebp, edx
pop edx
ret
tinf_err:
mov esi, nogzip
jmp prot_diefunc
length_bits:
db 0, 0, 0, 0, 0, 0, 0, 0
db 1, 1, 1, 1, 2, 2, 2, 2
db 3, 3, 3, 3, 4, 4, 4, 4
db 5, 5, 5, 5, 0, 0, 0, 0
length_base:
dw 3, 4, 5, 6, 7, 8, 9, 10
dw 11, 13, 15, 17, 19, 23, 27, 31
dw 35, 43, 51, 59, 67, 83, 99, 115
dw 131, 163, 195, 227, 258, 0, 0
dist_bits:
db 0, 0, 0, 0, 1, 1, 2, 2
db 3, 3, 4, 4, 5, 5, 6, 6
db 7, 7, 8, 8, 9, 9, 10, 10
db 11, 11, 12, 12, 13, 13, 0, 0
dists_base:
dw 1, 2, 3, 4, 5, 7, 9, 13
dw 17, 25, 33, 49, 65, 97, 129, 193
dw 257, 385, 513, 769, 1025, 1537, 2049, 3073
dw 4097, 6145, 8193, 12289, 16385, 24577, 0, 0
clcidx:
db 16, 17, 18, 0, 8, 7, 9, 6
db 10, 5, 11, 4, 12, 3, 13, 2
db 14, 1, 15
d_btype: db 255