I am learning to create an x86 protected mode program. Currently, the GDT is enabled, but I’m not sure if it is set up correctly. The issue I’m facing is that the CR3 register, regardless of what I do, always stays at 0000 0000. As I’m a beginner in this area, I would like to ask for guidance from those more experienced.
Qemu logs:
CR3 should be 00008000, but it's not.
EAX=80000bd0 EBX=000000d2 ECX=00000009 EDX=00000cf8ESI=07faf21e EDI=00000000 EBP=07faa5f0 ESP=00006becEIP=000ea0fe EFL=00000082 [--S----] CPL=0 II=0 A20=1 SMM=0 HLT=0ES =0010 00000000 ffffffff 00cf9300 DPL=0 DS [-WA]CS =0008 00000000 ffffffff 00cf9b00 DPL=0 CS32 [-RA]SS =0010 00000000 ffffffff 00cf9300 DPL=0 DS [-WA]DS =0010 00000000 ffffffff 00cf9300 DPL=0 DS [-WA]FS =0010 00000000 ffffffff 00cf9300 DPL=0 DS [-WA]GS =0010 00000000 ffffffff 00cf9300 DPL=0 DS [-WA]LDT=0000 00000000 0000ffff 00008200 DPL=0 LDTTR =0000 00000000 0000ffff 00008b00 DPL=0 TSS32-busyGDT= 000f6180 00000037IDT= 000f61be 00000000CR0=00000011 CR2=00000000 CR3=00000000 CR4=00000000DR0=00000000 DR1=00000000 DR2=00000000 DR3=00000000DR6=ffff0ff0 DR7=00000400EFER=0000000000000000FCW=037f FSW=0000 [ST=0] FTW=00 MXCSR=00001f80FPR0=0000000000000000 0000 FPR1=0000000000000000 0000FPR2=0000000000000000 0000 FPR3=0000000000000000 0000FPR4=0000000000000000 0000 FPR5=0000000000000000 0000FPR6=0000000000000000 0000 FPR7=0000000000000000 0000XMM00=0000000000000000 0000000000000000 XMM01=0000000000000000 0000000000000000XMM02=0000000000000000 0000000000000000 XMM03=0000000000000000 0000000000000000XMM04=0000000000000000 0000000000000000 XMM05=0000000000000000 0000000000000000XMM06=0000000000000000 0000000000000000 XMM07=0000000000000000 0000000000000000
boot.S
#include "os.h".section .data.section .text .global _start _start: jmp $0, $offest offest: movw $0, %ax movw %ax, %ds movw %ax, %ss movw %ax, %es movw %ax, %fs movw %ax, %gs movl $_start, %esp boot_load: movw $protected_mode_start, %bx movw $0x2, %cx movw $0x240, %ax int $0x13 jc boot_load cli lgdt gdt_desc movl %cr0, %eax orl $0x1, %eax movl %eax, %cr0 jmp $KERNEL_CODE_SEG, $protected_mode_start boot_sig: .org 0x1fe .byte 0x55, 0xaa protected_mode_start: movw $KERNEL_DATA_SEG, %ax movw %ax, %ds movw %ax, %ss movw %ax, %es movw %ax, %fs movw %ax, %gs movl $_start, %esp movl $pg_dir, %eax movl %eax, %cr3 movl %cr4, %eax orl $(1 << 4), %eax movl %eax, %cr4 movl %cr0, %eax orl $(1 << 31), %eax movl %eax, %cr0 jmp . gdt_desc: .word (256*8) - 1 .long gdt_table
os.c
#include "os.h"#include "page.h"#include <stdint.h>struct GDTDescriptor { uint16_t segment_limit; uint16_t base_address; uint16_t base_address_low; uint16_t base_address_high;} __attribute__((aligned(8)));uint32_t pg_dir[PG_SIZE] __attribute__((aligned(4096))) = { [0] = (0) | PDE_P | PDE_PS | PDE_W | PDE_U, };struct GDTDescriptor gdt_table[256] = { [KERNEL_CODE_SEG / 8] = {0xffff, 0x0000, 0x9a00, 0x00cf}, [KERNEL_DATA_SEG / 8] = {0xffff, 0x0000, 0x9200, 0x00cf}};
os.h
#ifndef OS_H#define OS_H#define KERNEL_CODE_SEG (1 * 8)#define KERNEL_DATA_SEG (2 * 8)#endif // OS_H
page.h
#ifndef PAGE_H#define PAGE_H#define PG_SIZE 1024#define PDE_P (1 << 0)#define PDE_W (1 << 1)#define PDE_U (1 << 2)#define PDE_PS (1 << 7)#endif // PAGE_H
my Makefile
OS_ARCH := x86BUILD_DIR := buildOBJECT_DIR := $(BUILD_DIR)/objBIN_DIR := $(BUILD_DIR)/binOS_NAME = systemOS_BIN = $(OS_NAME).binOS_ELF = $(OS_NAME).elfOS_IMG = $(OS_NAME).imgQEMU_MON_PORT := 45454CC := i686-elf-O := -O3W := -Wall -WextraCFLAGS := -m32 -std=gnu99 -ffreestanding $(O) $(W)LDFLAGS := -ffreestanding $(O) -nostdlib -lgccSOURCE_FILES := $(wildcard source/*.c source/*.S) OBJ_FILES := $(patsubst source/%.c, $(OBJECT_DIR)/%.o, $(patsubst source/%.S, $(OBJECT_DIR)/%.o, $(SOURCE_FILES)))$(OBJECT_DIR) $(BIN_DIR) $(IMG_DIR): @mkdir -p $@$(OBJECT_DIR)/%.o: source/%.S | $(OBJECT_DIR) $(CC)gcc $(CFLAGS) -c $< -o $@$(OBJECT_DIR)/%.o: source/%.c | $(OBJECT_DIR) $(CC)gcc $(CFLAGS) -c $< -o $@$(BIN_DIR)/$(OS_BIN): $(OBJ_FILES) | $(BIN_DIR) $(CC)ld -Ttext=0x7c00 -m elf_i386 $(OBJ_FILES) -o $(BIN_DIR)/$(OS_ELF) ${TOOL_PREFIX}objcopy -O binary $(BIN_DIR)/$(OS_ELF) $(BIN_DIR)/$(OS_BIN) ${TOOL_PREFIX}objdump -x -d -S $(BIN_DIR)/$(OS_ELF) > $(BIN_DIR)/$(OS_NAME)_dis.txt ${TOOL_PREFIX}readelf -a $(BIN_DIR)/$(OS_ELF) > $(BIN_DIR)/$(OS_NAME)_elf.txt dd if=$(BIN_DIR)/$(OS_BIN) of=$(BIN_DIR)/$(OS_IMG) conv=notruncall-debug: O := -O0all-debug: CFLAGS := -g -c -std=gnu99 -ffreestanding $(O) $(W) -fomit-frame-pointerall-debug: LDFLAGS := -ffreestanding $(O) -nostdlib -lgccall-debug: clean $(BIN_DIR)/$(OS_BIN) @i686-elf-objdump -D $(BIN_DIR)/$(OS_ELF) > dump @xxd $(BIN_DIR)/$(OS_ELF) > dump.hexall: $(BIN_DIR)/$(OS_BIN)clean: @rm -rf $(BUILD_DIR)run: $(BIN_DIR)/$(OS_IMG) @qemu-system-i386 -m 128M -drive file=$(BIN_DIR)/$(OS_IMG),index=0,media=disk,format=raw -monitor telnet::$(QEMU_MON_PORT),server,nowait & @sleep 1 @telnet 127.0.0.1 $(QEMU_MON_PORT)debug-bochs: all @bochs -q -f bochs.cfgdebug-qemu: all-debug @objcopy --only-keep-debug $(BIN_DIR)/$(OS_ELF) $(BUILD_DIR)/kernel.dbg @qemu-system-i386 -s -S -drive file=$(BIN_DIR)/$(OS_BIN),index=0,media=disk,format=raw & @gdb -s $(BUILD_DIR)/kernel.dbg \ -ex "target remote localhost:1234" \ -ex "set disassembly-flavor intel" \ -ex "set architecture i8086" \ -ex "continue" \ -ex "quit"
I checked the output dump, and the instructions are being executed.
00007e00 <protected_mode_start>: 7e00: 66 b8 10 00 mov $0x10,%ax 7e04: 8e d8 mov %eax,%ds 7e06: 8e d0 mov %eax,%ss 7e08: 8e c0 mov %eax,%es 7e0a: 8e e0 mov %eax,%fs 7e0c: 8e e8 mov %eax,%gs 7e0e: bc 00 7c 00 00 mov $0x7c00,%esp 7e13: 0f 20 d8 mov %cr3,%eax 7e16: 0d 00 80 00 00 or $0x8000,%eax 7e1b: 0f 22 d8 mov %eax,%cr3 7e1e: 0f 20 e0 mov %cr4,%eax 7e21: 83 c8 10 or $0x10,%eax 7e24: 0f 22 e0 mov %eax,%cr4 7e27: 0f 20 c0 mov %cr0,%eax 7e2a: 0d 00 00 00 80 or $0x80000000,%eax 7e2f: 0f 22 c0 mov %eax,%cr0 7e32: eb fe jmp 7e32 <protected_mode_start+0x32>00007e34 <gdt_desc>: 7e34: ff 07 incl (%edi) 7e36: 00 .byte 0x0 7e37: 90 nop ...Disassembly of section .data:00008000 <pg_dir>: 8000: 87 00 xchg %eax,(%eax) ...00009000 <gdt_table>: ... 9008: ff (bad) 9009: ff 00 incl (%eax) 900b: 00 00 add %al,(%eax) 900d: 9a cf 00 ff ff 00 00 lcall $0x0,$0xffff00cf 9014: 00 92 cf 00 00 00 add %dl,0xcf(%edx) ...
The environment I'm using is WSL with an i686 cross-compiler for compilation. Additionally, I would like to ask if the CS in the QEMU logs is correct, as other people see it as 00cf9a00 DPL=0 CS32 [-R-] ?