assembly 黑屏NASM UEFI

ss2ws0br  于 2022-11-13  发布在  其他
关注(0)|答案(1)|浏览(157)

我想 Boot 到我的NASM内核。但它是黑屏,并给出错误虚拟机无法在VMWare中引导。没有打印。代码:

内核.asm

; generate 64-bit code
bits 64

; use relative addresses
default rel

; contains the code that will run
section .text
; allows the linker to see the entry symbol
global start

%include "kernel-functions.asm"
%include "kernel-efi.asm"
%include "kernel-api.asm"

start:
    ; save the location of UEFI
    mov [ptrUEFI], rsp
    
    ; reserve space for 4 arguments
    sub rsp, 4 * 8
    
    ; see http://www.uefi.org/sites/default/files/resources/UEFI Spec 2_7_A Sept 6.pdf#G6.1000024
    ; the "2.3.4.1 Handoff State" section
    
    ; rcx is the 1st argument passed to us by the UEFI firmware
    ; it will contain the EFI_HANDLE
    mov [hndImageHandle], rcx
    
    ; rdx is the 2nd argument passed to us by the UEFI firmware
    ; it points to the EFI_SYSTEM_TABLE
    mov [ptrSystemTable], rdx
    
    ; verify the EFI_TABLE_HEADER.Signature
    call apiVerifySignature
    
    ; output the OS and Firmware versions
    call apiOutputHeader
    
    ; locate a graphics device and allocate a frame buffer
    call apiGetFrameBuffer
    
    ; get a memory map and exit UEFI boot services
    call apiExitUEFI
    
    ; load our kernel
    call apiLoadKernel
    
    add rsp, 4 * 8
    mov rax, EFI_SUCCESS
    ret

error:
    ; move to the location of UEFI and return
    mov rsp, [ptrUEFI]
    ret

errorCode:
    ; save our error code
    push rax
    
    ; display the message
    mov rcx, strErrorCode
    call efiOutputString
    
    ; grab our error code and write it
    ; see the UEFI definitions in kernel-efi.asm
    mov rcx, [rsp]
    call funIntegerToAscii
    
    ; restore the error code
    pop rax
    
    jmp error

codesize equ $ - $$

; contains nothing - but it is required by UEFI
section .reloc
section .multiboot_header
; contains the data being stored
section .data
    ; UEFI requires we use Unicode strings
    strHeader               db   __utf16__ `Rootupapps OS v0.1\r\nRunning on \0`
    strHeaderV              db   __utf16__ ` v\0`
    strErrorCode            db   __utf16__ `\r\n\nError Code #\0`
    strDebugText            db   __utf16__ `\r\n\nDebug: \0`
    
    ; stores the location of UEFI
    ptrUEFI                 dq   0
    
    ; stores the EFI_HANDLE
    hndImageHandle          dq   0
    
    ; stores the EFI_SYSTEM_TABLE
    ptrSystemTable          dq   0
    
    ; stores the EFI_GRAPHICS_OUTPUT_PROTOCOL
    ptrInterface            dq   0
    
    ; stores the memory map data
    intMemoryMapSize        dq   EFI_MEMORY_DESCRIPTOR_size * 1024
    bufMemoryMap            resb EFI_MEMORY_DESCRIPTOR_size * 1024
    ptrMemoryMapKey         dq   0
    ptrMemoryMapDescSize    dq   0
    ptrMemoryMapDescVersion dq   0
    
    ; stores the frame buffer base
    ptrFrameBuffer          dq   0
datasize equ $ - $$

内核-api.asm

apiVerifySignature:
    ; get the signature for the loaded EFI_SYSTEM_TABLE
    mov rcx, [ptrSystemTable]
    mov rcx, [rcx + EFI_SYSTEM_TABLE.Hdr + EFI_TABLE_HEADER.Signature]
    
    ; get the signature defined in the UEFI spec
    ; see http://www.uefi.org/sites/default/files/resources/UEFI Spec 2_7_A Sept 6.pdf#G8.1001773
    mov rdx, EFI_SYSTEM_TABLE_SIGNATURE
    
    ; set our error code
    mov rax, EFI_LOAD_ERROR
    
    ; compare the signatures and return the error code when they don't match
    cmp rdx, rcx
    jne error
    
    mov rax, EFI_SUCCESS
    
    ret

apiOutputHeader:
    ; clear the screen
    call efiClearScreen
    
    ; write the header
    mov rcx, strHeader
    call efiOutputString
    
    ; write the firmware vendor
    mov rcx, [ptrSystemTable]
    mov rcx, [rcx + EFI_SYSTEM_TABLE.FirmwareVendor]
    call efiOutputString
    
    ; write the v
    mov rcx, strHeaderV
    call efiOutputString
    
    ; write the firmware revision
    mov rcx, [ptrSystemTable]
    mov rcx, [rcx + EFI_SYSTEM_TABLE.FirmwareRevision]
    call funIntegerToAscii
    
    ret

apiGetFrameBuffer:
    ; locate the first EFI_GRAPHICS_OUTPUT_PROTOCOL
    ; and allocate a frame buffer
    call efiLocateProtocol
    
    ; get the base address of the frame buffer 
    mov rcx, [ptrInterface]
    mov rcx, [rcx + EFI_GRAPHICS_OUTPUT_PROTOCOL.Mode]
    mov rcx, [rcx + EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE.FrameBufferBase]
    
    mov [ptrFrameBuffer], rcx
    
    ret

apiExitUEFI:
    call efiGetMemoryMap
    call efiExitBootServices
    
    ret

apiLoadKernel:
    ; verify we have reached this point
    ; by resetting the machine
    ; mov rax, [ptrSystemTable]
    ; mov rax, [rax + EFI_SYSTEM_TABLE.RuntimeServices]
    ; call [rax + EFI_RUNTIME_SERVICES.ResetSystem]
    
    ; set the 1st argument to our frame buffer
    mov rcx, [ptrFrameBuffer]
    
    ; set the 2nd argument to our start position
    mov rdx, 0
    
    ; set the 3rd argument to our end position
    ; this should be in multiples of 4
    mov r8, 1024 * 100
    
    call funDrawLine
    
    ret

内核定义.asm

EFI_SUCCESS                       equ 0
EFI_LOAD_ERROR                    equ 0x8000000000000001 ; 9223372036854775809
EFI_INVALID_PARAMETER             equ 0x8000000000000002 ; 9223372036854775810
EFI_UNSUPPORTED                   equ 0x8000000000000003 ; 9223372036854775811
EFI_BAD_BUFFER_SIZE               equ 0x8000000000000004 ; 9223372036854775812
EFI_BUFFER_TOO_SMALL              equ 0x8000000000000005 ; 9223372036854775813
EFI_NOT_READY                     equ 0x8000000000000006 ; 9223372036854775814
EFI_NOT_FOUND                     equ 0x8000000000000014 ; 9223372036854775828

EFI_SYSTEM_TABLE_SIGNATURE        equ 0x5453595320494249

EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID db 0xde, 0xa9, 0x42, 0x90, 0xdc, 0x23, 0x38, 0x4a
                                  db 0x96, 0xfb, 0x7a, 0xde, 0xd0, 0x80, 0x51, 0x6a

%macro UINTN 0
    RESQ 1
    alignb 8
%endmacro

%macro UINT32 0
    RESD 1
    alignb 4
%endmacro

%macro UINT64 0
    RESQ 1
    alignb 8
%endmacro

%macro EFI_HANDLE 0
    RESQ 1
    alignb 8
%endmacro

%macro POINTER 0
    RESQ 1
    alignb 8
%endmacro

struc EFI_TABLE_HEADER
    .Signature  UINT64
    .Revision   UINT32
    .HeaderSize UINT32
    .CRC32      UINT32
    .Reserved   UINT32
endstruc

struc EFI_SYSTEM_TABLE
    .Hdr                  RESB EFI_TABLE_HEADER_size
    .FirmwareVendor       POINTER
    .FirmwareRevision     UINT32
    .ConsoleInHandle      EFI_HANDLE
    .ConIn                POINTER
    .ConsoleOutHandle     EFI_HANDLE
    .ConOut               POINTER
    .StandardErrorHandle  EFI_HANDLE
    .StdErr               POINTER
    .RuntimeServices      POINTER
    .BootServices         POINTER
    .NumberOfTableEntries UINTN
    .ConfigurationTable   POINTER
endstruc

struc EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL
    .Reset             POINTER
    .OutputString      POINTER
    .TestString        POINTER
    .QueryMode         POINTER
    .SetMode           POINTER
    .SetAttribute      POINTER
    .ClearScreen       POINTER
    .SetCursorPosition POINTER
    .EnableCursor      POINTER
    .Mode              POINTER
endstruc

struc EFI_BOOT_SERVICES
    .Hdr                                 RESB EFI_TABLE_HEADER_size
    .RaiseTPL                            POINTER
    .RestoreTPL                          POINTER
    .AllocatePages                       POINTER
    .FreePages                           POINTER
    .GetMemoryMap                        POINTER
    .AllocatePool                        POINTER
    .FreePool                            POINTER
    .CreateEvent                         POINTER
    .SetTimer                            POINTER
    .WaitForEvent                        POINTER
    .SignalEvent                         POINTER
    .CloseEvent                          POINTER
    .CheckEvent                          POINTER
    .InstallProtocolInterface            POINTER
    .ReinstallProtocolInterface          POINTER
    .UninstallProtocolInterface          POINTER
    .HandleProtocol                      POINTER
    .Reserved                            POINTER
    .RegisterProtocolNotify              POINTER
    .LocateHandle                        POINTER
    .LocateDevicePath                    POINTER
    .InstallConfigurationTable           POINTER
    .LoadImage                           POINTER
    .StartImage                          POINTER
    .Exit                                POINTER
    .UnloadImage                         POINTER
    .ExitBootServices                    POINTER
    .GetNextMonotonicCount               POINTER
    .Stall                               POINTER
    .SetWatchdogTimer                    POINTER
    .ConnectController                   POINTER
    .DisconnectController                POINTER
    .OpenProtocol                        POINTER
    .CloseProtocol                       POINTER
    .OpenProtocolInformation             POINTER
    .ProtocolsPerHandle                  POINTER
    .LocateHandleBuffer                  POINTER
    .LocateProtocol                      POINTER
    .InstallMultipleProtocolInterfaces   POINTER
    .UninstallMultipleProtocolInterfaces POINTER
    .CalculateCrc32                      POINTER
    .CopyMem                             POINTER
    .SetMem                              POINTER
    .CreateEventEx                       POINTER
endstruc

struc EFI_RUNTIME_SERVICES
    .Hdr                       RESB EFI_TABLE_HEADER_size
    .GetTime                   POINTER
    .SetTime                   POINTER
    .GetWakeupTime             POINTER
    .SetWakeupTime             POINTER
    .SetVirtualAddressMap      POINTER
    .ConvertPointer            POINTER
    .GetVariable               POINTER
    .GetNextVariableName       POINTER
    .SetVariable               POINTER
    .GetNextHighMonotonicCount POINTER
    .ResetSystem               POINTER
    .UpdateCapsule             POINTER
    .QueryCapsuleCapabilities  POINTER
    .QueryVariableInfo         POINTER
endstruc

struc EFI_GRAPHICS_OUTPUT_PROTOCOL
    .QueryMode POINTER
    .SetMode   POINTER
    .Blt       POINTER
    .Mode      POINTER
endstruc

; see Errata A page 494
struc EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE
    .MaxMode         UINT32
    .Mode            UINT32
    .Info            POINTER
    .SizeOfInfo      UINTN
    .FrameBufferBase UINT64
    .FrameBufferSize UINTN
endstruc

; the Related Definitions section
struc EFI_MEMORY_DESCRIPTOR
    .Type          UINT32
    .PhysicalStart POINTER
    .VirtualStart  POINTER
    .NumberOfPages UINT64
    .Attribute     UINT64
endstruc

; ---- Function Wrappers for the Protocols / Services

efiOutputString:
    ; set the 2nd argument to the passed in string
    mov rdx, rcx
    
    ; get the EFI_SYSTEM_TABLE
    mov rcx, [ptrSystemTable]
    
    ; set the 1st argument to EFI_SYSTEM_TABLE.ConOut
    ; which is pointing to EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL
    mov rcx, [rcx + EFI_SYSTEM_TABLE.ConOut]
    
    ; run EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.OutputString
    call [rcx + EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.OutputString]
    
    ; display any errors
    cmp rax, EFI_SUCCESS
    jne errorCode
    
    ret
efiClearScreen:
    ; get the EFI_SYSTEM_TABLE
    mov rcx, [ptrSystemTable]
    
    ; set the 1st argument to EFI_SYSTEM_TABLE.ConOut
    ; which is pointing to EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL
    mov rcx, [rcx + EFI_SYSTEM_TABLE.ConOut]
    
    ; run EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.ClearScreen
    call [rcx + EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.ClearScreen]
    
    ; display any errors
    cmp rax, EFI_SUCCESS
    jne errorCode
    
    ret
efiLocateProtocol:
    ; get the EFI_SYSTEM_TABLE
    mov rax, [ptrSystemTable]
    
    ; get the EFI_SYSTEM_TABLE.BootServices
    ; which is pointing to EFI_BOOT_SERVICES
    mov rax, [rax + EFI_SYSTEM_TABLE.BootServices]
    
    ; set the 1st argument to the GUID for the graphics protocol
    mov rcx, EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID
    
    ; set the 2nd argument to NULL
    mov rdx, 0
    
    ; set the 3rd argument to a variable that holds 
    ; the returned EFI_GRAPHICS_OUTPUT_PROTOCOL
    lea r8, [ptrInterface]
    
    ; run EFI_BOOT_SERVICES.LocateProtocol
    call [rax + EFI_BOOT_SERVICES.LocateProtocol]
    
    ; display any errors
    cmp rax, EFI_SUCCESS
    jne errorCode
    
    ret

efiGetMemoryMap:
    ; get the EFI_SYSTEM_TABLE
    mov rax, [ptrSystemTable]
    
    ; get the EFI_SYSTEM_TABLE.BootServices
    ; which is pointing to EFI_BOOT_SERVICES
    mov rax, [rax + EFI_SYSTEM_TABLE.BootServices]
    
    ; set the 1st argument to the memory map buffer size
    lea rcx, [intMemoryMapSize]
    
    ; set the 2nd argument to the memory map buffer
    lea rdx, [bufMemoryMap]
    
    ; set the 3rd argument to a variable that holds 
    ; the returned memory map key
    lea r8, [ptrMemoryMapKey]
    
    ; set the 4th argument to a variable that holds 
    ; the returned EFI_MEMORY_DESCRIPTOR size
    lea r9, [ptrMemoryMapDescSize]
    
    ; set the 5th argument to a variable that holds 
    ; the returned EFI_MEMORY_DESCRIPTOR version
    lea r10, [ptrMemoryMapDescVersion]
    
    ; save the top of the stack so we can return here
    mov rbx, rsp
    
    ; save the 5th argument to the stack
    push r10
    
    ; run EFI_BOOT_SERVICES.GetMemoryMap
    call [rax + EFI_BOOT_SERVICES.GetMemoryMap]
    
    ; display any errors
    cmp rax, EFI_SUCCESS
    jne errorCode
    
    ; return to the previous stack location
    mov rsp, rbx
    
    ret

efiExitBootServices:
    ; get the EFI_SYSTEM_TABLE
    mov rax, [ptrSystemTable]
    
    ; get the EFI_SYSTEM_TABLE.BootServices
    ; which is pointing to EFI_BOOT_SERVICES
    mov rax, [rax + EFI_SYSTEM_TABLE.BootServices]
    
    ; set the 1st argument to the stored EFI_HANDLE
    mov rcx, [hndImageHandle]
    
    ; set the 2nd argument to the memory map key
    mov rdx, [ptrMemoryMapKey]
    
    ; run EFI_BOOT_SERVICES.ExitBootServices
    call [rax + EFI_BOOT_SERVICES.ExitBootServices]
    
    ; display any errors
    cmp rax, EFI_SUCCESS
    jne errorCode
    
    ret

内核函数.asm

funIntegerToAscii:
    ; save rbx and rsi so that we can restore them later
    push rbx
    push rsi
    
    ; set rax to the passed in integer
    mov rax, rcx
    
    ; set our counter to 0
    mov rbx, 0
    
    ; there is no return and so we continue

funIntegerToAsciiDivide:
    ; increment our counter by 1
    inc rbx
    
    ; reset our ascii character
    mov rdx, 0
    
    ; divide rax by 10
    ; idiv works on rax
    ; e.g. 123 / 10 = 12.3
    mov rsi, 10
    idiv rsi
    
    ; the remainder is stored in rdx
    ; add 48 to get it's ASCII value
    ; 3 + 48 = 51 (the character '3')
    add rdx, 48
    
    ; save the ASCII value to the stack
    push rdx
    
    ; can rax be divided again
    ; rax = 12, yes it can
    cmp rax, 0
    jnz funIntegerToAsciiDivide
    
    ; there is no return and so we continue

funIntegerToAsciiOutput:
    ; increment our counter by 1
    dec rbx
    
    ; set the 1st argument to the top of the stack
    ; 1 <- we are here
    ; 2
    ; 3
    mov rcx, rsp
    
    ; write the ASCII character there and then remove it
    call efiOutputString
    pop rax
    
    ; have we written all the characters
    cmp rbx, 0
    jnz funIntegerToAsciiOutput
    
    ; restore rbx and rsi
    pop rsi
    pop rbx
    
    ret

funLoopForever:
    jmp funLoopForever

funDrawLine:
    ; draw a single pixel
    mov [rcx + rdx], byte 0x00     ; blue
    mov [rcx + rdx + 1], byte 0x00 ; green
    mov [rcx + rdx + 2], byte 0xFF ; red
    mov [rcx + rdx + 3], byte 0xFF ; alpha
    
    ; skip to the next pixel
    add rdx, 4
    
    ; stop drawing when we've reached rdx
    cmp rdx, r8
    jne funDrawLine
    
    ret

但我无法 Boot UEFI操作系统。我的错误在哪里?请帮助我给予缺失代码或删除错误提供商代码。

7jmck4yq

7jmck4yq1#

看起来您加载了正确的寄存器,但没有在堆栈上创建影子空间。在AMD64中,调用约定与Windows中使用的约定类似。在调用函数之前,创建影子空间并对齐堆栈是很重要的。
下面是一些例子,如果你想比较一下的话:https://github.com/bitRAKE/UEFI_playground

相关问题