内核开发:在实模式下设置ES:DI

时间:2014-12-21 16:19:45

标签: c assembly x86 real-mode

我正在开发一个玩具内核,用于娱乐和教育(不是课堂项目)。我正在开始处理我的内存管理器,因此我仍然在实时模式下使用INT 0x15, EAX=E820调用从BIOS获取内存映射。我正在改编我的函数来自osdev wiki(here,在“获取E820内存映射”一节中。但是,我希望这是一个我可以从我的C代码调用的函数,所以我试图改变它。我希望它有两个参数:一个指向存储映射条目的位置的指针,以及一个指向整数的指针,该整数将以表中的条目数递增。

根据wiki,ES:DI需要指向应该存储数据的位置,因此我将我的第一个参数拆分为两个(段选择器pointer_to_map / 16和偏移量{{ 1}})。这是C代码的一部分:

pointer_to_map % 16

这是我的ASM代码的一部分:

typedef struct SMAP_entry {
    unsigned int baseL; // Base address, a QWORD
    unsigned int baseH;
    unsigned int lengthL; // Length, a QWORD
    unsigned int lengthH;
    unsigned int type; // entry type
    unsigned int ACPI; // extra data from ACPI 3.0
} SMAP_entry_t;

SMAP_entry_t data[100];
kprint("Pointer: ");
kprint_int((int) data, 16);
kprint_newline();

int res = 0;
read_mem_map(((int) data) / 16, ((int) data) % 16, &res);
kprint("res: ");
kprint_int(res, 16);
kprint_newline();

这就是我所有的粘贴因为程序三重故障并关闭了那里的VM。通过移动; performs a INT 0x15, eax=0xE820 call to find the memory map ; inputs: the pointer to the data table / 16, the pointer % 16, a pointer to an dword (int) which will be ; incremented by the number of entries after this function returns. ; preserves: no registers except esi read_mem_map: mov es, [esp + 4] ; set es to the value of the first argument mov di, [esp + 8] ; set di to the value of the second argument 命令,我发现函数在第一行崩溃了。如果我在C中注释掉这个电话,那么一切都会按照您的预期运作。

我已经通过Google阅读了几乎没有理由直接设置ret,并且在我发现的代码中,他们将其设置为文字。我应该如何设置ES:DI,如果我不应该直接设置它,我应该如何使C和ASM以正确的方式进行交互?

1 个答案:

答案 0 :(得分:2)

每个段寄存器(在80x86上)都有一个可见部分和几个隐藏字段(段基,段限制和段的属性 - 读/写,权限级别等)。

在保护模式下;当您加载段寄存器时,CPU使用可见部分作为GDT或LDT的索引,并从该描述符(在GDT或LDT中)加载段的隐藏字段。

在实模式下; CPU完全不同 - 它只将段基设置为“可见部分* 16”,不使用任何(GDT,LDT)表。

鉴于您使用的是指向数据表的32位指针和32位堆栈指针(例如mov es, [esp + 4]);我假设您的C代码处于32位保护模式。这与实模式完全不兼容,部分原因是段加载完全不同,部分原因是默认操作数/地址大小为32位而不是16位。

所有BIOS功能均专为实模式设计。它们不能用于保护模式。

基本上;我建议:

  • 将指向数据表的指针作为32位整数/指针传递给程序集(而不是2个独立的16位整数)
  • 调用“转到实模式”功能(稍微有点棘手,因为您还要从32位堆栈切换到16位堆栈,并且需要一个“32位返回指令” 16位代码)。
  • 将指向数据表的指针拆分为其分段并在程序集中进行偏移,然后加载该段(当你现在处于实模式时,该段应正常工作)
  • 调用BIOS功能(现在可以在实模式下正常工作)
  • 调用“进入保护模式”功能(这将再次稍微棘手,包括32位代码中的“16位返回指令”)。
  • 返回(32位保护模式)来电者

英特尔系统程序员指南中包含从实模式切换到保护模式以及从保护模式切换到实模式的说明。 :)