發表文章

目前顯示的是有「組合語言」標籤的文章

Add Devkit8000 and SBC8100 initial support to 0xdroid

圖片
As you know, I've done Android Eclair porting for Devkit8000 in the past, which is based on Embinux. It's a experimental work for passing time, I have no time to maintain and fix bugs friends reported after that. However, I think it is not good because the result will be getting lost as time goes by. 0xdroid is another Android distribution which is different from Embinux, its developer  Jim Huang(jserv)  who has contacted me a few months ago, and he hope that I can try porting 0xdroid on the Devkit8000. Actually, I am glad to make 0xdroid takes over my work, it is the best result for me. Currently, I've done most works, 0xdroid can run on Devkit8000 with success. And also, My patches have been committed to 0xlab-devel mailing list. Because I have another platform SBC8100 which is also produced by Embest, I've done works on that as well. You can see my patches from 0xlab-devel mailing list, or you can visit my website to download it directly: http://people.lin...

輕輕鬆鬆玩 8x51 的 Serial Port 控制

圖片
使用 Serial Port 是一個很基礎且簡單的通訊方式,從中可以很容易了解到 RXD/TXD 的運作原理,而常見的網路卡、電話等等通訊都是建構在相同的原理之上。Serial Port 在電路上很單純,對兩個要互通的電路來說,就是『你的傳送 TXD 是我的接收 RXD 』,很簡單的觀念,只要跳線就可完成。 整個實作目標,是按下開始傳送按鈕後,將透過 Serial Port 傳送 2 Bytes 的資料到另一個外部裝置,當外部裝置傳送 2Bytes 的資料過來時,將此資料顯示在七段顯示器上。其中這 2 Bytes 分別為『個位數』和『十位數』,必需先加總成一個 8bits 的數值,再送到顯示器上。 其程式的設計流程大致如下: 詳細程式碼和註解: ORG 00H ; 程式開始處 JMP BEGIN ; 跳到 BEGIN ORG 03H ; 停止按鈕的外部中斷程式 JMP STOP ; 跳到 STOP ORG 13H ; 開始按鈕的外部中斷程式 JMP START ; 跳到 START BEGIN: ; 設定一組號碼 06,並拆成十位和個位兩數 MOV R0, #6 ; 設定第一個 Byte 記錄個位數 MOV R1, #0 ; 設定第二個 Byte 記錄十位數 MOV A, R0 ; R0 無法直接 mov 到 R2,故先暫存到 A MOV R2, A ; 將 A 的值移到 R2 MOV A, R1 ; R1 無法直接 mov 到 R3,故先暫存到 A MOV R3, A ; 將 A 的值移到 R3 CALL BOND ; 呼叫 BOND 去將兩個位數加總成一個數字到 A CALL INIT_SERIAL ; 初始化 Serial Port 相關設定 MOV IP, #00000000B ; 低位觸發 MOV IE,...

8x51 起手式 -LED 跑馬燈

圖片
講到自動控制一定會提到『 8x51 系列』的應用,這系列的晶片在近二十幾年來已經被廣泛開發到爛掉,無處不見其縱影呀,從燈號控制、定時裝置到各種自動化的家電、工業產品,都可以找到它的存在。因此,凡是講到要學習自動控制的應用與設計,『 8x51 系列』可說是必學的項目。 這學期因為專題教授強烈的『口頭勸說』和為了順便湊畢業學分,就跑去選修了『 8x51 微處理機』的課程,重溫了以前零星的經驗。話說這堂課有多次實作的作業,過程中玩弄電路板和程式非常有意思。不過課程免不了從最簡單的 LED 跑馬燈開始教,雖然乏味但也是一個惡搞經驗的開始〔尤其是不依照老師要求時 :D〕。 這是第一次作業的電路示意圖〔圖的標示和真實腳位不一樣,請參考 8x51 的腳位定義資料。〕: 作業目標是讓 LED 燈號從第一個燈開始,每 0.2 秒變一次燈號,向左旋轉三圈後,再往右反方向旋轉三圈,如此以重覆動作跑下去。程式設計流程大致上是: 程式是用 ASM 寫的,原始程式碼和詳細註解如下: MOV R0, #24 ; 設定切換 LED 次數:跑三圈共23次 ; 因為包括起始燈號,所以要設定成 n+1 次 MOV A, #11111110B ; 以 bit 為單位,設 1 代表該腳位會輸出 5V 電壓 ; 設 0 則腳位輸出 0V 電壓,會讓 LED 有電位差而亮燈 ; 這裡設最右邊第一顆 LED 燈泡為起始燈 RUNL: MOV P0, A ; 使用 A 的設定值來設定 P0 ,以控制 LED CALL SLEEP ; 呼叫 SLEEP 副程式,暫停 0.2 秒 RL A ; 將燈泡設定值向左平移 DJNZ R0, RUNL ; R0=R0-1 ; 然後判斷 R0是否為 0 ...

OrzMicrokernel main.asm 核心啟動主結構

作業系統核心的運作分兩個階段,第一個階段是初始化,第二個階段是規律的活下去。從第一階段到第二階段的流程和主結構都清楚地寫在 main.asm,而工作排程、記憶體規劃等設計都是由此再延伸出去。 main.asm 原始碼: %include "defines.asm" %include "orzmicro.inc" %include "16bit.asm" %include "32bit.asm" ;----------------------------------------------------------------------------------- ; Now, we are under 32 bit protected mode. Starting... mov al,1 ; 設定為 320x200 的圖形模式 call SetVideoMode ; 呼叫 video.asm 的子程式設定顯示模式 call InitTasks ; 呼叫 tasks.asm 的子程式初始化工作狀態記錄表 mov eax, Ts1 + 0x10 ; 設 EAX 為工作記憶體開始位址 mov ebx, Ts2 - Ts1 - 0x10 ; 設 EBX 為工作所佔記憶大小 mov ecx, [Ts1 + 8] ; 設 ECX 為工作二進位檔的第 8 個 bytes 所設定的堆疊大小 mov edx, [Ts1 + 12] ; 設 ECX 為工作二進位檔的第 12 個 bytes 所設定的資料大小 mov esi, ts1Name ; 設 ESI 為工作名稱 call CreateTask ; 呼叫 tasks.asm 的 CreateTask 子程式建立工作 mov eax, Ts2 + 0x10 ; 設 EAX 為工作記憶體開始位址 mov ebx, Ts3 - Ts2 - 0x10 ; 設 EBX 為工作所...

OrzMicrokernel tasks.asm 尋找工作函式註解

到目前為止,從 Orz Microkernel 運作流程來看,我們已經看過主要的程式碼了,剩下的部份就只有些零零星星的函式和各種服務程式的實作。其中最重要的就是 Orz Microkernel 自訂的 IPC 訊息中斷服務(Message Service),該服務會運用到工作處理方面的函式,所以現在先將工作相關的函式註解補齊。 程式碼和詳細註解: ;------------------------------------------------------------------------------ ; 尋找工作 FindTask ;;;; 輸入值: EAX = 工作編號 ID ;;;; 返回值:若進位旗標 CF=1 則表示找不到工作,否則 EAX = 工作狀態編號,EBP = 工作狀態指標 ;;;; 會影響到的暫存器:EAX, ECX, ESI, EBP FindTask: mov ecx, [tasksCount] ; 設 ECX 為工作總數量 jecxz FindTask1 ; 若 ECX 為零,則跳到 FindTask1 mov esi, tasksList ; 設 ESI 為工作清單的記憶體位址 FindTask0: movzx ebp, BYTE [esi] ; 從 ESI 取 2 Bytes(工作編號)到 EBP imul ebp, s_task.msize ; EBP = EBP x s_task.msize add ebp, tasks ; EBP = EBP + 工作狀態記錄所在記憶體位址 cmp eax, [ebp + s_task.taskID] ; 若 EAX = s_task.taskID 則零值旗標 ZF = 0 jz FindTask2 ; 若零值旗標 ZF = 0 則跳到 FindTask2 inc esi ; ESI 加一 loop FindTask0 ; 迴圈 ECX 次,繼續尋...

OrzMicrokernel irq_handlers.asm IRQ處理和操作系統計時器 IRQ0 的函式註解

irq_handlers.asm 是 Orz Microkernel 用來處理 IRQ 的函式檔案,裡面有著處理所有 IRQ 的程式碼。之前工作排程器的部份有提到,定時切換工作是靠 IRQ0 的系統計時器達成的,其原理是當工作被賦予執行權時,同時也被授權了能佔用 CPU 的時間長度,接著,再靠著系統計時器的功能倒數計時。最後,該工作能佔用 CPU 的時間被用完,系統計時器就會如同鬧鐘響起一般,去呼叫 tasks.asm 的 Schedule 準備切換到下一個工作行程。 程式碼和詳細註解: ;------------------------------------------------------------------------ ; IRQ 是處理硬體中斷請求的通道,硬體可透過 IRQ 要求 CPU 產生中斷,以處理硬體的 ; 相關操作。 ; ; IRQ 在中斷(INT)的編號定義: ; 08 Hardware IRQ0 System Timer ; 09 Hardware IRQ1 Keyboard ; 0A Hardware IRQ2 Redirected ; 0B Hardware IRQ3 Serial Comms. COM2/COM4 ; 0C Hardware IRQ4 Serial Comms. COM1/COM3 ; 0D Hardware IRQ5 Reserved/Sound Card ; 0E Hardware IRQ6 Floppy Disk Controller ; 0F Hardware IRQ7 Parallel Comms. ; 70 Hardware IRQ8 Real Time Clock ; 71 Hardware IRQ9 Redirected IRQ2 ; 72 Hardware IRQ10 Reserved ; 73 Hardware IRQ11 Reserved ; 74 Hardware IRQ12 PS/2 Mouse ; 75 Hardware IRQ13 Math...

OrzMicrokernel tasks.asm 工作排程器的切換執行權函式註解

工作新增、載入後,一切都準備就緒了,main.asm 最後一個任務,就是讓作業系統的心臟:『工作排程器』開始跳動,使所有工作能夠生生不息的運轉。Orz Microkernel 利用了 Schedule 這個 Function 切換到工作清單中的下一個工作,並利用 IRQ_0 的計時器,每一定單位時間就切換一次,使所有工作如同同時執行一般。 原始程式碼和詳細註解: ;-------------------------------------------------------------------------- ; Scheduler 工作排程器: ; 多工的實作原理是讓所有的工作行程,依序輪流切換佔用 CPU 的運算能力。 ; 由於每個工作佔用 CPU 的時間極小,因此近乎同時所有工作同時執行一般。 ; ; Schedule: 是用來切換到下一個工作,並讓其佔用 CPU 的函式。在 main.asm 中呼叫後, ; 就會設定 taskRunningTime 工作執行的時間長度,而在 irq_handlers.asm 中 ; 的 IRQ_0 計時器,就會開始依照 taskRunningTime 定時轉換到下一個工作。 tx_NoMoreTasks db "No more tasks",0 ; 設定沒有工作的訊息字串 Schedule: mov eax, [tasksCount] ; 設 EAX 為目前工作數量 and eax, eax ; 若工作數量為零則設定零值旗標 ZF = 1 jnz Schedule0 ; 若旗標 ZF = 0 則跳到 Schedule0 mov esi, tx_NoMoreTasks ; 在 ESI 寫入沒有工作的訊息字串 jmp GpFault ; 輸出訊息 Schedule0: mov eax, [currentTaskN] ; 設 EAX = currentTaskN ...

OrzMicrokernel tasks.asm 建立新工作函式註解

因為每天花在 Orz Microkernel 上的時間不多,而且這次的程式片斷比較長,所以讓我多花了幾天的時間做整理,直到現在才大約有個較完整的註解。繼續依順續閱讀 main.asm 中可以看到,在工作初始化多工機制和工作狀態的資料結構之後,就開始連續載入並新增 6 個工作到我們的工作清單中,main.asm 呼叫 tasks.asm 裡的 CreateTask 函式來新增工作。 以下是程式碼和詳細註解: ;-------------------------------------------------------------------------------------- ; 建立新的工作 CreateTask ;;;; 輸入值: EAX = 工作的開始位址, EBX = 工作所佔的記憶體大小, ECX = 工作的堆疊大小 ;;;; EDX = 工作的資料大小, ESI = 工作名稱指標 ;;;; 返回值:若進位旗標 CF=1 則表示建立新工作失敗,否則 EAX = 工作編號 ;;;; 會影響到的暫存器:EAX, EBX, ECX, EDX, ESI, EDI, EBP CreateTask: mov [taskNamePtr], esi ; 設 taskNamePtr 為工作的名稱 mov [taskBegin], eax ; 設 taskBegin 為工作的開始位址 mov [copySize], ebx ; 設 copySize 為工作所佔的記憶體大小 add ebx, ecx ; EBX 加工作的堆疊大小 add ebx, edx ; EBX 加工作的資料大小 mov [taskSize], ebx ; taskSize = 所佔記憶體 + 堆疊大小 + 資料大小 mov ebx, [tasksCount] ...

OrzMicrokernel tasks.asm 初始化多工機制和工作狀態的資料結構

main.asm 在設定完顯示模式後,緊接著就是開始初始化多工機制。我們將配置一塊記憶體來存放所有工作的名稱、執行狀態﹝包括各種暫存器的內容﹞,在 Orz Microkernel 中,工作數量被限制為 64 個,它被定義在 define.asm 裡頭。 程式碼和詳細註解: InitTasks: mov ecx, MAX_TASKS ; 設 ECX 為最大工作數量﹝定義在 define.asm﹞ mov ebp, tasks ; 設定工作狀態記錄所在位址﹝定義在tables.asm﹞ xor eax, eax ; 將 EAX 歸零 InitTasks0: mov [ebp + s_task.taskID], eax ; 初始化工作狀態記錄編號 add ebp, s_task.msize ; 移到下一個工作狀態記錄的開頭 loop InitTasks0 ; 重覆工作狀態記錄初始化 ecx 次 ret 從上面程式碼看到的 s_task,是工作狀態記錄的資料結構,它被定義在 task.asm 的開頭: ; 使用虛擬指令 RESB、RESD 宣告不含初值的資料結構 s_task struc s_task .taskID: resd 1 ; 工作編號 Dword(2 Bytes) .state: resb 1 ; 工作狀態 Dword(1 Byte) .newTick: resd 1 ; need for state=STATE_SLEEP .queue: resd (MAX_TASKS + 1) .qFirst: resd 1 .qLast: resd 1 .s_taskID: resd 1 .s_message: resd 1 .s_dataPtr: resd 1 .s_...

OrzMicrokernel video.asm 切換顯示模式的註解

依照 Orz Microkernel 在 main.asm 的核心啟動流程來看,在轉換到保護模式並做了最基本的初始化之後,就會 call SetVideoMode 來切換顯示模式到 320x200。關於這部份,比較複雜的是牽涉到 BIOS 中斷,由於在保護模式之下無法使用 BIOS INT,所以特別額外在 realmode.asm 寫了在保護模式下處理此類中斷的呼叫函式﹝關於 realmode.asm 的註解日後補上﹞。 程式碼和詳細註解: ;------------------------------------------------------------------------------ ; 文字模式﹝80x25,16色﹞:AL=0 ; 圖形模式﹝320x200,256色﹞:AL=1 SetVideoMode: and al, al jnz SetVideoMode0 ; 若 AL 不為 0 則呼叫 SetVideoMode0 mov [rmode_ax], WORD 0x03 ; 文字模式 mov al, 0x10 ; 中斷 10H ; 在保護模式下舊有的中斷向量表已被 IDT 代替 ; 導致 BIOS 中斷在保護模式下無法使用 ; 故 BIOS 中斷得在真實模式執行 ; 因此特別在 realmode.asm 中設計一個處理真實模式中斷的函式 jmp RmodeInt ; 呼叫在 realmode.asm 的 RmodeInt 處理中斷 SetVideoMode0: dec al ; AL=AL-1 jnz SetVideoMode1 ; 若 AL 不為 0 則呼叫 SetVideoMode1 返回 mov [rmode_ax], WORD 0x13 ; 圖形模式 mov al, 0x10 ; 中斷 10H jmp RmodeInt ; 呼...

OrzMicrokernel bit32.asm 進入保護模式後的核心初始化

OrzMicrokernel 在 bit16.asm 完成了轉換成保護模式的工作,緊接著會跳到 bit32.asm 初始化核心和設定硬體中斷周期。最重要的是,從跳轉到這檔案後,就可以開始使用 32 位元的各種延伸暫存器以及更大的記憶體定址,但前題是:我們得先將新的暫存器區段位址設定好,因為暫存器設定還是處於在真實模式時的狀態。 程式碼和詳細註解: [BITS 32] ; Intel 處理器的設計是以 dword 為單位來存取記憶體,所以記憶體位址定為 4 的倍數。 align 4 ; 設定所有資料的起始位址都是 4 的倍數 Begin32c: ; 初始化暫存器區段 mov ax, kernel_data - _GDT ; 從 tables.asm 的 kernel_data 開始 mov ds, ax mov es, ax mov fs, ax mov gs, ax mov ss, ax mov esp, 0x2FFFF ; 堆疊暫存器設在 2MB 記憶體後 call TestMemory ; 呼叫 mm.asm 的子程式測試記憶體 mov edi, memMap ; 初始化索引暫存器 ; memMap 記憶體大小有0x20000=128KB mov ecx, 0x100 / 32 ; 計數器設為 256/32=8 xor eax, eax ; 將 eax 歸零 dec eax rep stosd ; 每次從 EAX 中複製 4 Bytes 到 EDI ; 複製 8 次 mov ecx, 0x2000...

OrzMicrokernel bit16.asm 核心前置動作並轉換到保護模式的註解

bit16.asm 是 OrzMicrokernel 從真實模式轉換到保護模式的部份。保護模式是作業系統必要的運作環境,因為保護模式支援了 4GB 的實體記憶體定址、可擴充的記憶體分頁機制、多重任務機制、特權級等多工作業系統會用到的各種機制。 詳細程式碼和註解: [BITS 16] [ORG KERNEL_START] Start: ; 初始化暫存器區段 mov ax, cs mov ds, ax mov es, ax mov ss, ax ; 初始化堆疊區段 mov sp, 0x0000 ; 堆疊指標暫存器歸零 ; 準備開始切換到保護模式 cli ; 禁用中斷以免干擾初始化 cld ; 設定字串處理時由低住址往高位址 call PrepareIRQs ; 呼叫 irqs.asm 的副程式以初始化 IRQ ; A20 位址線控制器: ; 早期 8086 的 CPU 只有 20 bits 的位址匯流排,只能定址到 1MB 的記憶體 ; 因此,如果試圖存取超過 1MB 的記憶體,將會回到位址零重新定位循環下去 ; 所以,要打開 A20 位址線,讓電腦可以定址大於 1MB 的記憶體 call A20En ; 呼叫 irqs.asm 的副程式 ; 以打開 A20 位址線 lgdt [_GDT - KERNEL_START] ; 載入 GDT:_GDT 在 tables.asm lidt [_IDTR - KERNEL_START] ; 載入 IDT:_IDTR 在 tables.asm ; 切換到保護模式 ; 切換成保護模式的方法:將 CR0 的 PE ...

OrzMicrokernel boot.asm 啟動磁區定義和程式初始化註解

OrzMicrokernel 的 boot.asm 是針對 1.44 MB 磁碟片所設計的,採用的是 FAT12 ﹝注意不是 FAT16 或 FAT32﹞的檔案系統,所以,在啟動磁區的部份的定義上比較簡單且單純。另外,這次註解的內容主要是程式一開始的部份,包括初始化、在螢幕上顯示一段文字等。 程式碼與詳細註解: Base: jmp short Begin ; 從 Begin 執行 nop ; 空執行 ; 啟動磁區格式 oem db 'OrzMicro' ; 廠商軟體名 bytesPerSector dw 0x0200 ; 設每磁區的大小為 512 Bytes sectPerCluster db 0x02 ; 每磁叢的磁區數 resSectors dw 0x01 ; FAT 前的磁區數 ; ﹝開機記錄所佔用的磁區數﹞ fatCopies db 0x02 ; FAT 表總數 rootEntCnt dw 0x0070 ; 根目錄的最大檔案數 totalSectors dw 0x05A0 ; 邏輯磁區總數 media db 0xF9 ; 磁碟種類 sectPerFat dw 0x0003 ; 每個 FAT 表的磁區數 sectPerTrack dw 0x0009 ; 每磁軌的磁區數 heads dw 0x0002 ; 磁頭數﹝面數﹞ hiddenSectors dd 0 ; 隱藏磁區數 sectorHuge dd 0 ; 保留 4 Bytes ...

OrzMicrokernel boot.asm 磁碟內容參數的詳細註解

這是 OrzMicrokernel 裡 boot.asm 磁碟內容參數的部分,這部份比較直觀且不涉及硬體裝置的操作和定義,只要了解磁碟的資料配置結構,很容易就能了解其中的運作。 程式碼包括詳細註解: ;----------------------------------------------- ; 計算各項磁碟內容參數 ; ; 計算磁區位置: ; 1. FAT表磁區 ; 2. 根目錄磁區 ; 3. 資料磁區 ; ; 計算 FAT 檔案系統資訊: ; 1. FBD 所佔磁區數量 ;----------------------------------------------- ; ; 磁碟資料結構:[開機記錄磁區][隱藏磁區][FAT表磁區][根目錄磁區][資料磁區] ; [FAT表磁區] 是由許多 FAT 表所構成 ; [根目錄磁區] 是由許多 FBD 所構成 ; FBD(檔案描述區塊):大小為 32Bytes ; 每個檔案都有自己的 FBD,記錄檔案名稱、建檔日期、檔案大小等資料 ; 計算 FAT 的開始位置 ; 方法:跳過隱藏磁區和開機磁區 ; hiddenSectors = [高位元 2Bytes][低位元 2Bytes] mov si,[hiddenSectors] ; 低位元給 SI mov di,[hiddenSectors+2] ; 高位元給 DI add si,[resSectors] ; 跳過隱藏磁區加開機記錄所佔用的磁區數 adc di,0 ; DI:SI = 第一個 FAT 表的開始位置 mov [fatStart],si ; 用 fatStart 保存 FAT 的開始位置 mov [fatStart+2],di ; 計算根目錄磁區的開始位置 ; 方法:跳過 FAT 表磁區 ; FAT 表的總數 x 每個表的磁區數 = 所有 FAT 表的磁區總數 mov al,[fatCopies] ; AL = FAT 表總數 xo...

OrzMicrokernel 陪我度過颱風天的阿宅生活

最近幾次少數能以『強烈的颱風』身份影響並登陸台灣的,大概就屬這次的颱風了。還沒登陸,風就已經重擊了家裡的窗戶,呼呼砰砰聲搞得我醒著做事覺得煩、睡也睡不好。前兩天晚上去逛敦南誠品,在去的路上,風狂野的在短短一個街口,就把我的雨傘給吹成奇形怪狀﹝比翻過來還可怕﹞,後來回家時只好淋著雨一身濕答答的走回停車處。在被風玩弄之後,我就決定這兩天不出門了,弄得自己閒得發荒,一直在家當阿宅 Orz。 我突然想起前陣子 Jserv 寫的 OrzMicrokernel,一直沒能好好的找個時間去讀它,所以,藉著這次颱風過境,就好好品嘗一下了﹝笑﹞。一切果然如同大家所說, OrzMicrokernel 真的是簡潔有力,是一個作業系統設計的優良範例,它的設計非常直觀易懂;可是我也有聽到一群朋友,看得要死還是看不大懂 OrzMicrokernel 。搞半天,原來他們對組合語言並不是說非常熟悉,還有對磁碟 LBA、CHS、FAT12 等等這種格式定義很陌生!不過也難怪,大多人平時寫程式都太高階了,早就忘了電腦是怎麼動起來的。 尋思如果很多想了解的人,都卡在對組合語言的一點不熟悉和資料結構定義這種問題上,導致無法踏入 OrzMicrokernel 的話,那真的是太可惜了。所以,無聊到極點的我,就決定開始幫 OrzMicrokernel 逐行中文註解,希望從組合語言指令用法開始加註說明,還有說明重要的資料結構﹝註解寫起來比程式碼還多行,驚!﹞。為了說明的完全清晰正確,我還重新查資料驗證自己的觀念,生怕有一點遺漏。 以下是 boot.asm 讀取磁區的註解片段: ; DX:AX = LBA 磁區位置, ES:BX = 緩衝區位址 ReadSector: ; 磁區 CHS 表示法 ; 磁碟和磁片的記錄方式『不是』一整面的磁區用完再換面儲存,而是以空心圓柱狀的方式。 ; 因為磁片只有簡單兩面,以磁片為例: ; 正確的磁片資料記錄順序為:第零面第零軌、第一面第零軌、第零面第一軌、第一面第一軌... ; 每面的同一軌都用滿後才換下一個磁軌紀錄資料,形狀如同空心圓柱,故稱磁柱(cylinder)。 ; 因此以磁片來說,第 0 面第 0 軌和第 1 面第 0 軌就是第 0 磁柱 ; 磁區 LBA 表示法 ; LBA 編號法是不考慮磁區的實...

PC 作業系統實作馬上入門

最近在整理過去的許多筆記,看到了很多懷念的東西,尋思當初許多的瓶頸,都缺少一個人幫我打通任督二脈,讓我一路走起來倍感艱辛,雖然不後悔這樣沒章法的強幹式學習,但許多冤枉路我心裡明白是白走了,尤其在作業系統這部份,對大多數人來說,更是不易突破的關卡。因為,看程式方面的書籍它不會教你,看硬體架構的書又不告訴你程式實作,如果想自己融會貫通,又因為沒有良好的入門範例,不知道該注意哪些事項而挫折連連。 開始前,你要有個體認,我們要寫的是作業系統,整台電腦都將由我們的程式完全控制,所以,如果你的程式不正常,將會落得停格當機下場,沒有『程式關閉,請聯絡...』或是『Core...』這套。另外,不要想說有任何 API 可以用,你都要一一自己打造這一切,因為系統開發本來就是一件辛苦的事,你正在開拓一個沙漠的綠洲。 而大多數人在學習作業系統撰寫時,常都會卡在第一步:我要如何讓自己的作業系統啟動?然後如同第一次學寫程式時,出現一行 Hello World?當初的我也在這問題上打轉好一陣子,縱使我會組合語言、有過不少寫程式經驗、看過許許多多的相關書籍,但我還是不知道該從哪開始。 我們先來了解電腦啟動的流程: 電腦開啟電源,會啟動 ROM 裡面的 BIOS 執行硬體檢查和初始化。 BIOS 會依序搜尋 BIOS 設定中的啟動裝置(Boot Device),如硬碟。 一旦在某個啟動裝置上發現了啟動磁區(Boot Sector 大小為 512 Bytes),就會將此磁區 512 Bytes 的程式載入到記憶體位址 0000:7c00 BIOS 會跳到記憶體位址 0000:7c00 執行被載入的程式,並將執行權全權交給它。 以下是一個 512 Bytes 的簡單開機程式實作範例﹝組合語言﹞: org 07c00h ;此程式將被載入到 0000:7c00 執行 mov ax, cs mov ds, ax mov es, ax call Disp ;呼叫 Disp 顯示字串 jmp $ ;無限回圈 Disp: mov ax, BootMsg mov bp, ax ;指定 BootMsg ...