Assembly 在引导加载程序中初始化单独的CPU内核

Assembly 在引导加载程序中初始化单独的CPU内核,assembly,multiprocessing,bootloader,Assembly,Multiprocessing,Bootloader,我是bootloader开发的新手。我尝试了一些基本的东西,比如打印字符串“Hello World”之类的东西。我想问一些事情,比如 是否有可能使用asm/c/c++/mixed在引导加载程序上单独初始化多核芯片中的内核?(例如,我想单独初始化第一个核心或单独初始化第三个核心) 如果可能,请分享代码 是否有可能使用asm/c/c++/mixed在引导加载程序上单独初始化多核芯片中的内核 是的,完全有可能 如果可能,请分享代码 仅仅因为它是可能的并不意味着代码存在;即使代码存在,也不意味着它小到可

我是bootloader开发的新手。我尝试了一些基本的东西,比如打印字符串“Hello World”之类的东西。我想问一些事情,比如

是否有可能使用asm/c/c++/mixed在引导加载程序上单独初始化多核芯片中的内核?(例如,我想单独初始化第一个核心或单独初始化第三个核心)

如果可能,请分享代码

是否有可能使用asm/c/c++/mixed在引导加载程序上单独初始化多核芯片中的内核

是的,完全有可能

如果可能,请分享代码

仅仅因为它是可能的并不意味着代码存在;即使代码存在,也不意味着它小到可以粘贴到这里

现实情况是,要正确执行此操作(在80x86上),您需要:

  • 如果您处于实模式(例如BIOS引导加载程序),请切换到保护模式和长模式
  • 解析表(ACPI的MADT/APIC表,或英特尔的多处理器规范表(如果没有ACPI),以确定本地APIC的位置、其他CPU的数量以及这些CPU使用的ID。请注意,仅查找这些表(在解析它们之前)可能涉及搜索物理地址空间中的区域以查找签名并检查校验和
  • 建立某种类型的时间源,用于延迟和超时
  • 查找/分配一些适合AP CPU启动蹦床的内存(0x00100000以下,从页面边界开始)。在某些情况下,这可能比您假设的更复杂(对于UEFI,无法保证0x00100000以下的任何内存是可用的,您可能需要调用
    exitBootServices()
    ,然后合适的内存才会变为可用,并且您可能需要在调用
    exitBootServices()之前初始化自己的视频输出代码)
    这样您就可以在不再依赖UEFI的控制台支持后显示错误消息等)
  • 初始化AP启动trampoline,这通常涉及复制到找到/分配的内存中,可能涉及在trampoline中设置各种值(例如CPU应用于堆栈的地址等)。当然,这也意味着在(16位实模式)汇编中编写代码,通常需要更多的代码切换到保护模式或长模式,这样AP CPU在蹦床中启动代码时,可以使CPU达到可以执行“正常”代码的状态
  • 执行AP CPU启动顺序(包括在一个CPU上使用本地APIC向另一个CPU发送特殊的中断序列,带有时间延迟、超时和错误处理)

当然,所有这些都是大量的工作,其中大部分是出于多种原因而完成的工作。例如,您可能会找到APCI(和/或多处理器规范)表并在以后将其用于100种不同的事情,然后您可能会初始化计时器并在以后将其用于100种不同的事情,您可能会初始化物理内存管理器并将其用于100种不同的事情,等等。这意味着完成这些事情的代码最终会在整个引导过程中传播(一些在引导加载程序中,一些在其他引导代码中,一些在内核中),而且“几乎永远”都在一个方便的地方(比如“这是一个文件中启动其他CPU的所有内容”)。

您搜索过Intels文档吗?你发现了什么?谢谢你的回复。你是说“英特尔引导加载程序开发工具包”文档?如果还有其他东西,请在这里分享链接。老实说,这听起来有点像有人在说,“既然我已经做了一辆火柴盒汽车,我想做一辆轻便摩托车。”基本上,在编写自己的引导程序之前,你真的需要进行更多的练习。如果你在谈论x86或ARM,这两个方面都有例子。但是x86示例将SIPI(启动处理器间中断)广播到所有逻辑核,而不是枚举并使其有选择地执行。@PeterCordes:是的,可以通过首先在内存中找到ACPI表的基,然后找到MADT(APIC)来枚举它们表中的所有类型0条目都是每个处理器的条目,包括是否应忽略处理器(即:因为BIOS中禁用了超读、cpu出现故障等)、其lapic id、lapic版本等。