1.引導程式
core_base_address equ 0x00040000
core_start_sector equ 0x00000001
SECTION mbr vstart=0x00007c00
; 此刻cs内容是0x0000
mov ax,cs
mov ss,ax
; 設定sp
mov sp,0x7c00
; gdt基位址
mov eax,[cs:pgdt+0x02]
xor edx,edx
mov ebx,16
div ebx
mov ds,eax
mov ebx,edx
; 段基位址31~24 G D/B L AVL 段界限19~16 P DPL S TYPE 段基位址23~16
; 段基位址15~0 段界限15~0
; 0x00 cf 98 00
; 0x00 00 ff ff
; 段基位址:0x0000 0000
; 段界限:f ffff
; 段屬性:4kb計量 32位 段在記憶體 0特權級 非系統段 代碼段
mov dword [ebx+0x08],0x0000ffff
mov dword [ebx+0x0c],0x00cf9800
; 段基位址:0x0000 0000
; 段界限:f ffff
; 段屬性:4kb計量 32位 段在記憶體 0特權級 非系統段 可讀可寫資料段
mov dword [ebx+0x10],0x0000ffff
mov dword [ebx+0x14],0x00cf9200
mov word [cs: pgdt],23
; 通知處理器gdt界限,基位址
lgdt [cs: pgdt]
; 開啟a20位址線
in al,0x92
or al,0000_0010B
out 0x92,al
; 禁止中斷
cli
; 進入保護模式
mov eax,cr0
or eax,1
mov cr0,eax
; 執行指令跳轉
jmp dword 0x0008:flush
[bits 32]
flush:
; 統一采用全局資料段
mov eax,0x00010
mov ds,eax
mov es,eax
mov fs,eax
mov gs,eax
mov ss,eax
; 設定esp
mov esp,0x7000
; 核心基礎位址
mov edi,core_base_address
; 核心任務邏輯扇區
mov eax,core_start_sector
; 核心基礎位址
mov ebx,edi
; 讀取磁盤扇區到實體記憶體
call read_hard_disk_0
; 讀取核心任務頭4位元組
mov eax,[edi]
xor edx,edx
mov ecx,512
div ecx
or edx,edx
jnz @1
dec eax
@1:
or eax,eax
jz pge
mov ecx,eax
mov eax,core_start_sector
inc eax
@2:
call read_hard_disk_0
inc eax
loop @2
; 到這裡已經把核心任務完整的讀取到了實體記憶體
pge:
; 這是用作頁目錄表的起始位置
mov ebx,0x00020000
; 設定頁目錄表最後一項指向頁目錄表自己
mov dword [ebx+4092],0x00020003
; 這個是頁表的起始位置
mov edx,0x00021003
; 設定頁目錄表索引0項和索引512項指向頁表
mov [ebx+0x000],edx
mov [ebx+0x800],edx
; 設定頁表前256項
; 這樣設定後,虛拟空間前1mb内的線性位址的實體位址就是線性位址自身
mov ebx,0x00021000
xor eax,eax
xor esi,esi
.b1:
mov edx,eax
or edx,0x00000003
mov [ebx+esi*4],edx
add eax,0x1000
inc esi
cmp esi,256
jl .b1
; 通知處理器頁目錄表位置
mov eax,0x00020000
mov cr3,eax
; 從處理器擷取gdt界限,基位址資訊
sgdt [pgdt]
mov ebx,[pgdt+2]
add dword [pgdt+2],0x80000000
; 通知處理器gdt界限,基位址資訊[線性位址改成虛拟位址高區間的]
lgdt [pgdt]
; 開啟分頁機制
mov eax,cr0
or eax,0x80000000
mov cr0,eax
; 令esp指向虛拟位址高區間的
add esp,0x80000000
; 指令跳轉
; cs指向全局代碼段,從記憶體取出4位元組段内偏移
; 這個段内偏移是線性位址,按頁目錄表-頁表轉換後得到的實體位址将是
; 核心任務過程start起始實體位置
jmp [0x80040004]
read_hard_disk_0:
push eax
push ecx
push edx
push eax
mov dx,0x1f2
mov al,1
out dx,al
inc dx
pop eax
out dx,al
inc dx
mov cl,8
shr eax,cl
out dx,al
inc dx
shr eax,cl
out dx,al
inc dx
shr eax,cl
or al,0xe0
out dx,al
inc dx
mov al,0x20
out dx,al
.waits:
in al,dx
and al,0x88
cmp al,0x08
jnz .waits
mov ecx,256
mov dx,0x1f0
.readw:
in ax,dx
mov [ebx],ax
add ebx,2
loop .readw
pop edx
pop ecx
pop eax
ret
pgdt dw 0
dd 0x00008000
times 510-($-$$) db 0
db 0x55,0xaa
2.核心任務
flat_4gb_code_seg_sel equ 0x0008
flat_4gb_data_seg_sel equ 0x0018
idt_linear_address equ 0x8001f000
%macro alloc_core_linear 0
mov ebx,[core_tcb+0x06]
add dword [core_tcb+0x06],0x1000
call flat_4gb_code_seg_sel:alloc_inst_a_page
%endmacro
%macro alloc_user_linear 0
mov ebx,[esi+0x06]
add dword [esi+0x06],0x1000
call flat_4gb_code_seg_sel:alloc_inst_a_page
%endmacro
SECTION core vstart=0x80040000
core_length dd core_end
core_entry dd start
[bits 32]
; ds:ebx指向首個待顯示字元的線性位址
put_string:
push ebx
push ecx
cli
.getc:
mov cl,[ebx]
or cl,cl
jz .exit
call put_char
inc ebx
jmp .getc
.exit:
sti
pop ecx
pop ebx
retf
put_char:
pushad
mov dx,0x3d4
mov al,0x0e
; 向0x3d4寫入0x0e
out dx,al
inc dx
; 從0x3d5讀取1位元組
in al,dx
; 讀取的是16位光标位置高8位
mov ah,al
dec dx
mov al,0x0f
; 向0x3d4寫入0x0f
out dx,al
inc dx
; 從0x3d5讀取1位元組
in al,dx
; bx就是16位光标位置
mov bx,ax
and ebx,0x0000ffff
cmp cl,0x0d
jnz .put_0a
; 字元是0x0d時的處理
mov ax,bx
mov bl,80
div bl
mul bl
; 這是将光标位置設定到行首---回車
mov bx,ax
jmp .set_cursor
.put_0a:
cmp cl,0x0a
jnz .put_other
; 字元是0x0a時的處理,這是換行
add bx,80
jmp .roll_screen
.put_other:
; 由光标位置得到顯存位置
shl bx,1
; 字元存入顯存
mov [0x800b8000+ebx],cl
shr bx,1
; 更新光标位置
inc bx
.roll_screen:
cmp bx,2000
jl .set_cursor
; 将顯存内每一行的内容拷貝到前面一行
; 最後一行全部顯示空格
; 光标位置設定為最後一行的行首
cld
mov esi,0x800b80a0
mov edi,0x800b8000
mov ecx,1920
rep movsd
mov bx,3840
mov ecx,80
.cls:
mov word [0x800b8000+ebx],0x0720
add bx,2
loop .cls
mov bx,1920
.set_cursor:
mov dx,0x3d4
mov al,0x0e
out dx,al
inc dx
mov al,bh
out dx,al
dec dx
mov al,0x0f
out dx,al
inc dx
mov al,bl
out dx,al
popad
ret
; eax:磁盤邏輯扇區
; ds:ebx:實體記憶體起始位置線性位址
read_hard_disk_0:
cli
push eax
push ecx
push edx
push eax
mov dx,0x1f2
mov al,1
; 向0x1f2寫入1---磁盤要傳輸的扇區數
out dx,al
inc dx
pop eax
; 向0x1f3寫入28位邏輯扇區号的最低8位
out dx,al
inc dx
mov cl,8
shr eax,cl
; 向0x1f4寫入28位邏輯扇區号的次低8位
out dx,al
inc dx
shr eax,cl
; 向0x1f5寫入28位邏輯扇區号的次次低8位
out dx,al
inc dx
shr eax,cl
or al,0xe0
; 向0x1f6寫入28位邏輯扇區号的高4位,同時高4位是1110
out dx,al
inc dx
mov al,0x20
; 向0x1f7寫入0x20---通知磁盤開始資料傳輸
out dx,al
.waits:
; 從0x1f7讀取1位元組
in al,dx
and al,0x88
; 如果磁盤不忙且準備就緒
cmp al,0x08
; 否則,繼續等待
jnz .waits
; 向實體記憶體寫入512位元組
mov ecx,256
mov dx,0x1f0
.readw:
; 取出2位元組就緒資料
in ax,dx
; 存儲到ds:ebx
mov [ebx],ax
add ebx,2
loop .readw
pop edx
pop ecx
pop eax
sti
retf
; edx存儲了32位數值,将此數值按16進制顯示
put_hex_dword:
pushad
mov ebx,bin_hex
mov ecx,8
.xlt:
rol edx,4
mov eax,edx
and eax,0x0000000f
xlat
push ecx
mov cl,al
call put_char
pop ecx
loop .xlt
popad
retf
; 在gdt中安裝8位元組描述符
set_up_gdt_descriptor:
push eax
push ebx
push edx
; 從處理器獲得gdt的界限,基位址(線性位址)
sgdt [pgdt]
movzx ebx,word [pgdt]
inc bx
; ebx此時是區域尾後位置
add ebx,[pgdt+2]
; 8位元組描述符存入區域尾部
mov [ebx],eax
mov [ebx+4],edx
add word [pgdt],8
; 通知處理器gdt區域界限,基位址
lgdt [pgdt]
mov ax,[pgdt]
xor dx,dx
mov bx,8
div bx
mov cx,ax
; 剛剛安裝描述符的選擇子
shl cx,3
pop edx
pop ebx
pop eax
retf
; 段基位址31~24 G D/B L AVL 段界限19~16 P DPL S TYPE 段基位址23~16
; 段基位址15~0 段界限15~0
; 傳入:eax段基位址,ebx段界限,ecx屬性資訊
; 傳出:edx:eax 8位描述符
make_seg_descriptor:
mov edx,eax
shl eax,16
or ax,bx
and edx,0xffff0000
rol edx,8
bswap edx
xor bx,bx
or edx,ebx
or edx,ecx
retf
; 段内偏移31~16 P DPL 0 TYPE(1100) 000 參數個數(5位)
; 例程所在代碼段選擇子 段内偏移15~0
; eax:32位段偏移
; ebx:16位例程所在代碼段選擇子
; cx:16位屬性位
make_gate_descriptor:
push ebx
push ecx
mov edx,eax
and edx,0xffff0000
or dx,cx
and eax,0x0000ffff
shl ebx,16
or eax,ebx
pop ecx
pop ebx
retf
; 實體頁尋找與配置設定
; eax傳回時存儲了實體頁實體位址
allocate_a_4k_page:
push ebx
push ecx
push edx
xor eax,eax
.b1:
; 将線性位址指向位置指定偏移的比特位從記憶體送入寄存器,然後對應位置設定為1
bts [page_bit_map],eax
jnc .b2
inc eax
cmp eax,page_map_len*8
jl .b1
mov ebx,message_3
call flat_4gb_code_seg_sel:put_string
hlt
.b2:
shl eax,12
pop edx
pop ecx
pop ebx
ret
alloc_inst_a_page:
push eax
push ebx
push esi
; 保留高10位
mov esi,ebx
and esi,0xffc00000
; 成為低10位
shr esi,20
; 高20位采用0xfffff
or esi,0xfffff000
; 線性位址ds:esi,esi高20位得到實體頁---頁目錄表自己
; 原始ebx的高10位構成索引
test dword [esi],0x00000001
jnz .b1
; 表示索引對應的目錄項指向的頁表不存在
; 配置設定4kb實體頁
call allocate_a_4k_page
or eax,0x00000007
; 在頁目錄表對應項設定頁表
mov [esi],eax
.b1:
; 0b [0000000000] {0000000000} '000000000000'
mov esi,ebx
; 0b 0000000000 [0000000000] {0000000000} '00'
shr esi,10
; 0b 0000000000 [0000000000] 0000000000 00
and esi,0x003ff000
; 0b 1111111111 [0000000000] 0000000000 00
or esi,0xffc00000
; 0b [0000000000] {0000000000} '000000000000'
; -->0b 0000000000 {0000000000} 000000000000
and ebx,0x003ff000
; 0b 0000000000 0000000000 {0000000000} 00
shr ebx,10
; 0b 1111111111 [0000000000] 0000000000 00
; 0b 0000000000 0000000000 {0000000000} 00
;->0b 1111111111 [0000000000] {0000000000} 00
or esi,ebx
; 搜尋并配置設定4kb實體頁
call allocate_a_4k_page
or eax,0x00000007
; 用高10位尋找頁目錄表得到頁表(其實是頁目錄表自身)
; 用傳入線性位址高10位在頁表定位到實體頁(其實是頁表)
; 用 傳入線性位址次高10位+00 在實體頁定位偏移
; 通路的其實是頁表索引項--》索引号是傳入線性位址次高10位
; 修改索引項讓其指向傳入線性位址對應的實體頁
mov [esi],eax
pop esi
pop ebx
pop eax
retf
; 傳回時eax是新配置設定的4kb實體頁的實體位址
; 這個實體頁拷貝了目前頁目錄表的1024項
create_copy_cur_pdir:
push esi
push edi
push ebx
push ecx
; 配置設定4kb實體頁
call allocate_a_4k_page
mov ebx,eax
or ebx,0x00000007
; 這是設定頁目錄表倒數第2項指向剛剛配置設定的4kb實體頁
mov [0xfffffff8],ebx
; 給定線性位址,通知處理器檢查此線性位址是否在tlb(快表中)
; 如在,更新塊表中對應的線性位址--實體位址映射
invlpg [0xfffffff8]
mov esi,0xfffff000
mov edi,0xffffe000
mov ecx,1024
; 将頁目錄表1024項,依次拷貝到新配置設定的4kb實體頁
cld
; 每次拷貝4位元組
repe movsd
pop ecx
pop ebx
pop edi
pop esi
retf
; 通用中斷處理
general_interrupt_handler:
push eax
mov al,0x20
; 向0xa0寫入0x20
out 0xa0,al
; 向0x20寫入0x20
out 0x20,al
pop eax
iretd
; 通用異常處理
general_exception_handler:
mov ebx,excep_msg
call flat_4gb_code_seg_sel:put_string
hlt
; 0x70中斷處理
rtm_0x70_interrupt_handle:
pushad
mov al,0x20
; 向0xa0寫入0x20
out 0xa0,al
; 向0x20寫入0x20
out 0x20,al
mov al,0x0c
; 向0x70寫入0x0c
out 0x70,al
; 從0x71讀取1位元組
in al,0x71
mov eax,tcb_chain
.b0:
; 首次:取得tcb連結清單首個對象線性位址
; 非首次:取得eax指向tcb對象下一個tcb對象線性位址
mov ebx,[eax]
or ebx,ebx
; 連結清單空
jz .irtn
; 判斷目前指向tcb對象狀态
cmp word [ebx+0x04],0xffff
; 狀态忙
je .b1
; 更新eax
mov eax,ebx
jmp .b0
.b1:
; eax指向上一個tcb對象線性位址(初始指向tcb_chain)
; ebx指向目前tcb對象,它的狀态為忙
; 取得下一個tcb對象線性位址
mov ecx,[ebx]
; 完成忙對象從連結清單删除
; 設定上一tcb對象下一個tcb對象為下下tcb對象
mov [eax],ecx
.b2:
; 取得下一tcb對象
mov edx,[eax]
or edx,edx
; 下一tcb對象不存在
jz .b3
mov eax,edx
jmp .b2
; 将狀态忙的tcb對象加傳入連結式結構尾部
.b3:
; 設定下一tcb對象為忙的tcb對象
mov [eax],ebx
; 設定忙tcb對象下一tcb對象為0x0000 0000
mov dword [ebx],0x00000000
; 鍊式結構中無tcb對象
mov eax,tcb_chain
; 從鍊式結構尋找狀态空閑的任務
.b4:
mov eax,[eax]
or eax,eax
jz .irtn
; 如果eax指向tcb對象狀态是空閑
cmp word [eax+0x04],0x0000
jnz .b4
; 不忙的tcb對象狀态修改為忙
not word [eax+0x04]
; 狀态忙的tcb對象的狀态修改為不忙
not word [ebx+0x04]
; 通過jmp實作任務切換
jmp far [eax+0x14]
.irtn:
popad
iretd
terminate_current_task:
mov eax,tcb_chain
.b0:
mov ebx,[eax]
cmp word [ebx+0x04],0xffff
je .b1
mov eax,ebx
jmp .b0
.b1:
; 修改任務狀态為0x3333
mov word [ebx+0x04],0x3333
.b2:
hlt
jmp .b2
pgdt dw 0
dd 0
pidt dw 0
dd 0
; 屬于核心自己出于邏輯實作需要弄處理的東西。處理器層面無
tcb_chain dd 0
core_tcb times 32 db 0
page_bit_map db 0xff,0xff,0xff,0xff,0xff,0xff,0x55,0x55
db 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
db 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
db 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
db 0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55
db 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
db 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
db 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
page_map_len equ $-page_bit_map
salt:
salt_1 db '@PrintString'
times 256-($-salt_1) db 0
dd put_string
dw flat_4gb_code_seg_sel
salt_2 db '@ReadDiskData'
times 256-($-salt_2) db 0
dd read_hard_disk_0
dw flat_4gb_code_seg_sel
salt_3 db '@PrintDwordAsHexString'
times 256-($-salt_3) db 0
dd put_hex_dword
dw flat_4gb_code_seg_sel
salt_4 db '@TerminateProgram'
times 256-($-salt_4) db 0
dd terminate_current_task
dw flat_4gb_code_seg_sel
salt_item_len equ $-salt_4
salt_items equ ($-salt)/salt_item_len
excep_msg db '********Exception encounted********',0
message_0 db ' Working in system core with protection '
db 'and paging are all enabled.System core is mapped '
db 'to address 0x80000000.',0x0d,0x0a,0
message_1 db ' System wide CALL-GATE mounted.',0x0d,0x0a,0
message_3 db '********No more pages********',0
core_msg0 db ' System core task running!',0x0d,0x0a,0
bin_hex db '0123456789ABCDEF'
core_buf times 512 db 0
cpu_brnd0 db 0x0d,0x0a,' ',0
cpu_brand times 52 db 0
cpu_brnd1 db 0x0d,0x0a,0x0d,0x0a,0
; 在使用者任務的ldt安裝8位元組描述符
fill_descriptor_in_ldt:
push eax
push edx
push edi
; ldt基位址---線性位址
mov edi,[ebx+0x0c]
xor ecx,ecx
; ldt界限
mov cx,[ebx+0x0a]
inc cx
mov [edi+ecx+0x00],eax
mov [edi+ecx+0x04],edx
add cx,8
dec cx
mov [ebx+0x0a],cx
mov ax,cx
xor dx,dx
mov cx,8
div cx
mov cx,ax
shl cx,3
; 得到剛剛安裝8位元組描述符的選擇子
or cx,0000_0000_0000_0100B
pop edi
pop edx
pop eax
ret
load_relocate_program:
pushad
mov ebp,esp
; 目前用的是核心任務的頁目錄表
; 将此頁目錄表前512項設定為0x0000 0000
mov ebx,0xfffff000
xor esi,esi
.b1:
mov dword [ebx+esi*4],0x00000000
inc esi
cmp esi,512
jl .b1
mov eax,cr3
; 可以使得快表内所有項失效
; 塊表是一個寄存器,包含多個項
; 每個向給出線性位址--實體位址映射,可以加快位址轉換
; 頁目錄表,頁表更新後,快表的更新需要手動觸發
; 快表不命中時,會自動進行更新
mov cr3,eax
mov eax,[ebp+40]
mov ebx,core_buf
call flat_4gb_code_seg_sel:read_hard_disk_0
mov eax,[core_buf]
mov ebx,eax
and ebx,0xfffff000
add ebx,0x1000
test eax,0x00000fff
mov eax,ebx
mov ecx,eax
; ecx代表了容納使用者任務所需的4kb頁數量
shr ecx,12
mov eax,[ebp+40]
; tcb線性位址
mov esi,[ebp+36]
.b2:
alloc_user_linear
push ecx
mov ecx,8
.b3:
call flat_4gb_code_seg_sel:read_hard_disk_0
inc eax
loop .b3
pop ecx
loop .b2
; 在核心任務虛拟區域劃分可用4kb用作使用者任務的tss
alloc_core_linear
; TCB對象結構
; 0x44 2位元組頭部選擇子
; 0x40 2特權級棧的初始ESP
; 0x3e 2特權級棧選擇子
; 0x3a 2特權級棧基位址
; 0x36 2特權級棧以4KB為機關的長度
; 0x32 1特權級棧的初始ESP
; 0x30 1特權級棧選擇子
; 0x2c 1特權級棧基位址
; 0x28 1特權級棧以4kb為機關的長度
; 0x24 0特權級棧的初始ESP
; 0x22 0特權級棧選擇子
; 0x1e 0特權級棧基位址
; 0x1a 0特權級棧以4kb為機關的長度
; 0x18 tss選擇子
; 0x14 tss基位址
; 0x12 tss界限值
; 0x10 ldt選擇子
; 0x0c ldt基位址
; 0x0a ldt目前界限值
; 0x06 程式加載基位址
; 0x04 任務狀态
; 0x00 下一個tcb基位址
; 使用者任務tcb中設定使用者任務tss基位址--線性位址
mov [esi+0x14],ebx
; 使用者任務tcb中設定使用者任務tss界限
mov word [esi+0x12],103
; 在使用者任務虛拟區域劃分可用4kb區域用作使用者任務ldt區域
alloc_user_linear
; 使用者任務tcb中設定ldt基位址--線性位址
mov [esi+0x0c],ebx
mov eax,0x00000000
mov ebx,0x000fffff
; 4kb計量 32位 段在記憶體 特權級3 非系統段 代碼段
mov ecx,0x00c0f800
; 構造代碼段
call flat_4gb_code_seg_sel:make_seg_descriptor
mov ebx,esi
; 在使用者任務ldt區域安裝代碼段描述符
call fill_descriptor_in_ldt
; 段選擇子請求特權級是3
or cx,0000_0000_0000_0011B
mov ebx,[esi+0x14]
; TSS格式
; I/OMapAddr Reserved 100
; Reserved LDT_Sector 96
; Reserved GS 92
; Reserved FS 88
; Reserved DS 84
; Reserved SS 80
; Reserved CS 76
; Reserved ES 72
; EDI 68
; ESI 64
; EBP 60
; ESP 56
; EBX 52
; EDX 48
; ECX 44
; EAX 40
; EFLAGS 36
; EIP 32
; CR3(PDBR) 28
; Reserved SS2 24
; ESP2 20
; Reserved SS1 16
; ESP1 12
; Reserved SS0 8
; ESP0 4
; Reserved Pre_Task_Tss 0
; 在使用者任務tss中設定cs--代碼段選擇子
mov [ebx+76],cx
mov eax,0x00000000
mov ebx,0x000fffff
; 4kb計量 32位 段在記憶體 特權級3 非系統段 可讀可寫資料段
mov ecx,0x00c0f200
call flat_4gb_code_seg_sel:make_seg_descriptor
mov ebx,esi
call fill_descriptor_in_ldt
or cx,0000_0000_0000_0011B
mov ebx,[esi+0x14]
; 在使用者任務tss中設定ds,es,fs,gs--資料段選擇子
mov [ebx+84],cx
mov [ebx+72],cx
mov [ebx+88],cx
mov [ebx+92],cx
alloc_user_linear
mov ebx,[esi+0x14]
; 在使用者任務tss中設定ss--棧段選擇子
mov [ebx+80],cx
mov edx,[esi+0x06]
; 在使用者任務tss中設定esp--棧段的esp,初始時刻指向區域尾後位置
mov [ebx+56],edx
; 使用者任務虛拟空間内劃分4kb可用空間用于特權級0棧
alloc_user_linear
mov eax,0x00000000
mov ebx,0x000fffff
mov ecx,0x00c09200
call flat_4gb_code_seg_sel:make_seg_descriptor
mov ebx,esi
; 在使用者任務ldt區域安裝段描述符
call fill_descriptor_in_ldt
or cx,0000_0000_0000_0000B
mov ebx,[esi+0x14]
; 在使用者任務tss中設定ss0--0特權級棧段選擇子
mov [ebx+8],cx
mov edx,[esi+0x06]
; 在使用者任務tss中設定esp0--0特權級棧段的esp
mov [ebx+4],edx
alloc_user_linear
mov eax,0x00000000
mov ebx,0x000fffff
mov ecx,0x00c0b200
call flat_4gb_code_seg_sel:make_seg_descriptor
mov ebx,esi
call fill_descriptor_in_ldt
or cx,0000_0000_0000_0001B
mov ebx,[esi+0x14]
; 在使用者任務tss中設定ss1--1特權級棧段選擇子
mov [ebx+16],cx
mov edx,[esi+0x06]
; 在使用者任務tss中設定esp1--1特權級棧段的esp
mov [ebx+12],edx
alloc_user_linear
mov eax,0x00000000
mov ebx,0x000fffff
mov ecx,0x00c0d200
call flat_4gb_code_seg_sel:make_seg_descriptor
mov ebx,esi
call fill_descriptor_in_ldt
or cx,0000_0000_0000_0010B
mov ebx,[esi+0x14]
; 在使用者任務tss中設定ss2--2特權級棧段選擇子
mov [ebx+24],cx
mov edx,[esi+0x06]
; 在使用者任務tss中設定esp2--2特權級棧段的esp
mov [ebx+20],edx
cld
; 對使用者任務的每個符号進行内循環處理
; 使用者任務符号數
mov ecx,[0x0c]
; 首個符号的段内偏移
mov edi,[0x08]
.b4:
push ecx
push edi
; 對使用者任務目前符号edi,依次将核心每個符号與其比對
; 核心任務符号數
mov ecx,salt_items
; 核心任務首個符号偏移---就是符号的線性位址
mov esi,salt
.b5:
push edi
push esi
push ecx
mov ecx,64
repe cmpsd
jnz .b6
; 比較并比對
mov eax,[esi]
; 使用者任務在符号頭存儲4位元組段内偏移
mov [edi-256],eax
mov ax,[esi+4]
or ax,0000000000000011B
; 使用者任務在符号頭5,6位元組存儲門選擇子(請求特權級是3)
mov [edi-252],ax
.b6:
pop ecx
pop esi
; esi指向核心下一符号
add esi,salt_item_len
pop edi
loop .b5
pop edi
; edi指向使用者任務下一符号
add edi,256
pop ecx
loop .b4
; 使用者任務tcb對象線性位址
mov esi,[ebp+36]
; TCB對象結構
; 0x44 2位元組頭部選擇子
; 0x40 2特權級棧的初始ESP
; 0x3e 2特權級棧選擇子
; 0x3a 2特權級棧基位址
; 0x36 2特權級棧以4KB為機關的長度
; 0x32 1特權級棧的初始ESP
; 0x30 1特權級棧選擇子
; 0x2c 1特權級棧基位址
; 0x28 1特權級棧以4kb為機關的長度
; 0x24 0特權級棧的初始ESP
; 0x22 0特權級棧選擇子
; 0x1e 0特權級棧基位址
; 0x1a 0特權級棧以4kb為機關的長度
; 0x18 tss選擇子
; 0x14 tss基位址
; 0x12 tss界限值
; 0x10 ldt選擇子
; 0x0c ldt基位址
; 0x0a ldt目前界限值
; 0x06 程式加載基位址
; 0x04 任務狀态
; 0x00 下一個tcb基位址
; 使用者任務ldt基位址--線性位址
mov eax,[esi+0x0c]
; 使用者任務ldt區域界限
movzx ebx,word [esi+0x0a]
; 位元組計量 32位 段在記憶體 特權級0 系統段 可讀可寫資料段
mov ecx,0x00408200
call flat_4gb_code_seg_sel:make_seg_descriptor
; 使用者任務ldt區域的描述符需要安裝在gdt
call flat_4gb_code_seg_sel:set_up_gdt_descriptor
; 使用者任務tcb對象中設定ldt段的選擇子
mov [esi+0x10],cx
mov ebx,[esi+0x14]
; TSS格式
; I/OMapAddr Reserved 100
; Reserved LDT_Sector 96
; Reserved GS 92
; Reserved FS 88
; Reserved DS 84
; Reserved SS 80
; Reserved CS 76
; Reserved ES 72
; EDI 68
; ESI 64
; EBP 60
; ESP 56
; EBX 52
; EDX 48
; ECX 44
; EAX 40
; EFLAGS 36
; EIP 32
; CR3(PDBR) 28
; Reserved SS2 24
; ESP2 20
; Reserved SS1 16
; ESP1 12
; Reserved SS0 8
; ESP0 4
; Reserved Pre_Task_Tss 0
; 使用者任務tss對象中設定使用者任務ldt區域的選擇子
mov [ebx+96],cx
; 使用者任務tss對象中設定前一任務tss選擇子為0x00 00
mov word [ebx+0],0
mov dx,[esi+0x12]
; 使用者任務tss對象中設定i/o映射資訊
mov [ebx+102],dx
mov word [ebx+100],0
; 入口點的段内偏移
mov eax,[0x04]
; 使用者任務tss對象中設定eip
mov [ebx+32],eax
; 擷取目前eflags
pushfd
pop edx
; 使用者任務tss對象中設定eflags
mov [ebx+36],edx
; 使用者任務tss基位址
mov eax,[esi+0x14]
; 使用者任務tss界限值
movzx ebx,word [esi+0x12]
; 位元組計量 32位 段在記憶體 0特權級 系統段 代碼段&已經通路
mov ecx,0x00408900
call flat_4gb_code_seg_sel:make_seg_descriptor
call flat_4gb_code_seg_sel:set_up_gdt_descriptor
; 使用者任務tcb中設定tss段的選擇子
mov [esi+0x18],cx
; 配置設定4kb實體頁,将目前頁目錄表拷貝到新配置設定的實體頁
call flat_4gb_code_seg_sel:create_copy_cur_pdir
mov ebx,[esi+0x14]
; 使用者任務tss對象中設定cr3---使用者任務頁目錄表的實體位址
mov dword [ebx+28],eax
popad
; 出棧并控制跳轉,跳轉前繼續出棧8位元組
ret 8
; 加入tcb鍊式結構
append_to_tcb_link:
cli
push eax
push ebx
mov eax,tcb_chain
.b0:
; 取出下一tcb對象
mov ebx,[eax]
or ebx,ebx
; 下一tcb對象不存在
jz .b1
mov eax,ebx
jmp .b0
.b1:
; 設定下一tcb對象
mov [eax],ecx
; 設定傳入tcb對象的下一tcb對象為不存在
mov dword [ecx],0x00000000
pop ebx
pop eax
sti
ret
start:
mov eax,general_exception_handler
mov bx,flat_4gb_code_seg_sel
; P DPL 0 TYPE(1100) 000 參數個數(5位)
; 門指向代碼在記憶體 特權級0 類别
mov cx,0x8e00
call flat_4gb_code_seg_sel:make_gate_descriptor
mov ebx,idt_linear_address
xor esi,esi
.idt0:
mov [ebx+esi*8],eax
mov [ebx+esi*8+4],edx
inc esi
cmp esi,19
jle .idt0
mov eax,general_interrupt_handler
mov bx,flat_4gb_code_seg_sel
; 門指向代碼在記憶體 特權級0 類别
mov cx,0x8e00
call flat_4gb_code_seg_sel:make_gate_descriptor
mov ebx,idt_linear_address
.idt1:
mov [ebx+esi*8],eax
mov [ebx+esi*8+4],edx
inc esi
cmp esi,255
jle .idt1
mov eax,rtm_0x70_interrupt_handle
mov bx,flat_4gb_code_seg_sel
; 門指向代碼在記憶體 特權級0 類别
mov cx,0x8e00
call flat_4gb_code_seg_sel:make_gate_descriptor
mov ebx,idt_linear_address
mov [ebx+0x70*8],eax
mov [ebx+0x70*8+4],edx
; 設定idt區域前256個8位元組描述符&通知處理器
mov word [pidt],256*8-1
mov dword [pidt+2],idt_linear_address
lidt [pidt]
mov al,0x11
; 向0x20寫入0x11
out 0x20,al
mov al,0x20
; 向0x21寫入0x20
out 0x21,al
mov al,0x04
; 向0x21寫入0x04
out 0x21,al
mov al,0x01
; 向0x21寫入0x01
out 0x21,al
mov al,0x11
; 向0xa0寫入0x11
out 0xa0,al
mov al,0x70
; 向0xa1寫入0x70
out 0xa1,al
mov al,0x04
; 向0xa1寫入0x04
out 0xa1,al
mov al,0x01
; 向0xa1寫入0x01
out 0xa1,al
mov al,0x0b
; 得到0x8b
or al,0x80
; 向0x70寫入0x8b
out 0x70,al
mov al,0x12
; 向0x71寫入0x12
out 0x71,al
; 從0xa1讀取1位元組
in al,0xa1
; 讀取1位元組最低位設定為0
and al,0xfe
; 向0xa1寫入a1
out 0xa1,al
mov al,0x0c
; 向0x70寫入0x0c
out 0x70,al
; 從0x71讀取1位元組
in al,0x71
; 進入核心任務是硬體中斷是關閉的,中斷機制準備就緒後,才開啟硬體中斷
sti
mov ebx,message_0
call flat_4gb_code_seg_sel:put_string
mov eax,0x80000002
cpuid
mov [cpu_brand + 0x00],eax
mov [cpu_brand + 0x04],ebx
mov [cpu_brand + 0x08],ecx
mov [cpu_brand + 0x0c],edx
mov eax,0x80000003
cpuid
mov [cpu_brand + 0x10],eax
mov [cpu_brand + 0x14],ebx
mov [cpu_brand + 0x18],ecx
mov [cpu_brand + 0x1c],edx
mov eax,0x80000004
cpuid
mov [cpu_brand + 0x20],eax
mov [cpu_brand + 0x24],ebx
mov [cpu_brand + 0x28],ecx
mov [cpu_brand + 0x2c],edx
mov ebx,cpu_brnd0
call flat_4gb_code_seg_sel:put_string
mov ebx,cpu_brand
call flat_4gb_code_seg_sel:put_string
mov ebx,cpu_brnd1
call flat_4gb_code_seg_sel:put_string
mov edi,salt
mov ecx,salt_items
.b4:
push ecx
mov eax,[edi+256]
mov bx,[edi+260]
; P DPL 0 TYPE(1100) 000 參數個數(5位)
; 門指向代碼在記憶體 特權級3 類别
mov cx,1_11_0_1100_000_00000B
call flat_4gb_code_seg_sel:make_gate_descriptor
call flat_4gb_code_seg_sel:set_up_gdt_descriptor
; 符号中本來存儲段選擇子的現在存儲門選擇子
mov [edi+260],cx
add edi,salt_item_len
pop ecx
loop .b4
mov ebx,message_1
call far [salt_1+256]
; TCB對象結構
; 0x44 2位元組頭部選擇子
; 0x40 2特權級棧的初始ESP
; 0x3e 2特權級棧選擇子
; 0x3a 2特權級棧基位址
; 0x36 2特權級棧以4KB為機關的長度
; 0x32 1特權級棧的初始ESP
; 0x30 1特權級棧選擇子
; 0x2c 1特權級棧基位址
; 0x28 1特權級棧以4kb為機關的長度
; 0x24 0特權級棧的初始ESP
; 0x22 0特權級棧選擇子
; 0x1e 0特權級棧基位址
; 0x1a 0特權級棧以4kb為機關的長度
; 0x18 tss選擇子
; 0x14 tss基位址
; 0x12 tss界限值
; 0x10 ldt選擇子
; 0x0c ldt基位址
; 0x0a ldt目前界限值
; 0x06 程式加載基位址
; 0x04 任務狀态
; 0x00 下一個tcb基位址
; 設定任務狀态
mov word [core_tcb+0x04],0xffff
; 設定核心任務下一可用線性位址
mov dword [core_tcb+0x06],0x80100000
; 設定ldt目前界限值
mov word [core_tcb+0x0a],0xffff
; tcb對象加傳入連結式結構
mov ecx,core_tcb
call append_to_tcb_link
; 配置設定4kb可用虛拟區域 ---用于存儲核心任務tss對象
alloc_core_linear
; TSS格式
; I/OMapAddr Reserved 100
; Reserved LDT_Sector 96
; Reserved GS 92
; Reserved FS 88
; Reserved DS 84
; Reserved SS 80
; Reserved CS 76
; Reserved ES 72
; EDI 68
; ESI 64
; EBP 60
; ESP 56
; EBX 52
; EDX 48
; ECX 44
; EAX 40
; EFLAGS 36
; EIP 32
; CR3(PDBR) 28
; Reserved SS2 24
; ESP2 20
; Reserved SS1 16
; ESP1 12
; Reserved SS0 8
; ESP0 4
; Reserved Pre_Task_Tss 0
; tss對象設定前一任務tss選擇子
mov word [ebx+0],0
mov eax,cr3
; tss對象設定頁目錄表---每個任務有自己的頁目錄表,這裡存儲的是頁目錄表的實體位址
; 頁目錄表,頁表中目錄項的位址資訊也是實體位址的資訊
mov dword [ebx+28],eax
; tss對象設定ldt選擇子
mov word [ebx+96],0
; tss對象設定i/o映射
mov word [ebx+100],0
mov word [ebx+102],103
mov eax,ebx
mov ebx,103
; 位元組計量 32位 段在記憶體 特權級0 系統段 代碼段&被通路過
mov ecx,0x00408900
call flat_4gb_code_seg_sel:make_seg_descriptor
call flat_4gb_code_seg_sel:set_up_gdt_descriptor
mov [core_tcb+0x18],cx
ltr cx
alloc_core_linear
; 新的區域用于使用者任務tcb對象
; TCB對象結構
; 0x44 2位元組頭部選擇子
; 0x40 2特權級棧的初始ESP
; 0x3e 2特權級棧選擇子
; 0x3a 2特權級棧基位址
; 0x36 2特權級棧以4KB為機關的長度
; 0x32 1特權級棧的初始ESP
; 0x30 1特權級棧選擇子
; 0x2c 1特權級棧基位址
; 0x28 1特權級棧以4kb為機關的長度
; 0x24 0特權級棧的初始ESP
; 0x22 0特權級棧選擇子
; 0x1e 0特權級棧基位址
; 0x1a 0特權級棧以4kb為機關的長度
; 0x18 tss選擇子
; 0x14 tss基位址
; 0x12 tss界限值
; 0x10 ldt選擇子
; 0x0c ldt基位址
; 0x0a ldt目前界限值
; 0x06 程式加載基位址
; 0x04 任務狀态
; 0x00 下一個tcb基位址
; tcb對象設定任務狀态
mov word [ebx+0x04],0
; tcb對象設定使用者任務下一可用線性位址
mov dword [ebx+0x06],0
; tcb對象設定ldt目前界限值
mov word [ebx+0x0a],0xffff
push dword 50
push ebx
call load_relocate_program
mov ecx,ebx
call append_to_tcb_link
alloc_core_linear
; 新的區域用于使用者任務tcb對象
; TCB對象結構
; 0x44 2位元組頭部選擇子
; 0x40 2特權級棧的初始ESP
; 0x3e 2特權級棧選擇子
; 0x3a 2特權級棧基位址
; 0x36 2特權級棧以4KB為機關的長度
; 0x32 1特權級棧的初始ESP
; 0x30 1特權級棧選擇子
; 0x2c 1特權級棧基位址
; 0x28 1特權級棧以4kb為機關的長度
; 0x24 0特權級棧的初始ESP
; 0x22 0特權級棧選擇子
; 0x1e 0特權級棧基位址
; 0x1a 0特權級棧以4kb為機關的長度
; 0x18 tss選擇子
; 0x14 tss基位址
; 0x12 tss界限值
; 0x10 ldt選擇子
; 0x0c ldt基位址
; 0x0a ldt目前界限值
; 0x06 程式加載基位址
; 0x04 任務狀态
; 0x00 下一個tcb基位址
mov word [ebx+0x04],0
mov dword [ebx+0x06],0
mov word [ebx+0x0a],0xffff
push dword 100
push ebx
call load_relocate_program
mov ecx,ebx
call append_to_tcb_link
.core:
mov ebx,core_msg0
call flat_4gb_code_seg_sel:put_string
jmp .core
core_code_end:
SECTION core_trail
core_end:
3.使用者任務
program_length dd program_end
entry_point dd start
salt_position dd salt_begin
salt_items dd (salt_end-salt_begin)/256
salt_begin:
PrintString db '@PrintString'
times 256-($-PrintString) db 0
TerminateProgram db '@TerminateProgram'
times 256-($-TerminateProgram) db 0
ReadDiskData db '@ReadDiskData'
times 256-($-ReadDiskData) db 0
PrintDwordAsHex db '@PrintDwordAsHexString'
times 256-($-PrintDwordAsHex) db 0
salt_end:
message_0 db ' User task A->;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;'
db 0x0d,0x0a,0
[bits 32]
start:
mov ebx,message_0
call far [PrintString]
jmp start
call far [TerminateProgram]
program_end:
4.使用者任務2
program_length dd program_end
entry_point dd start
salt_position dd salt_begin
salt_items dd (salt_end-salt_begin)/256
salt_begin:
PrintString db '@PrintString'
times 256-($-PrintString) db 0
TerminateProgram db '@TerminateProgram'
times 256-($-TerminateProgram) db 0
ReadDiskData db '@ReadDiskData'
times 256-($-ReadDiskData) db 0
PrintDwordAsHex db '@PrintDwordAsHexString'
times 256-($-PrintDwordAsHex) db 0
salt_end:
message_0 db ' User task B->$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$'
db 0x0d,0x0a,0
[bits 32]
start:
mov ebx,message_0
call far [PrintString]
jmp start
call far [TerminateProgram]
program_end: