我正在编写一个基本内核来学习并且在启用分页时遇到了困难,因此我可以在长模式下工作。
为了简单起见,我精简了我的代码。
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.cfg
in 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'.