我正在编写一个非常基本的内核,并且为了获取物理内存映射,我使用了来自osdev的代码
global do_e820
do_e820:
xor ebx, ebx ; ebx must be 0 to start
xor bp, bp ; keep an entry count in bp
mov edx, 0x0534D4150 ; Place "SMAP" into edx
mov eax, 0xe820
mov [es:di + 20], dword 1 ; force a valid ACPI 3.X entry
mov ecx, 24 ; ask for 24 bytes
int 0x15
jc short .failed ; carry set on first call means "unsupported function"
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:
extern memMapLength
mov [memMapLength], bp ; store the entry count
clc ; there is "jc" on end of list to this point, so the carry must be cleared
jmp .done
.failed:
;stc ; "function unsupported" error exit
hlt
ret
.done:
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;
} 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;
}
}
}
在kernel_main函数中,我调用do_e820函数,然后调用DetectMem,如下所示:
do_e820();
DetectMem();
char *arr = (char *)&availableMemBytes;
terminal_write(arr);
然而,我无法启动我的内核,因为启动陷入无限循环。我做错了什么?
答案 0 :(得分:1)
此答案使用了英特尔大会。
您刚刚删除了一段非常重要的代码。
mov di, 0x8004
使用jmp .done
代替ret
。
删除.done
空块。
您是否还在使用REAL MODE?因此,您应该在Boot Loader中执行此操作。
使用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 ++需要标准库。 xcbuild
基于Python,目前处于实验阶段。有时会创建大型程序集文件。它不会更改任何指针,因此您将不得不更改这些指针。如果您使用64位输出,由于intel2gas
中的当前错误,您将在NASM中获得少量的GAS(来自push
指令)。您可以直接调用它的原因是 she bang 行。由于intel2gas
中的其他错误,xcbuild
会执行intel2gas
之前和之后的intel2gas
任务。 intel2gas
之前的任务正在对代码进行“二进制化”以使其准备好intel2gas
。 Binarifying包括删除前4行以及LFE*:
行及其下的3行。它还会删除.cfi_*
行和其他垃圾。 LFB
是代码,LFE
是Linux废话。