Почему диапазон адресов 0xC0000000 ~ 0xFFFFFFFF всегда дает 0x00 или 0xFF после перехода в защищенный режим перед включением пейджинга?

Делаю кастомный загрузчик, сейчас на стадии включения пейджинга после перехода в защищенный режим. Я попытался проверить, можно ли использовать весь диапазон памяти от 0x00000000 до 0xFFFFFFFF, чтобы убедиться, что мое ядро ​​​​имеет полный контроль над памятью. Проверка выполняется путем копирования значения в адрес памяти и печати значения через видеопамять (0xB8000). Но диапазон адресов от 0xC0000000 до 0xFFFFFFFF всегда содержит 0x00 (если выполняется QEMU) или 0xFF (если выполняется на реальном оборудовании через устаревшую загрузку).

Я искал причину в течение последних 3 недель, но не смог найти четкого ответа. В результате поиска я нашел некоторые подсказки, такие как преобразование физических и виртуальных адресов, режим ядра и режим пользователя, MMU, зарезервированный диапазон аппаратной памяти.

  • Это явление связано с трансляцией физических и виртуальных адресов.
    #P3#

Виртуальный адрес: 0x12345678 -> Физический адрес: 0x12345678

Кажется, это не связано с конкретным диапазоном адресов, всегда содержащим 0x00 или 0xFF.

  • Это явление связано с режимом ядра и режимом пользователя.
    #P6#

Таким образом, не определено правило, такое как - диапазон пространства пользователя/ядра Пример) Пространство памяти пользователя: от 0x00000000 до 0xBFFFFFFFF Пространство памяти ядра: от 0xC0000000 до 0xFFFFFFFF - как будет отображаться виртуальная память виртуальная память 0x00010000 -> 0xC0010000 - страницы

  • #P8# <блочная цитата> #P9#
  • #P10# <блочная цитата> #P11#

Теперь я понятия не имею, почему это происходит.

Почему диапазон памяти от 0xC0000000 до 0xFFFFFFFF всегда содержит 0x00 или 0xFF? (Описание «всегда содержать 0x00 или 0xFF», потому что я не уверен в том, является ли память недоступной, память недоступна для записи, память недоступна для чтения и т. д.)

Результат и коды размещены ниже.

■ BootLoader.asm

%include "MBR.asm"
%include "BootSector2.asm"

■ MBR.asm

[ORG 0x0000]
[BITS 16]

; ──────────────────────────────────────────────────
; EQU
; ──────────────────────────────────────────────────

MBRBaseAddress:     equ     0x7C00
ReadSectorCount:    equ     0x0001

; ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
; Code Section
; ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

SECTION .text

MBR:

; ──────────────────────────────────────────────────
; Initialize Registers
; ──────────────────────────────────────────────────

    jmp     0x0000:(MBRBaseAddress + 0x0005)                                ; Initialize CS (Code Segment) Register / Absolute Far Jump / set cs = 0x0000, jump to 0x07C05 (0x7C00 + 0x0005)

    mov     ax, word 0x0000
    mov     ds, ax                                                          ; Initialize DS (Data Segment) Register
    mov     ss, ax                                                          ; Initialize SS (Stack Segment) Register
    mov     ax, word 0x1000
    mov     es, ax                                                          ; Initialize ES (Extra Segment) Register
    mov     ax, word 0xB800
    mov     fs, ax                                                          ; Initialize FS Register

    mov     ax, word 0x0000                                                 ; Initialize AX (Accumulator) Register
    mov     bx, word 0x0000                                                 ; Initialize BX (Base) Register
    mov     cx, word 0x0000                                                 ; Initialize CX (Count) Register
    mov     dx, word 0x0000                                                 ; Initialize DX (Data) Register
    mov     si, word 0x0000                                                 ; Initialize SI (Source Index) Register
    mov     di, word 0x0000                                                 ; Initialize DI (Destination Index) Register
    mov     sp, word 0xFFFE                                                 ; Initialize SP (Stack Pointer) Register
    mov     bp, word 0xFFFE                                                 ; Initialize BP (Base Pointer) Register

; ──────────────────────────────────────────────────
; Clear Screen
; ──────────────────────────────────────────────────

.Clear1Digit:

    mov     [fs:di], word 0x0A00                                            ; [0xB800:di] 0x00 / [0xB800:di + 1] 0x0A / 0 -> 0000 (Background Attribute) / A -> 1010 (Text Attribute)
    add     di, 2
    cmp     di, 2 * 80 * 25                                                 ; Compare di to 2 * 80 * 25 (= 4000 = 0x0FA0)
    jl      .Clear1Digit

    mov     di, word 0x0000                                                 ; Clear di

; ──────────────────────────────────────────────────
; Print String : Real Mode String
; ──────────────────────────────────────────────────

    push    RealModeString
    push    0
    call    .PrintString
    mov     sp, bp

; ──────────────────────────────────────────────────
; Print String : Start Reading Sectors String
; ──────────────────────────────────────────────────

    push    StartReadingSectorsString
    push    1 * 2 * 80
    call    .PrintString
    mov     sp, bp

; ──────────────────────────────────────────────────
; Read Sectors (via BIOS interrupt)
; ──────────────────────────────────────────────────

.ReadSectors:

    mov     si, word 0x0000                                                 ; Initialize si (Read sector count)

    mov     al, 1                                                           ; Initialize read sector count (1)
    mov     dl, byte 0x80                                                   ; Initialize drive to read from (Hard Disk C:)
    mov     bx, word 0x0000                                                 ; Offset to read to
    mov     ah, byte 0x02                                                   ; BIOS interrupt : Read sector

.Read1Sector:

    mov     ch, byte [MBRBaseAddress + CylinderIndex]                       ; Set cylinder value to read from
    mov     dh, byte [MBRBaseAddress + HeadIndex]                           ; Set head value to read from
    mov     cl, byte [MBRBaseAddress + SectorIndex]                         ; Set sector value to read from

    cmp     si, ReadSectorCount                                             ; Compare si to ReadSectorCount
    jge     .ReadSectorsEnd                                                 ; Jump to .ReadSectorsEnd if

    int     0x13                                                            ; Call BIOS interrupt

    add     si, 1
    add     cl, 1
    mov     [MBRBaseAddress + SectorIndex], cl
    add     bx, 512
    jmp     .Read1Sector

.ReadSectorsEnd:

; ──────────────────────────────────────────────────
; Print Value : Sectors Read Count
; ──────────────────────────────────────────────────

    push    si
    push    2 * 2 * 80
    call    .PrintValue
    mov     sp, bp

; ──────────────────────────────────────────────────
; Print String : Sectors Read String
; ──────────────────────────────────────────────────

    push    SectorsReadString
    push    (2 * 2 * 80) + (2 * 5)
    call    .PrintString
    mov     sp, bp

; ──────────────────────────────────────────────────
; Switch to Protected Mode
; ──────────────────────────────────────────────────

    cli
    lgdt    [MBRBaseAddress + GDT]
    ;mov        eax, dword 0x4000003B
    mov     eax, cr0
    or      al, 1
    mov     cr0, eax

    jmp     dword 0x0008:0x00010000

; ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
; Functions
; ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

; ──────────────────────────────────────────────────
; Print Value
; ──────────────────────────────────────────────────

.PrintValue:

    push    bp                                                              ; Copy current bp to memory whose address is current sp
    mov     bp, sp                                                          ; Set new bp by current sp

    mov     cl, byte 12                                                     ; Initialize cl (Shift right count)
    mov     di, [bp + 4]                                                    ; Initialize di (2nd argument / Video memory offset where to print)

.PrintValueLoop:

    mov     si, [bp + 6]                                                    ; Copy 1st argument (Value to print) to si
    shr     si, cl                                                          ; Shift right si cl times
    and     si, word 0x000F                                                 ; Keep last 4 bits and discard (fill) other bytes to 0
    mov     bl, byte [MBRBaseAddress + ASCIIString + si]                    ; Copy ASCII value, corresponding to si, to bl
    mov     [fs:di], bl                                                     ; [0xB800:di] bl / Copy 1 character to video memory

    sub     cl, 4
    add     di, 2
    cmp     cl, 0
    jg      .PrintValueLoop

    mov     si, [bp + 6]                                                    ; Copy 1st argument (Value to print) to si
    and     si, word 0x000F                                                 ; Keep last 4 bits and discard (fill) other bytes to 0
    mov     bl, byte [MBRBaseAddress + ASCIIString + si]                    ; Copy ASCII value, corresponding to si, to bl
    mov     [fs:di], bl                                                     ; [0xB800:di] bl / Copy 1 character to video memory

.PrintValueEnd:

    pop     bp                                                              ; Copy memory whose address is current sp to bp
    ret

; ──────────────────────────────────────────────────
; Print String
; ──────────────────────────────────────────────────

.PrintString:

    push    bp                                                              ; Copy current bp to memory whose address is current sp
    mov     bp, sp                                                          ; Set new bp by current sp

    mov     bx, word [bp + 6]                                               ; Initialize bx (1st argument / String offset)
    mov     si, 0                                                           ; Initialize si (String index)
    mov     di, word [bp + 4]                                               ; Initialize di (2nd argument / Video memory offset where to print)

.PrintStringLoop:

    mov     cl, byte [MBRBaseAddress + bx + si]                             ; Copy 1 character from memory (MBRBaseAddress + String offset + String index) to cl
    cmp     cl, 0                                                           ; Compare cl to 0
    je      .PrintStringEnd
    mov     [fs:di], cl                                                     ; [0xB800:di] cl / Copy 1 character to video memory

    add     si, 1
    add     di, 2
    jmp     .PrintStringLoop

.PrintStringEnd:

    pop     bp                                                              ; Copy memory whose address is current sp to bp
    ret

; ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
; Data (Read Only)
; ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

; ──────────────────────────────────────────────────
; ASCII String
; ──────────────────────────────────────────────────

ASCIIString:

    db      '0123456789ABCDEF', 0

; ──────────────────────────────────────────────────
; Strings
; ──────────────────────────────────────────────────

RealModeString:

    db      '[Current Mode : Real Mode]', 0

StartReadingSectorsString:

    db      'Start Reading Sectors', 0

SectorsReadString:

    db      'Sectors Read', 0

; ──────────────────────────────────────────────────
; Cylinder, Head, Sector Index
; ──────────────────────────────────────────────────

CylinderIndex:

    db      0x00

HeadIndex:

    db      0x00

SectorIndex:

    db      0x02

; ──────────────────────────────────────────────────
; GDT (Global Descriptor Table)
; ──────────────────────────────────────────────────

GDTStart:
GDTNullDescriptor:

    dq      0x0000000000000000

GDTCodeDescriptor:

    dw      0xFFFF
    dw      0x0000
    db      0x00
    db      0x9A
    db      0xCF
    db      0x00

GDTDataDescriptor:

    dw      0xFFFF
    dw      0x0000
    db      0x00
    db      0x92
    db      0xCF
    db      0x00

GDTEnd:
GDT:

    dw      GDTEnd - GDTStart
    dd      MBRBaseAddress + GDTStart

; ──────────────────────────────────────────────────
; Declare Zeros
; ──────────────────────────────────────────────────

    times   510 - ($ - $$)  db  0x00

; ──────────────────────────────────────────────────
; Boot Signature
; ──────────────────────────────────────────────────

    dw      0xAA55

■ BootSector2.asm

[BITS 32]

; ──────────────────────────────────────────────────
; EQU
; ──────────────────────────────────────────────────

BootSector2BaseOffset:      equ     0x0000FE00                              ; ※ 0x00010000 (Read sector address) - 0x00000200 (Initial label offset) = 0x0000FE00 in order to use label as if it begins from 0x00000000 [ex) BootSector2Offset (0x0000FE00) + LABEL (0x000002XX) = 0x000100XX]
VideoMemory:                equ     0x000B8000

BootSector2:

    mov     ax, word 0x0010
    mov     ds, ax
    mov     es, ax
    mov     fs, ax
    mov     gs, ax
    mov     ss, ax

    mov     eax, dword 0x000B8000
    mov     ebx, dword 0x00000000
    mov     cl, 28
    mov     esi, dword 0x00000000
    mov     edi, dword VideoMemory + (3 * 2 * 80)
    mov     esp, dword 0xFFFC0004;0xBFFFFFFC;0xC0000000 + 0x00010000 + 0x000000E4
    mov     ebp, dword 0xFFFC0004;0xBFFFFFFC;0xC0000000 + 0x00010000 + 0x000000E4

.Loop1:

    mov     esi, esp
    shr     esi, cl
    and     esi, dword 0x0000000F

    mov     bl, byte [MBRBaseAddress + ASCIIString + esi]
    mov     [edi], bl

    sub     cl, 4
    add     edi, 2
    cmp     cl, 0
    jg      .Loop1

    mov     esi, esp
    and     esi, dword 0x0000000F

    mov     bl, byte [MBRBaseAddress + ASCIIString + esi]
    mov     [edi], bl


    mov     edi, dword VideoMemory + (4 * 2 * 80)
    push    dword 0xABCD1234
    mov     cl, 28


.Loop2:

    mov     esi, esp
    shr     esi, cl
    and     esi, dword 0x0000000F

    mov     bl, byte [MBRBaseAddress + ASCIIString + esi]
    mov     [edi], bl

    sub     cl, 4
    add     edi, 2
    cmp     cl, 0
    jg      .Loop2

    mov     esi, esp
    and     esi, dword 0x0000000F

    mov     bl, byte [MBRBaseAddress + ASCIIString + esi]
    mov     [edi], bl


    mov     edi, dword VideoMemory + (5 * 2 * 80)
    mov     cl, 28

.Loop3:

    mov     esi, dword [0xFFFC0000]
    shr     esi, cl
    and     esi, dword 0x0000000F

    mov     bl, byte [MBRBaseAddress + ASCIIString + esi]
    mov     [edi], bl

    sub     cl, 4
    add     edi, 2
    cmp     cl, 0
    jg      .Loop3

    mov     esi, dword [0xFFFC0000]
    and     esi, dword 0x0000000F

    mov     bl, byte [MBRBaseAddress + ASCIIString + esi]
    mov     [edi], bl

    jmp     $

; ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
; Data (Read Only)
; ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

ProtectedModeString:

    db      '[Current Mode : Protected Mode]', 0

SampleValue:

    dd      0x12345678

    times   1024 - ($ - $$) db 0x00

введите здесь описание изображения

введите здесь описание изображения

введите здесь описание изображения

введите здесь описание изображения


person YoonSeok OH    schedule 27.06.2019    source источник
comment
Вопрос не может быть таким длинным. ИМХО, надо сделать короче, чтобы получить ответ.   -  person ceremcem    schedule 27.06.2019
comment
Церемония спасибо. Я реорганизую и обрежу содержание короче.   -  person YoonSeok OH    schedule 27.06.2019
comment
Я не просматривал весь код, но вам действительно следует включить линию A20, особенно на реальном оборудовании. Хотя он может быть включен, возможно, это не так. wiki.osdev.org/A20_Line   -  person Michael Petch    schedule 27.06.2019
comment
Спасибо, сэр Майкл Петч. Следующее, что я собирался сделать перед пейджингом, это проверка и включение строки A20. Включу А20 и проверю исчезнет ли явление.   -  person YoonSeok OH    schedule 27.06.2019
comment
Также память видеокарты часто начинается с физического адреса 0xc0000000.   -  person Michael Petch    schedule 27.06.2019
comment
Не уверен, что это будет ваша проблема или нет (или способствующий фактор). Было просто наблюдение. Вы уверены, что память по адресу 0xc0000000 пригодна для использования? Карта памяти говорит, что она доступна? Если диапазон памяти не определяется картой памяти E820, этот диапазон следует считать отсутствующим.   -  person Michael Petch    schedule 27.06.2019
comment
Согласно int 0x15 eax 0xE820, зарезервировано 0xBFFE0000 ~ 0xC0000000. 0xC0000001 ~ 0xFFFBFFFF не отображается (дескриптор перескакивает с 0xBFFE0000 ~ 0xC0000000 на 0xFFFC0000 ~ 0xFFFFFFFF). Таким образом, непоказанный адрес памяти 0xC0000001 ~ 0xFFFBFFFF следует считать отсутствующим.   -  person YoonSeok OH    schedule 27.06.2019
comment
По совпадению, есть очень недавний вопрос (и хороший ответ) о явлении чтения/записи данных в области памяти, которых нет: stackoverflow.com/questions/56763862/   -  person Michael Petch    schedule 27.06.2019
comment
Если диапазон не показан, его следует считать отсутствующим, и вы не должны его тестировать или использовать. Однако непонятно, почему вы тестируете память. Карта E820 должна быть всем, что вам нужно в большинстве случаев.   -  person Michael Petch    schedule 27.06.2019
comment
В основном между 0xc0000000 и концом памяти (последний 1 гигабайт) большая часть области может быть связана с устройствами PCI с отображением памяти, видеопамятью, PnP NVRAM, APIC IO, локальными APIC, BIOS и т. д. Сколько и где находится зависит от аппаратного обеспечения и будет варьироваться от BIOS к BIOS и от типа материнской платы к типу материнской платы.   -  person Michael Petch    schedule 27.06.2019
comment
ОЙ! Ссылка, которую вы дали, отвечает. Обычно чтение памяти в несуществующую память возвращает все FF, а запись в память будет отброшена. Благодарю вас! Причина, по которой я пытался копировать в адреса памяти, заключалась в том, чтобы проверить, «что я понял правильно». В статье, лекциях или книгах, которые я видел, говорилось: «после переключения в защищенный режим адрес памяти от 0x00000000 до 0xFFFFFFFF становится доступным». Я хотел убедиться, какие адреса доступны или пригодны для использования, и что произойдет, если я получу доступ или неиспользуемые адреса памяти.   -  person YoonSeok OH    schedule 27.06.2019
comment
Возможный дубликат Что делать, если доступ к несуществующему физический адрес в системе X86? . Я отмечаю это как дубликат другого.   -  person Michael Petch    schedule 27.06.2019
comment
Диапазон памяти для пространства конфигурации PCIe находится в этой области (на реальном оборудовании; возможно, не в qemu). Это определенно не будет все 0 или все 1. Вы можете найти точный диапазон адресов для него в таблице ACPI MCFG.   -  person prl    schedule 27.06.2019
comment
Кроме того, во многих статьях о виртуальной памяти в Linux объяснялось, что 0x00000000 ~ 0xBFFFFFFF — это пользовательская память, 0xC0000000 — память ядра, и эти диапазоны были решением разработчика ОС. Мой загрузчик находится в режиме ядра, и я не устанавливал и не инструктировал ничего, связанное с адресом памяти 0xC0000000, поэтому у меня возникли сомнения, почему при копировании значения в нем отображалось 0x00 или 0xFF.   -  person YoonSeok OH    schedule 27.06.2019
comment
Речь идет о диапазонах виртуальных адресов, а не физических.   -  person prl    schedule 27.06.2019
comment
Извините за то, что мои ссылки кажутся неуклюжими, мои ответы предшествуют вашему предыдущему комментарию.   -  person YoonSeok OH    schedule 27.06.2019
comment
Спасибо прл. Я буду искать «таблицу ACPI MCFG» в качестве ключевого слова.   -  person YoonSeok OH    schedule 27.06.2019
comment
прл. Я думаю, что не понимаю, что означает «это» из-за того, что речь идет о диапазонах виртуальных адресов, а не о физических. Будет ли это беспокоить, если я попрошу подробностей?   -  person YoonSeok OH    schedule 27.06.2019
comment
Вы должны использовать карту E820 для обнаружения памяти. Хотя карту памяти можно получить из конфигурации оборудования, проблема заключается в том, что некоторая полезная память используется прошивкой для хранения таблиц ACPI и тому подобного.   -  person Margaret Bloom    schedule 27.06.2019
comment
Статьи, в которых говорится, что верхняя четверть адресного пространства — это память ядра, говорят о виртуальном адресном пространстве. Но ваш вопрос касается физического адресного пространства (поскольку вы не включили пейджинг). Так что они совершенно не связаны.   -  person prl    schedule 27.06.2019