C 无法使用e820获取内存映射
我正在编写一个非常基本的内核,为了获得物理内存映射,我使用了 C代码如下:C 无法使用e820获取内存映射,c,assembly,memory-management,operating-system,x86-16,C,Assembly,Memory Management,Operating System,X86 16,我正在编写一个非常基本的内核,为了获得物理内存映射,我使用了 C代码如下: uint8_t memMapLength=0; uint64_t availableMemBytes=0; typedef struct memoryMapEntry{ uint32_t baseLow; uint32_t baseHigh; uint64_t length; uint32_t type; uint32_t acpi_null; } memoryM
uint8_t memMapLength=0;
uint64_t availableMemBytes=0;
typedef struct memoryMapEntry{
uint32_t baseLow;
uint32_t baseHigh;
uint64_t length;
uint32_t type;
uint32_t acpi_null;
} memoryMapEntry;
memoryMapEntry* memMapArr=0;
void DetectMem(){
memMapArr= (memoryMapEntry*)(0x00007c40);
uint8_t i;
for(i=0;i<memMapLength;i++){
if(memMapArr[i].type==1){
availableMemBytes += memMapArr[i].length;
}
}
}
do_e820();
DetectMem();
char *arr = (char *)&availableMemBytes;
terminal_write(arr);
然而,我无法启动我的内核,因为启动卡在一个无限循环中。我犯了什么错误?此答案使用英特尔汇编。
您刚刚删除了一段非常重要的代码
mov di, 0x8004
不要使用jmp.done
而是使用ret
删除
.done
空块。您是否使用实模式?因此,您应该在引导加载程序中执行此操作。
使用
pusha
和popa
使其遵循调用约定。要使其符合以下要求:
pop es
要使其工作,请使用此程序集:
jmp kmain
do_e820:
pop es
pusha
mov di, 0x8004
xor ebx, ebx
xor bp, bp
mov edx, 0x0534D4150
mov eax, 0xe820
mov [es:di + 20], dword 1
mov ecx, 24
int 0x15
jc short .failed
mov edx, 0x0534D4150 ; Some BIOSes apparently trash this register?
cmp eax, edx ; on success, eax must have been reset to "SMAP"
jne short .failed
test ebx, ebx ; ebx = 0 implies list is only 1 entry long (worthless)
je short .failed
jmp short .jmpin
.e820lp:
mov eax, 0xe820 ; eax, ecx get trashed on every int 0x15 call
mov [es:di + 20], dword 1 ; force a valid ACPI 3.X entry
mov ecx, 24 ; ask for 24 bytes again
int 0x15
jc short .e820f ; carry set means "end of list already reached"
mov edx, 0x0534D4150 ; repair potentially trashed register
.jmpin:
jcxz .skipent ; skip any 0 length entries
cmp cl, 20 ; got a 24 byte ACPI 3.X response?
jbe short .notext
test byte [es:di + 20], 1 ; if so: is the "ignore this data" bit clear?
je short .skipent
.notext:
mov ecx, [es:di + 8] ; get lower uint32_t of memory region length
or ecx, [es:di + 12] ; "or" it with upper uint32_t to test for zero
jz .skipent ; if length uint64_t is 0, skip entry
inc bp ; got a good entry: ++count, move to next storage spot
add di, 24
.skipent:
test ebx, ebx ; if ebx resets to 0, list is complete
jne short .e820lp
.e820f:
mov di, 0x8000
mov [es:di], bp
clc
popa
ret
.failed:
stc
popa
ret
用内核主函数名替换kmain
。构建:
为此使用Linux或WSL。
准备:
sudo apt install python3 wget -y
wget http://dl.devdrive.org/xcdk.py -o ./xcdk.py
sudo python3 ./xcdk.py
用于生成的Envar表:
Envar Description
=================================
CFILE A file with your C code! No spaces. Extension must be .c
ASM A file with the above assembly! No spaces. Extension must be .asm
TEMP A temporary file. No spaces.
OUT This is gonna be your build result. No spaces.
建造:
xcbuild 16 $ASM $CFILE $TEMP
nasm -fbin -o $OUT $TEMP
关于
xcbuild
:它使用gcc
和intel2gas
将不同的文件合并到一个NASM程序集文件中。安装程序脚本将为您安装此。它支持.asm
、.s
和.c
文件。没有C++支持,因为C++需要一个标准库。code>xcbuild基于Python,目前处于实验阶段。它有时会创建大的部件文件。它不会更改任何指针,因此您必须更改这些指针。如果您使用64位输出,由于intel2gas
中的当前错误,您将在NASM中获得少量气体(来自push
指令)。您可以直接调用它的原因是shebang行。由于intel2gas
中的其他错误,xcbuild
执行intel2gas前任务和intel2gas后任务。intel2gas
之前的任务正在对代码进行“二值化”,以便为intel2gas
做好准备。二进制化包括删除前4行,以及LFE*:
行和它们下面的3行。它还删除.cfi.*
行和其他垃圾LFB
是代码,LFE
是Linux垃圾。[ES:DI]指向哪里?很难说,因为这不是一个问题。另外,要学会使用调试器,至少要确定哪个部件卡住了。你不能将汇编的使用限制在对e820服务的单个调用中吗?此外,汇编代码是实模式,C代码也是?此外,您正在从C调用asm代码,但似乎没有遵循任何调用约定,您确定您的编译器对诸如归零bp
之类的内容满意吗?根据Tommylee2k已经提出的问题,如何设置es:di;mov-es,bx;mov-di,0h;
xcbuild 16 $ASM $CFILE $TEMP
nasm -fbin -o $OUT $TEMP