bztsrc--bootboot/x86_64-bios/bootboot.asm

3132 lines
110 KiB
NASM

;*
;* x86_64-bios/bootboot.asm
;*
;* Copyright (C) 2017 - 2021 bzt (bztsrc@gitlab)
;*
;* Permission is hereby granted, free of charge, to any person
;* obtaining a copy of this software and associated documentation
;* files (the "Software"), to deal in the Software without
;* restriction, including without limitation the rights to use, copy,
;* modify, merge, publish, distribute, sublicense, and/or sell copies
;* of the Software, and to permit persons to whom the Software is
;* furnished to do so, subject to the following conditions:
;*
;* The above copyright notice and this permission notice shall be
;* included in all copies or substantial portions of the Software.
;*
;* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
;* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
;* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
;* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
;* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
;* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
;* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
;* DEALINGS IN THE SOFTWARE.
;*
;* This file is part of the BOOTBOOT Protocol package.
;* @brief 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
;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 prot_sleep delay
{
mov ecx, delay
call near prot_sleepfunc
}
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)
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
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-------------
realmode_start:
cli
cld
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
;get CDROM drive code
mov ax, word 4B01h
mov si, entrypoint ; bss area
mov byte [si + 2], 0E0h
push si
int 13h
pop si
jc @f
mov al, byte [si + 2]
mov byte [cdromdev], al
@@:
;-----initialize serial port COM1,115200,8N1------
; mov ax, 0401h
; xor bx, bx
; mov cx, 030Bh
; xor dx, dx
; int 14h
mov dx, word [400h]
or dx, dx
jnz @f
; if the IO port isn't set, try the default one of COM1
mov dx, 3f8h
mov word [400h], dx
; initialize the serial outselves, because Bochs BIOS is buggy
@@: call serialsetup
; if there's no serial, but BIOS incorrectly sets the IO port for it
mov dx, word [400h]
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
;do we have PAE?
bt edx, 6
jnc .cpuerror
;what about MSR?
bt edx, 5
jnc .cpuerror
;do we have RDTSC instruction?
bt edx, 4
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
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 ---
serialsetup:
inc dx
xor al, al
out dx, al ; IER int off
mov al, 80h
add dx, 2
out dx, al ; LCR set divisor mode
mov al, 1
sub dx, 3
out dx, al ; DLL divisor lo 115200
xor al, al
inc dx
out dx, al ; DLH divisor hi
inc dx
out dx, al ; FCR fifo off
mov al, 43h
inc dx
out dx, al ; LCR 8N1, break on
mov al, 8
inc dx
out dx, al ; MCR Aux out 2
xor al, al
sub dx, 4
in al, dx ; clear receiver/transmitter
ret
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
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:
; calibrate RDTSC
rdtsc
mov dword [ncycles], eax
mov dword [ncycles+4], edx
; wait 200 usec
xor cx, cx
mov dx, 200
mov ah, 086h
int 15h
rdtsc
sub eax, dword [ncycles]
sbb edx, dword [ncycles+4]
mov dword [ncycles], eax
mov dword [ncycles+4], edx
; 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-----
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
and al, 0F0h ;clear lower tetrad for type
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:
;-----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 ----
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:ap_prot
USE32
ap_prot: mov ax, DATA_PROT
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
; enable Local APIC
mov esi, dword [lapic_ptr]
mov eax, dword [esi + 0F0h]
or ah, 1
mov dword [esi + 0F0h], eax
mov ecx, 1Bh ; enable APIC MSR
rdmsr
bt eax, 1
wrmsr
lock inc word [ap_done]
; spinlock until BSP finishes
@@: pause
cmp byte [bsp_done], 0
jz @b
jmp longmode_init
;writes the reason, waits for a key and reboots.
prot_diefunc:
prot_realmode
USE16
real_diefunc:
xor ax, ax
mov ds, ax
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
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
real_printfunc:
lodsb
or al, al
jz .end
;out 0e9h, al
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
;if BIOS timed out, clear the IO address
;so that further calls won't try sending
and ah, 80h
jz @f
mov word[400h], 0
@@: pop si
jmp real_printfunc
.end: ret
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
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
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]
cmp dl, byte [cdromdev]
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
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
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
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: ecx delay time in 200 usec units
prot_sleepfunc:
push edx
rdtsc
mov dword [gpt_ptr], eax
mov dword [gpt_ptr+4], edx
mov eax, dword [ncycles]
mov edx, dword [ncycles+4]
mul ecx
add dword [gpt_ptr], eax
adc dword [gpt_ptr+4], edx
@@: pause
rdtsc
cmp dword [gpt_ptr+4], edx
jl @b
cmp dword [gpt_ptr], eax
jl @b
pop edx
ret
; IN: al, character to 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
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
protmode_start:
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]
add ecx, ebx
add ebx, 2ch
mov edi, lapic_ids
.nextmadtentry:
cmp word [bootboot.numcores], 255
jae .acpidone
cmp byte [ebx], 0 ; madt_entry.type: is it a Local APIC Processor?
jne @f
mov al, byte [ebx+4] ; madt_entry.lapicproc.flag & ENABLED
and al, 1
jz .badmadt
xor ax, ax
mov al, byte [ebx+3] ; madt_entry.lapicproc.lapicid
cmp al, 0FFh
je .badmadt
stosw ; ACPI table holds 1 byte id, but internally we have 2 bytes
inc word [bootboot.numcores]
jmp @f
.badmadt: mov byte [bad_madt], 1
@@: xor eax, eax
mov al, byte [ebx+1] ; madt_entry.size
or al, al
jz .acpidone
add ebx, eax
cmp ebx, ecx
jae .acpidone
jmp .nextmadtentry
.trymp: ; in lack of ACPI, try legacy MP structures
mov esi, dword [bootboot.mp_ptr]
or esi, esi
jz .acpidone
mov esi, dword [esi+4]
cmp dword [esi], 'PCMP'
jne .acpidone
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], 255
jae .acpidone
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
.acpidone:
; failsafe
cmp dword [lapic_ptr], 0
jz @f
cmp word [bootboot.numcores], 1
ja .smpok
@@: mov word [bootboot.numcores], 1
mov ax, word [bootboot.bspid]
mov word [lapic_ids], ax
mov dword [lapic_ptr], 0
jmp .stks
.smpok:
if BBDEBUG eq 1
xor eax, eax
mov dword [gpt_ptr], eax
mov dword [gpt_num], eax
prot_realmode
mov bx, word [bootboot.numcores]
mov di, gpt_ptr
mov cx, 100
mov dx, bx
cmp bx, cx
jl @f
mov ax, bx
xor dx, dx
div cx
add al, '0'
stosb
@@: mov cx, 10
mov ax, dx
xor dx, dx
div cx
cmp bx, cx
jl @f
add al, '0'
stosb
@@: mov al, dl
add al, '0'
stosb
xor al, al
stosb
mov si, dbg_smp
call real_printfunc
mov si, gpt_ptr
call real_printfunc
cmp byte [bad_madt], 0
jz @f
mov si, dbg_madt
call real_printfunc
@@: mov si, crlf
call real_printfunc
real_protmode
end if
.stks: ; remove core stacks from memory map
xor eax, eax
mov ax, word [bootboot.numcores]
shl eax, 10
add eax, 0FFFh ; round up to page size
and ax, 0F000h
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
push ds
push es
int 10h
pop es
pop ds
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
push ds
push es
int 10h
pop es
pop ds
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
push ds
push es
int 10h
pop es
pop ds
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
mov al, 0FFh ;disable PIC
out 021h, al
out 0A1h, al
in al, 70h ;disable NMI
or al, 80h
out 70h, al
; ------- send INIT IPI and SIPI --------
cmp word [bootboot.numcores], 2
jb .nosmp
cmp dword [lapic_ptr], 0
jz .nosmp
; relocate AP trampoline
mov esi, ap_trampoline
mov edi, 7000h
mov ecx, (ap_start-ap_trampoline+3)/4
repnz movsd
; disable ICMR
mov al, 070h
out 22h, al
in al, 23h
or al, 1
out 23h, al
; enable Local APIC
mov esi, dword [lapic_ptr]
mov al, 1
shl eax, 24
mov dword [esi + 0D0h], eax ; logical destination
xor eax, eax
sub eax, 1
mov dword [esi + 0E0h], eax ; destination form
mov eax, dword [esi + 0F0h] ; spurious + enable
mov ax, 1FFh
mov dword [esi + 0F0h], eax
mov dword [esi + 080h], 0 ; task priority
; make sure we use the correct Local APIC ID for the BSP
mov eax, dword [esi + 020h]
shr eax, 24
mov word [bootboot.bspid], ax
mov ecx, 1Bh ; enable APIC MSR
rdmsr
bt eax, 1
wrmsr
mov al, 0fh ; CMOS warm reset code 0A
out 70h, al
mov al, 0ah
out 71h, al
mov dword [467h], 07000000h ; warm reset vector
; use broadcast IPI if MADT is okay (no bcast id and all CPUs enabled)
cmp byte [bad_madt], 0
jnz .onebyone
; send Broadcast INIT IPI
mov eax, 0C4500h
mov dword [esi + 300h], eax
; wait 10 millisec
prot_sleep 50
; send Broadcast STARTUP IPI
mov eax, 0C4607h
mov dword [esi + 300h], eax
; wait 200 microsec
prot_sleep 1
; send second STARTUP IPI
mov eax, 0C4607h
mov dword [esi + 300h], eax
; wait 200 microsec
prot_sleep 1
jmp .nosmp
.onebyone:
; send IPIs to specific cores one by one
xor edx, edx
.initcore: cmp dx, word [bootboot.numcores]
jae .sipi
mov esi, edx
inc edx
shl esi, 1
add esi, lapic_ids
mov bx, word [esi]
cmp bx, word [bootboot.bspid]
je .initcore
shl ebx, 24
; clear APIC error
mov esi, dword [lapic_ptr]
mov dword [esi + 280h], 0
mov eax, dword [esi + 280h]
add esi, 20h
; select AP
@@: pause
mov eax, dword [esi + 300h]
bt eax, 12
jc @b
mov eax, dword [esi + 310h]
and eax, 00ffffffh
or eax, ebx
mov dword [esi + 310h], eax
; trigger INIT IPI
mov eax, dword [esi + 300h]
and eax, 0fff00000h
or eax, 00C500h
mov dword [esi + 300h], eax
; wait 200 microsec
prot_sleep 1
; select AP
@@: pause
mov eax, dword [esi + 300h]
bt eax, 12
jc @b
mov eax, dword [esi + 310h]
and eax, 00ffffffh
or eax, ebx
mov dword [esi + 310h], eax
; deassert INIT IPI
mov eax, dword [esi + 300h]
and eax, 0fff00000h
or eax, 008500h
mov dword [esi + 300h], eax
jmp .initcore
.sipi:
; wait 10 millisec
prot_sleep 50
xor edx, edx
.nextcore: cmp dx, word [bootboot.numcores]
jae .nosmp
mov esi, edx
inc edx
shl esi, 1
add esi, lapic_ids
mov bx, word [esi]
cmp bx, word [bootboot.bspid]
je .nextcore
shl ebx, 24
mov word [ap_done], 0
; select AP
mov esi, dword [lapic_ptr]
@@: pause
mov eax, dword [esi + 300h]
bt eax, 12
jc @b
mov eax, dword [esi + 310h]
and eax, 00ffffffh
or eax, ebx
mov dword [esi + 310h], eax
; send STARTUP IPI
mov eax, dword [esi + 300h]
and eax, 0fff0f800h
or eax, 004607h ; start at 0700:0000h
mov dword [esi + 300h], eax
; wait 10 millisec
prot_sleep 50
; do we need a second SIPI?
cmp word [ap_done], 0
jnz .nextcore
; select AP
@@: pause
mov eax, dword [esi + 300h]
bt eax, 12
jc @b
mov eax, dword [esi + 310h]
and eax, 00ffffffh
or eax, ebx
mov dword [esi + 310h], eax
; send STARTUP IPI
mov eax, dword [esi + 300h]
and eax, 0fff0f800h
or eax, 004607h
mov dword [esi + 300h], eax
; wait 10 millisec
prot_sleep 50
jmp .nextcore
.nosmp:
;Enter long mode
cli
;release AP spinlock
lock inc byte [bsp_done]
;don't use stack below this line
longmode_init:
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 [GDT64_value] ;read 80 bit address
jmp 8:.bootboot_startcore
USE64
.bootboot_startcore:
xor rax, rax ;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, dword [lapic_ptr]
or eax, eax
jz @f
mov eax, dword [rax + 020h]
shr eax, 24
@@: mov edx, eax
; 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
@@: mov rdi, 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
jmp qword[entrypoint]
nop
nop
nop
nop
USE32
include "fs.inc"
include "tinf.inc"
;encryption support for FS/Z
; --- SHA-256 ---
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
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
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
inc ecx
xor eax, eax
; if(ctx->l<56) {while(i<56) ctx->d[i++]=0x00;}
cmp cl, 57
jae @f
neg ecx
add ecx, 56
repnz stosb
jmp .padded
@@: ; else {while(i<64) ctx->d[i++]=0x00;sha256_t(ctx);memset(ctx->d,0,56);}
neg ecx
add ecx, 64
repnz stosb
call .sha_t
mov ecx, 56/4
mov edi, sha_d
repnz stosd
.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
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
GDT_table: dd 0, 0 ;null descriptor
DATA_PROT = $-GDT_table
dd 0000FFFFh,00CF9200h ;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
GDT_value: dw $-GDT_table-1
dd GDT_table
dd 0,0
align 16
GDT64_table:dd 0, 0 ;null descriptor
dd 0000FFFFh,00209800h ;supervisor mode (ring 0) cs
dd 0000FFFFh,00809200h ;flat data segment
dd 00000068h,00008900h ;TSS, not used but required by vt-x
dd 0,0
GDT64_value:dw $-GDT64_table-1
dd GDT64_table
dd 0,0
;lookup tables for initrd encryption
dw 0
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
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
idt16: dw 3FFh
dq 0
lbapacket: ;lba packet for BIOS
.size: dw 10h
.count: dw 8
.addr: dd 0A000h
.sect0: dd 0
.sect1: dd 0
spc_packet: db 18h dup 0
reqwidth: dd 1024
reqheight: dd 768
ebdaptr: dd 0
hw_stack: dd 0
bpb_sec: dd 0 ;ESP's first sector
root_sec: dd 0 ;root directory's first sector
data_sec: dd 0 ;first data sector
clu_sec: dd 0 ;sector per cluster
origcount: dw 0
cdromdev: db 0
bootdev: db 0
readdev: db 0
cntdev: db 0
hasinitrd: db 0
hasconfig: db 0
iscdrom: db 0
nosmp: db 0
bad_madt:
ap_done: dw 0
bsp_done: db 0 ;flag to indicate APs can run
fattype: db 0
bkp: dd ' '
if BBDEBUG eq 1
dbg_cpu db " * Detecting CPU",13,10,0
dbg_A20 db " * Enabling A20",13,10,0
dbg_mem db " * E820 Memory Map",13,10,0
dbg_systab db " * System tables",13,10,0
dbg_time db " * System time",13,10,0
dbg_serial db " * Initrd over serial",13,10,0
dbg_gpt db " * Reading GPT",13,10,0
dbg_cdrom db " * Detected CDROM boot",13,10,0
dbg_env db " * Environment",13,10,0
dbg_initrd db " * Initrd loaded",13,10,0
dbg_gzinitrd db " * Gzip compressed initrd",13,10,0
dbg_scan db " * Autodetecting kernel",13,10,0
dbg_elf db " * Parsing ELF64",13,10,0
dbg_pe db " * Parsing PE32+",13,10,0
dbg_smp db " * SMP numcores ",0
dbg_madt db " (bad MADT)",0
dbg_vesa db " * Screen VESA VBE",13,10,0
end if
backup: db " * Backup initrd",13,10,0
passphrase: db " * Passphrase? ",0
decrypting: db 13," * Decrypting...",0
clrdecrypt: db 13," ",13,0
starting: db "Booting OS..."
crlf: db 13,10,0
panic: db "-PANIC: ",0
noarch: db "Hardware not supported",0
a20err: db "Failed to enable A20",0
memerr: db "E820 memory map not found",0
nogzmem: db "Inflating: "
noenmem: db "Not enough memory",0
noacpi: db "ACPI not found",0
nogpt: db "No GPT found",0
nopar: db "No boot partition",0
nord: db "Initrd not found",0
nolib: db "/sys not found in initrd",0
nocore: db "Kernel not found in initrd",0
badcore: db "Kernel is not a valid executable",0
bigcore: db "Kernel is too big",0
novbe: db "VESA VBE error, no framebuffer",0
nogzip: db "Unable to uncompress",0
notcdsect: db "Not 2048 sector aligned",0
nocipher: db "Unsupported cipher",13,10,0
badpass: db 13,"BOOTBOOT-ERROR: Bad passphrase",13,10,0
cfgfile: db "sys/config",0,0,0
kernel: db "sys/core"
db (64-($-kernel)) dup 0
;-----------padding to be multiple of 512----------
db (511-($-loader+511) mod 512) dup 0
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 ?
ncycles: dq ?
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 ?