2022-08-22  2024-09-15    1285 字  3 分钟
AOS

初始化寄存器

我将物理地址0x050000-0x070008之间的内存分配给了堆栈。栈顶设置为0x070008的原因是,kernel函数在编译后会在函数开头加上这样一行汇编代码sub $0x8,%rsp,将栈顶设置为0x070008可以保证在经过此操作后,栈顶为0x070000

段寄存器

  • CS: 指向存放程序的内存段,IP用来存放下条待执行的指令在该段的偏移量。CS:IP所指向的指令就是下次要执行的指令。
  • SS: 指向用于堆栈的内存段,SP用来指向该堆栈的栈顶。
  • DS: 指向数据段
  • ES: 指向附加段 (辅助段寄存器)
  • FS: 指向标志段 (辅助段寄存器)
  • GS: 指向全局段 (辅助段寄存器)

缺省段寄存器

  • 当偏移量用到了指针寄存器BP,则其缺省的段寄存器也是SS,并且用BP可访问整个堆栈,不仅仅是只访问栈顶。
  • 通常,缺省的数据段寄存器是DS
  • 在进行串操作时,其目的地址的段寄存器规定为ES

代码

Use this command to check your USB Stick FAT32 Fields

sudo hexdump -C -n 512 /dev/sdb

Write the bootloader to first 512 bytes of the usb stick

sudo dd if=boot.bin of=/dev/sdb conv=notrunc

boot.asm

[BITS 16]

[ORG 0x7c00]

;----------------------------------------------- [Jump Instruction; offset: 0x00; length: 3  Bytes]

    jmp short Label_Start                           ; 2 Bytes
    nop                                             ; 1 Bytes

;----------------------------------------------- [FAT32; offset: 0x03; length: 87 Bytes]

%include "fat32.asm"

;----------------------------------------------- [Bootstrap Code; offset: 0x5A; length: 420 Bytes]

Label_Start:
    call Print_StartBoot

    mov sp, BaseOfStack

    push    cs
    pop     ds

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Search and Read "loader.bin" ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

    and     byte [BS_RootDirectoryStart+3], 0x0F ; mask cluster value
    mov     esi, [BS_RootDirectoryStart]         ; esi=cluster # of root dir

RootDirReadContinue:
    push    BaseOfLoader
    pop     es
    xor     bx, bx
    call    ReadCluster     ; read one cluster of root dir
    push    esi             ; save esi=next cluster # of root dir
    pushf                   ; save carry="not last cluster" flag

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Look for the loader file to load and run ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

    push    BaseOfLoader
    pop     es
    xor     di, di                  ; es:di -> root entries array
    mov     si, Filename_Loader     ; ds:si -> program name

    mov     al, [BPB_SectorsPerCluster]
    cbw
    mul     word [BPB_BytesPerSector]   ; ax = bytes per cluster
    shr     ax, 5
    mov     dx, ax                      ; dx = # of dir entries to search in

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Looks for a file/dir by its name      ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Input:  DS:SI -> file name (11 chars) ;;
;;         ES:DI -> root directory array ;;
;;         DX = number of root entries   ;;
;; Output: ESI = cluster number          ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

    mov     cx, 11     ; the length of loader filename

FindNameCycle:
    cmp     byte [es:di], 0xC
    jne     FindNameNotEnd
    jmp     Print_Error_NoLoader                 ; end of root directory (NULL entry found)
FindNameNotEnd:
    pusha
    repe    cmpsb
    popa
    je      FindNameFound
    add     di, 32
    dec     dx
    jnz     FindNameCycle           ; next root entry
    popf                            ; restore carry="not last cluster" flag
    pop     esi                     ; restore esi=next cluster # of root dir
    jc      RootDirReadContinue     ; continue to the next root dir cluster
    jmp     Print_Error_NoLoader    ; end of root directory (dir end reached)
FindNameFound:
    push    word [es:di+0x14]
    push    word [es:di+0x1A]
    pop     esi                     ; si = cluster no.

;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Load the entire file ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;

    push    BaseOfLoader
    pop     es
    xor     bx, bx
FileReadContinue:
    call    ReadCluster             ; read one cluster of root dir

    pushf
    pusha
    inc byte [CLU]
    mov ax, 0xB800
    mov gs, ax
    mov ah, 0x0F       ; 0000: 黑底    1111: 白字
    mov al, [CLU]
    mov [gs:((80 * 0 + 39) * 2)], ax  ; 屏幕第 0 行, 第 39 列。
    popa
    popf

    jc      FileReadContinue

EnterLoader:
    mov bl, byte [LINE]              ; save line number
    jmp BaseOfLoader:OffsetOfLoader

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Reads a FAT32 cluster        ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Inout:  ES:BX -> buffer      ;;
;;           ESI = cluster no   ;;
;; Output:   ESI = next cluster ;;
;;         ES:BX -> next addr   ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

ReadCluster:
    mov     ax, [BPB_BytesPerSector]
    shr     ax, 2                           ; ax=# of FAT32 entries per sector
    cwde
    mov     ebp, esi                        ; ebp=esi=cluster #
    xchg    eax, esi
    cdq
    div     esi                             ; eax=FAT sector #, edx=entry # in sector
    movzx   edi, word [BPB_ReservedSectors]
    add     edi, [BPB_HiddenSectors]
    add     eax, edi

    push    dx                              ; save dx=entry # in sector on stack
    mov     cx, 1
    call    ReadSectorLBA                   ; read 1 FAT32 sector

    pop     si                              ; si=entry # in sector
    add     si, si
    add     si, si
    and     byte [es:si+3], 0x0F            ; mask cluster value
    mov     esi, [es:si]                    ; esi=next cluster #

    lea     eax, [ebp-2]
    movzx   ecx, byte [BPB_SectorsPerCluster]
    mul     ecx
    mov     ebp, eax

    movzx   eax, byte [BPB_TotalFATs]
    mul     dword [BS_BigSectorsPerFAT]

    add     eax, ebp
    add     eax, edi

    call    ReadSectorLBA

    mov     ax, [BPB_BytesPerSector]
    shr     ax, 4                   ; ax = paragraphs per sector
    mul     cx                      ; ax = paragraphs read

    mov     cx, es
    add     cx, ax
    mov     es, cx                  ; es:bx updated

    cmp     esi, 0x0FFFFFF8         ; carry=0 if last cluster, and carry=1 otherwise
    ret

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Reads a sector using BIOS Int 13h fn 42h ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Input:  EAX = LBA                        ;;
;;         CX    = sector count             ;;
;;         ES:BX -> buffer address          ;;
;; Output: CF = 1 if error                  ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

ReadSectorLBA:
    pushad

ReadSectorLBANext:
    pusha

    push    byte 0
    push    byte 0 ; 32-bit LBA only: up to 2TB disks
    push    eax
    push    es
    push    bx
    push    byte 1 ; sector count word = 1
    push    byte 16 ; packet size byte = 16, reserved byte = 0

    mov     ah, 42h
    mov     dl, [BS_DriveNumber]
    mov     si, sp
    push    ss
    pop     ds
    int     13h
    push    cs
    pop     ds

    jc      short Print_Error_Read
    add     sp, 16 ; the two instructions are swapped so as not to overwrite carry flag

    popa
    dec     cx
    jz      ReadSectorLBADone2      ; last sector

    add     bx, [BPB_BytesPerSector] ; adjust offset for next sector
    add     eax, byte 1             ; adjust LBA for next sector
    jmp     short ReadSectorLBANext

ReadSectorLBADone2:
    popad
    ret

Print_StartBoot:
    pusha
    mov cx, 10
    mov bp, Message_StartBoot
    mov bx, 0x000f
    call Message_Print_End
    popa
    ret

Print_Error_Read:
    mov cx, 11
    mov bp, Message_ReadError
    mov bx, 0x000f
    call Message_Print_End
    jmp $

Print_Error_NoLoader:
    mov cx, 15
    mov bp, Message_NoLoader
    mov bx, 0x000c
    call Message_Print_End
    jmp $

Message_Print_End:
    push es
    push ds
    mov ax, 0
    mov ds, ax
    mov es, ax
    mov ax, 0x1301
    mov dl, 0
    mov dh, [LINE]
    inc byte [LINE]
    int 10h
    pop ds
    pop es
    ret


BaseOfLoader:         EQU   0x1000
OffsetOfLoader:       EQU   0x0000
BaseOfStack:          EQU   0x7C00


Message_StartBoot:    DB    "Start Boot"      ; 10
Message_ReadError:    DB    "ERROR: Read"     ; 11
Message_NoLoader:     DB    "No Loader Found" ; 15
Filename_Loader:      DB    "LOADER  BIN"     ; 11

LINE:                 DB    0x00
CLU:                  DB    0x41

    TIMES 510 - ($ - $$)  DB  0

;----------------------------------------------- [End of Sector Marker; offset: 0x1FE; length: 2 Bytes]

    DW  0xAA55