我正在写一个操作系统,我想切换到长模式。
问题是我的交叉编译器(
x86_64-elf-gcc
)即使我通过了
-fno-pic
选项
靴子s
/* boot.S - bootstrap the kernel */
/* https://www.kernel.org/doc/Documentation/x86/boot.txt */
#include <boot/param.h>
#include <asm/control_registers.h>
/* 32-bit startup code. */
.code32
.text
.global _start
.type _start, @function
_start:
/* Clear DF flag */
cld
/* Setup stack */
movl $stack_top, %esp
/* Check Multiboot2 */
call check_multiboot2
testl %eax, %eax
jnz wrong_multiboot2
/* Check CPUID */
call check_cpuid
testl %eax, %eax
jnz no_cpuid
/* Check if CPU can run in long mode */
call check_longmode
testl %eax, %eax
jnz no_longmode
/* TODO: Check the KEEP_SEGMENTS flag. */
/* Update the Global Descriptor Table with 64-bit segments */
lgdt gdt64
/* Enable PAE */
movl %cr4, %eax
orl $(1 << X86_CR4_PAE_BIT), %eax
movl %eax, %cr4
/* TODO: Build the structure for paging. */
/* TODO: Transition to long mode. */
movl $0x2f4b2f4f, 0xb8000
cli
1: hlt
jmp 1b
wrong_multiboot2:
movl $'0, %eax
jmp error
no_cpuid:
movl $'1, %eax
jmp error
no_longmode:
movl $'2, %eax
error:
movl $0x4f524f45, (0xb8000)
movl $0x4f3a4f52, (0xb8004)
movl $0x4f204f20, (0xb8008)
movb %al, (0xb800a)
1: hlt
jmp 1b
#include "check.S"
.section .rodata
/* GDT */
gdt64:
.word gdt_end - gdt - 1 /* limit */
.quad gdt /* base */
gdt:
.quad 0 /* Null Descriptor */
.quad 0x00af9a000000ffff /* Kernel Mode Code Segment */
.quad 0x00cf92000000ffff /* Kernel Mode Data Segment */
.quad 0x00affa000000ffff /* User Mode Code Segment */
.quad 0x00cff2000000ffff /* User Mode Data Segment */
/* TODO: Task State Segment */
gdt_end:
.bss
/* Stack */
.balign 4
stack_bottom:
.fill STACK_SIZE, 1, 0
stack_top:
检查s
/* check.S : check for multiboot2, cpuid, long mode */
#include <boot/multiboot2.h>
/* Check multiboot2 */
check_multiboot2:
cmpl $MULTIBOOT2_BOOTLOADER_MAGIC, %eax
jne .Lcheck_wrong_multiboot2
xorl %eax, %eax
ret
.Lcheck_wrong_multiboot2:
movl $1, %eax
ret
/* Check if CPUID is supported by attempting to flip the ID bit (bit 21) in
the FLAGS register. If we can flip it, CPUID is available. */
check_cpuid:
pushf
push $0
popf
/* Copy FLAGS in to EAX via stack */
pushfl
popl %eax
/* Copy to EBX as well for comparing later on */
movl %eax, %ebx
/* Flip the ID bit */
xorl $(1 << 21), %eax
/* Copy EAX to FLAGS via the stack */
pushl %eax
popfl
/* Copy FLAGS back to EAX (with the flipped bit if CPUID is supported) */
pushfl
popl %eax
/* Restore FLAGS from the old version stored in ECX (i.e. flipping the ID bit
back if it was ever flipped). */
/* push ecx */
/* Compare EAX and EBX. If they are equal then that means the bit wasn't
flipped, and CPUID isn't supported. */
cmpl %eax, %ebx
jz .Lcheck_no_cpuid
popf
xorl %eax, %eax
ret
.Lcheck_no_cpuid:
popf
movl $1, %eax
ret
/* Check if CPU can support long mode (64 bits) */
check_longmode:
pushf
push $0
popf
/* test if extended processor info in available */
/* implicit argument for cpuid */
movl $0x80000000, %eax
/* get highest supported argument */
cpuid
/* it needs to be at least 0x80000001 */
cmpl $0x80000001, %eax
jb .Lcheck_no_longmode
/* use extended info to test if long mode is available */
/* argument for extended processor info */
movl $0x80000001, %eax
cpuid
/* test if the LM-bit is set in the D-register */
testl $(1 << 29), %edx
/* If it's not set, there is no long mode */
jz .Lcheck_no_longmode
popf
xorl %eax, %eax
ret
.Lcheck_no_longmode:
popf
movl $1, %eax
ret
我用
x86_64-elf-gcc -Wall -Wextra -nostdlib -lgcc -mno-red-zone -ffreestanding -std=gnu99 -fno-pic -c src/boot/boot.S -o build/boot.o -I include
这是我们的目标
boot.o
0000000000000000 <_start>:
0: fc cld
1: bc 00 00 00 00 mov $0x0,%esp
6: e8 6d 00 00 00 call 78 <check_multiboot2>
b: 85 c0 test %eax,%eax
d: 75 30 jne 3f <wrong_multiboot2>
f: e8 74 00 00 00 call 88 <check_cpuid>
14: 85 c0 test %eax,%eax
16: 75 2e jne 46 <no_cpuid>
18: e8 8b 00 00 00 call a8 <check_longmode>
1d: 85 c0 test %eax,%eax
1f: 75 2c jne 4d <no_longmode>
21: 0f 01 15 00 00 00 00 lgdt 0x0(%rip) # 28 <_start+0x28>
28: 0f 20 e0 mov %cr4,%rax
2b: 83 c8 20 or $0x20,%eax
2e: 0f 22 e0 mov %rax,%cr4
31: c7 05 00 80 0b 00 4f movl $0x2f4b2f4f,0xb8000(%rip) # b803b <stack_top+0xb403b>
38: 2f 4b 2f
3b: fa cli
3c: f4 hlt
3d: eb fd jmp 3c <_start+0x3c>
000000000000003f <wrong_multiboot2>:
3f: b8 30 00 00 00 mov $0x30,%eax
44: eb 0c jmp 52 <error>
0000000000000046 <no_cpuid>:
46: b8 31 00 00 00 mov $0x31,%eax
4b: eb 05 jmp 52 <error>
000000000000004d <no_longmode>:
4d: b8 32 00 00 00 mov $0x32,%eax
0000000000000052 <error>:
52: c7 05 00 80 0b 00 45 movl $0x4f524f45,0xb8000(%rip) # b805c <stack_top+0xb405c>
59: 4f 52 4f
5c: c7 05 04 80 0b 00 52 movl $0x4f3a4f52,0xb8004(%rip) # b806a <stack_top+0xb406a>
63: 4f 3a 4f
66: c7 05 08 80 0b 00 20 movl $0x4f204f20,0xb8008(%rip) # b8078 <stack_top+0xb4078>
6d: 4f 20 4f
70: a2 0a 80 0b 00 f4 eb movabs %al,0x3dfdebf4000b800a
77: fd
0000000000000078 <check_multiboot2>:
78: 3d 89 62 d7 36 cmp $0x36d76289,%eax
7d: 75 03 jne 82 <check_multiboot2+0xa>
7f: 31 c0 xor %eax,%eax
81: c3 ret
82: b8 01 00 00 00 mov $0x1,%eax
87: c3 ret
0000000000000088 <check_cpuid>:
88: 9c pushf
89: 6a 00 push $0x0
8b: 9d popf
8c: 9c pushf
8d: 58 pop %rax
8e: 89 c3 mov %eax,%ebx
90: 35 00 00 20 00 xor $0x200000,%eax
95: 50 push %rax
96: 9d popf
97: 9c pushf
98: 58 pop %rax
99: 39 c3 cmp %eax,%ebx
9b: 74 04 je a1 <check_cpuid+0x19>
9d: 9d popf
9e: 31 c0 xor %eax,%eax
a0: c3 ret
a1: 9d popf
a2: b8 01 00 00 00 mov $0x1,%eax
a7: c3 ret
00000000000000a8 <check_longmode>:
a8: 9c pushf
a9: 6a 00 push $0x0
ab: 9d popf
ac: b8 00 00 00 80 mov $0x80000000,%eax
b1: 0f a2 cpuid
b3: 3d 01 00 00 80 cmp $0x80000001,%eax
b8: 72 13 jb cd <check_longmode+0x25>
ba: b8 01 00 00 80 mov $0x80000001,%eax
bf: 0f a2 cpuid
c1: f7 c2 00 00 00 20 test $0x20000000,%edx
c7: 74 04 je cd <check_longmode+0x25>
c9: 9d popf
ca: 31 c0 xor %eax,%eax
cc: c3 ret
cd: 9d popf
ce: b8 01 00 00 00 mov $0x1,%eax
d3: c3 ret
我们可以看到
movl $0x2f4b2f4f, 0xb8000
被编译成
movl $0x2f4b2f4f,0xb8000(%rip)
所以我不能正确地从开始写入VGA文本缓冲区
0xb8000
.
我也在接受其他建议。