问题描述
我正在学习mit6.828课程,我不明白为什么在lab4中启动AP时必须间接调用。我尝试直接调用call mp_main
(源代码:movl $mp_main,%eax; call *%eax
),但它导致了三重故障。这是部分源代码
###################################################################
# entry point for APs
###################################################################
# Each non-boot cpu ("AP") is started up in response to a STARTUP
# IPI from the boot cpu. Section B.4.2 of the Multi-Processor
# Specification says that the AP will start in real mode with CS:IP
# set to XY00:0000,where XY is an 8-bit value sent with the
# STARTUP. Thus this code must start at a 4096-byte boundary.
#
# Because this code sets DS to zero,it must run from an address in
# the low 2^16 bytes of physical memory.
#
# boot_aps() (in init.c) copies this code to MPENTRY_PADDR (which
# satisfies the above restrictions). Then,for each AP,it stores the
# address of the pre-allocated per-core stack in mpentry_kstack,sends
# the STARTUP IPI,and waits for this code to ackNowledge that it has
# started (which happens in mp_main in init.c).
#
# This code is similar to boot/boot.S except that
# - it does not need to enable A20
# - it uses MPBOOTPHYS to calculate absolute addresses of its
# symbols,rather than relying on the linker to fill them
# Switch to the per-cpu stack allocated in boot_aps()
movl mpentry_kstack,%esp
movl $0x0,%ebp # nuke frame pointer
# Call mp_main(). (Exercise for the reader: why the indirect call?)
movl $mp_main,%eax
call *%eax
我不知道如何在多 cpu 中使用 gdb 进行调试,尤其是在启动时,但 entry.S 与此代码类似,并且很容易调试。这里是 entry.S 密钥代码
mov $relocated,%eax
jmp *%eax
relocated:
movl $0x0,%ebp # nuke frame pointer
下面是正确代码的gdb输出。在 jmp *%eax
之前,eip 是低地址,但之后 eip 是高地址。下一条指令是mov $0,%ebp
。
(gdb) si
=> 0x10002d: jmp *%eax
0x0010002d in ?? ()
(gdb) info reg eax eip
eax 0xf010002f -267386833
eip 0x10002d 0x10002d
(gdb) si
=> 0xf010002f: mov $0x0,%ebp
0xf010002f in ?? ()
(gdb) info reg eax eip
eax 0xf010002f -267386833
eip 0xf010002f 0xf010002f
如果我们改成直接call relocated
而不是mov $relocated,%eax; jmp *%eax
,会导致三重故障,gdb输出:
(gdb)
=> 0x100028: call 0x10002d
0x00100028 in ?? ()
(gdb) info reg eip
eip 0x100028 0x100028
(gdb) si
=> 0x100028: call 0x10002d
0x00100028 in ?? ()
如果我们查看 objdump 输出
call relocated
f0100028: e8 00 00 00 00 call f010002d <relocated>
f010002d <relocated>:
relocated:
# Clear the frame pointer register (EBP)
# so that once we get into debugging C code,# stack backtraces will be terminated properly.
movl $0x0,%ebp # nuke frame pointer
f010002d: bd 00 00 00 00 mov $0x0,%ebp
这里虚拟地址 [0xf0000000,0xf0000000+4MB) 和 [0,4MB) 都映射到物理地址 [0,4MB)
我想知道间接调用如何改变这一点。您可以在 github 中找到的完整代码只需在 kern/entry.S 和 kern/mpentry.S 中搜索“mit6.828”
解决方法
暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!
如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。
小编邮箱:dio#foxmail.com (将#修改为@)