commit d7d2aff8e71d0b3ed264aec0c9d18abe1e435c86 Author: bzt Date: Wed Dec 30 20:34:42 2020 +0100 Additional BPs diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..d5a5919 --- /dev/null +++ b/Makefile @@ -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 + diff --git a/bootboot.asm b/bootboot.asm new file mode 100644 index 0000000..ed374ff --- /dev/null +++ b/bootboot.asm @@ -0,0 +1,2916 @@ +;* +;* x86_64-bios/bootboot.asm +;* +;* 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 Booting code for BIOS, MultiBoot, El Torito, Linux boot +;* +;* Stage2 loader, compatible with GRUB and BIOS boot specification +;* 1.0.1 (even expansion ROM), El Torito "no emulation" CDROM boot, +;* as well as Linux boot protocol. +;* +;* text segment occupied: 800-7C00, bss: 8000-x +;* +;* Memory map +;* 0h - 600h reserved for the system +;* 600h - 800h stage1 (MBR/VBR, boot.bin) +;* 800h - 6C00h stage2 (this) +;* 6C00h - 7C00h stack (7000h - 700Fh SMP trampoline code) +;* 8000h - 9000h bootboot structure +;* 9000h - A000h environment +;* A000h - B000h disk buffer / PML4 +;* B000h - C000h PDPE, higher half core 4K slots +;* C000h - D000h PDE 4K +;* D000h - E000h PTE 4K +;* E000h - F000h PDPE, 4G physical RAM identity mapped 2M +;* F000h - 10000h PDE 2M +;* 10000h - 11000h PDE 2M +;* 11000h - 12000h PDE 2M +;* 12000h - 13000h PDE 2M +;* 13000h - 14000h PTE 4K +;* 14000h - 9F000h core stacks (1k per core) +;* +;* At first big enough free hole, initrd. Usually at 1Mbyte. +;* +;* WARNING: supports BOOTBOOT Protocol level 1 only (static mappings) +;* + +BBDEBUG equ 1 + +format ELF64 + +;get Core boot parameter block +include "bootboot.inc" + +;VBE filter (available, has additional info, color, graphic, linear fb) +VBE_MODEFLAGS equ 1+2+8+16+128 + +;********************************************************************* +;* Macros * +;********************************************************************* + +;Writes a message on screen. +macro real_print msg +{ +if ~ msg eq si + push si + mov si, msg +end if + call real_printfunc +if ~ msg eq si + pop si +end if +} + +;protected and real mode are functions, because we have to switch beetween +macro real_protmode +{ + USE16 + call near real_protmodefunc + USE32 +} + +macro prot_realmode +{ + USE32 + call near prot_realmodefunc + USE16 +} + +;edx:eax sector, edi:pointer +macro prot_readsector +{ + call near prot_readsectorfunc +} + +macro DBG msg +{ +if BBDEBUG eq 1 + real_print msg +end if +} + +macro DBG32 msg +{ +if BBDEBUG eq 1 + prot_realmode + real_print msg + real_protmode +end if +} + +virtual at 0 + bpb.jmp db 3 dup 0 + bpb.oem db 8 dup 0 + bpb.bps dw 0 + bpb.spc db 0 + bpb.rsc dw 0 + bpb.nf db 0 ;16 + bpb.nr dw 0 + bpb.ts16 dw 0 + bpb.media db 0 + bpb.spf16 dw 0 ;22 + bpb.spt dw 0 + bpb.nh dw 0 + bpb.hs dd 0 + bpb.ts32 dd 0 + bpb.spf32 dd 0 ;36 + bpb.flg dd 0 + bpb.rc dd 0 ;44 + bpb.vol db 6 dup 0 + bpb.fst db 8 dup 0 ;54 + bpb.dmy db 20 dup 0 + bpb.fst2 db 8 dup 0 ;84 +end virtual + +virtual at 0 + fatdir.name db 8 dup 0 + fatdir.ext db 3 dup 0 + fatdir.attr db 9 dup 0 + fatdir.ch dw 0 + fatdir.attr2 dd 0 + fatdir.cl dw 0 + fatdir.size dd 0 +end virtual + +;********************************************************************* +;* header * +;********************************************************************* +;offs len desc +; 0 2 expansion ROM magic (AA55h) +; 2 1 size in blocks (40h) +; 3 1 magic E9h +; 4 2 real mode entry point (relative) +; 6 2 checksum +; 8 8 magic 'BOOTBOOT' +; 16 10 zeros, at least one and a padding +; 26 2 pnp ptr, must be zero +; 28 4 flags, must be zero +; 32 32 MultiBoot header with protected mode entry point +; 64 x free to use +;497 127 Linux x86 boot protocol header +;any format can follow. + + USE16 + ORG 800h +;BOOTBOOT stage2 header (64 bytes) +public loader +loader: db 55h,0AAh ;ROM magic + db (loader_end-loader)/512 ;size in 512 blocks +.executor: jmp near realmode_start ;entry point +.checksum: dw 0 ;checksum +.name: db "BOOTBOOT" + dw 0 + dd 0, 0 +.pnpptr: dw 0 +.flags: dd 0 +MB_MAGIC equ 01BADB002h +MB_FLAGS equ 010001h + align 8 +.mb_header: dd MB_MAGIC ;magic + dd MB_FLAGS ;flags + dd -(MB_MAGIC+MB_FLAGS) ;checksum (0-magic-flags) + dd .mb_header ;our location (GRUB should load us here) + dd 0800h ;the same... load start + dd 07C00h ;load end + dd 0h ;no bss + dd multiboot_start ;entry point + +;no segments or sections, code comes right after the header + +;********************************************************************* +;* code * +;********************************************************************* + +;----------------Multiboot stub----------------- + USE32 +public multiboot_start +multiboot_start: + cli + cld + ;clear drive code, initrd ptr and environment + xor edx, edx + mov edi, 9000h + mov dword [edi], edx + mov dword [bootboot.initrd_ptr], edx + mov dword [bootboot.initrd_size], edx + ;no GRUB environment available? + cmp eax, 2BADB002h + jne @f + ;save drive code for boot device + mov dl, byte [ebx+12] + ;is there a module? mod_count!=0 + cmp dword [ebx+20], 0 + jz @f + ;mod_addr!=0 + mov eax, dword [ebx+24] + or eax, eax + jz @f + ;mods[0].end + mov ecx, dword [eax+4] + sub ecx, dword [eax] + mov dword [bootboot.initrd_size], ecx + ;mods[0].start + mov ecx, dword [eax] + mov dword [bootboot.initrd_ptr], ecx + inc byte [hasinitrd] + ;mod_count>1? + cmp dword [ebx+20], 1 + jbe @f + ;mods[1], copy environment (4k) + mov esi, dword [eax+16] + mov ecx, 1024 + repnz movsd + inc byte [hasconfig] +@@: lgdt [GDT_value] + mov ax, DATA_BOOT ;clear shadow segment registers + mov ds, ax + mov es, ax + mov ss, ax + xor esp, esp ;GRUB leaves the upper 16 bits non-zero, we must clear it + jmp CODE_BOOT:.real ;load 16 bit mode segment into cs + USE16 +.real: mov eax, CR0 + and eax, 07FFFFFFEh ;switching back to real mode + mov CR0, eax + xor ax, ax + mov ds, ax ;load segment registers DS and CS + jmp 0:@f +@@: lidt [idt16] ;restore IDT as newer GRUBs mess it up + ;fallthrough realmode_start + +;-----------realmode-protmode stub------------- +public realmode_start +realmode_start: + cli + cld + xchg bx, bx + mov sp, 7C00h + xor ax, ax + mov es, ax + mov ss, ax + ;relocate ourself from ROM to RAM if necessary + call .getaddr +.getaddr: pop si + mov ax, cs + or ax, ax + jnz .reloc + cmp si, .getaddr + je .noreloc +.reloc: mov ds, ax + mov di, loader + sub si, .getaddr-loader + mov cx, (loader_end-loader)/2 + repnz movsw + xor ax, ax + mov ds, ax + jmp 0:.clrdl +.noreloc: or dl, dl + jnz @f +.clrdl: mov dl, 80h +@@: mov byte [bootdev], dl + + ;-----initialize serial port COM1,115200,8N1------ + mov ax, 0401h + xor bx, bx + mov cx, 030Bh + xor dx, dx + int 14h + ; if there's no serial, but BIOS incorrectly sets the IO port for it + mov dx, word [400h] + or dx, dx + jz @f + add dx, 5 + in al, dx + cmp al, 0FFh + jne @f + mov word [400h], 0 +@@: real_print starting + + ; flush PS/2 keyboard + in al, 060h ; read key + in al, 061h ; ack + out 061h, al + + DBG dbg_cpu + + ;-----check CPU----- + ;at least 286? + pushf + pushf + pop dx + xor dh,40h + push dx + popf + pushf + pop bx + popf + cmp dx, bx + jne .cpuerror + mov ebp, 200000h + ;check for 386 + ;look for cpuid instruction + pushfd + pop eax + mov ebx, eax + xor eax, ebp + and ebx, ebp + push eax + popfd + pushfd + pop eax + and eax, ebp + xor eax, ebx + shr eax, 21 + and al, 1 + jz .cpuerror + ;ok, now we can get cpu feature flags + mov eax, 1 + cpuid + shr al, 4 + shr ebx, 24 + mov word [bootboot.bspid], bx + ;look for minimum family + cmp ax, 0600h + jb .cpuerror + ;look for minimum feature flags + ;so we have PAE? + bt edx, 6 + jnc .cpuerror + ;what about MSR? + bt edx, 5 + jnc .cpuerror + ;and can we use long mode (LME)? + mov eax, 80000000h + mov ebp, eax + inc ebp + cpuid + cmp eax, ebp + jb .cpuerror + mov eax, ebp + cpuid + ;long mode + bt edx, 29 + jc cpuok +.cpuerror: mov si, noarch + jmp real_diefunc + ;okay, we can do 64 bit! + +;--- Linux x86 boot protocol header --- + db 01F1h-($-$$) dup 090h +public hdr +hdr: +setup_sects: db (loader_end-loader-511)/512 +root_flags: dw 0 +syssize: dd (loader_end-loader)/16 +ram_size: dw 0 +vid_mode: dw 0 +root_dev: dw 0 +boot_flag: dw 0AA55h + db 0EBh ; short jmp + db start_of_setup-@f ; no space to jump to realmode_start directly +@@: db "HdrS" + dw 020eh +realmode_swtch: dd 0 +start_sys_seg: dw 0 + dw 0 ; we don't have Linux kernel version... +type_of_loader: db 0FFh +loadflags: db 0 +setup_move_size: dw 08000h +code32_start: dd 0 ; we dont' use this either... +ramdisk_image: dd 0 +ramdisk_size: dd 0 +bootsect_kludge: dd 0 +heap_end_ptr: dd loader_end+1024-512 ; we don't care, we set our stack directly +ext_loader_ver: db 0 +ext_loader_type: db 0 +cmd_line_ptr: dd 0 +initrd_addr_max: dd 07fffffffh +kernel_alignment: dd 16 +relocatable_kernel: db 0 +min_alignment: db 4 +xloadflags: dw 0 +cmdline_size: dd 0 +hardware_subarch: dd 0 +hardware_subarch_data: dq 0 +payload_offset: dd 0 +payload_length: dd 0 +setup_data: dq 0 +pref_address: dq 90000h ; qemu does not handle anything else +init_size: dd loader_end-loader +handover_offset: dd 0 +acpi_rsdp_addr: dq 0 +start_of_setup: + ; fix: qemu forces address and set CS to 0x9020, but we must jump to segment 0x9000. + jmp 9000h:realmode_start-loader +; --- end of Linux boot protocol header --- + +public cpuok +cpuok: DBG dbg_A20 + + ;-----enable A20----- + ;no problem even if a20 is already turned on. + mov ax, 2401h ;BIOS enable A20 function + int 15h + ;see if it worked + call a20chk + jz a20ok + ;keyboard nightmare + call a20wait + mov al, 0ADh + out 64h, al + call a20wait + mov al, 0D0h + out 64h, al + call a20wait2 + in al, 60h + push ax + call a20wait + mov al, 0D1h + out 64h, al + call a20wait + pop ax + or al, 2 + out 60h, al + call a20wait + mov al, 0AEh + out 64h, al + call a20wait + call a20chk + jz a20ok + ;fast enable method + in al, 92h + test al, 2 + jnz a20ok + or al, 2 + and al, 0FEh + out 92h, al + jmp a20ok + +public a20chk +a20chk: push es + xor ax, ax + dec ax + mov es, ax + mov ah, byte [es:510h] + mov byte [ds:500h], 0 + mov byte [es:510h], al + mov al, byte [ds:500h] + mov byte [es:510h], ah + pop es + or al, al + ret +a20wait: in al, 64h + test al, 2 + jnz a20wait + ret +a20wait2: in al, 64h + test al, 1 + jz a20wait2 + ret +a20ok: + ; wait for a key press for half a sec, if pressed use backup initrd + mov word [origcount], 0 + sti +.waitkey: mov ax, word 0100h + or al, al ; make sure ZF is clear + int 16h + jz @f + or al, al + jz @f + ; this blocks, so only call it if we are sure there's a keystroke waiting + xor ah, ah + int 16h + mov eax, ' BAK' + mov dword [bkp], eax + real_print backup + jmp .waitend +@@: ; wait 10 millisec + xor cx, cx + mov dx, 10000 + mov ah, 086h + int 15h + ; repeat loop 50 times + inc word [origcount] + cmp word [origcount], 50 + jl .waitkey +.waitend: cli + + ;-----detect memory map----- +public getmemmap +getmemmap: + DBG dbg_mem + + xor eax, eax + mov edi, bootboot.acpi_ptr + mov ecx, 16 + repnz stosd + cmp byte [hasconfig], 0 + jnz @f + mov dword [9000h], eax +@@: cmp byte [hasinitrd], 0 + jnz @f + mov dword [bootboot.initrd_ptr], eax + mov dword [bootboot.initrd_size], eax +@@: mov dword [bootboot.initrd_ptr+4], eax + mov dword [bootboot.initrd_size+4], eax + mov eax, bootboot_MAGIC + mov dword [bootboot.magic], eax + mov dword [bootboot.size], 128 + mov dword [bootboot.protocol], PROTOCOL_STATIC or LOADER_BIOS + mov di, bootboot.fb_ptr + mov cx, 800h-28h + xor ax, ax + repnz stosw + mov di, bootboot.mmap + xor ebx, ebx + clc +.nextmap: cmp word [bootboot.size], 4096 + jae .nomoremap + mov edx, 'PAMS' + xor ecx, ecx + mov cl, 20 + xor eax, eax + mov ax, 0E820h + int 15h + jc .nomoremap + cmp eax, 'PAMS' + jne .nomoremap + ;is this the first memory hole? If so, mark + ;ourself as reserved memory + cmp dword [di+4], 0 + jnz .notfirst + cmp dword [di], 0 + jnz .notfirst + ; "allocate" memory for loader + mov eax, 14000h + add dword [di], eax + sub dword [di+8], eax + ;convert E820 memory type to BOOTBOOT memory type +.notfirst: mov al, byte [di+16] + cmp al, 1 + je .noov + cmp al, 4 + je .isacpi + cmp al, 3 + jne @f +.isacpi: mov al, MMAP_ACPI + jmp .noov + ; everything else reserved +@@: mov al, MMAP_USED +.noov: ;copy memory type to size's least significant byte + mov byte [di+8], al + xor ecx, ecx + ;is it ACPI area? + cmp al, MMAP_ACPI + jne .notacpi + mov dword [bootboot.acpi_ptr], edi + jmp .entryok + ;is it free slot? +.notacpi: cmp al, MMAP_FREE + jne .notmax +.freemem: ;do we have a ramdisk area? + cmp dword [bootboot.initrd_ptr], 0 + jnz .entryok + ;is it big enough for the compressed and the inflated ramdisk? + mov ebp, (INITRD_MAXSIZE+2)*1024*1024 + shr ebp, 20 + shl ebp, 20 + ;is this free memory hole big enough? (first fit) +.sizechk: mov eax, dword [di+8] ;load size + xor al, al + mov edx, dword [di+12] + and edx, 000FFFFFFh + or edx, edx + jnz .bigenough + cmp eax, ebp + jb .entryok +.bigenough: mov eax, dword [di] + ;save ramdisk pointer + mov dword [bootboot.initrd_ptr], eax +.entryok: ;get limit of memory + mov eax, dword [di+8] ;load size + xor al, al + mov edx, dword [di+12] + add eax, dword [di] ;add base + adc edx, dword [di+4] + and edx, 000FFFFFFh +.notmax: add dword [bootboot.size], 16 + ;bubble up entry if necessary + push si + push di +.bubbleup: mov si, di + cmp di, bootboot.mmap + jbe .swapdone + sub di, 16 + ;order by base asc + mov eax, dword [si+4] + cmp eax, dword [di+4] + jb .swapmodes + jne .swapdone + mov eax, dword [si] + cmp eax, dword [di] + jae .swapdone +.swapmodes: push di + mov cx, 16/2 +@@: mov dx, word [di] + lodsw + stosw + mov word [si-2], dx + dec cx + jnz @b + pop di + jmp .bubbleup +.swapdone: pop di + pop si + add di, 16 + cmp di, bootboot.mmap+4096 + jae .nomoremap +.skip: or ebx, ebx + jnz .nextmap +.nomoremap: cmp dword [bootboot.size], 128 + jne .E820ok +.noE820: mov si, memerr + jmp real_diefunc + +.E820ok: ;check if we have memory for the ramdisk + xor ecx, ecx + cmp dword [bootboot.initrd_ptr], ecx + jnz .enoughmem +.nomem: mov si, noenmem + jmp real_diefunc +.enoughmem: + +public systables +systables: + ;-----detect system structures----- + DBG dbg_systab + + ;do we need that scanning shit? + mov eax, dword [bootboot.acpi_ptr] + or eax, eax + jz @f + shr eax, 4 + mov es, ax + ;no if E820 map was correct + cmp dword [es:0], 'XSDT' + je .detsmbi + cmp dword [es:0], 'RSDT' + je .detsmbi +@@: inc dx + ;get starting address min(EBDA,E0000) + mov ah,0C1h + stc + int 15h + mov bx, es + jnc @f + mov ax, [ebdaptr] +@@: cmp ax, 0E000h + jb .acpinext + mov ax, 0E000h + ;detect ACPI ptr +.acpinext: mov es, ax + cmp dword [es:0], 'RSD ' + jne .acpinotf + cmp dword [es:4], 'PTR ' + jne .acpinotf + ;ptr found + ; do we have XSDT? + cmp dword [es:28], 0 + jne .acpi2 + cmp dword [es:24], 0 + je .acpi1 +.acpi2: mov eax, dword [es:24] + mov dword [bootboot.acpi_ptr], eax + mov edx, dword [es:28] + mov dword [bootboot.acpi_ptr+4], edx + jmp .chkacpi + ; no, fallback to RSDT +.acpi1: mov eax, dword [es:16] +@@: mov dword [bootboot.acpi_ptr], eax + xor edx, edx + jmp .chkacpi +.acpinotf: xor eax, eax + mov ax, es + inc ax + cmp ax, 0A000h + jne @f + add ax, 03000h +@@: ;end of 1Mb? + or ax, ax + jnz .acpinext + mov si, noacpi + jmp real_diefunc +.chkacpi: ; check if memory is marked as ACPI in the memory map + mov esi, bootboot.mmap + mov edi, bootboot.magic + add edi, dword [bootboot.size] +.nextmm: cmp edx, dword [si+4] + jne .skipmm + mov ebx, dword [si] + cmp eax, ebx + jl .skipmm + add ebx, dword [si+8] + and bl, 0F0h + cmp eax, ebx + jge .skipmm + mov al, byte [si+8] + and al, 0F0h + or al, MMAP_ACPI + mov byte [si+8], al + jmp .detsmbi +.skipmm: add si, 16 + cmp si, di + jl .nextmm + + ;detect SMBios tables +.detsmbi: xor eax, eax + mov ax, 0E000h + xor dx, dx +.smbnext: mov es, ax + push ax + cmp dword [es:0], '_SM_' + je .smbfound + cmp dword [es:0], '_MP_' + jne .smbnotf + shl eax, 4 + mov dword [bootboot.mp_ptr], eax + bts dx, 2 + jmp .smbnotf +.smbfound: shl eax, 4 + mov dword [bootboot.smbi_ptr], eax + bts dx, 1 +.smbnotf: pop ax + bt ax, 0 + mov bx, ax + and bx, 03h + inc ax + ;end of 1Mb? + or ax, ax + jnz .smbnext + ;restore ruined es +.detend: push ds + pop es + + DBG dbg_time + + ; ------- BIOS date and time ------- + mov ah, 4 + int 1Ah + jc .nobtime + ;ch century + ;cl year + xchg ch, cl + mov word [bootboot.datetime], cx + ;dh month + ;dl day + xchg dh, dl + mov word [bootboot.datetime+2], dx + mov ah, 2 + int 1Ah + jc .nobtime + ;ch hour + ;cl min + xchg ch, cl + mov word [bootboot.datetime+4], cx + ;dh sec + ;dl daylight saving on/off + xchg dh, dl + mov word [bootboot.datetime+6], dx +.nobtime: + + ;---- enable protmode ---- + cli + cld + lgdt [GDT_value] + mov eax, cr0 + or al, 1 + mov cr0, eax + jmp CODE_PROT:protmode_start + + ;---- enable protmode on APs ---- +public ap_trampoline +ap_trampoline: + ;--this code will be relocated to the SIPI address -- + cli + cld + jmp 0:ap_start + ;--relocation end-- +ap_start: xor ax, ax + mov ds, ax + lgdt [GDT_value] + mov eax, cr0 + or al, 1 + mov cr0, eax + jmp CODE_PROT:@f + USE32 +@@: mov ax, DATA_PROT + mov ds, ax + mov es, ax + mov fs, ax + mov gs, ax + mov ss, ax + ; spinlock until BSP finishes +@@: pause + cmp byte [bsp_done], 0 + jz @b + jmp longmode_init + +;writes the reason, waits for a key and reboots. +public prot_diefunc +prot_diefunc: + prot_realmode + USE16 +public real_diefunc +real_diefunc: + push si + real_print loader.name + real_print panic + pop si + call real_printfunc + mov si, crlf + call real_printfunc + call real_getchar + mov al, 0FEh + out 64h, al + jmp far 0FFFFh:0 ;invoke BIOS POST routine + +; get a character from keyboard or from serial line +public real_getchar +real_getchar: + pushf + sti + push si + push di +.chkser: cmp word [400h], 0 + jz @f + mov ah, byte 03h + xor dx, dx + int 14h + bt ax, 8 + jnc @f + mov ah, byte 02h + xor dx, dx + int 14h + jmp .gotch +@@: mov ah, byte 01h + int 16h + jz .chkser + xor ah, ah + int 16h +.gotch: pop di + pop si + popf + xor ah, ah + ret + +;ds:si zero terminated string to write +public real_printfunc +real_printfunc: + lodsb + or al, al + jz .end + push si + push ax + mov ah, byte 0Eh + mov bx, word 11 + int 10h + pop ax + cmp word [400h], 0 + jz @f + mov ah, byte 01h + xor dx, dx + int 14h +@@: pop si + jmp real_printfunc +.end: ret + +public real_protmodefunc +real_protmodefunc: + cli + ;get return address + xor ebp, ebp + pop bp + mov dword [hw_stack], esp + lgdt [GDT_value] + mov eax, cr0 ;enable protected mode + or al, 1 + mov cr0, eax + jmp CODE_PROT:.init + + USE32 +.init: mov ax, DATA_PROT + mov ds, ax + mov es, ax + mov fs, ax + mov gs, ax + mov ss, ax + mov esp, dword [hw_stack] + jmp ebp + +public prot_realmodefunc +prot_realmodefunc: + cli + ;get return address + pop ebp + ;save stack pointer + mov dword [hw_stack], esp + jmp CODE_BOOT:.back ;load 16 bit mode segment into cs + USE16 +.back: mov eax, CR0 + and al, 0FEh ;switching back to real mode + mov CR0, eax + xor ax, ax + mov ds, ax ;load registers 2nd turn + mov es, ax + mov ss, ax + jmp 0:.back2 +.back2: mov sp, word [hw_stack] + sti + jmp bp + + USE32 +public prot_readsectorfunc +prot_readsectorfunc: + push eax + push ecx + push esi + push edi + ;load 8 sectors (1 page) or more in low memory + mov dword [lbapacket.sect0], eax + prot_realmode + ;try all drives from bootdev-87 to support RAID mirror + mov dl, byte [bootdev] + mov byte [readdev], dl + mov byte [cntdev], 0 + mov byte [iscdrom], 0 +.again: mov ax, word [lbapacket.count] + mov word [origcount], ax + mov dl, byte [readdev] + ;don't use INT 13h / AX=4B01h, that's buggy on many BIOSes + cmp dl, 0E0h + jl @f + ;use 2048 byte sectors instead of 512 if it's a cdrom + mov al, byte [lbapacket.sect0] + and al, 011b + or al, al + jz .cdok + ;this should never happen. + ; - GPT is loaded from PMBR, from LBA 0 (%4==0) + ; - ESP is at LBA 128 or 2048 (%4==0) + ; - root dir is at LBA 172 (%4==0) for FAT16, and it's cluster aligned for FAT32 + ; - cluster size is multiple of 4 sectors + mov si, notcdsect + jmp real_diefunc +.cdok: shr dword [lbapacket.sect0], 2 + add word [lbapacket.count], 3 + shr word [lbapacket.count], 2 + mov byte [iscdrom], 1 +@@: mov ah, byte 42h + mov esi, lbapacket + clc + int 13h + jnc .rdok + ;we do not expect this to fail, but if so, load sector from another + ;drive assuming we have a RAID mirror. This will fail for non-RAIDs + mov al, byte [readdev] + inc al + cmp al, 87h + jle @f + mov al, 80h +@@: mov byte [readdev], al + inc byte [cntdev] + cmp byte [cntdev], 8 + jle .again +.rdok: xor ebx, ebx + mov bl, ah + real_protmode + pop edi + or edi, edi + jz @f + push edi + ;and copy to addr where it wanted to be (maybe in high memory) + mov esi, dword [lbapacket.addr] + xor ecx, ecx + mov cx, word [origcount] + shl ecx, 7 + repnz movsd + pop edi +@@: pop esi + pop ecx + pop eax + ret + +public prot_hex2bin +prot_hex2bin: + xor eax, eax + xor ebx, ebx +@@: mov bl, byte [esi] + cmp bl, '0' + jb @f + cmp bl, '9' + jbe .num + cmp bl, 'A' + jb @f + cmp bl, 'F' + ja @f + sub bl, 7 +.num: sub bl, '0' + shl eax, 4 + add eax, ebx + inc esi + dec cx + jnz @b +@@: ret + +public prot_dec2bin +prot_dec2bin: + xor eax, eax + xor ebx, ebx + xor edx, edx + mov ecx, 10 +@@: mov bl, byte [esi] + cmp bl, '0' + jb @f + cmp bl, '9' + ja @f + mul ecx + sub bl, '0' + add eax, ebx + inc esi + jmp @b +@@: ret + +;IN: eax=str ptr, ecx=length OUT: eax=num +public prot_oct2bin +prot_oct2bin: + push ebx + push edx + mov ebx, eax + xor eax, eax + xor edx, edx +@@: shl eax, 3 + mov dl, byte[ebx] + sub dl, '0' + add eax, edx + inc ebx + dec ecx + jnz @b + pop edx + pop ebx + ret + +; IN: al, character to send +public uart_send +uart_send: mov ah, al + mov dx, word [400h] ;3fdh + add dx, 5 +@@: pause + in al, dx + and al, 20h + jz @b + sub dx, 5 + mov al, ah + out dx, al + ret + +; IN: edi pointer to store the received char +public uart_getc +uart_getc: mov dx, word [400h] ;3fdh + add dx, 5 +@@: pause + in al, dx + and al, 1 + jz @b + sub dl, 5 + in al, dx + stosb + ret + +public protmode_start +protmode_start: + xchg bx, bx + mov ax, DATA_PROT + mov ds, ax + mov es, ax + mov fs, ax + mov gs, ax + mov ss, ax + mov esp, 7C00h + + ; ------- Locate initrd -------- + cmp byte [hasinitrd], 0 + jnz .initrdrom + mov esi, 0C8000h +.nextrom: cmp word [esi], 0AA55h + jne @f + cmp dword [esi+8], 'INIT' + jne @f + cmp word [esi+12], 'RD' + jne @f + mov ecx, dword [esi+16] + mov dword [bootboot.initrd_size], ecx + add esi, 32 + cmp word [esi], 08b1fh + je .initrdrom + ; copy from ROM to RAM + mov edi, dword [bootboot.initrd_ptr] + repnz movsb + jmp .noinflate +@@: add esi, 2048 + cmp esi, 0F4000h + jb .nextrom + + ;---- notify raspbootcom / USBImager to send the initrd over serial line ---- + cmp word [400h], 0 + jz .getgpt + + mov al, 3 + call uart_send + call uart_send + call uart_send + + ; wait for response with timeout + mov ah, al + mov cx, 10000 + mov dx, word [400h] + add dx, 5 +@@: dec cx + jz .getgpt + pause + in al, dx + and al, 1 + jz @b + + DBG32 dbg_serial + + ; read the initrd's size + mov edi, bootboot.initrd_size + call uart_getc + call uart_getc + call uart_getc + call uart_getc + mov ecx, dword [bootboot.initrd_size] + ; send negative or positive acknowledge + cmp ecx, 32 + jb .se + cmp ecx, INITRD_MAXSIZE*1024*1024 + jb .ok +.se: mov al, 'S' + call uart_send + mov al, 'E' + call uart_send + jmp .getgpt +.ok: mov al, 'O' + call uart_send + mov al, 'K' + call uart_send + mov edi, dword [bootboot.initrd_ptr] + ; read in the image +@@: call uart_getc + dec ecx + jnz @b + jmp .initrdloaded + + ;---- read GPT ----- +.getgpt: xor eax, eax + xor edi, edi + prot_readsector +if BBDEBUG eq 1 + cmp byte [iscdrom], 0 + jz @f + DBG32 dbg_cdrom + jmp .isgpt +@@: DBG32 dbg_gpt +.isgpt: +end if + mov esi, 0A000h+512 + cmp dword [esi], 'EFI ' + je @f +.nogpt: mov esi, nogpt + jmp prot_diefunc +@@: mov edi, 0B000h + mov ebx, edi + mov ecx, 896 + repnz movsd + mov esi, ebx + mov ecx, dword [esi+80] ;number of entries + mov ebx, dword [esi+84] ;size of one entry + add esi, 512 + mov edx, esi ;first entry + mov dword [gpt_ent], ebx + mov dword [gpt_num], ecx + mov dword [gpt_ptr], edx + ; first, look for a partition with bootable flag + mov esi, edx +@@: cmp dword [esi], 0 ;failsafe, jump to parttype search + jne .notz + cmp dword [esi+32], 0 + jz .nextgpt +.notz: bt word [esi+48], 2 ;EFI_PART_USED_BY_OS? + jc .loadesp2 + add esi, ebx + dec ecx + jnz @b + ; if none, look for specific partition types +.nextgpt: mov esi, dword [gpt_ptr] + mov ebx, dword [gpt_ent] + mov ecx, dword [gpt_num] + mov eax, 0C12A7328h + mov edx, 011D2F81Fh +@@: cmp dword [esi], eax ;GUID match? + jne .note + cmp dword [esi+4], edx + je .loadesp +.note: cmp dword [esi], 'OS/Z' ;or OS/Z root partition for this architecture? + jne .noto + cmp word [esi+4], 08664h + jne .noto + cmp dword [esi+12], 'root' + je .loadesp +.noto: add esi, ebx + dec ecx + jnz @b +.nopart: mov esi, nopar + jmp prot_diefunc + + ; load ESP at free memory hole found +.loadesp: mov dword [gpt_ptr], esi + mov dword [gpt_num], ecx +.loadesp2: mov ecx, dword [esi+40] ;last sector + mov eax, dword [esi+32] ;first sector + mov edx, dword [esi+36] + or edx, edx + jnz .nextgpt + or ecx, ecx + jz .nextgpt + or eax, eax + jz .nextgpt + mov dword [bpb_sec], eax + ;load BPB + mov edi, dword [bootboot.initrd_ptr] + mov word [lbapacket.count], 8 + prot_readsector + + ;parse fat on EFI System Partition +@@: cmp dword [edi + bpb.fst2], 'FAT3' + je .isfat + cmp dword [edi + bpb.fst], 'FAT1' + je .isfat + ;no, then it's an initrd on the entire partition + or eax, eax + jz .nopart + or ecx, ecx + jz .nopart + sub ecx, eax + shl ecx, 9 + mov dword [bootboot.initrd_size], ecx + ; load INITRD from partition + dec ecx + shr ecx, 12 + mov edi, dword [bootboot.initrd_ptr] +@@: add edi, 4096 + prot_readsector + add eax, 8 + dec ecx + jnz @b + jmp .initrdloaded + +.isfat: cmp word [edi + bpb.bps], 512 + jne .nextgpt + ;calculations + xor eax, eax + xor ebx, ebx + xor ecx, ecx + xor edx, edx + mov bx, word [edi + bpb.spf16] + or bx, bx + jnz @f + mov ebx, dword [edi + bpb.spf32] +@@: mov al, byte [edi + bpb.nf] + mov cx, word [edi + bpb.rsc] + ;data_sec = numFat*secPerFat + mul ebx + ;data_sec += reservedSec + add eax, ecx + ;data_sec += ESPsec + add eax, dword [bpb_sec] + mov dword [data_sec], eax + mov dword [root_sec], eax + xor eax, eax + mov al, byte [edi + bpb.spc] + mov dword [clu_sec], eax + ;FAT16 + ;data_sec += (numRootEnt*32+511)/512 + cmp word [edi + bpb.spf16], 0 + je .fat32bpb + cmp byte [edi + bpb.fst + 4], '6' + jne .nextgpt + xor eax, eax + mov ax, word [edi + bpb.nr] + shl eax, 5 + add eax, 511 + shr eax, 9 + add dword [data_sec], eax + mov byte [fattype], 0 + xor ecx, ecx + mov cx, word [edi + bpb.spf16] + jmp .loadfat +.fat32bpb: ;FAT32 + ;root_sec += (rootCluster-2)*secPerCluster + mov eax, dword [edi + bpb.rc] + sub eax, 2 + xor edx, edx + mov ebx, dword [clu_sec] + mul ebx + add dword [root_sec], eax + mov byte [fattype], 1 + mov ecx, dword [edi + bpb.spf32] + ;load FAT +.loadfat: xor eax, eax + mov ax, word [edi+bpb.rsc] + add eax, dword [bpb_sec] + shr ecx, 3 + inc ecx + mov edi, 0x10000 + mov word [lbapacket.count], 8 +@@: prot_readsector + add edi, 4096 + add eax, 8 + dec ecx + jnz @b + mov ax, word [clu_sec] + mov word [lbapacket.count], ax + + ;load root directory + mov eax, dword [root_sec] + mov edi, dword [bootboot.initrd_ptr] + prot_readsector + + ;look for BOOTBOOT directory + mov esi, edi + mov eax, 'BOOT' + mov ecx, 255 +.nextroot: cmp dword [esi], eax + jne @f + cmp dword [esi+4], eax + jne @f + cmp word [esi+8], ' ' + je .foundroot +@@: add esi, 32 + cmp byte [esi], 0 + jz .nextgpt + dec ecx + jnz .nextroot + jmp .nextgpt +.foundroot: xor eax, eax + cmp byte [fattype], 0 + jz @f + mov ax, word [esi + fatdir.ch] + shl eax, 16 +@@: mov ax, word [esi + fatdir.cl] + ;sec = (cluster-2)*secPerCluster+data_sec + sub eax, 2 + mov ebx, dword [clu_sec] + mul ebx + add eax, dword [data_sec] + mov edi, dword [bootboot.initrd_ptr] + prot_readsector + + ;look for CONFIG and INITRD + mov esi, edi + mov ecx, 255 + mov edx, dword [bkp] +.nextdir: cmp dword [esi], 'CONF' + jne .notcfg + cmp dword [esi+4], 'IG ' + jne .notcfg + cmp dword [esi+7], ' ' + jne .notcfg + ; load environment from FS0:/BOOTBOOT/CONFIG + push edx + push esi + push edi + push ecx + mov ecx, dword [esi + fatdir.size] + cmp ecx, 4095 + jbe @f + mov ecx, 4095 +@@: mov dword [core_len], ecx + xor eax, eax + cmp byte [fattype], 0 + jz @f + mov ax, word [esi + fatdir.ch] + shl eax, 16 +@@: mov ax, word [esi + fatdir.cl] + mov edi, 9000h +.nextcfg: push eax + ;sec = (cluster-2)*secPerCluster+data_sec + sub eax, 2 + mov ebx, dword [clu_sec] + mov word [lbapacket.count], bx + mul ebx + shl ebx, 9 + add eax, dword [data_sec] + push ebx + prot_readsector + pop ebx + pop eax + add edi, ebx + sub ecx, ebx + js .cfgloaded + jz .cfgloaded + ;get next cluster from FAT + cmp byte [fattype], 0 + jz @f + shl eax, 2 + add eax, 0x10000 + mov eax, dword [eax] + jmp .nextcfg +@@: shl eax, 1 + add eax, 0x10000 + mov ax, word [eax] + and eax, 0FFFFh + jmp .nextcfg +.cfgloaded: pop ecx + pop edi + pop esi + pop edx + xor eax, eax + mov ecx, 4096 + sub ecx, dword [core_len] + mov edi, 9000h + add edi, dword [core_len] + repnz stosb + mov dword [core_len], eax + mov byte [9FFFh], al + jmp .notinit +.notcfg: + cmp dword [esi], 'X86_' + jne @f + cmp dword [esi+4], '64 ' + je .altinitrd +@@: cmp dword [esi], 'INIT' + jne .notinit + cmp dword [esi+4], 'RD ' + jne .notinit + cmp dword [esi+7], edx + jne .notinit + +.altinitrd: mov ecx, dword [esi + fatdir.size] + mov dword [bootboot.initrd_size], ecx + xor eax, eax + cmp byte [fattype], 0 + jz @f + mov ax, word [esi + fatdir.ch] + shl eax, 16 +@@: mov ax, word [esi + fatdir.cl] + jmp .loadinitrd + +.notinit: add esi, 32 + cmp byte [esi], 0 + jz .loadinitrd + dec ecx + jnz .nextdir +.noinitrd: mov esi, nord + jmp prot_diefunc + + ;load cluster chain, eax=cluster, ecx=size +.loadinitrd: + mov edi, dword [bootboot.initrd_ptr] +.nextclu: push eax + ;sec = (cluster-2)*secPerCluster+data_sec + sub eax, 2 + mov ebx, dword [clu_sec] + mov word [lbapacket.count], bx + mul ebx + shl ebx, 9 + add eax, dword [data_sec] + push ebx + prot_readsector + pop ebx + pop eax + add edi, ebx + sub ecx, ebx + js .initrdloaded + jz .initrdloaded + ;get next cluster from FAT + cmp byte [fattype], 0 + jz @f + shl eax, 2 + add eax, 0x10000 + mov eax, dword [eax] + jmp .nextclu +@@: shl eax, 1 + add eax, 0x10000 + mov ax, word [eax] + and eax, 0FFFFh + jmp .nextclu + +.initrdloaded: + DBG32 dbg_initrd + mov esi, dword [bootboot.initrd_ptr] +.initrdrom: + mov edi, dword [bootboot.initrd_ptr] + cmp word [esi], 08b1fh + jne .noinflate + DBG32 dbg_gzinitrd + mov ebx, esi + mov eax, dword [bootboot.initrd_size] + add ebx, eax + sub ebx, 4 + mov ecx, dword [ebx] + mov dword [bootboot.initrd_size], ecx + add edi, eax + add edi, 4095 + shr edi, 12 + shl edi, 12 + add eax, ecx + cmp eax, (INITRD_MAXSIZE+2)*1024*1024 + jb @f + mov esi, nogzmem + jmp prot_diefunc +@@: mov dword [bootboot.initrd_ptr], edi + ; inflate initrd + xor eax, eax + add esi, 2 + lodsb + cmp al, 8 + jne tinf_err + lodsb + mov bl, al + add esi, 6 + test bl, 4 + jz @f + lodsw + add esi, eax +@@: test bl, 8 + jz .noname +@@: lodsb + or al, al + jnz @b +.noname: test bl, 16 + jz .nocmt +@@: lodsb + or al, al + jnz @b +.nocmt: test bl, 2 + jz @f + add esi, 2 +@@: call tinf_uncompress +.noinflate: + ;round up to page size + mov eax, dword [bootboot.initrd_size] + add eax, 4095 + shr eax, 12 + shl eax, 12 + mov dword [bootboot.initrd_size], eax + + ;do we have an environment configuration? + mov ebx, 9000h + cmp byte [ebx], 0 + jnz .parsecfg + + ;-----load /sys/config------ + mov edx, fsdrivers +.nextfs1: xor ebx, ebx + mov bx, word [edx] + or bx, bx + jz .errfs1 + mov esi, dword [bootboot.initrd_ptr] + mov ecx, dword [bootboot.initrd_size] + add ecx, esi + mov edi, cfgfile + push edx + call ebx + pop edx + or ecx, ecx + jnz .fscfg + add edx, 2 + jmp .nextfs1 +.fscfg: mov edi, 9000h + add ecx, 3 + shr ecx, 2 + repnz movsd +.errfs1: + ;do we have an environment configuration? + mov ebx, 9000h + cmp byte [ebx], 0 + jz .noconf + + ;parse +.parsecfg: push ebx + DBG32 dbg_env + pop esi + jmp .getnext + + ;skip comments +.nextvar: cmp byte[esi], '#' + je .skipcom + cmp word[esi], '//' + jne @f + add esi, 2 +.skipcom: lodsb + cmp al, 10 + je .getnext + cmp al, 13 + je .getnext + or al, al + jz .parseend + cmp esi, 0A000h + ja .parseend + jmp .skipcom +@@: cmp word[esi], '/*' + jne @f +.skipcom2: inc esi + cmp word [esi-2], '*/' + je .getnext + cmp byte [esi], 0 + jz .parseend + cmp esi, 0A000h + ja .parseend + jmp .skipcom2 + ;only match on beginning of line +@@: cmp esi, 9000h + je @f + cmp byte [esi-1], ' ' + je @f + cmp byte [esi-1], 13 + jae .next + ;parse screen dimensions +@@: cmp dword[esi], 'scre' + jne @f + cmp word[esi+4], 'en' + jne @f + cmp byte[esi+6], '=' + jne @f + add esi, 7 + call prot_dec2bin + mov dword [reqwidth], eax + inc esi + call prot_dec2bin + mov dword [reqheight], eax + jmp .getnext + ;get kernel's filename +@@: cmp dword[esi], 'kern' + jne @f + cmp word[esi+4], 'el' + jne @f + cmp byte[esi+6], '=' + jne @f + add esi, 7 + mov edi, kernel +.copy: lodsb + or al, al + jz .copyend + cmp al, ' ' + jz .copyend + cmp al, 13 + jbe .copyend + cmp esi, 0A000h + ja .copyend + cmp edi, loader_end-1 + jae .copyend + stosb + jmp .copy +.copyend: xor al, al + stosb + jmp .getnext +@@: cmp dword[esi], 'nosm' + jne .next + cmp word[esi+4], 'p=' + jne .next + cmp byte[esi+6], '1' + jne .next + mov byte[nosmp], 1 +.next: inc esi + ;failsafe +.getnext: cmp esi, 0A000h + jae .parseend + cmp byte [esi], 0 + je .parseend + ;skip white spaces + cmp byte [esi], ' ' + je @b + cmp byte [esi], 13 + jbe @b + jmp .nextvar +.noconf: mov edi, ebx + mov ecx, 1024 + xor eax, eax + repnz stosd + mov dword [ebx+0], '// N' + mov dword [ebx+4], '/A' or (10 shl 16) +.parseend: + + ;-----load /sys/core------ + mov edx, fsdrivers +.nextfs: xor ebx, ebx + mov bx, word [edx] + or bx, bx + jz .errfs + mov esi, dword [bootboot.initrd_ptr] + mov ecx, dword [bootboot.initrd_size] + add ecx, esi + mov edi, kernel + push edx + call ebx + pop edx + or ecx, ecx + jnz .coreok + add edx, 2 + jmp .nextfs +.errfs2: mov esi, nocore + jmp prot_diefunc +.errfs: ; if all drivers failed, search for the first elf executable + DBG32 dbg_scan + mov esi, dword [bootboot.initrd_ptr] + mov ecx, dword [bootboot.initrd_size] + add ecx, esi + dec esi +@@: inc esi + cmp esi, ecx + jae .errfs2 + cmp dword [esi], 5A2F534Fh ; OS/Z magic + je .alt + cmp dword [esi], 464C457Fh ; ELF magic + je .alt + cmp word [esi], 5A4Dh ; MZ magic + jne @b + mov eax, dword [esi+0x3c] + cmp eax, 65536 + jnl @b + add eax, esi + cmp dword [eax], 00004550h ; PE magic + jne @b + cmp word [eax+4], 8664h ; x86_64 + jne @b + cmp word [eax+20], 20Bh + jne @b +.alt: cmp word [esi+4], 0102h ;lsb 64 bit + jne @b + cmp word [esi+18], 62 ;x86_64 + jne @b + cmp word [esi+0x38], 0 ;e_phnum > 0 + jz @b +.coreok: + ; parse PE + cmp word [esi], 5A4Dh ; MZ magic + jne .tryelf + mov ebx, esi + cmp dword [esi+0x3c], 65536 + jnl .badcore + add esi, dword [esi+0x3c] + cmp dword [esi], 00004550h ; PE magic + jne .badcore + cmp word [esi+4], 8664h ; x86_64 architecture + jne .badcore + cmp word [esi+20], 20Bh ; PE32+ format + jne .badcore + + DBG32 dbg_pe + + mov eax, dword [esi+36] ; entry point + mov dword [entrypoint], eax + mov dword [entrypoint+4], 0FFFFFFFFh + mov ecx, eax + sub ecx, dword [esi+40] ; - code base + add ecx, dword [esi+24] ; + text size + add ecx, dword [esi+28] ; + data size + mov edx, dword [esi+32] ; bss size + shr eax, 31 + jz .badcore + jmp .mkcore + + ; parse ELF +.tryelf: cmp dword [esi], 5A2F534Fh ; OS/Z magic + je @f + cmp dword [esi], 464C457Fh ; ELF magic + jne .badcore +@@: cmp word [esi+4], 0102h ;lsb 64 bit, little endian + jne .badcore + cmp word [esi+18], 62 ;x86_64 architecture + je @f +.badcore: mov esi, badcore + jmp prot_diefunc +@@: + DBG32 dbg_elf + + mov ebx, esi + mov eax, dword [esi+0x18] + mov dword [entrypoint], eax + mov eax, dword [esi+0x18+4] + mov dword [entrypoint+4], eax + ;parse ELF binary + mov cx, word [esi+0x38] ; program header entries phnum + mov eax, dword [esi+0x20] ; program header + add esi, eax + sub esi, 56 + inc cx +.nextph: add esi, 56 + dec cx + jz .badcore + cmp word [esi], 1 ; p_type, loadable + jne .nextph + cmp word [esi+22], 0FFFFh ; p_vaddr == negative address + jne .nextph + ;got it + add ebx, dword [esi+8] ; + P_offset + mov ecx, dword [esi+32] ; p_filesz + ; hack to keep symtab and strtab for shared libraries + cmp byte [ebx+16], 3 + jne @f + add ecx, 04000h +@@: mov edx, dword [esi+40] ; p_memsz + sub edx, ecx + + ;ebx=ptr to core segment, ecx=segment size, edx=bss size +.mkcore: or ecx, ecx + jz .badcore + mov eax, ecx + add eax, edx + cmp eax, 2*1024*1024 - 256*1024 - 2*4096; 2M minus stack for 256 cores minus bootboot and environment + jl @f + mov esi, bigcore + jmp prot_diefunc +@@: mov edi, dword [bootboot.initrd_ptr] + add edi, dword [bootboot.initrd_size] + mov dword [core_ptr], edi + mov dword [core_len], ecx + ;copy code from segment after initrd + mov esi, ebx + mov ebx, ecx + and bl, 3 + shr ecx, 2 + repnz movsd + or bl, bl + jz @f + mov cl, bl + repnz movsb + ;zero out bss +@@: or edx, edx + jz @f + add dword [core_len], edx + xor eax, eax + mov ecx, edx + and dl, 3 + shr ecx, 2 + repnz stosd + or dl, dl + jz @f + mov cl, dl + repnz stosb + ;round up to page size +@@: mov eax, dword [core_len] + add eax, 4095 + shr eax, 12 + shl eax, 12 + mov dword [core_len], eax + + ;exclude initrd area and core from free mmap + mov esi, bootboot.mmap + mov ebx, dword [bootboot.initrd_ptr] + mov edx, dword [core_ptr] + add edx, eax + mov cx, 248 + ; initrd+core (ebx..edx) +.nextfree: cmp dword [esi], ebx + ja .excludeok + mov eax, dword [esi+8] + and al, 0F0h + add eax, dword [esi] + cmp edx, eax + ja .notini + ; +--------------+ + ; ####### + cmp dword [esi], ebx + jne .splitmem + ; ptr = initrd_ptr+initrd_size+core_len + mov dword [esi], edx + sub edx, ebx + and dl, 0F0h + ; size -= initrd_size+core_len + sub dword [esi+8], edx + jmp .excludeok + ; +--+ +----------+ + ; ####### +.splitmem: mov edi, bootboot.magic + add edi, dword [bootboot.size] + add dword [bootboot.size], 16 +@@: mov eax, dword [edi-16] + mov dword [edi], eax + mov eax, dword [edi-12] + mov dword [edi+4], eax + mov eax, dword [edi-8] + mov dword [edi+8], eax + mov eax, dword [edi-4] + mov dword [edi+12], eax + sub edi, 16 + cmp edi, esi + ja @b + mov eax, ebx + sub eax, dword [esi] + sub dword [esi+24], eax + inc al + mov dword [esi+8], eax + mov dword [esi+16], edx + sub edx, ebx + sub dword [esi+24], edx + jmp .excludeok +.notini: add esi, 16 + dec cx + jnz .nextfree +.excludeok: + ; -------- SMP --------- + ; clear LAPIC address and logical core id list + mov edi, lapic_ptr + mov ecx, 512/4+1 + xor eax, eax + repnz stosd + ; clear flags + mov byte [bsp_done], al + + cmp byte [nosmp], al + jne .nosmp + + ; try ACPI first + mov esi, dword [bootboot.acpi_ptr] + or esi, esi + jz .trymp + mov edx, 4 + cmp byte [esi], 'X' ; XSDT has 8 bytes pointers, but we can only access 4G + jne @f + mov edx, 8 +@@: mov ecx, dword [esi+4] + add esi, 024h + sub ecx, 024h +.nextsdt: mov ebx, dword [esi] + add esi, edx + cmp dword [ebx], 'APIC' ; look for MADT + je .madt + sub ecx, edx + or ecx, ecx + jz .trymp + jmp .nextsdt + ; MADT found. +.madt: mov eax, dword [ebx+24h] + mov dword [lapic_ptr], eax ; madt.lapic_address + mov ecx, dword [ebx+4] + sub ecx, 2ch + add ebx, 2ch + mov edi, lapic_ids +.nextmadtentry: + cmp word [bootboot.numcores], 256 + jae .dosmp + cmp byte [ebx], 0 ; madt_entry.type: is it a Local APIC Processor? + jne @f + xor ax, ax + mov al, byte [ebx+2] ; madt_entry.lapicproc.lapicid + stosw ; ACPI table holds 1 byte id, but internally we have 2 bytes + inc word [bootboot.numcores] +@@: xor eax, eax + mov al, byte [ebx+1] ; madt_entry.size + or al, al + jz .dosmp + add ebx, eax + sub ecx, eax + cmp ecx, 0 + jg .nextmadtentry + jmp .dosmp + + +.trymp: ; in lack of ACPI, try legacy MP structures + mov esi, dword [bootboot.mp_ptr] + or esi, esi + jz .nosmp + mov esi, dword [esi+4] + cmp dword [esi], 'PCMP' + jne .nosmp + mov eax, dword [esi+36] ; pcmp.lapic_address + mov dword [lapic_ptr], eax + mov cx, word [esi+34] ; pcmp.numentries + add esi, 44 ; pcmp header length + mov edi, lapic_ids +.nextpcmpentry: + cmp word [bootboot.numcores], 256 + jae .dosmp + cmp byte [esi], 0 ; pcmp_entry.type: is it a Local APIC Processor? + jne @f + xor ax, ax + mov al, byte [esi+1] ; pcmp_entry.lapicproc.lapicid + stosw ; PCMP has 1 byte id, but we use 2 bytes internally + inc word [bootboot.numcores] + add esi, 12 +@@: add esi, 8 + dec cx + jnz .nextpcmpentry + + ; send IPI and SIPI +.dosmp: cmp word [bootboot.numcores], 2 + jb .nosmp + + DBG32 dbg_smp + + ; relocate AP trampoline + mov esi, ap_trampoline + mov edi, 7000h + mov ecx, (ap_start-ap_trampoline+3)/4 + repnz movsd + + ; send Broadcast INIT IPI + mov esi, dword [lapic_ptr] + add esi, 300h + mov eax, 0C4500h + mov dword [esi], eax + + ; wait 10 millisec + prot_realmode + xor cx, cx + mov dx, 10000 + mov ah, 086h + sti + int 15h + cli + real_protmode + + ; send Broadcast STARTUP IPI + mov eax, 0C4607h ; start at 0700:0000h + mov dword [esi], eax + + ; wait 200 microsec + prot_realmode + xor cx, cx + mov dx, 200 + mov ah, 086h + sti + int 15h + cli + real_protmode + + mov eax, 0C4607h ; second SIPI + mov dword [esi], eax + +.nosmp: ; failsafe + cmp word [bootboot.numcores], 0 + jnz @f + inc word [bootboot.numcores] + mov ax, word [bootboot.bspid] + mov word [lapic_ids], ax +@@: ; remove core stacks from memory map + xor eax, eax + mov ax, word [bootboot.numcores] + shl eax, 10 + mov edi, bootboot.mmap + add dword [edi], eax + sub dword [edi+8], eax + + ; ------- set video resolution ------- + prot_realmode + + DBG dbg_vesa + + xor ax, ax + mov es, ax + ;get VESA VBE2.0 info + mov ax, 4f00h + mov di, 0A000h + mov dword [di], 'VBE2' + ;this call requires a big stack + int 10h + cmp ax, 004fh + je @f +.viderr: mov si, novbe + jmp real_diefunc + ;read dword pointer and copy string to 1st 64k + ;available video modes +@@: xor esi, esi + xor edi, edi + mov si, word [0A000h+0Eh] + mov ax, word [0A000h+10h] + mov ds, ax + xor ax, ax + mov es, ax + mov di, 0A000h+400h + mov cx, 64 +@@: lodsw + cmp ax, 0ffffh + je @f + or ax, ax + jz @f + stosw + dec cx + jnz @b +@@: xor ax, ax + stosw + ;iterate on modes + mov si, 0A000h+400h +.nextmode: mov di, 0A000h+800h + xor ax, ax + mov word [0A000h+802h], ax ; vbe mode + lodsw + or ax, ax + jz .viderr + mov cx, ax + mov ax, 4f01h + push bx + push cx + push si + push di + int 10h + pop di + pop si + pop cx + pop bx + cmp ax, 004fh + jne .viderr + bts cx, 13 + bts cx, 14 + mov ax, word [0A000h+800h] ; vbe flags + and ax, VBE_MODEFLAGS + cmp ax, VBE_MODEFLAGS + jne .nextmode + ;check memory model (direct) + cmp byte [0A000h+81bh], 6 + jne .nextmode + ;check bpp + cmp byte [0A000h+819h], 32 + jne .nextmode + ;check min width + mov ax, word [reqwidth] + cmp ax, 640 + ja @f + mov ax, 640 +@@: cmp word [0A000h+812h], ax + jne .nextmode + ;check min height + mov ax, word [reqheight] + cmp ax, 480 + ja @f + mov ax, 480 +@@: cmp word [0A000h+814h], ax + jb .nextmode + ;match? go no further +.match: xor edx, edx + xor ebx, ebx + xor eax, eax + mov bx, word [0A000h+810h] + mov word [bootboot.fb_scanline], bx + mov ax, word [0A000h+812h] + mov word [bootboot.fb_width], ax + mov ax, word [0A000h+814h] + mov word [bootboot.fb_height], ax + mul ebx + mov dword [bootboot.fb_size], eax + mov eax, dword [0A000h+828h] + mov dword [bootboot.fb_ptr], eax + mov byte [bootboot.fb_type],FB_ARGB ; blue offset + cmp byte [0A000h+824h], 0 + je @f + mov byte [bootboot.fb_type],FB_RGBA + cmp byte [0A000h+824h], 8 + je @f + mov byte [bootboot.fb_type],FB_ABGR + cmp byte [0A000h+824h], 16 + je @f + mov byte [bootboot.fb_type],FB_BGRA +@@: ; set video mode + mov bx, cx + bts bx, 14 ;flat linear + mov ax, 4f02h + int 10h + cmp ax, 004fh + jne .viderr + ;no debug output after this point + + ;inform firmware that we're about to leave it's realm + mov ax, 0EC00h + mov bx, 2 ; 64 bit + int 15h + real_protmode + + ; -------- paging --------- + ;map core at higher half of memory + ;address 0xffffffffffe00000 + xor eax, eax + mov edi, 0A000h + mov ecx, (14000h+256*1024-0A000h)/4 + repnz stosd + + ;PML4 + mov edi, 0A000h + ;pointer to 2M PDPE (first 4G RAM identity mapped) + mov dword [edi], 0E003h + ;pointer to 4k PDPE (core mapped at -2M) + mov dword [edi+4096-8], 0B003h + + ;4K PDPE + mov edi, 0B000h + mov dword [edi+4096-8], 0C003h + ;4K PDE + mov edi, 0C000h+3840 + mov eax, dword[bootboot.fb_ptr] ;map framebuffer + mov al,83h + mov ecx, 31 +@@: stosd + add edi, 4 + add eax, 2*1024*1024 + dec ecx + jnz @b + mov dword [0C000h+4096-8], 0D003h + + ;4K PT + mov dword[0D000h], 08001h ;map bootboot + mov dword[0D008h], 09001h ;map configuration + mov edi, 0D010h + mov eax, dword[core_ptr] ;map core text segment + inc eax + mov ecx, dword[core_len] + shr ecx, 12 + inc ecx +@@: stosd + add edi, 4 + add eax, 4096 + dec ecx + jnz @b + ;map core stacks (one page per 4 cores) + mov edi, 0DFF8h + mov eax, 014003h + mov cx, word [bootboot.numcores] + add cx, 3 + shr cx, 2 +@@: mov dword[edi], eax + sub edi, 8 + add eax, 1000h + dec cx + jnz @b + + ;identity mapping + ;2M PDPE + mov edi, 0E000h + mov dword [edi], 0F003h + mov dword [edi+8], 010003h + mov dword [edi+16], 011003h + mov dword [edi+24], 012003h + ;2M PDE + mov edi, 0F000h + xor eax, eax + mov al, 83h + mov ecx, 512* 4;G RAM +@@: stosd + add edi, 4 + add eax, 2*1024*1024 + dec ecx + jnz @b + ;first 2M mapped by page + mov dword [0F000h], 013003h + mov edi, 013000h + mov eax, 3 + mov ecx, 512 +@@: stosd + add edi, 4 + add eax, 4096 + dec ecx + jnz @b + + ;generate new 64 bit gdt + mov edi, GDT_table+8 + ;8h core code + xor eax, eax ;supervisor mode (ring 0) + mov ax, 0FFFFh + stosd + mov eax, 00209800h + stosd + ;10h core data + xor eax, eax ;flat data segment + mov ax, 0FFFFh + stosd + mov eax, 00809200h + stosd + ;18h mandatory tss + xor eax, eax ;required by vt-x + mov al, 068h + stosd + mov eax, 00008900h + stosd + xor eax, eax + stosd + stosd + + ;Enter long mode + cli + mov al, 0FFh ;disable PIC + out 021h, al + out 0A1h, al + in al, 70h ;disable NMI + or al, 80h + out 70h, al + ;release AP spinlock + inc byte [bsp_done] + + ;don't use stack below this line +public longmode_init +longmode_init: + xchg bx, bx + mov eax, 1101101000b ;Set PAE, MCE, PGE; OSFXSR, OSXMMEXCPT (enable SSE) + mov cr4, eax + mov eax, 0A000h + mov cr3, eax + mov ecx, 0C0000080h ;EFER MSR + rdmsr + or eax, 100h ;enable long mode + wrmsr + + mov eax, 0C0000011h ;clear EM, MP (enable SSE) and WP + mov cr0, eax ;enable paging with cache disabled + lgdt [GDT_value] ;read 80 bit address + jmp @f + nop +@@: jmp 8:@f + USE64 +@@: xor eax, eax ;load long mode segments + mov ax, 10h + mov ds, ax + mov es, ax + mov ss, ax + mov fs, ax + mov gs, ax + ; find out our lapic id + mov eax, 1 + cpuid + shr ebx, 24 + mov edx, ebx + ; get array index for it + xor rbx, rbx + mov rsi, lapic_ids + mov cx, word [bootboot.numcores] +@@: lodsw + cmp ax, dx + je @f + inc ebx + dec cx + jnz @b + xor rbx, rbx +@@: shl rbx, 10 ; 1k stack for each core + + ; set stack and call _start() in sys/core + xor rsp, rsp ;sp = core_num * -1024 + sub rsp, rbx + xchg bx, bx + jmp qword[entrypoint] + nop + nop + nop + nop + + USE32 + include "fs.inc" + include "tinf.inc" + + ;encryption support for FS/Z +; --- SHA-256 --- +public sha_init +sha_init: xor eax, eax + mov dword [sha_l], eax + mov dword [sha_b], eax + mov dword [sha_b+4], eax + mov dword [sha_s ], 06a09e667h + mov dword [sha_s+ 4], 0bb67ae85h + mov dword [sha_s+ 8], 03c6ef372h + mov dword [sha_s+12], 0a54ff53ah + mov dword [sha_s+16], 0510e527fh + mov dword [sha_s+20], 09b05688ch + mov dword [sha_s+24], 01f83d9abh + mov dword [sha_s+28], 05be0cd19h + ret + + ; IN: ebx = buffer, ecx = length +public sha_upd +sha_upd: push esi + or ecx, ecx + jz .end + mov esi, ebx + mov edi, dword [sha_l] + add edi, sha_d + ; for(;len--;d++) { + ; ctx->d[ctx->l++]=*d; +.next: movsb + inc byte [sha_l] + ; if(ctx->l==64) { + cmp byte [sha_l], 64 + jne @f + ; sha256_t(ctx); + call sha_final.sha_t + ; SHA_ADD(ctx->b[0],ctx->b[1],512); + add dword [sha_b], 512 + adc dword [sha_b+4], 0 + ; ctx->l=0; + mov byte [sha_l], 0 + sub edi, 64 + ; } +@@: dec ecx + jnz .next +.end: pop esi + ret + + ; IN: edi = output buffer +public sha_final +sha_final: push esi + push edi + mov ebx, edi + ; i=ctx->l; ctx->d[i++]=0x80; + mov edi, dword [sha_l] + mov ecx, edi + add edi, sha_d + mov al, 80h + stosb + xor eax, eax + ; if(ctx->l<56) {while(i<56) ctx->d[i++]=0x00;} + cmp cl, 56 + jae @f + neg ecx + add ecx, 63 + xor al, al + repnz stosb + jmp .padded +@@: ; else {while(i<64) ctx->d[i++]=0x00;sha256_t(ctx);memset(ctx->d,0,56);} + stosb + call .sha_t + push ecx + mov ecx, 56/4 + repnz stosd + pop ecx + inc cl + cmp cl, 64 + jne @b +.padded: ; SHA_ADD(ctx->b[0],ctx->b[1],ctx->l*8); + mov eax, dword [sha_l] + shl eax, 3 + add dword [sha_b], eax + adc dword [sha_b+4], 0 + ; ctx->d[63]=ctx->b[0];ctx->d[62]=ctx->b[0]>>8;ctx->d[61]=ctx->b[0]>>16;ctx->d[60]=ctx->b[0]>>24; + mov eax, dword [sha_b] + bswap eax + mov dword [sha_d+60], eax + ; ctx->d[59]=ctx->b[1];ctx->d[58]=ctx->b[1]>>8;ctx->d[57]=ctx->b[1]>>16;ctx->d[56]=ctx->b[1]>>24; + mov eax, dword [sha_b+4] + bswap eax + mov dword [sha_d+56], eax + ; sha256_t(ctx); + call .sha_t + ; for(i=0;i<4;i++) { + ; h[i] =(ctx->s[0]>>(24-i*8)); h[i+4] =(ctx->s[1]>>(24-i*8)); + ; h[i+8] =(ctx->s[2]>>(24-i*8)); h[i+12]=(ctx->s[3]>>(24-i*8)); + ; h[i+16]=(ctx->s[4]>>(24-i*8)); h[i+20]=(ctx->s[5]>>(24-i*8)); + ; h[i+24]=(ctx->s[6]>>(24-i*8)); h[i+28]=(ctx->s[7]>>(24-i*8)); + ; } + mov edi, ebx + mov esi, sha_s + mov cl, 8 +@@: lodsd + bswap eax + stosd + dec cl + jnz @b + pop edi + pop esi + ret +; private func, sha transform +.sha_t: push esi + push edi + push edx + push ecx + push ebx + ; for(i=0,j=0;i<16;i++,j+=4) m[i]=(ctx->d[j]<<24)|(ctx->d[j+1]<<16)|(ctx->d[j+2]<<8)|(ctx->d[j+3]); + mov cl, 16 + mov edi, _m + mov esi, sha_d +@@: lodsd + bswap eax + stosd + dec cl + jnz @b + ; for(;i<64;i++) m[i]=SHA_SIG1(m[i-2])+m[i-7]+SHA_SIG0(m[i-15])+m[i-16]; + mov cl, 48 + ; SHA_SIG0[m[i-15]) (SHA_ROTR(x,7)^SHA_ROTR(x,18)^((x)>>3)) +@@: mov eax, dword [edi-15*4] + mov ebx, eax + mov edx, eax + ror eax, 7 + ror ebx, 18 + shr edx, 3 + xor eax, ebx + xor eax, edx + ; SHA_SIG1(m[i-2]) (SHA_ROTR(x,17)^SHA_ROTR(x,19)^((x)>>10)) + mov ebx, dword [edi-2*4] + mov edx, ebx + ror ebx, 17 + ror edx, 19 + xor ebx, edx + rol edx, 19 + shr edx, 10 + xor ebx, edx + add eax, ebx + ; m[i-7] + add eax, dword [edi-7*4] + ; m[i-16] + add eax, dword [edi-16*4] + stosd + dec cl + jnz @b + ; a=ctx->s[0];b=ctx->s[1];c=ctx->s[2];d=ctx->s[3]; + ; e=ctx->s[4];f=ctx->s[5];g=ctx->s[6];h=ctx->s[7]; + xor ecx, ecx + mov cl, 8 + mov esi, sha_s + mov edi, _a + repnz movsd + ; for(i=0;i<64;i++) { + mov esi, _m +@@: ; t1=h+SHA_EP1(e)+SHA_CH(e,f,g)+sha256_k[i]+m[i]; + mov eax, dword [_h] + mov dword [t1], eax + ; SHA_EP1(e) (SHA_ROTR(x,6)^SHA_ROTR(x,11)^SHA_ROTR(x,25)) + mov eax, dword [_e] + mov ebx, eax + ror eax, 6 + ror ebx, 11 + xor eax, ebx + ror ebx, 14 ; 25 = 11+14 + xor eax, ebx + add dword [t1], eax + ; SHA_CH(e,f,g) (((x)&(y))^(~(x)&(z))) + mov eax, dword [_e] + mov ebx, eax + not ebx + and eax, dword [_f] + and ebx, dword [_g] + xor eax, ebx + add dword [t1], eax + ; sha256_k[i] + mov eax, dword [sha256_k+4*ecx] + add dword [t1], eax + ; m[i] + lodsd + add dword [t1], eax + ; t2=SHA_EP0(a)+SHA_MAJ(a,b,c); + ; SHA_EP0(a) (SHA_ROTR(x,2)^SHA_ROTR(x,13)^SHA_ROTR(x,22)) + mov eax, dword [_a] + mov ebx, eax + ror eax, 2 + ror ebx, 13 + xor eax, ebx + ror ebx, 9 ; 22 = 13+9 + xor eax, ebx + mov dword [t2], eax + ; SHA_MAJ(a,b,c) (((x)&(y))^((x)&(z))^((y)&(z))) + mov eax, dword [_a] + mov edx, dword [_c] + mov ebx, eax + and eax, dword [_b] + and ebx, edx + xor eax, ebx + mov ebx, dword [_b] + and ebx, edx + xor eax, ebx + add dword [t2], eax + ; h=g;g=f;f=e;e=d+t1;d=c;c=b;b=a;a=t1+t2; + mov eax, dword [_g] + mov dword [_h], eax + mov eax, dword [_f] + mov dword [_g], eax + mov eax, dword [_e] + mov dword [_f], eax + mov eax, dword [_d] + add eax, dword [t1] + mov dword [_e], eax + mov eax, dword [_c] + mov dword [_d], eax + mov eax, dword [_b] + mov dword [_c], eax + mov eax, dword [_a] + mov dword [_b], eax + mov eax, dword [t1] + add eax, dword [t2] + mov dword [_a], eax + ; } + inc cl + cmp cl, 64 + jne @b + ; ctx->s[0]+=a;ctx->s[1]+=b;ctx->s[2]+=c;ctx->s[3]+=d; + ; ctx->s[4]+=e;ctx->s[5]+=f;ctx->s[6]+=g;ctx->s[7]+=h; + mov cl, 8 + mov esi, _a + mov edi, sha_s +@@: lodsd + add dword [edi], eax + add edi, 4 + dec cl + jnz @b + pop ebx + pop ecx + pop edx + pop edi + pop esi + xor eax, eax + ret + +; --- CRC-32c --- + ; IN: esi = buffer, ecx = length + ; OUT: edx = crc +public crc32_calc +crc32_calc: xor edx, edx + xor eax, eax + xor ebx, ebx + or cx, cx + jz .end +.next: lodsb + mov bl, dl + xor bl, al + mov eax, edx + shr edx, 8 + xor edx, dword [crclkp+4*ebx] + dec cx + jnz .next +.end: ret + +;********************************************************************* +;* Data * +;********************************************************************* + ;global descriptor table + align 16 +public GDT_table +GDT_table: dd 0, 0 ;null descriptor +DATA_PROT = $-GDT_table + dd 0000FFFFh,008F9200h ;flat ds +DATA_BOOT = $-GDT_table + dd 0000FFFFh,00009200h ;16 bit legacy real mode ds +CODE_BOOT = $-GDT_table + dd 0000FFFFh,00009800h ;16 bit legacy real mode cs +CODE_PROT = $-GDT_table + dd 0000FFFFh,00CF9A00h ;32 bit prot mode ring0 cs + dd 00000068h,00CF8900h ;32 bit TSS, not used but required +public GDT_value +GDT_value: dw $-GDT_table + dd GDT_table + dd 0,0 + ;lookup tables for initrd encryption + dw 0 +public crclkp +crclkp: dd 000000000h, 0F26B8303h, 0E13B70F7h, 01350F3F4h, 0C79A971Fh, 035F1141Ch, 026A1E7E8h, 0D4CA64EBh + dd 08AD958CFh, 078B2DBCCh, 06BE22838h, 09989AB3Bh, 04D43CFD0h, 0BF284CD3h, 0AC78BF27h, 05E133C24h + dd 0105EC76Fh, 0E235446Ch, 0F165B798h, 0030E349Bh, 0D7C45070h, 025AFD373h, 036FF2087h, 0C494A384h + dd 09A879FA0h, 068EC1CA3h, 07BBCEF57h, 089D76C54h, 05D1D08BFh, 0AF768BBCh, 0BC267848h, 04E4DFB4Bh + dd 020BD8EDEh, 0D2D60DDDh, 0C186FE29h, 033ED7D2Ah, 0E72719C1h, 0154C9AC2h, 0061C6936h, 0F477EA35h + dd 0AA64D611h, 0580F5512h, 04B5FA6E6h, 0B93425E5h, 06DFE410Eh, 09F95C20Dh, 08CC531F9h, 07EAEB2FAh + dd 030E349B1h, 0C288CAB2h, 0D1D83946h, 023B3BA45h, 0F779DEAEh, 005125DADh, 01642AE59h, 0E4292D5Ah + dd 0BA3A117Eh, 04851927Dh, 05B016189h, 0A96AE28Ah, 07DA08661h, 08FCB0562h, 09C9BF696h, 06EF07595h + dd 0417B1DBCh, 0B3109EBFh, 0A0406D4Bh, 0522BEE48h, 086E18AA3h, 0748A09A0h, 067DAFA54h, 095B17957h + dd 0CBA24573h, 039C9C670h, 02A993584h, 0D8F2B687h, 00C38D26Ch, 0FE53516Fh, 0ED03A29Bh, 01F682198h + dd 05125DAD3h, 0A34E59D0h, 0B01EAA24h, 042752927h, 096BF4DCCh, 064D4CECFh, 077843D3Bh, 085EFBE38h + dd 0DBFC821Ch, 02997011Fh, 03AC7F2EBh, 0C8AC71E8h, 01C661503h, 0EE0D9600h, 0FD5D65F4h, 00F36E6F7h + dd 061C69362h, 093AD1061h, 080FDE395h, 072966096h, 0A65C047Dh, 05437877Eh, 04767748Ah, 0B50CF789h + dd 0EB1FCBADh, 0197448AEh, 00A24BB5Ah, 0F84F3859h, 02C855CB2h, 0DEEEDFB1h, 0CDBE2C45h, 03FD5AF46h + dd 07198540Dh, 083F3D70Eh, 090A324FAh, 062C8A7F9h, 0B602C312h, 044694011h, 05739B3E5h, 0A55230E6h + dd 0FB410CC2h, 0092A8FC1h, 01A7A7C35h, 0E811FF36h, 03CDB9BDDh, 0CEB018DEh, 0DDE0EB2Ah, 02F8B6829h + dd 082F63B78h, 0709DB87Bh, 063CD4B8Fh, 091A6C88Ch, 0456CAC67h, 0B7072F64h, 0A457DC90h, 0563C5F93h + dd 0082F63B7h, 0FA44E0B4h, 0E9141340h, 01B7F9043h, 0CFB5F4A8h, 03DDE77ABh, 02E8E845Fh, 0DCE5075Ch + dd 092A8FC17h, 060C37F14h, 073938CE0h, 081F80FE3h, 055326B08h, 0A759E80Bh, 0B4091BFFh, 0466298FCh + dd 01871A4D8h, 0EA1A27DBh, 0F94AD42Fh, 00B21572Ch, 0DFEB33C7h, 02D80B0C4h, 03ED04330h, 0CCBBC033h + dd 0A24BB5A6h, 0502036A5h, 04370C551h, 0B11B4652h, 065D122B9h, 097BAA1BAh, 084EA524Eh, 07681D14Dh + dd 02892ED69h, 0DAF96E6Ah, 0C9A99D9Eh, 03BC21E9Dh, 0EF087A76h, 01D63F975h, 00E330A81h, 0FC588982h + dd 0B21572C9h, 0407EF1CAh, 0532E023Eh, 0A145813Dh, 0758FE5D6h, 087E466D5h, 094B49521h, 066DF1622h + dd 038CC2A06h, 0CAA7A905h, 0D9F75AF1h, 02B9CD9F2h, 0FF56BD19h, 00D3D3E1Ah, 01E6DCDEEh, 0EC064EEDh + dd 0C38D26C4h, 031E6A5C7h, 022B65633h, 0D0DDD530h, 00417B1DBh, 0F67C32D8h, 0E52CC12Ch, 01747422Fh + dd 049547E0Bh, 0BB3FFD08h, 0A86F0EFCh, 05A048DFFh, 08ECEE914h, 07CA56A17h, 06FF599E3h, 09D9E1AE0h + dd 0D3D3E1ABh, 021B862A8h, 032E8915Ch, 0C083125Fh, 0144976B4h, 0E622F5B7h, 0F5720643h, 007198540h + dd 0590AB964h, 0AB613A67h, 0B831C993h, 04A5A4A90h, 09E902E7Bh, 06CFBAD78h, 07FAB5E8Ch, 08DC0DD8Fh + dd 0E330A81Ah, 0115B2B19h, 0020BD8EDh, 0F0605BEEh, 024AA3F05h, 0D6C1BC06h, 0C5914FF2h, 037FACCF1h + dd 069E9F0D5h, 09B8273D6h, 088D28022h, 07AB90321h, 0AE7367CAh, 05C18E4C9h, 04F48173Dh, 0BD23943Eh + dd 0F36E6F75h, 00105EC76h, 012551F82h, 0E03E9C81h, 034F4F86Ah, 0C69F7B69h, 0D5CF889Dh, 027A40B9Eh + dd 079B737BAh, 08BDCB4B9h, 0988C474Dh, 06AE7C44Eh, 0BE2DA0A5h, 04C4623A6h, 05F16D052h, 0AD7D5351h + +public sha256_k +sha256_k: dd 0428a2f98h, 071374491h, 0b5c0fbcfh, 0e9b5dba5h, 03956c25bh, 059f111f1h, 0923f82a4h, 0ab1c5ed5h + dd 0d807aa98h, 012835b01h, 0243185beh, 0550c7dc3h, 072be5d74h, 080deb1feh, 09bdc06a7h, 0c19bf174h + dd 0e49b69c1h, 0efbe4786h, 00fc19dc6h, 0240ca1cch, 02de92c6fh, 04a7484aah, 05cb0a9dch, 076f988dah + dd 0983e5152h, 0a831c66dh, 0b00327c8h, 0bf597fc7h, 0c6e00bf3h, 0d5a79147h, 006ca6351h, 014292967h + dd 027b70a85h, 02e1b2138h, 04d2c6dfch, 053380d13h, 0650a7354h, 0766a0abbh, 081c2c92eh, 092722c85h + dd 0a2bfe8a1h, 0a81a664bh, 0c24b8b70h, 0c76c51a3h, 0d192e819h, 0d6990624h, 0f40e3585h, 0106aa070h + dd 019a4c116h, 01e376c08h, 02748774ch, 034b0bcb5h, 0391c0cb3h, 04ed8aa4ah, 05b9cca4fh, 0682e6ff3h + dd 0748f82eeh, 078a5636fh, 084c87814h, 08cc70208h, 090befffah, 0a4506cebh, 0bef9a3f7h, 0c67178f2h +public idt16 +idt16: dw 3FFh + dq 0 +public lbapacket +lbapacket: ;lba packet for BIOS +.size: dw 10h +.count: dw 8 +.addr: dd 0A000h +.sect0: dd 0 +.sect1: dd 0 +public spc_packet +spc_packet: db 18h dup 0 +public reqwidth +reqwidth: dd 1024 +public reqheight +reqheight: dd 768 +public ebdaptr +ebdaptr: dd 0 +public hw_stack +hw_stack: dd 0 +public bpb_sec +bpb_sec: dd 0 ;ESP's first sector +public root_sec +root_sec: dd 0 ;root directory's first sector +public data_sec +data_sec: dd 0 ;first data sector +public clu_sec +clu_sec: dd 0 ;sector per cluster +public origcount +origcount: dw 0 +public bootdev +bootdev: db 0 +public readdev +readdev: db 0 +public cntdev +cntdev: db 0 +public hasinitrd +hasinitrd: db 0 +public hasconfig +hasconfig: db 0 +public iscdrom +iscdrom: db 0 +public nosmp +nosmp: db 0 +public bsp_done +bsp_done: ;flag to indicate APs can run +public fattype +fattype: db 0 +public bkp +bkp: dd ' ' +if BBDEBUG eq 1 +dbg_cpu db " * Detecting CPU",10,13,0 +dbg_A20 db " * Enabling A20",10,13,0 +dbg_mem db " * E820 Memory Map",10,13,0 +dbg_systab db " * System tables",10,13,0 +dbg_time db " * System time",10,13,0 +dbg_serial db " * Initrd over serial",10,13,0 +dbg_gpt db " * Reading GPT",10,13,0 +dbg_cdrom db " * Detected CDROM boot",10,13,0 +dbg_env db " * Environment",10,13,0 +dbg_initrd db " * Initrd loaded",10,13,0 +dbg_gzinitrd db " * Gzip compressed initrd",10,13,0 +dbg_scan db " * Autodetecting kernel",10,13,0 +dbg_elf db " * Parsing ELF64",10,13,0 +dbg_pe db " * Parsing PE32+",10,13,0 +dbg_smp db " * SMP init",10,13,0 +dbg_vesa db " * Screen VESA VBE",10,13,0 +end if +backup: db " * Backup initrd",10,13,0 +passphrase: db " * Passphrase? ",0 +decrypting: db 13," * Decrypting...",0 +clrdecrypt: db 13," ",13,0 +public starting +starting: db "Booting OS..." +crlf: db 10,13,0 +public panic +panic: db "-PANIC: ",0 +public noarch +noarch: db "Hardware not supported",0 +public a20err +a20err: db "Failed to enable A20",0 +public memerr +memerr: db "E820 memory map not found",0 +public nogzmem +nogzmem: db "Inflating: " +public noenmem +noenmem: db "Not enough memory",0 +public noacpi +noacpi: db "ACPI not found",0 +public nogpt +nogpt: db "No GPT found",0 +public nopar +nopar: db "No boot partition",0 +public nord +nord: db "Initrd not found",0 +public nolib +nolib: db "/sys not found in initrd",0 +public nocore +nocore: db "Kernel not found in initrd",0 +public badcore +badcore: db "Kernel is not a valid executable",0 +public bigcore +bigcore: db "Kernel is too big",0 +public novbe +novbe: db "VESA VBE error, no framebuffer",0 +public nogzip +nogzip: db "Unable to uncompress",0 +public notcdsect +notcdsect: db "Not 2048 sector aligned",0 +public nocipher +nocipher: db "Unsupported cipher",10,13,0 +public badpass +badpass: db 13,"BOOTBOOT-ERROR: Bad passphrase",10,13,0 +public cfgfile +cfgfile: db "sys/config",0,0,0 +public kernel +kernel: db "sys/core" + db (64-($-kernel)) dup 0 +;-----------padding to be multiple of 512---------- + db (511-($-loader+511) mod 512) dup 0 +public loader_end +loader_end: + +;-----------BIOS checksum------------ +chksum = 0 +repeat $-loader + load b byte from (loader+%-1) + chksum = (chksum + b) mod 100h +end repeat +store byte (100h-chksum) at (loader.checksum) + +;-----------bss area----------- +entrypoint: dq ? +core_ptr: dd ? +core_len: dd ? +gpt_ptr: dd ? +gpt_num: dd ? +gpt_ent: dd ? +lapic_ptr: dd ? +lapic_ids: +tinf_bss_start: +d_end: dd ? +d_lzOff: dd ? +d_dict_ring:dd ? +d_dict_size:dd ? +d_dict_idx: dd ? +d_tag: db ? +d_bitcount: db ? +d_bfinal: db ? +d_curlen: dw ? +d_ltree: +d_ltree_table: + dw 16 dup ? +d_ltree_trans: + dw 288 dup ? +d_dtree: +d_dtree_table: + dw 16 dup ? +d_dtree_trans: + dw 288 dup ? +offs: dw 16 dup ? +num: dw ? +lengths: db 320 dup ? +hlit: dw ? +hdist: dw ? +hclen: dw ? +tinf_bss_end: + +virtual at tinf_bss_start +pass: db 256 dup ? +sha_d: db 64 dup ? +sha_l: dd ? +sha_b: dd 2 dup ? +sha_s: dd 8 dup ? +_a: dd ? +_b: dd ? +_c: dd ? +_d: dd ? +_e: dd ? +_f: dd ? +_g: dd ? +_h: dd ? +t1: dd ? +t2: dd ? +_m: dd 64 dup ? +chk: db 32 dup ? +iv: db 32 dup ? +pl: dd ? +_i: dd ? +end virtual + +;-----------bound check------------- +;fasm will generate an error if the code +;is bigger than it should be +db 07C00h-4096-($-loader) dup ? diff --git a/bootboot.inc b/bootboot.inc new file mode 100644 index 0000000..3dc7b6a --- /dev/null +++ b/bootboot.inc @@ -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 + + + + + + + diff --git a/disk-x86.img.gz b/disk-x86.img.gz new file mode 100644 index 0000000..05ce581 Binary files /dev/null and b/disk-x86.img.gz differ diff --git a/fs.inc b/fs.inc new file mode 100644 index 0000000..a132eaf --- /dev/null +++ b/fs.inc @@ -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' && ptrsymbol 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