stage0-uefi/amd64/Development/hex2.M1

812 lines
23 KiB
Plaintext

# SPDX-FileCopyrightText: 2022 Andrius Štikonas <andrius@stikonas.eu>
# SPDX-FileCopyrightText: 2017 Jeremiah Orians <jeremiah@pdp10.guru>
#
# SPDX-License-Identifier: GPL-3.0-or-later
DEFINE add_rax, 4805
DEFINE add_rbx, 4883C3
DEFINE add_rbx,[rdi+BYTE] 48035F
DEFINE add_rdi, 4883C7
DEFINE add_rdx, 4881C2
DEFINE add_rsi, 4883C6
DEFINE add_rsp, 4883C4
DEFINE add_r12, 4983C4
DEFINE add_r13, 4983C5
DEFINE add_rax,r14 4C01F0
DEFINE call E8
DEFINE call_[rcx+BYTE] FF51
DEFINE call_[r14+BYTE] 41FF56
DEFINE call_[r14+DWORD] 41FF96
DEFINE cmp_al, 3C
DEFINE cmp_rax, 4883F8
DEFINE cmp_rbx, 4883FB
DEFINE cmp_rcx, 4883F9
DEFINE cmp_r8, 4983F8
DEFINE cmp_r15, 4983FF
DEFINE cmp_al,bl 38D8
DEFINE cmp_rbx,rdx 4839D3
DEFINE je 0F84
DEFINE jl 0F8C
DEFINE jmp E9
DEFINE jne 0F85
DEFINE lea_rdx,[rip+DWORD] 488D15
DEFINE mov_al, B0
DEFINE mov_rax, 48C7C0
DEFINE mov_rcx, 48C7C1
DEFINE mov_rdx, 48C7C2
DEFINE mov_r11, 49C7C3
DEFINE mov_r13, 49C7C5
DEFINE mov_r14, 49C7C6
DEFINE mov_r15, 49C7C7
DEFINE mov_rax,r12 4C89E0
DEFINE mov_rbp,rsp 4889E5
DEFINE mov_rbx,r12 4C89E3
DEFINE mov_rcx,rax 4889C1
DEFINE mov_rcx,r9 4C89C9
DEFINE mov_rcx,r8 4C89C1
DEFINE mov_rcx,r11 4C89D9
DEFINE mov_rdi,rax 4889C7
DEFINE mov_rdx,rax 4889C2
DEFINE mov_rdx,rbx 4889DA
DEFINE mov_rdx,rsb 4889E2
DEFINE mov_rdx,rsp 4889E2
DEFINE mov_rdx,r13 4C89EA
DEFINE mov_rsp,rbp 4889EC
DEFINE mov_rsp,r8 4989E0
DEFINE mov_r8,rsp 4989E0
DEFINE mov_r11,rax 4989C3
DEFINE mov_r12,rax 4989C4
DEFINE mov_r12,rbx 4989DC
DEFINE mov_r14,rax 4989C6
DEFINE mov_al,[rbx] 8A03
DEFINE mov_al,[rsi] 8A06
DEFINE mov_bl,[rdi] 8A1F
DEFINE mov_rcx,[rbx] 488B0B
DEFINE mov_rcx,[rcx] 488B09
DEFINE mov_[rax],r11 4C8918
DEFINE mov_[rbx], C603
DEFINE mov_[rbx],al 8803
DEFINE mov_[rbx],rcx 48890B
DEFINE mov_rax,[rcx+BYTE] 488B41
DEFINE mov_rbx,[rdi+BYTE] 488B5F
DEFINE mov_rcx,[rdi+BYTE] 488B4F
DEFINE mov_r14,[rdx+BYTE] 4C8B72
DEFINE mov_rsi,[rcx+BYTE] 488B71
DEFINE mov_rax,[rip+DWORD] 488B05
DEFINE mov_rbx,[rip+DWORD] 488B1D
DEFINE mov_rcx,[rip+DWORD] 488B0D
DEFINE mov_rdi,[rip+DWORD] 488B3D
DEFINE mov_r14,[rip+DWORD] 4C8B35
DEFINE mov_r8,[rip+DWORD] 4C8B05
DEFINE mov_r9,[rip+DWORD] 4C8B0D
DEFINE mov_[rax+BYTE],r13 4C8968
DEFINE mov_[r11+BYTE],r12 4D8963
DEFINE mov_[rip+DWORD],rax 488905
DEFINE mov_[rip+DWORD],rcx 48890D
DEFINE mov_[rip+DWORD],r14 4C8935
DEFINE movzx_rax,al 480FB6C0
DEFINE movzx_rbx,bl 480FB6DB
DEFINE not_r15 49F7D7
DEFINE pop_rax 58
DEFINE pop_rbx 5B
DEFINE pop_rcx 59
DEFINE pop_rdx 5A
DEFINE pop_rsi 5E
DEFINE pop_r8 4158
DEFINE pop_r9 4159
DEFINE pop_r11 415B
DEFINE push 6A
DEFINE push_rax 50
DEFINE push_rbx 53
DEFINE push_rcx 51
DEFINE push_rdx 52
DEFINE push_rsi 56
DEFINE push_r11 4153
DEFINE ret C3
DEFINE ror_r9 49D1C9
DEFINE shl_r14, 49C1E6
DEFINE sub_rax, 83E8
DEFINE sub_rbx, 4883EB
DEFINE sub_rsp, 4883EC
DEFINE sub_rax,rdx 4829D0
DEFINE test_esi_esi 85F6
DEFINE xor_eax_eax 31C0
DEFINE xor_edx_edx 31D2
DEFINE xor_esi_esi 31F6
DEFINE xor_r9,r9 4D31C9
# Register usage:
# r15 => Flag
# r14 => High bits
# r13 => IP
# r12 => MALLOC
# r11 => HEAD
# Struct format: (size 24)
# NEXT => 0
# TARGET => 8
# NAME => 16
# efi_main(void *image_handle, struct efi_system_table *system)
:_start
mov_rbp,rsp # save stack pointer
mov_[rip+DWORD],rcx %image_handle # save image_handle
mov_r14,[rdx+BYTE] !96 # system->boot
mov_[rip+DWORD],r14 %SystemBoot # save system->boot
# Open Loaded Image protocol
mov_r9,[rip+DWORD] %image_handle # arg4 = image_handle
lea_rdx,[rip+DWORD] %LOADED_IMAGE_PROTOCOL # guid = &LOADED_IMAGE_PROTOCOL
mov_rcx,r9 # arg1 = image_handle
call %open_protocol # open protocol
mov_rdi,rax # save image
# Get root file system
mov_r9,[rip+DWORD] %image_handle # arg4 = image_handle
lea_rdx,[rip+DWORD] %SIMPLE_FS_PROTOCOL # guid = &SIMPLE_FS_PROTOCOL
mov_rcx,[rdi+BYTE] !24 # arg1 = root_device = image->device
mov_[rip+DWORD],rcx %root_device # save root_device
call %open_protocol # open protocol
mov_rcx,rax # get rootfs
# Get root directory
lea_rdx,[rip+DWORD] %rootdir # arg2 = &rootdir
push_rax # allocate shadow stack space for UEFI function
push_rax # allocate shadow stack space for UEFI function
call_[rcx+BYTE] !8 # rootfs->open_volume(rootfs, &rootdir)
pop_rax # deallocate stack
pop_rax # deallocate stack
# Push command line arguments onto stack
mov_rbx,[rdi+BYTE] !56 # options = image->load_options
mov_rdx,rbx # save beginning of load_options
add_rbx,[rdi+BYTE] !48 # go to the end of load_options
push !0 # Save end of arguments (NULL) onto stack
:loop_options
cmp_rbx,rdx # Check if we are done
je %loop_options_done # We are done
sub_rbx, !2 # --options
mov_al,[rbx] # *options
cmp_al, !0x20 # if *options != ' '
jne %loop_options # then continue looping
mov_[rbx], !0 # zero it
add_rbx, !2 # ++options
push_rbx # push another argument onto stack
jmp %loop_options # next argument
:loop_options_done
# Open file for reading
pop_r8 # arg3 = in
push !1 # Set exit code in case of failure
cmp_r8, !0 # If NULL
je %failed_input # then exit
lea_rdx,[rip+DWORD] %fin # arg2 = &fin
push !1 # arg5 = EFI_FILE_READ_ONLY
push !1 # prepare to set arg4 to EFI_FILE_MODE_READ
pop_r9 # arg4 = EFI_FILE_MODE_READ
mov_rcx,[rip+DWORD] %rootdir # arg1 = rootdir
sub_rsp, !32 # allocate shadow stack space for UEFI function
call_[rcx+BYTE] !8 # rootdir->open()
cmp_rax, !0 # If failed to open
jne %failed_input # then exit
add_rsp, !48 # deallocate stack
# Open file for writing
pop_r8 # arg3 = out
push !1 # Set exit code in case of failure
cmp_r8, !0 # If NULL
je %failed_output # then exit
lea_rdx,[rip+DWORD] %fout # arg2 = &fout
push !0 # arg5 = 0
push !7 # to get 0x8000000000000003 we set the rightmost 3 bits
pop_r9 # and then do right rotation by 1
ror_r9 # arg4 = EFI_FILE_MODE_CREATE| EFI_FILE_MODE_WRITE | EFI_FILE_MODE_READ
mov_rcx,[rip+DWORD] %rootdir # arg1 = rootdir
sub_rsp, !32 # allocate shadow stack space for UEFI function
call_[rcx+BYTE] !8 # rootdir->open()
add_rsp, !48 # deallocate stack
# Allocate ourselves 16 MiB of memory
mov_rdx, %0x1000000 # allocate 16 MiB of memory
call %allocate_pool
mov_[rip+DWORD],rax %scratch # Allocate space for scratch area
add_rax, %0x800 # 2 KiB of scratch
mov_r12,rax # save structs pointer
call %ClearScratch # Zero scratch
mov_r15, %-1 # Our flag for byte processing
mov_r14, %0 # temp storage for the sum
mov_r13, %0x00600000 # Our starting IP
mov_r11, %0 # HEAD = NULL
call %First_pass # Process it
# rewind input file
push_r11 # Protect r11
mov_rcx,[rip+DWORD] %fin # Using our input file
xor_edx_edx # Offset Zero
push_rax # allocate shadow stack space for UEFI function
push_rax # allocate shadow stack space for UEFI function
call_[rcx+BYTE] !56 # fin->set_position(fin, 0)
pop_rax # deallocate stack
pop_rax # deallocate stack
pop_r11 # restore r11
mov_r15, %-1 # Our flag for byte processing
mov_r14, %0 # temp storage for the sum
mov_r13, %0x00600000 # Our starting IP
call %Second_pass # Process it
jmp %Done
:First_pass
call %Read_byte
# Deal with EOF
cmp_rax, !-4
je %First_pass_done
# Check for :
cmp_rax, !0x3A
jne %First_pass_0
# Deal with label
call %StoreLabel
:First_pass_0
# Check for !
cmp_rax, !0x21
je %First_pass_pointer
# Check for @
cmp_rax, !0x40
je %First_pass_pointer
# Check for $
cmp_rax, !0x24
je %First_pass_pointer
# Check for %
cmp_rax, !0x25
je %First_pass_pointer
# Check for &
cmp_rax, !0x26
je %First_pass_pointer
# Deal with everything else
call %hex # Process our char
# Deal with EOF
cmp_rax, !-4
je %First_pass_done
# deal with -1 values
cmp_rax, !0
jl %First_pass
# deal with toggle
cmp_r15, !0
je %First_pass_1
add_r13, !1 # Increment IP
:First_pass_1
not_r15
jmp %First_pass
:Update_Pointer
# Check for !
cmp_rax, !0x21
je %Update_Pointer_1
# Check for @
cmp_rax, !0x40
je %Update_Pointer_2
# Check for $
cmp_rax, !0x24
je %Update_Pointer_2
# Check for %
cmp_rax, !0x25
je %Update_Pointer_4
# Check for &
cmp_rax, !0x26
je %Update_Pointer_4
# deal with bad input
call %fail
:Update_Pointer_4
add_r13, !2 # Increment IP
:Update_Pointer_2
add_r13, !1 # Increment IP
:Update_Pointer_1
add_r13, !1 # Increment IP
ret
:First_pass_pointer
# Deal with Pointer to label
call %Update_Pointer # Increment IP
mov_rbx,[rip+DWORD] %scratch # Using scratch
call %consume_token # Read token
call %ClearScratch # Throw away token
cmp_rax, !0x3E # check for '>'
jne %First_pass # Loop again
# Deal with %label>label case
mov_rbx,[rip+DWORD] %scratch # Write to scratch
call %consume_token # get token
call %ClearScratch # Clean up after ourselves
jmp %First_pass # Loop again
:First_pass_done
ret
:hex
# deal with EOF
cmp_rax, !-4
je %EOF
# deal with line comments starting with #
cmp_rax, !0x23
je %ascii_comment
# deal with line comments starting with ;
cmp_rax, !0x3B
je %ascii_comment
# deal all ascii less than 0
cmp_rax, !0x30
jl %ascii_other
# deal with 0-9
cmp_rax, !0x3A
jl %ascii_num
# deal with all ascii less than A
cmp_rax, !0x41
jl %ascii_other
# deal with A-F
cmp_rax, !0x47
jl %ascii_high
# deal with all ascii less than a
cmp_rax, !0x61
jl %ascii_other
# deal with a-f
cmp_rax, !0x67
jl %ascii_low
# The rest that remains needs to be ignored
jmp %ascii_other
:Second_pass
call %Read_byte
# Deal with EOF
cmp_rax, !-4
je %Second_pass_done
# Simply drop the label
cmp_rax, !0x3A
jne %Second_pass_0
mov_rbx,[rip+DWORD] %scratch # Using scratch
call %consume_token # Read token
call %ClearScratch # Throw away token
jmp %Second_pass
:Second_pass_0
# Deal with % pointer
cmp_rax, !0x25
je %StorePointer_rel4
# Deal with @ pointer
cmp_rax, !0x40
je %StorePointer_rel2
# Deal with ! pointer
cmp_rax, !0x21
je %StorePointer_rel1
# Deal with & pointer
cmp_rax, !0x26
je %StorePointer_abs4
# Deal with $ pointer
cmp_rax, !0x24
je %StorePointer_abs2
:Second_pass_1
# Deal with everything else
call %hex # Process our char
# Deal with EOF
cmp_rax, !-4
je %Second_pass_done
# deal with -1 values
cmp_rax, !0
jl %Second_pass
# deal with toggle
cmp_r15, !0
je %print
# process first byte of pair
mov_r14,rax
mov_r15, %0
jmp %Second_pass
:Second_pass_done
:EOF
ret
:ascii_num
sub_rax, !0x30
ret
:ascii_low
sub_rax, !0x57
ret
:ascii_high
sub_rax, !0x37
ret
:ascii_other
mov_rax, %-1
ret
:ascii_comment
call %Read_byte
cmp_rax, !0x0D
je %ascii_comment_cr
cmp_rax, !0x0A
jne %ascii_comment
:ascii_comment_cr
mov_rax, %-1
ret
# process second byte of pair
:print
# update the sum and store in output
shl_r14, !4
add_rax,r14
# flip the toggle
not_r15 # r15 = -1
# Print our first Hex
mov_rdx, %1 # set the size of chars we want
call %print_chars
add_r13, !1 # Increment IP
jmp %Second_pass
:Read_byte
push_r11 # Protect r11
mov_rcx,[rip+DWORD] %fin # arg1 = fin
push !1 # size = 1
mov_rdx,rsb # arg2 = &size
xor_esi_esi # zero rsi
push_rsi # allocate stack
mov_rsp,r8 # arg3 = &input
push_rax # allocate shadow stack space for UEFI function
push_rax # allocate shadow stack space for UEFI function
push_rax # allocate shadow stack space for UEFI function
call_[rcx+BYTE] !32 # fin->read()
pop_rax # deallocate stack
pop_rax # deallocate stack
pop_rax # deallocate stack
pop_rax # save input to rax
pop_rsi # save size to rsi
pop_r11 # restore r11
# If the file ended (0 bytes read) return EOF
test_esi_esi
jne %Read_byte_1
mov_rax, %-4 # Put EOF in rax
:Read_byte_1
ret
# Writes bytes stored in rax
:print_chars
push_r11 # Protect r11
mov_rcx,[rip+DWORD] %fout # arg1 = fout
push_rdx # set size
mov_rdx,rsp # arg2 = &size
push_rax # allocate stack
mov_rsp,r8 # arg3 = &output
push_rax # allocate shadow stack space for UEFI function
push_rax # allocate shadow stack space for UEFI function
push_rax # allocate shadow stack space for UEFI function
call_[rcx+BYTE] !40 # fout->write()
add_rsp, !40 # deallocate stack
pop_r11 # restore r11
ret # return
# Receives pointer in RBX
# Writes out char and updates RBX
:consume_token
call %Read_byte # Consume_token
# Check for \t
cmp_rax, !0x09
je %consume_token_done
# Check for \n
cmp_rax, !0x0A
je %consume_token_done
# Check for ' '
cmp_rax, !0x20
je %consume_token_done
# Check for '>'
cmp_rax, !0x3E
je %consume_token_done
# Looks like we are still reading token
mov_[rbx],al # Store char
add_rbx, !1 # Point to next spot
jmp %consume_token # loop until done
:consume_token_done
mov_rcx, %0 # Pad with nulls
mov_[rbx],rcx
add_rbx, !8
ret
:StoreLabel
mov_rax,r12 # ENTRY
add_r12, !24 # CALLOC
mov_[rax+BYTE],r13 !8 # ENTRY->TARGET = IP
mov_[rax],r11 # ENTRY->NEXT = JUMP_TABLE
mov_r11,rax # JUMP_TABLE = ENTRY
mov_[r11+BYTE],r12 !16 # ENTRY->NAME = TOKEN
mov_rbx,r12 # Write Starting after struct
call %consume_token # Collect whole string
mov_r12,rbx # Update HEAP
jmp %First_pass
:GetTarget
mov_rdi,[rip+DWORD] %scratch # Reset scratch
mov_rcx,r11 # Grab JUMP_TABLE
mov_rsi,[rcx+BYTE] !16 # I->NAME
:GetTarget_loop
mov_al,[rsi] # I->NAME[0]
mov_bl,[rdi] # scratch[0]
movzx_rbx,bl # Zero extend
movzx_rax,al # Zero extend
cmp_al,bl # IF TOKEN == I->NAME
jne %GetTarget_miss # Oops
add_rsi, !1
add_rdi, !1
cmp_al, !0
jne %GetTarget_loop # Loop until
jmp %GetTarget_done # Match
# Miss
:GetTarget_miss
mov_rcx,[rcx] # I = I->NEXT
cmp_rcx, !0 # IF NULL == I
je %fail # Abort hard
mov_rsi,[rcx+BYTE] !16 # I->NAME
mov_rdi,[rip+DWORD] %scratch # Reset scratch
jmp %GetTarget_loop
:GetTarget_done
mov_rax,[rcx+BYTE] !8 # Get address
ret
:ClearScratch
push_rax # Protect against changes
push_rbx # And overwrites
push_rcx
push_rdx # While we work
mov_rbx,[rip+DWORD] %scratch # Where our table is
mov_al, !0 # Using null
mov_rdx,rbx # Get scratch
add_rdx, %0x800 # end of scratch area
:ClearScratch_loop
cmp_rbx,rdx # Make sure
je %ClearScratch_end # we do not overflow
mov_rcx,[rbx] # Get current value
mov_[rbx],al # Because we want null
add_rbx, !1 # Increment
cmp_rcx, !0 # Check if we hit null
jne %ClearScratch_loop # Keep looping
:ClearScratch_end
pop_rdx
pop_rcx # Don't Forget to
pop_rbx # Restore Damage
pop_rax # Entirely
ret
:StorePointer
call %Update_Pointer # Increment IP
mov_rbx,[rip+DWORD] %scratch # Write to scratch
call %consume_token # get token
push_rax # Protect base_sep_p
mov_rax,[rip+DWORD] %scratch # Pointer to scratch
call %GetTarget # Get address of pointer
call %ClearScratch # Clean up after ourselves
mov_rdx,r13 # base = IP
pop_rbx # Restore base_sep_p
cmp_rbx, !0x3E # If base_sep_p == '>'
jne %StorePointer_done # If not
# Deal with %label>label case
push_rax # We need to preserve main target
mov_rbx,[rip+DWORD] %scratch # Write to scratch
call %consume_token # get token
mov_rax,[rip+DWORD] %scratch # Pointer to scratch
call %GetTarget # Get address of pointer
call %ClearScratch # Clean up after ourselves
mov_rdx,rax # Use our new base
pop_rax # Restore main target
:StorePointer_done
ret
:StorePointer_rel4
call %StorePointer # Do Common
sub_rax,rdx # target - ip
mov_rdx, %4 # set the size of chars we want
call %print_chars
jmp %Second_pass
:StorePointer_rel2
call %StorePointer # Do Common
sub_rax,rdx # target - ip
mov_rdx, %2 # set the size of chars we want
call %print_chars
jmp %Second_pass
:StorePointer_rel1
call %StorePointer # Do Common
sub_rax,rdx # target - ip
mov_rdx, %1 # set the size of chars we want
call %print_chars
jmp %Second_pass
:StorePointer_abs4
call %StorePointer # Do Common
mov_rdx, %4 # set the size of chars we want
call %print_chars
jmp %Second_pass
:StorePointer_abs2
call %StorePointer # Do Common
mov_rdx, %2 # set the size of chars we want
call %print_chars
jmp %Second_pass
:fail
mov_rax, %1 # Set exit code 1
jmp %terminate
:Done
xor_eax_eax # Set exit code 0
:terminate
push_rax # save exit code
mov_r14,[rip+DWORD] %SystemBoot # get system->boot
mov_rcx,[rip+DWORD] %scratch # arg1 = scratch
push_rax # allocate shadow stack space for UEFI function
call_[r14+BYTE] !72 # system->boot->free_pool(scratch)
pop_rax # deallocate stack
mov_rcx,[rip+DWORD] %fout # get fout
call %close_file # close fout
:failed_output
mov_rcx,[rip+DWORD] %fin # get fin
call %close_file # close fin
:failed_input
mov_rcx,[rip+DWORD] %rootdir # get rootdir
call %close_file # close rootdir
mov_r8,[rip+DWORD] %image_handle # arg3 = image_handle
lea_rdx,[rip+DWORD] %SIMPLE_FS_PROTOCOL # guid = &SIMPLE_FS_PROTOCOL
mov_rcx,[rip+DWORD] %root_device # arg1 = root_device
call %close_protocol # close protocol
mov_r8,[rip+DWORD] %image_handle # arg3 = image_handle
lea_rdx,[rip+DWORD] %LOADED_IMAGE_PROTOCOL # guid = &LOADED_IMAGE_PROTOCOL
mov_rcx,r8 # arg1 = image_handle
call %close_protocol # close protocol
pop_rax # restore exit code
:abort
mov_rsp,rbp # restore stack
ret # return to UEFI
# rcx: file handle
:close_file
push_rax # allocate shadow stack space for UEFI function
call_[rcx+BYTE] !16 # file_handle->close(file_handle)
pop_rax # deallocate stack
ret
# rcx: handle
# rdx: &guid
# r9: agent_handle
# returns interface
:open_protocol
push_rax # allocate stack for interface
mov_r8,rsp # arg3 = &interface
push !1 # arg6 = EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL
push !0 # arg5 = NULL
sub_rsp, !32 # allocate shadow stack space for UEFI function
call_[r14+DWORD] %280 # system->boot->open_protocol(handle, &guid, &interface, agent_handle, 0, EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL)
add_rsp, !48 # deallocate stack
pop_rax # get interface
ret
# rcx: handle
# rdx: &guid
# r8: agent_handle
:close_protocol
xor_r9,r9 # arg4 = NULL
sub_rsp, !32 # allocate shadow stack space for UEFI function
call_[r14+DWORD] %288 # system->boot->close_protocol(handle, &guid, agent_handle, 0)
add_rsp, !32 # deallocate stack
ret
# rdx: number of bytes to allocate
# r14: system->boot
# returns pointer in rax
:allocate_pool
push_rdx # allocate stack for pool pointer
mov_r8,rsp # arg3 = &pool
push !2
pop_rcx # arg1 = EFI_LOADER_DATA
sub_rsp, !24 # allocate shadow stack space for UEFI
call_[r14+BYTE] !64 # system->boot->allocate_pool(EFI_LOADER_DATA, 2048, &pool)
add_rsp, !24 # deallocate stack
pop_rax # get pool
ret
# Protocol GUIDs
:LOADED_IMAGE_PROTOCOL
%0x5b1b31a1
@0x9562
@0x11d2
:LOADED_IMAGE_PROTOCOL_8
!0x8e !0x3f !0 !0xa0 !0xc9 !0x69 !0x72 !0x3b
:SIMPLE_FS_PROTOCOL
%0x0964e5b22
@0x6459
@0x11d2
:SIMPLE_FS_PROTOCOL_8
!0x8e !0x39 !0 !0xa0 !0xc9 !0x69 !0x72 !0x3b
:fin
%0 %0
:fout
%0 %0
:scratch
%0 %0
:rootdir
%0 %0
:SystemBoot
%0 %0
:image_handle
%0 %0
:root_device
%0 %0
:PE32_end