今天原本的任務看書和把以前寫的FragileOS整理一下,可是到如今還在摸魚,書也只看一點。後來整理了一下寫這個系列的思路,本來的目的是對操做系統原理性的學習和對以前寫的一個玩具型操做系統的回顧,就是想對操做系統的知識的輪廓能有一個瞭解,如今想來想減小對以前寫的系統的回顧,畢竟也只有2000多行,可是仍是要有對整個思路的展示。而後增長對Linux 0.12源碼的一些學習。因此離標題可能比較遠了一點,可是就這樣吧git
本來這一節是寫計算機系統和操做系統概述的,可是寫到一半以爲太水就刪了。就總結幾句,後面用到什麼就補什麼。計算機系統的概述應該屬於計算機組成原理的內容,這倆部分也是《操做系統:精髓和設計原理》的第一二章。可是以爲若是對於想學習操做系統內部的代碼的話,換成彙編的內容會更好。github
進入正題,操做系統是什麼windows
對於計算機來講最根本的運行方式,就是取指執行緩存
對於在屏幕上輸出Hello,World!的過程,首先CPU拿到內存中的指令,這些指令是通知CPU把存在某個內存中的'H''E''L'等移動到顯存位置,這樣在屏幕上就能夠看到這些字符了。這就是計算機最原始的運行方式網絡
而操做系統就是對硬件層面的抽象,讓咱們不用在直面硬件,若是想要再次在屏幕輸出字符,只要直接調用操做系統的write(windows下的好像是這個名),C語言中的printf下就是一個系統調用架構
固然操做系統絕對是比想象中的龐大的多,操做系統還對內存、終端、磁盤、網絡和文件等等進行管理,光windows 2000應該就有3000多萬行的代碼了。固然有簡陋的內存、進程管理和文件系統的玩具型內核,只要幾千行代碼就能夠完成了。學習
對於X86架構的計算機,開機時一共作這幾件事spa
開機時的CS = 0xFFFF, IP = 0x0000操作系統
這時候的CPU處理實模式,也就是尋址的方式是CS:IP (實模式和保護模式屬於CPU的工做模式,其中比較大的區別就是尋址的方式)設計
尋址0xFFFF0
檢查硬件設備,像鍵盤顯示器之類的
將磁盤0磁道0扇區讀入0x7c00處
會從這裏讀入512字節,也就是傳說中的引導程序,這裏放着計算機執行的第一段代碼
設置cs = 0x7c00 ip = 0x0000
這個是我以前寫的FragileOS的boot,採用的是Intel彙編格式
主要的邏輯就是:
(部分代碼)
org 0x7c00; ;加載到內存0x7c00處
LoadAddr EQU 08000h ;內核的內存地址
BufferAddr EQU 7E0h ;讀取扇區的時候進行的緩存
BaseOfStack EQU 07c00h
entry:
mov ax, 0 ;進行寄存器的初始化操做
mov ss, ax
mov ds, ax
mov ax, BufferAddr
mov es, ax ;ES:BX 數據存儲緩衝區,指示扇區加載後放置的地址
mov ax, 0
mov ss, ax
mov sp, BaseOfStack
mov di, ax
mov si, ax
mov BX, 0 ;ES:BX 數據存儲緩衝區
mov CH, 1 ;CH 用來存儲柱面號
mov DH, 0 ;DH 用來存儲磁頭號
mov CL, 0 ;CL 用來存儲扇區號
read_floppy: ;每次都把扇區寫入緩存地址07E00處
cmp byte [load_count], 0 ;比較load_count地址處的值,若是=0就跳轉到begin_load
je begin_load
mov bx, 0
inc CL
mov AH, 0x02 ;AH = 02 表示要作的是讀盤操做
mov AL, 1 ;AL 表示要練習讀取幾個扇區
mov DL, 0 ;驅動器編號,通常咱們只有一個軟盤驅動器,因此寫死
int 0x13 ;調用BIOS中斷實現磁盤讀取功能
jc fin
複製代碼
Linux 0.12的boot天然比上面的複雜的多,Linux採用的boot的彙編是as86格式的,其他的彙編採用的都是AT&T
Linux 0.12下的boot一共有三個文件:
(代碼太長不所有貼了,有須要的能夠私信我)
bootsect的主要做用就是把本身移動到0x90000處執行,而後再加載setup模塊 *(也就是setup.s)*到bootsect的後面,再把system模塊加載到0x10000處,這個也就是內核的主要部分
bootsect的開頭是一些常量的定義
SETUPLEN = 4 ! nr of setup-sectors
BOOTSEG = 0x07c0 ! original address of boot-sector
INITSEG = 0x9000 ! we move boot here - out of the way
SETUPSEG = 0x9020 ! setup starts here
SYSSEG = 0x1000 ! system loaded at 0x10000 (65536).
ENDSEG = SYSSEG + SYSSIZE ! where to stop loading
複製代碼
_start先設置好目的地址和源地址
ds:si和es:di
而後執行rep指令
rep指令是重複的意思,它以cx寄存器的值爲判斷,若是cx的值爲0就中止
movw指令
開始從[si]處移動cx個字到[di]處,這裏也就是一共移動了256個字,512字節
最後跳轉到0x9000開始執行
_start:
mov ax,#BOOTSEG
mov ds,ax
mov ax,#INITSEG
mov es,ax
mov cx,#256
sub si,si
sub di,di
rep
movw
jmpi go,INITSEG
複製代碼
go: mov ax,cs
mov ds,ax
mov es,ax
! put stack at 0x9ff00.
mov ss,ax
mov sp,#0xFF00 ! arbitrary value >>512
複製代碼
這一部分和我以前的同樣,就是調用中斷來讀取磁盤內容,只是Linux讀取的是在第二扇區的setup模塊
若是失敗就從新設置驅動器而後跳回從新讀取
成功就跳到ok_load_setup
ok_load_setup是設置根文件系統設備的,而且讀入SYSTEM模塊 *(內核的主要部分)*到0x10000處,結尾是跳到SETUP模塊
load_setup:
mov dx,#0x0000 ! drive 0, head 0
mov cx,#0x0002 ! sector 2, track 0
mov bx,#0x0200 ! address = 512, in INITSEG
mov ax,#0x0200+SETUPLEN ! service 2, nr of sectors
int 0x13 ! read it
jnc ok_load_setup ! ok - continue
mov dx,#0x0000
mov ax,#0x0000 ! reset the diskette
int 0x13
j load_setup
複製代碼
一個簡單的boot引導程序,顧名思義就是把作一些引導工做的,進行一些初始化設置再讀入真正的內核部分,進入OS。
其實Linux 0.12一個完整的boot應該還包括setup.s用來完成OS啓動前最後的設置 (進入保護模式等),head.s則是進入以後的設置。可是由於這兩部分包含了一些其它重要概念,因此打算再下一篇寫。