833 lines
24 KiB
ArmAsm
833 lines
24 KiB
ArmAsm
// vim: et:sw=12:ts=12:sts=12
|
|
// lboot.S: boot code for legacy BIOS boot over PXE.
|
|
|
|
/* The assembly code in this project follows its own
|
|
* made up calling convention, because it is more convenient
|
|
* than the conventional ones for working in unreal mode.
|
|
*
|
|
* Callees preserve all registers,
|
|
* except those which they use to return values.
|
|
* All 32 bits of a register are preserved.
|
|
* Saved registers are push to the stack before the frame pointer,
|
|
* as this simplifies frame cleanup.
|
|
* Addresses/pointers are returned in EBX,
|
|
* all other values are returned in EAX.
|
|
*
|
|
* DS, ES have a 4Gb limit, and an offset of 0.
|
|
* CS has an offset of 0. SS is unspecified.
|
|
*/
|
|
|
|
.global _start
|
|
.text
|
|
.code16
|
|
|
|
.set PACKET_SIZE, 512
|
|
.set TX_BUF_SIZE, 4096
|
|
|
|
.macro pxe_call, opcode
|
|
push %eax
|
|
push %ebx
|
|
push %ecx
|
|
push %edx
|
|
|
|
mov %sp, %bx
|
|
add $16, %bx
|
|
|
|
push %ss
|
|
push %bx
|
|
push $\opcode
|
|
lcall *pxe_api
|
|
add $6, %sp
|
|
|
|
mov %ss:(%bx), %cx
|
|
or %cx, %ax
|
|
jnz _pcerr
|
|
|
|
pop %edx
|
|
pop %ecx
|
|
pop %ebx
|
|
pop %eax
|
|
.endm
|
|
|
|
// _start: entry point
|
|
_start: cli
|
|
cld
|
|
mov %sp, %bp
|
|
xor %ax, %ax
|
|
mov %ax, %ds
|
|
mov %ax, %es
|
|
|
|
mov $_bss_start, %di
|
|
mov $_bss_end, %cx
|
|
sub %di, %cx
|
|
xor %al, %al
|
|
rep stosb
|
|
|
|
call init_com1
|
|
|
|
mov $msg_start, %si
|
|
call print
|
|
mov $msg_start, %si
|
|
call print
|
|
|
|
mov %ss:4(%bp), %si
|
|
mov %ss:6(%bp), %ax
|
|
mov %ax, %fs
|
|
.set PXE_MAGIC, 0x45585021
|
|
cmpl $PXE_MAGIC, %fs:(%si)
|
|
je 1f
|
|
mov $msg_pserr, %si
|
|
call print
|
|
jmp hang
|
|
1: mov %fs:16(%si), %eax
|
|
mov %eax, pxe_api
|
|
|
|
mov $msg_a20, %si
|
|
call print
|
|
call enable_a20
|
|
|
|
.set PXE_GET_CACHED_INFO, 0x0071
|
|
push $0
|
|
push %cs
|
|
push $tx_buf
|
|
push $TX_BUF_SIZE
|
|
push $2
|
|
push $0
|
|
pxe_call PXE_GET_CACHED_INFO
|
|
add $12, %sp
|
|
mov tx_buf+20, %eax
|
|
mov %eax, server_ip
|
|
mov tx_buf+24, %eax
|
|
mov %eax, gateway_ip
|
|
|
|
mov $msg_unreal, %si
|
|
call print
|
|
call unreal
|
|
|
|
mov $msg_getmap, %si
|
|
call print
|
|
call get_map
|
|
|
|
mov $msg_mkheap, %si
|
|
call print
|
|
call make_heap
|
|
|
|
mov $msg_paging, %si
|
|
call print
|
|
call paging
|
|
|
|
mov $msg_read, %si
|
|
call print
|
|
mov $fn_initrd, %esi
|
|
call read_file
|
|
mov %ebx, bb_ird_ptr
|
|
|
|
mov $msg_vbe, %si
|
|
call print
|
|
call vbe_setup
|
|
|
|
mov $msg_long, %si
|
|
call print
|
|
//jmp hang // REMOVE ME
|
|
call long
|
|
|
|
jmp hang
|
|
|
|
.set COM1, 0x3F8
|
|
.macro com1_write offset=0, byte
|
|
mov $COM1+\offset, %dx
|
|
mov $\byte, %al
|
|
outb %al, %dx
|
|
.endm
|
|
|
|
// init_com1: Set up COM1 port for debug output
|
|
init_com1: com1_write 1, 0x00 // clear interrupts
|
|
com1_write 3, 0x80 // set DLAB to 1
|
|
com1_write 0, 0x0C // 9600 baud rate
|
|
com1_write 1, 0x00
|
|
com1_write 3, 0x07 // 8 bit data + 1 parity bit
|
|
ret
|
|
|
|
// enable_a20: Allow use of 'high' (>1Mb) memory
|
|
enable_a20: // Of all the ways to toggle A20, we only try the Fast A20 Gate.
|
|
// This is known to cause problems on some ancient systems,
|
|
// but as our bootloader exclusively runs on 64-bit machines,
|
|
// we should not run into any of those systems.
|
|
// Modern machines apparently don't even have the A20 line anymore.
|
|
inb $0x92, %al
|
|
or $2, %al
|
|
outb %al, $0x92
|
|
ret
|
|
|
|
// unreal: Enter unreal mode
|
|
unreal: push %ds
|
|
push %es
|
|
lgdt gdt16_ptr
|
|
|
|
mov %cr0, %eax
|
|
or $0x01, %al
|
|
mov %eax, %cr0
|
|
ljmp $0x8, $_urprot
|
|
|
|
_urprot: mov $0x10, %cx
|
|
mov %cx, %ds
|
|
mov %cx, %es
|
|
|
|
and $0xFE, %al
|
|
mov %eax, %cr0
|
|
ljmp $0x0, $_urunreal
|
|
|
|
_urunreal: pop %es
|
|
pop %ds
|
|
ret
|
|
|
|
// get_map: Retrieve memory map using e820 BIOS function
|
|
get_map: mov $bb_memmap, %edi
|
|
xor %ebx, %ebx
|
|
mov $0x534D4150, %edx // e820 magic number
|
|
_gmnext: movl $0, 20(%di)
|
|
mov $24, %ecx
|
|
mov $0xE820, %eax
|
|
int $0x15
|
|
jc _gmdone
|
|
test %ebx, %ebx
|
|
jz _gmdone
|
|
add $24, %di
|
|
jmp _gmnext
|
|
_gmdone: add $24, %di
|
|
sub $bootboot, %edi
|
|
mov %edi, bb_size
|
|
ret
|
|
|
|
// paging: Set up initial page tables for long mode
|
|
paging:
|
|
mov heap_ptr, %eax
|
|
mov %eax, %ecx
|
|
add $6*4096, %ecx
|
|
cmp heap_end, %ecx
|
|
ja out_of_mem
|
|
mov %ecx, heap_ptr
|
|
|
|
mov %eax, pd_ptr
|
|
add $4*4096, %eax
|
|
mov %eax, pdp_ptr
|
|
add $4096, %eax
|
|
mov %eax, pml4_ptr
|
|
|
|
// fill PDEs with identity map < 4Gb
|
|
mov pd_ptr, %edi
|
|
xor %ecx, %ecx
|
|
_pgnext: mov %ecx, %eax
|
|
shl $21, %eax
|
|
or $0b10000011, %eax
|
|
movl %eax, 0(%edi)
|
|
movl $0, 4(%edi)
|
|
add $8, %edi
|
|
inc %ecx
|
|
cmp $4*512, %ecx
|
|
jne _pgnext
|
|
|
|
// link to PDs in PDP
|
|
mov pdp_ptr, %edi
|
|
mov pd_ptr, %eax
|
|
orl $0b11, %eax
|
|
|
|
movl %eax, 0(%edi)
|
|
movl $0, 4(%edi)
|
|
add $0x1000, %eax
|
|
movl %eax, 8(%edi)
|
|
movl $0, 12(%edi)
|
|
add $0x1000, %eax
|
|
movl %eax, 16(%edi)
|
|
movl $0, 20(%edi)
|
|
add $0x1000, %eax
|
|
movl %eax, 24(%edi)
|
|
movl $0, 28(%edi)
|
|
|
|
// link to PDP in PML4
|
|
mov pml4_ptr, %edi
|
|
mov pdp_ptr, %eax
|
|
orl $0b11, %eax
|
|
movl %eax, 0(%edi)
|
|
movl $0, 4(%edi)
|
|
|
|
ret
|
|
|
|
// make_heap: find a memory range suitable for heap usage
|
|
make_heap: mov $bb_memmap-24, %esi
|
|
_mhnext: add $24, %si
|
|
mov $bootboot, %eax
|
|
add bb_size, %eax
|
|
cmp %ax, %si
|
|
jae _mhdone
|
|
|
|
cmpl $1, 16(%si)
|
|
jne _mhnext
|
|
cmpl $0, 4(%si)
|
|
ja _mhnext
|
|
|
|
mov 0(%si), %eax
|
|
mov 8(%si), %ecx
|
|
|
|
// find end of range, clip to 4Gb
|
|
add %eax, %ecx
|
|
jnc 1f
|
|
mov $0xFFFFFFFF, %ecx
|
|
|
|
// handle wraparound if length > 4Gb
|
|
1: cmpl $0, 12(%si)
|
|
je 1f
|
|
mov $0xFFFFFFFF, %ecx
|
|
|
|
// adjust base to above 1Mb, above the bootloader
|
|
1: cmp $0x10000, %eax
|
|
jae 1f
|
|
mov $0x10000, %eax
|
|
|
|
// align start to 4Kb boundary
|
|
1: add $0xFFF, %eax
|
|
and $0xFFFFF000, %eax
|
|
|
|
// Is this entry larger than current heap?
|
|
mov %ecx, %edx
|
|
sub %eax, %edx
|
|
mov heap_end, %ebx
|
|
sub heap_ptr, %ebx
|
|
cmp %ebx, %edx
|
|
jbe _mhnext
|
|
|
|
// If so, switch to it.
|
|
mov %eax, heap_ptr
|
|
mov %ecx, heap_end
|
|
mov %esi, heap_mment
|
|
jmp _mhnext
|
|
|
|
_mhdone: ret
|
|
|
|
.set PXE_TFTP_OPEN, 0x0020
|
|
.set PXE_TFTP_CLOSE, 0x0021
|
|
.set PXE_TFTP_READ, 0x0022
|
|
|
|
read_file: push %bp
|
|
mov %sp, %bp
|
|
|
|
call tftp_open
|
|
mov heap_ptr, %ebx
|
|
mov %ebx, %edi
|
|
|
|
_rdloop: call tftp_read
|
|
mov $tx_buf, %esi
|
|
mov $PACKET_SIZE, %ecx
|
|
addr32 rep movsb
|
|
cmp heap_end, %edi
|
|
ja out_of_mem
|
|
cmp $PACKET_SIZE, %ax
|
|
je _rdloop
|
|
|
|
mov %edi, heap_ptr
|
|
call tftp_close
|
|
|
|
leave
|
|
ret
|
|
|
|
// tftp_open: Open a file stream over TFTP.
|
|
// A pointer to the filename is passed in ESI.
|
|
tftp_open: push %ecx
|
|
push %esi
|
|
push %edi
|
|
push %bp
|
|
mov %sp, %bp
|
|
|
|
mov %esi, %ebx
|
|
|
|
mov $msg_topen, %si
|
|
call print
|
|
|
|
push $PACKET_SIZE
|
|
push $69<<8
|
|
mov $128, %ecx
|
|
sub %cx, %sp
|
|
mov %ss, %edi
|
|
shl $4, %edi
|
|
add %esp, %edi
|
|
xor %ax, %ax
|
|
cld
|
|
addr32 rep stosb
|
|
mov %ebx, %esi
|
|
mov $6, %ecx
|
|
mov %ss, %edi
|
|
shl $4, %edi
|
|
add %esp, %edi
|
|
cld
|
|
addr32 rep movsb
|
|
push gateway_ip+2
|
|
push gateway_ip
|
|
push server_ip+2
|
|
push server_ip
|
|
push $0
|
|
|
|
mov %ss, %esi
|
|
shl $4, %esi
|
|
add %esp, %esi
|
|
mov $128, %ecx
|
|
call dump
|
|
|
|
pxe_call PXE_TFTP_OPEN
|
|
|
|
leave
|
|
pop %edi
|
|
pop %esi
|
|
pop %ecx
|
|
ret
|
|
|
|
// tftp_close: Close the TFTP stream.
|
|
tftp_close: push %bp
|
|
mov %sp, %bp
|
|
|
|
mov $msg_tclose, %si
|
|
call print
|
|
|
|
push $0
|
|
pxe_call PXE_TFTP_CLOSE
|
|
|
|
leave
|
|
ret
|
|
|
|
// tftp_read: Read the next TFTP packet into tx_buf, return size in AX.
|
|
tftp_read: push %ebx
|
|
push %bp
|
|
mov %sp, %bp
|
|
|
|
mov $msg_tread, %si
|
|
call print
|
|
|
|
push %cs
|
|
push $tx_buf
|
|
push $0
|
|
push $0
|
|
push $0
|
|
pxe_call PXE_TFTP_READ
|
|
mov %sp, %bx
|
|
mov %ss:4(%bx), %ax
|
|
|
|
leave
|
|
pop %ebx
|
|
ret
|
|
|
|
out_of_mem: mov $msg_memerr, %si
|
|
call print
|
|
jmp hang
|
|
|
|
// print: print NUL-terminated string pointed to by SI
|
|
print: push %eax
|
|
push %si
|
|
push %bp
|
|
mov %sp, %bp
|
|
1: lodsb
|
|
or %al, %al
|
|
jz 2f
|
|
call printch
|
|
jmp 1b
|
|
2: leave
|
|
pop %si
|
|
pop %eax
|
|
ret
|
|
|
|
printch: push %eax
|
|
push %ebx
|
|
push %edx
|
|
push %ebp
|
|
|
|
mov %ax, %bx
|
|
|
|
1: mov $COM1+5, %dx
|
|
inb %dx, %al
|
|
test $0x20, %al
|
|
jz 1b
|
|
|
|
mov %bx, %ax
|
|
|
|
mov $COM1, %dx
|
|
outb %al, %dx
|
|
|
|
xor %bx, %bx
|
|
mov $0x0E, %ah
|
|
int $0x10
|
|
|
|
pop %ebp
|
|
pop %edx
|
|
pop %ebx
|
|
pop %eax
|
|
ret
|
|
|
|
dump: push %eax
|
|
push %ebx
|
|
push %ecx
|
|
push %edx
|
|
push %esi
|
|
push %bp
|
|
mov %sp, %bp
|
|
|
|
xor %dx, %dx
|
|
|
|
1: cmp %cx, %dx
|
|
jae 2f
|
|
inc %dx
|
|
|
|
addr32 lodsb
|
|
push %ax
|
|
mov %al, %bl
|
|
shr $4, %bx
|
|
and $0x0F, %bx
|
|
mov hex_digits(%bx), %al
|
|
call printch
|
|
pop %bx
|
|
and $0x0F, %bx
|
|
mov hex_digits(%bx), %al
|
|
call printch
|
|
|
|
mov $' ', %al
|
|
call printch
|
|
test $0xF, %dx
|
|
jnz 1b
|
|
mov $'\r', %al
|
|
call printch
|
|
mov $'\n', %al
|
|
call printch
|
|
jmp 1b
|
|
|
|
2: mov $'\r', %al
|
|
call printch
|
|
mov $'\n', %al
|
|
call printch
|
|
|
|
leave
|
|
pop %esi
|
|
pop %edx
|
|
pop %ecx
|
|
pop %ebx
|
|
pop %eax
|
|
ret
|
|
|
|
vbe_setup:
|
|
push %eax
|
|
push %ecx
|
|
push %esi
|
|
push %bp
|
|
mov %sp, %bp
|
|
|
|
call vbe_getinfo
|
|
|
|
mov vbe_info+14, %si
|
|
mov vbe_info+16, %cx
|
|
mov %cx, %fs
|
|
|
|
_vbenext: mov %fs:(%si), %cx
|
|
add $2, %si
|
|
cmp $0xFFFF, %cx
|
|
je _vbedone
|
|
|
|
call vbe_getmode
|
|
//mov , bb_fb_size
|
|
mov tx_buf+16, %ax
|
|
mov %ax, bb_fb_scanl
|
|
mov tx_buf+18, %ax
|
|
mov %ax, bb_fb_width
|
|
mov tx_buf+20, %ax
|
|
mov %ax, bb_fb_height
|
|
mov tx_buf+40, %eax
|
|
mov %eax, bb_fb_ptr
|
|
|
|
testw $0x80, tx_buf
|
|
jz _vbenext
|
|
|
|
mov %cx, %bx
|
|
and $0x0FFF, %bx
|
|
or $0x4000, %bx
|
|
call vbe_setmode
|
|
|
|
jmp _vbedone
|
|
|
|
_vbedone:
|
|
leave
|
|
pop %esi
|
|
pop %ecx
|
|
pop %eax
|
|
ret
|
|
|
|
vbe_getinfo:
|
|
push %eax
|
|
push %edi
|
|
push %bp
|
|
mov %sp, %bp
|
|
|
|
mov $0x4F00, %ax
|
|
mov $vbe_info, %di
|
|
int $0x10
|
|
|
|
cmp $0x4F, %ax
|
|
je 1f
|
|
mov $msg_vbeerr, %si
|
|
call print
|
|
jmp hang
|
|
1:
|
|
|
|
cmpl $0x41534556, vbe_info // "VESA"
|
|
je 1f
|
|
mov $msg_vbeerr, %si
|
|
call print
|
|
jmp hang
|
|
|
|
1: leave
|
|
pop %edi
|
|
pop %eax
|
|
ret
|
|
|
|
vbe_getmode:
|
|
push %eax
|
|
push %edi
|
|
push %bp
|
|
mov %sp, %bp
|
|
|
|
mov $0x4F01, %ax
|
|
mov $tx_buf, %di
|
|
int $0x10
|
|
|
|
cmp $0x4F, %ax
|
|
je 1f
|
|
mov $msg_vbeerr, %si
|
|
call print
|
|
jmp hang
|
|
|
|
1: leave
|
|
pop %edi
|
|
pop %eax
|
|
ret
|
|
|
|
vbe_setmode:
|
|
push %eax
|
|
push %bp
|
|
mov %sp, %bp
|
|
|
|
mov $0x4F02, %ax
|
|
int $0x10
|
|
|
|
cmp $0x4F, %ax
|
|
je 1f
|
|
mov $msg_vbeerr, %si
|
|
call print
|
|
jmp hang
|
|
|
|
1: leave
|
|
pop %eax
|
|
ret
|
|
|
|
vbe_info:
|
|
.ascii "VBE2"
|
|
.skip 512 - 4
|
|
|
|
// long: Enter long mode
|
|
long:
|
|
// Enable PAE
|
|
mov %cr4, %eax
|
|
or $0b100000, %eax
|
|
mov %eax, %cr4
|
|
|
|
// Load page table
|
|
mov pml4_ptr, %eax
|
|
mov %eax, %cr3
|
|
|
|
// Enable long mode
|
|
.set IA32_EFER, 0xC0000080
|
|
mov $IA32_EFER, %ecx
|
|
rdmsr
|
|
or $0x100, %eax
|
|
wrmsr
|
|
|
|
// Enable protected mode + paging
|
|
mov %cr0, %eax
|
|
or $0x80000001, %eax
|
|
mov %eax, %cr0
|
|
|
|
// Linearize stack address
|
|
mov %ss, %eax
|
|
shl $4, %eax
|
|
add %eax, %esp
|
|
mov %esp, %ebp
|
|
|
|
// Load long mode GDT, switch to 64-bit CS
|
|
lgdt gdt64_ptr
|
|
ljmp $0x8, $trampo64
|
|
|
|
// hang: sleep indefinitely
|
|
hang: hlt
|
|
jmp hang
|
|
|
|
_pcerr: mov $msg_pcerr, %si
|
|
call print
|
|
jmp hang
|
|
|
|
// gdt16: Protected mode / Unreal mode 16-bit GDT
|
|
gdt16: // entry 0: null descriptor
|
|
.word 0
|
|
.word 0
|
|
.byte 0
|
|
.byte 0
|
|
.byte 0
|
|
.byte 0
|
|
// entry 1: code segment
|
|
.word 0xFFFF
|
|
.word 0
|
|
.byte 0
|
|
.byte 0b10011010
|
|
.byte 0x8F
|
|
.byte 0
|
|
// entry 2: data segment
|
|
.word 0xFFFF
|
|
.word 0
|
|
.byte 0
|
|
.byte 0b10010010
|
|
.byte 0x8F
|
|
.byte 0
|
|
.set gdt16_size, .-gdt16
|
|
gdt16_ptr: .word gdt16_size-1
|
|
.long gdt16
|
|
|
|
// gdt64: Long mode 64-bit GDT
|
|
gdt64: // entry 0: null descriptor
|
|
.quad 0
|
|
// entry 1: code segment
|
|
.word 0
|
|
.word 0
|
|
.byte 0
|
|
.byte 0x98
|
|
.byte 0x60
|
|
.byte 0
|
|
// entry 2: data segment
|
|
.word 0
|
|
.word 0
|
|
.byte 0
|
|
.byte 0x92
|
|
.byte 0x00
|
|
.byte 0
|
|
.set gdt64_size, .-gdt64
|
|
gdt64_ptr: .word gdt64_size-1
|
|
.quad gdt64
|
|
|
|
// Messages to print
|
|
msg_start: .asciz "Netboot via fernlader v1 ...\r\n"
|
|
msg_a20: .asciz " * Enabling A20\r\n"
|
|
msg_unreal: .asciz " * Unreal Mode\r\n"
|
|
msg_getmap: .asciz " * Memory Map\r\n"
|
|
msg_mkheap: .asciz " * Making Space\r\n"
|
|
msg_paging: .asciz " * Paging\r\n"
|
|
msg_read: .asciz " * Retrieving\r\n"
|
|
msg_vbe: .asciz " * Framebuffer\r\n"
|
|
msg_long: .asciz " * Long Mode\r\n"
|
|
msg_pserr: .asciz "panic: Missing !PXE structure.\r\n"
|
|
msg_pcerr: .asciz "panic: PXE call failed.\r\n"
|
|
msg_vbeerr: .asciz "panic: VBE call failed.\r\n"
|
|
msg_memerr: .asciz "panic: Out of heap space.\r\n"
|
|
msg_topen: .asciz "tftp_open\r\n"
|
|
msg_tclose: .asciz "tftp_close\r\n"
|
|
msg_tread: .asciz "tftp_read\r\n"
|
|
|
|
fn_initrd: .asciz "initrd"
|
|
|
|
pxe_api: .long 0
|
|
server_ip: .space 4
|
|
gateway_ip: .space 4
|
|
|
|
heap_ptr: .long 0
|
|
heap_end: .long 0
|
|
heap_mment: .long tx_buf
|
|
|
|
// Long mode initial page tables
|
|
pd_ptr: .long 0
|
|
pdp_ptr: .long 0
|
|
pml4_ptr: .long 0
|
|
|
|
// Points to the end of the memory map
|
|
memmap_end: .short 0
|
|
|
|
tx_buf: .space TX_BUF_SIZE
|
|
|
|
.code64
|
|
// trampo64: Trampoline function to load long-mode segments
|
|
// before entering the loader.
|
|
trampo64:
|
|
mov $0x10, %eax
|
|
mov %eax, %ds
|
|
mov %eax, %es
|
|
mov %eax, %fs
|
|
mov %eax, %gs
|
|
mov %eax, %ss
|
|
|
|
// Remove our heap from the memory map so it doesn't get overwritten
|
|
mov heap_mment, %esi
|
|
mov 8(%rsi), %rcx
|
|
add 0(%rsi), %rcx
|
|
mov heap_ptr, %eax
|
|
sub %rax, %rcx
|
|
mov %rax, 0(%rsi)
|
|
mov %rcx, 8(%rsi)
|
|
|
|
// Mangle e820 memmap into bootboot's format
|
|
mov $bb_memmap, %rsi
|
|
mov $bb_memmap, %rdi
|
|
mov $bootboot, %edx
|
|
add bb_size, %edx
|
|
1:
|
|
mov 0(%rsi), %rax
|
|
mov 8(%rsi), %rcx
|
|
mov 16(%rsi), %ebx
|
|
|
|
cmp $6, %ebx
|
|
jb 2f
|
|
mov $2, %ebx
|
|
2: mov type_table(%rbx), %bl
|
|
|
|
and $-16, %rcx
|
|
or %rbx, %rcx
|
|
|
|
mov %rax, 0(%rdi)
|
|
mov %rcx, 8(%rdi)
|
|
|
|
add $24, %rsi
|
|
add $16, %rdi
|
|
|
|
cmp %rdx, %rsi
|
|
jb 1b
|
|
sub $bootboot, %edi
|
|
mov %edi, bb_size
|
|
|
|
mov $bootboot, %edi
|
|
jmp loader_main
|
|
|
|
type_table: .byte 0
|
|
.byte 1
|
|
.byte 0
|
|
.byte 2
|
|
.byte 2
|
|
.byte 0
|
|
|
|
hex_digits: .ascii "0123456789ABCDEF"
|
|
|
|
.section .data.bootboot
|
|
bootboot: .ascii "BOOT"
|
|
bb_size: .long 128
|
|
.byte 1
|
|
.byte 0
|
|
.short 1
|
|
.short 0
|
|
.space 10, 0
|
|
bb_ird_ptr: .quad 0
|
|
bb_ird_size:.quad 0
|
|
bb_fb_ptr: .quad 0
|
|
bb_fb_size: .long 0
|
|
bb_fb_width:.long 0
|
|
bb_fb_height:.long 0
|
|
bb_fb_scanl:.long 0
|
|
.space 64, 0
|
|
bb_memmap:
|
|
.space 4096-128, 0
|