使用x86汇编编写一个多线程、多任务系统 (五)

ap_16.asm是AP1和AP2刚启动时执行的代码,它的作用同运行于BSP的mbr.asm一样,使AP1和AP2进入32位保护模式和页管理模式,再跳转到地址为0x80200000的ap_32.asm代码继续执行。其中,ap_32.asm为AP1、AP2执行的32位的主体代码,会完成使能中断、安装系统进程、安装用户进程的工作。

ap_16.asm执行的顺序为:

序号

功能

1

屏蔽NMI中断

2

屏蔽8259可能产生的所有中断,避免后面使能IO APIC后中断相互干扰

3

使能本AP的GDT段。这里要注意的是:

  1. BSP和各个AP都有各自独立的gdt的寄存器,需要各自使能
  2. 系统的code段描述符和data段描述符已经在BSP中写入GDT段了,AP在这里不再写入,直接使用即可
  3. AP在操作GDT之前,需要检测信号量,保证互斥的进行GDT操作

4

进入保护模式后,判断是AP1还是AP2,调整各自的esp栈指针指向不同的地址

5

页目录地址写入cr3。注意,BSP和两个AP使用相同的页目录,因此三个线程的地址映射完全相同

6

AP重新调整GDP段的虚拟地址,因为在页表映射中,GDT段的地址被从0x00008000映射到了0x80008000

7

跳转到0x80200000开始执行ap_32.asm的代码

ap_16.asm的代码如下:

;-----------------------------常数定义-----------------------------------
    page_dir_address       equ 0x1000              ;常数,页目录硬件地址(第1页)
    ap_lock_addr           equ 0x00006000          ;AP启动信号量的地址
    gdt_base_address       equ 0x00008000          ;常数,gdt表的起始地址
    ap_id_1_esp_addr       equ (0x00028000+4092)   ;常数,ap_1线程使用的esp地址
    ap_id_2_esp_addr       equ (0x00029000+4092)   ;常数,ap_2线程使用的esp地址

;-----------------------------AP代码开始----------------------------------
SECTION  ap_16  vstart=0x00020000
    cli                                ;中断机制尚未工作

    xor ax, ax                         ;初始化ds和ss段寄存器 
    mov ds, ax
    mov ax, cs
    mov ss, ax
    mov sp, 0xA000                     ;sp临时指向0xA000,进入保护模式后,AP根据不同的ID值设置不同的堆栈指针
         
;----------------------屏蔽NMI和8259可能产生的中断-----------------------
    ;屏蔽NMI中断
    in al, 0x70                        ; port 0x70
    or al, 0x80                        ; disable all NMI source
    out 0x70, al

    ;屏蔽8259可能产生的所有中断
    mov al, 0x0ff
    out 0x21, al

;-----------------------初始化描述符表寄存器GDTR-----------------------
    ; 检测信号量,避免多AP搞乱GDT
_lock_for_ap1:
    lock bts dword [ap_lock_addr], 0      ; 将信号量第0位放入CF,并设置信号量第0位为1
    jc _lock_for_ap1     
    
    ;初始化描述符表寄存器GDTR
    sgdt [pgdt]
    mov dword [pgdt+2], gdt_base_address
    mov word [pgdt],23                    ;描述符表的界限(三个描述符)   
    lgdt [pgdt]                           ;将gdt写入gdt寄存器 
    
    ; 信号量复位
    mov dword [ap_lock_addr], 0  

    in al,0x92                            ;南桥芯片内的端口 
    or al,0000_0010B
    out 0x92,al                           ;打开A20

    mov eax,cr0                  
    or eax,1
    mov cr0,eax                           ;设置PE位
      
    ;以下进入保护模式... ...
    jmp dword 0x0008:flush

;----------------------------以下是32位模式------------------------------------
    [bits 32]               
  flush:                                  
    mov eax, 0x00010
    mov ds,eax
    mov es,eax
    mov fs,eax
    mov gs,eax
    mov ss,eax                    
    mov esp,ap_id_1_esp_addr               ; 需要根据AP不同的ID来设置堆栈指针
                                           ; 如果APIC ID = 1, esp = 0x0x00028000
                                           ; 如果APIC ID = 2, esp = 0x0x00029000

    ; 获取APIC ID,如果ID!=1, 等待一段时间
    mov eax, 1
    cpuid
    mov eax, ebx
    shr eax, 24                            ; 右移后,al中为ID值
    cmp al, 0x01
    jz _ap1_go2                            ; 如果ID=1,跳过esp的修改 
    mov esp,ap_id_2_esp_addr               ; APIC ID = 2, esp = 0x00029000

_ap1_go2:

;----------------------------进入页管理模式------------------------------------
    ;令CR3寄存器指向页目录,并正式开启页功能 
    mov eax, page_dir_address              ;PCD=PWT=0
    mov cr3,eax

    mov eax,cr0
    or eax,0x80000000
    mov cr0,eax                            ;开启分页机制

    ;调整堆栈指针 
    add esp, 0x80000000

    ;测试一下页管理开启情况
    mov eax, paged
    add eax, 0x80000000
    jmp eax

paged:
    xor eax, eax

    ; 检测信号量,避免多AP搞乱GDT
_lock_for_ap2:
    lock bts dword [ap_lock_addr], 0       ; 将信号量第0位放入CF,并设置信号量第0位为1
    jc _lock_for_ap2   

    ; 进入页管理模式,先将GDT的线性地址映射到从0x80000000开始的相同位置
    sgdt [pgdt]
    mov ebx,[pgdt+2]
    add dword [pgdt+2],0x80000000            ;GDTR也用的是线性地址
    lgdt [pgdt]

    ; 信号量复位
    mov dword [ap_lock_addr], 0

;-------------------------进入系统Core开始执行--------------------------------
    ;直接跳到core代码起始处开始执行 
    mov eax, 0x80200000
    jmp eax
    hlt

;--------------------------系统使用的全局变量---------------------------------                             
align 4    
    pgdt  dw 0
          dd gdt_base_address                       ;GDT的物理地址:8K处开始 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值