0

我正在编写一个基本内核来学习并且在启用分页时遇到了困难,因此我可以在长模式下工作。

为了简单起见,我精简了我的代码。

boot.asm

;==================================================
; Entry point.
;
; In this file, we are in 32-bit mode.
;==================================================

%include "multiboot2.inc"

global _start

PAGE_TABLE_SIZE         equ  4096
PAGE_TABLE_ENTRY_COUNT  equ  512

; Section "text"
;--------------------------------------------------

section .text

bits 32

;
; Entry point.
;
_start:
  call  setup_ptables
  call  enable_paging

  mov  word [0xb8000], 0x0247 ; 'G'.

  cli

;
; Sets up page tables.
;
setup_ptables:
  ; Point the first entry of level 4 page table to the first entry in the level 3 page table.
  mov  eax, ptable_l3
  or   eax, 0b11
  mov  dword [ptable_l4 + 0], eax

  ; Point the first entry of level 3 page table to the first entry in the level 2 page table.
  mov  eax, ptable_l2
  or   eax, 0b11
  mov  dword [ptable_l3 + 0], eax

  mov  ecx, 0  ; Loop counter.
.map_ptable_l2:
  mov  eax, 0x200000               ; 2 MB.
  mul  ecx
  or   eax, 0b10000011
  mov  [ptable_l2 + ecx * 8], eax

  ; Increment counter and if there are more entries to fill, loop.
  inc  ecx
  cmp  ecx, PAGE_TABLE_ENTRY_COUNT
  jne  .map_ptable_l2

  ; Otherwise, return.
  ret

;
; Enables paging (IA-32e mode).
;
; Reference: https://www.intel.com/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-software-developer-vol-3a-part-1-manual.pdf.
;
enable_paging:
  ; Enable PAE.
  ; Set the PAE flag in CR4 to 1.
  mov  eax, cr4
  or   eax, 1 << 5
  mov  cr4, eax

  ; Load CR3 with the physical base address of the level 4 page table.
  mov  eax, ptable_l4
  mov  cr3, eax

  ; Enable long mode.
  ; Set the LME flag in MSR to 1.
  mov  ecx, 0xC0000080
  rdmsr
  or   eax, 1 << 8
  wrmsr

  ; Enable paging.
  ; Set the PG flag in CR0 to 1
  mov  eax, cr0
  or   eax, 1 << 31
  ;or   eax, 1 << 16
  mov  cr0, eax

  ; Return
  ret

; Section "bss"
;--------------------------------------------------

section .bss

align PAGE_TABLE_SIZE

ptable_l4:
  resb  PAGE_TABLE_SIZE
ptable_l3:
  resb  PAGE_TABLE_SIZE
ptable_l2:
  resb  PAGE_TABLE_SIZE

header.asm

;==================================================
; Multiboot header.
;
; Reference: https://www.gnu.org/software/grub/manual/multiboot2/multiboot.html.
;
; Multiboot header fields:
; ┏━━━━━━━━┯━━━━━━┯━━━━━━━━━━━━━━━┓
; ┃ Offset │ Type │ Field Name    ┃
; ┠────────┼──────┼───────────────┨
; ┃ 0      │ u32  │ magic         ┃
; ┃ 4      │ u32  │ architecture  ┃
; ┃ 8      │ u32  │ header_length ┃
; ┃ 12     │ u32  │ checksum      ┃
; ┃ 16-XX  │      │ tags          ┃
; ┗━━━━━━━━┷━━━━━━┷━━━━━━━━━━━━━━━┛
;==================================================


%include "multiboot2.inc"

; Header magic fields.
MAGIC     equ  MULTIBOOT2_HEADER_MAGIC
ISA       equ  MULTIBOOT_ARCHITECTURE_I386
LEN       equ  header_end - header_start
CHECKSUM  equ  0x100000000 - (MAGIC + ISA + LEN)

; Section "multiboot"
;--------------------------------------------------

section .multiboot

align MULTIBOOT_HEADER_ALIGN

header_start:
  ; Header magic fields.
  dd  MAGIC     ; magic.
  dd  ISA       ; architecture.
  dd  LEN       ; header_length.
  dd  CHECKSUM  ; checksum.

align MULTIBOOT_TAG_ALIGN

.efi_boot_services_tag:
  dw  MULTIBOOT_HEADER_TAG_EFI_BS  ; type.
  dw  0                            ; flags.
  dd  8                            ; size.

align MULTIBOOT_TAG_ALIGN

.efi_amd64_tag:
  dw  MULTIBOOT_HEADER_TAG_ENTRY_ADDRESS_EFI64  ; type.
  dw  0                                         ; flags.
  dd  12                                        ; size.

align MULTIBOOT_TAG_ALIGN

.end_tag:
  dw  MULTIBOOT_HEADER_TAG_END  ; type.
  dw  0                         ; flags.
  dd  8                         ; size.

header_end:

multiboot2.inc

;
; Multiboot2 constants.
;
; Reference: https://www.gnu.org/software/grub/manual/multiboot2/multiboot.html.
;

%ifndef __SPOT_MULTIBOOT2__
%define __SPOT_MULTIBOOT2__

%define  MULTIBOOT_HEADER_ALIGN  8

%define  MULTIBOOT2_HEADER_MAGIC  0xe85250d6

%define  MULTIBOOT2_BOOTLOADER_MAGIC  0x36d76289

%define  MULTIBOOT_TAG_ALIGN  8

%define  MULTIBOOT_HEADER_TAG_END                  0
%define  MULTIBOOT_HEADER_TAG_EFI_BS               7
%define  MULTIBOOT_HEADER_TAG_ENTRY_ADDRESS_EFI64  9

%define  MULTIBOOT_ARCHITECTURE_I386  0

%endif ;__SPOT_MULTIBOOT2__

_start,mov word [0xb8000], 0x0247似乎永远无法到达。

感谢所有帮助!

我使用 CMake,但为读者整理了一个快速脚本:

nasm -f elf64 boot.asm -o boot.o
nasm -f elf64 header.asm -o header.o

x86_64-elf-ld -n -o iso/boot/kernel.bin -T iso/linker.ld boot.o header.o

grub-mkrescue /usr/lib/grub/i386-pc -o dist/kernel.iso iso

以上假设你有一个grub.cfgin iso/boot/grub。我的看起来像:

set timeout=0
set default=0

menuentry "spot" {
  multiboot2 /boot/kernel.bin
  boot
}

并且linker.ld

ENTRY(_start)

SECTIONS
{
  . = 1M;

  .boot :
  {
    KEEP(*(.multiboot))
  }

  .text :
  {
    *(.text)
  }
}

然后在 QEmu 中运行:qemu-system-x86_64 -cdrom dist/kernel.iso.

这是我的构建环境的 Dockerfile:

FROM randomdude/gcc-cross-x86_64-elf

RUN apt-get update
RUN apt-get upgrade -y

RUN apt-get install -y gdb

RUN apt-get install -y xorriso

RUN apt-get install -y grub-pc-bin
RUN apt-get install -y grub-common

RUN apt-get install -y nasm

ARG       cmake_version=3.21
ARG       cmake_revision=4
WORKDIR   /root
RUN       wget https://github.com/Kitware/CMake/releases/download/v${cmake_version}.${cmake_revision}/cmake-${cmake_version}.${cmake_revision}-linux-x86_64.tar.gz
RUN       tar -xzf cmake-${cmake_version}.${cmake_revision}-linux-x86_64.tar.gz
WORKDIR   /root/cmake-${cmake_version}.${cmake_revision}-linux-x86_64
RUN       cp -rf ./bin ./share /usr/local

VOLUME /root/env
WORKDIR /root/env

更新#1:

我注意到检查 Multiboot2 失败:

check_multiboot:
  ; EAX should have a magic value.
  cmp  eax, MULTIBOOT2_BOOTLOADER_MAGIC
  jne  .no_multiboot

  ret
.no_multiboot:
  mov  word [0xb8000], 0x044D ; 'M'.
4

0 回答 0