本章我们将详细讲解BSP剩下的执行代码,它们被安排在bp_32.asm文件中。
bp_32.asm主要完成以下功能:
系统中断初始化
加载字符图形数据到内存区域
将AP的启动代码和32位保护模式下的代码分别加载到内存中
显示主界面以及系统启动信息
向所有AP群发启动命令
进入守护线程的大循环:
接收并处理鼠标数据,在界面上显示鼠标
接收并显示键盘输入
显示两个AP用户线程的实时状态
显示BSP已经执行的时间 时:分:秒
3.1 启动系统中断
3.1.1总体初始化
BSP这部分的32位代码从0x80016000地址处开始执行。cli指令关中断,再调用init_interrupt_function函数设置系统中断,最后sti指令开启系统中断。
我们使用APIC来设置和使能系统中断。APIC全称Advanced Programmable InterruptController。每个执行内核都有一个APIC,称为LocalAPIC(LAPIC)。每个LAPIC包含一系列的寄存器,这些寄存器控制LAPIC如何将中断信号发送到执行内核中。
LAPIC架构图
APIC根据实现不同,分成LAPIC和x2APIC,这两个APIC寄存器基本一样,唯一不同的是LAPIC通过内存访问APIC寄存器,x2APIC通过MSR寄存器访问APIC寄存器。
1. xAPIC:APIC寄存器被映射到4KB大小的MMIO内存区,操作系统通过MMIO内存访问APIC。
2. x2APIC: 一部分MSR地址区间为APIC寄存器预留,访问APIC是通过MSR。这样的好处是不用再担心内存地址的冲突问题。
LAPIC可以从以下几个来源接收到中断:
Locallyconnected I/O devices: 直接连接到处理器的本地中断引脚(LINT0和LINT1)的I/O设备触发的中断
Externallyconnected I/O devices :外部链接的I/O设备发出的中断
Inter-processor interrupts (IPIs) :执行内核可以使用IPI机制向系统总线上的其它执行内核发送中断
APICtimer generated interrupts:APIC定时器中断
Performancemonitoring counter interrupts :性能计数器中断
ThermalSensor interrupts :热传感器中断 (power)
APICinternal error interrupts :APIC内部异常中断
Local APIC的使能需要设置两个寄存器:IA32_APIC_BASE寄存器的第11位(置1)、SVR寄存器的第8位(置1)。
IA32_APIC_BASE寄存器为MSR(Model-Specific Register),对应的编号为0x1B。需要使用RDMSR/WRMSR来读写,命令格式为:
mov ecx, 0x1B
rdmsr
操作MSR寄存器时,须先将MSR寄存器的编号写入ecx,读出的MSR寄存器值放在EDX:EAX中,高位在EDX,低位在EAX。
IA32_APIC_BASE寄存器的第12位以上还保存着APIC寄存器的物理基地址。默认情况下该物理基地址值为0xFEE00000。
SVR寄存器地址为0xFEE00010。
经过BIOS的初始化,IA32_APIC_BASE寄存器第11位以及SVR寄存器的第8位都为1,Local APIC默认就是启动的,我们无需再设。
下面是IO APIC的初始化。外部设备先与IO APIC对接,产生的中断由IO APIC通过总线发送到Local APIC,之后再发送到执行内核。
init_interrupt_function函数完成IO APIC的初始化。
对IO APIC进行操作,首先要做两件事:
设置IO APIC寄存器的默认地址(index/data/EOI这三个寄存器);
启动IO APIC功能。
IO APIC寄存器默认地址对应OIC寄存器的0~7bits位,IOAPIC的使能控制位于OIC寄存器的第8位。正常情况下,IO APIC三个寄存器的默认地址就是index-0xFEC00000、data-0xFEC00010、EOI-0xFEC00040。
IO APIC其它寄存是都是通过index和data寄存器来间接访问,各寄存器的index值为:
index |
寄存器 |
Size |
0x0 |
ID |
32位 |
0x1 |
Version |
32位 |
0x2~0x0F |
Reserved |
|
0x10~0x11 |
Redirection table 0 |
64位 |
0x12~0x13 |
Redirection table 1 |
64位 |
… |
|
|
0x3C~0x3D |
Redirection table 22 |
64位 |
0x3E~0x3F |
Redirection table 23 |
64位 |
0x40~0xFF |
Reserved |
|
IO APIC寄存器对应index值
启动IOC APIC:
OIC寄存器位于RCBA(root complex base address)寄存器的0x31FE偏移上。READ_PCI_DWORD 0,31,0,0x0f0 以及 and eax, 0xFFFFC000用于获取RCBA寄存器的地址。
之后,mov esi, [eax +0x31fe]获取OIC寄存器的值。然后第8位置1,使能IO APIC功能,同时0~7位置0,将IO APIC寄存器的基地址设置为0xFEC00000起始。最后再写入OIC寄存器,完成设置。
IO APIC的index寄存器写入0,选择IO APIC的ID寄存器。之后,IO APIC的data寄存器写入0x0F0000000,将BSP对应的IO APIC的ID号设置位0x0F。
下面,开始设置操作系统需要使用到的各个中断,包括键盘、高精度HPET0时钟、鼠标。
对于该类外部中断,IO APIC都需要使用Redirection table寄存器进行设置。Redirection table寄存器格式如下:
中断在配置时需要至少提供4类数据:
中断服务程序的Vector值(中断向量号)
中断的Delivery mode:Fixed、lowestpriority、SMI、NMI、INIT或ExtINT模式
触发模式:edge或是level触发模式
目标执行内核:physical或logical目标模式,并在destionation中提供目标执行内核的ID号(BSP的ID号就是0)
同时,IO APIC对应的IRQ为:
IRQ |
中断源 |
对应配置寄存器 |
0 |
连接8259中断控制器 |
Redirection table 0 |
1 |
Keyboard(键盘) |

本文详细讲述了BSP如何初始化32位保护模式,包括系统中断、APIC、IOAPIC的配置,以及键盘、鼠标、HPETtimer0的初始化。此外,还介绍了如何处理键盘和鼠标中断,显示系统时间和AP状态,以及安装和处理系统调用。最后,阐述了BSP的守护循环,涉及鼠标和键盘的输入处理以及AP状态的显示。

被折叠的 条评论
为什么被折叠?



