【问题标题】:Confused about X86 segmentation对 X86 分割感到困惑
【发布时间】:2020-05-23 07:21:17
【问题描述】:

我正在编写一个引导扇区来加载我的 16 位实模式 DOS 克隆,但我遇到了一些可能非常明显的问题,但我花了几个小时试图理解为什么它不起作用.

基本上,我正在尝试将DSCSSS 设置为零,但将ES 设置为直接超过 7C00 以加载系统。

但是当通过调试器运行我的代码时,它说没有任何东西被读入内存,即:root、FAT 等 (???)

基本上,我正在尝试将 DS:SI (0000:7C00+FILE) 与 ES:DI (07E0:0000) 进行比较,但无济于事。我听说有人告诉我它实际上检查了DS:SIDS:DI,所以我尝试了它,但这也没有用。 07E0:0000 不应该直接在 0000:7C00 之后吗? cmpsb 是否要求 ESDS 相同?

我查看了英特尔手册,但它说cmpsbDS:SIES:DI 进行比较,但我认为我并没有误解太多。 07E0:0000 是 0x7E00,不是吗?

无论如何,感谢您的帮助。我很感激。

编辑:我忘了提到如果我将ES 归零并将加载地址放入BX,一切正常。但是当它被翻转时,ES=07E0BX=0,没有任何效果,甚至没有被读取。不知道为什么,因为不管你走哪条路,ES:BX 都应该是一样的。

我的代码:

ORG 7C00H
    USE16

BPBBEG:
    JMP  SHORT BPBPEND
    NOP

        DB "PEDOS1.0"
BYTSPERSEC: DW 512      ; total bytes per sector on this volume
SECPERCLUS: DB 1        ; total sectors per cluster on this volume
RSVDSECCNT: DW 1        ; unused
NUMFATS:    DB 2        ; total FATs on this volume
ROOTENTCNT: DW 224      ; total entries in the Root Directory
        DW 80 * 36
        DB 240
FATSZ16:    DW 9        ; total sectors per FAT on this volume
SECPERTRK:  DW 18       ; total sectors per track on this idks
NUMHEADS:   DW 2        ; total heads per cyliner on this idks
        DD 0
        DD 0
        DB 0
        DB 0
        DB 41
        DD 0
        DB "           "
        DB "FAT12   "
;
; PEDOS MEMORY MAP
;
;   -  --  ROM / VIDEO  -- A000:0
;   -   -----------------
;   -  --  BIOS DATA    -- 8000:0
;   -   -----------------
;   -  --  FREE         -- ????:?
;   -   -----------------
;   -  --  BOOT / FREE  -- 0000:7C00
;   -   -----------------
;   -  --  FREE         -- ????:?
;   -   -----------------
;   -  --  DRIVERS      -- ????:?
;   -   -----------------
;   -  --  SYSTEM       -- 0050:0
;   -   -----------------
;   -  --  BIOS BATA    -- 0000:400
;   -   -----------------
;   -  --  IVT          -- 0000:0
;

;
; INITIALIZE SEGMENT REGISTERS
;
BPBPEND:
    XOR  AX, AX
    MOV  DS, AX
    CLI
    PUSH DS
    POP  SS
    MOV  SP, 7C00H
    PUSH DS
    PUSH CHKDSK
    STI
    RETF    ; SET CS TO KNOWN VALUE
;
; LOAD ROOT DIRECTORY AND CHECK FOR
; SYSTEM FILE
;
CHKDSK:
    MOV  AX, WORD BUFFER
    SHR  AX, 4
    MOV  ES, AX ; ES = 07E0
    XOR  AX, AX
    MOV  AX, WORD [FATSZ16]
    MUL  WORD [NUMFATS]
    ADD  AL, BYTE [RSVDSECCNT]
    ;mov  bx, 0x7e00
    MOV  DI, 1
    CALL READSEC


;   mov  ah, 14
;   mov  al, '/'
;   int  16
;   jmp  $

    LEA  SI, [FILE] ; ADDRESS OF FILENAME
    MOV  DI, 0
    MOV  CX, 11     ; 11 BYTES PER FAT FILENAME
    CLD
    REPZ CMPSB
    JZ   LOADFILE
    JMP  ERROR

; DOSBIOS.SYS CONFIRMED: LOAD THE
; FILE INTO MEMORY.

LOADFILE:
    mov  ah, 14
    mov  al, '.'
    int  16
    jmp  $

    MOV  AX, 32
    MOV  BX, WORD [ROOTENTCNT]  ; TOTAL FATS ON DISK
    MUL  BX
    MOV  BX, WORD [BYTSPERSEC]  ; FAT SIZE IN SECTORS
    DIV  BX
    ;
    ; AX = SIZE OF ROOT DIRECTORY
    ;   IN SECTORS
    ;
    ADD  AX, BP ; SIZE + LOCATION = DATA REGION
    POP  BX
    PUSH BX
    MOV  DI, 1  ; DOS SIZE IS HARD CODED FOR NOW - MAY
    CALL READSEC    ; CHANGE IN THE FUTURE
RUNDOS:
    POP  BX
    PUSH 0
    PUSH BX
    RETF
;
; READ THE SPECIFIED SECTORS INTO MEMORY
; AT LOGICAL ES:BX      
;
; IN:   DX:AX   = HEAD, TRACK, SECTOR NUMBER
;   DI  = SECTOR COUNT
;
READSEC:
    PUSHA
    DIV  WORD [SECPERTRK]
    ;
    ; AX = LBA / SECPERTRACK
    ; DX = LBA % SECPERTRACK
    ;
    MOV  CX, DX
    INC  CX     ; CX = LBA 1
    XOR  DX, DX
    DIV  WORD [NUMHEADS]
    ;
    ; AX = (LBA / SECPERTRACK) / CYLHEADCNT = CYLINDER
    ; DX = (LBA / SECPERTRACK) % CYLHEADCNT = HEAD
    ;
    MOV  CH, AL
    SHL  AH, 6
    OR   CL, AH
    MOV  DH, DL
    MOV  DL, 0
    ;
    ; DH = HEAD HUMBER
    ; DL = DRIVE
    ;
    MOV  AH, 2
    MOV  AL, 1
    INT  19
    JNC  NEXTSEC    ; IN CASE OF ERRORS, FOLLOW
ERROR:
    LEA  SI, [ERRMSG]   ; SOMETHING WENT WRONG, SO THROW AN ERROR
;
; WRITE SPECIFIED STRING TO VIDEO
; MEMORY
;
; DS:SI = ADDRESS OF STRING
;
PRINT:
    LODSB
    OR   AL, 0
    JZ   HALT
    MOV  AH, 14
    MOV  BX, 7
    INT  16
    JMP  PRINT
HALT:
    MOV AX, 0
    INT 22
    INT 25
;
; CONTINUE 'READSEC'
;
NEXTSEC:
    POPA
    DEC  DI
    JZ   RETURN ; SKIP PRINT SUBROUTINE
    ADD  BX, WORD [BYTSPERSEC]
    ADD  AX, 1
    ADC  DX, 0
    JMP  READSEC
RETURN:
    RET
;
; KEEP DATA BELOW CODE, UNTIL SECTOR
; MARKER
;
ERRMSG: DB 10, "Disk Error or DOSBIOS.SYS is missing.", 13
    DB 10, "Press any key to restart.", 13, 10, 10, 0
FILE:   DB "DOSBIOS SYS"

    TIMES (512 - 2) - ($ - $$) DB 0

MARKER: DW 0AA55H
BUFFER:
;
; THE SYSTEM IS LOADED DIRECTLY AFTER
; BOOTSTRAP
;

【问题讨论】:

  • Does Cmpsb require ES & DS to be the same?
  • 07E0:0 is 0x7E00,no?
  • Shouldn't 07E0:0 be directly after 0000:7c00? 有 512 个字节“紧接在”是。
  • 你不应该在堆栈建立之前 push 任何东西(首先 "push ds" 在 "BPBPEND" 之后)
  • @Tommylee2k:为什么不呢?在某处肯定有一个有效的堆栈,不与你的代码的 512 字节或任何 BIOS 认为有价值的东西重叠。 (否则这将是一个大量错误的 BIOS)。否则int无法工作,跳转到引导扇区时启用中断。

标签: assembly nasm x86-16 bootloader memory-segmentation


【解决方案1】:

检查您的尺码!

一方面你定义:

RSVDSECCNT: DW 1        ; unused
NUMFATS:    DB 2        ; total FATs on this volume
ROOTENTCNT: DW 224      ; total entries in the Root Directory

另一方面,你计算:

MOV  AX, WORD [FATSZ16]
MUL  WORD [NUMFATS]
ADD  AL, BYTE [RSVDSECCNT]
  1. 汇编器将对您询问的内容进行编码,并将AX 与涉及使用垃圾高字节(在本例中为值 224)的单词 NUMFATS 相乘!
  2. 同样错误地添加了 RSVDSECCNT,因为所涉及的数字非常小 - 至少在第一个问题得到纠正的情况下!但既然那个被定义为单词,你真的应该写add ax, [RSVDSECCNT]

解决方案:

MOVZX AX, BYTE [NUMFATS]
MUL   AX, WORD [FATSZ16]
ADD   AX, WORD [RSVDSECCNT]

指针进入ES:BX

CHKDSK:
    MOV  AX, WORD BUFFER
    SHR  AX, 4
    MOV  ES, AX ; ES = 07E0
    XOR  AX, AX

XOR AX, AX 更改为 XOR BX, BX

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-09-18
    • 1970-01-01
    • 2012-06-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-09-13
    • 2012-07-22
    相关资源
    最近更新 更多