file descriptor
一個檔案在檔案系統中涉及五個要素:
- 檔案內容(資料)所佔用的磁區
- i-node
- i-node 在 inode-map 中佔用的一位
- 資料磁區在 sector-map 中佔用的一位或多位
- 檔案在目錄中佔有的目錄項(direntry)
建立檔案
- 為檔案內容(資料)分配磁區
- 在 inode_array 中分配一個 i-node
- 在 inode-map 中分配一位
- 在 sector-map 中分配一位或多位
- 在相應目錄中寫入一個目錄項(direntry)
刪除檔案
- 釋放 inode-map 中的相應位
- 釋放 sector-map 中的相應位
- 刪除根目錄中的目錄項
程式碼
boot/boot.asm
; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; boot.asm
; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; Forrest Yu, 2005
; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;%define _BOOT_DEBUG_ ; 做 Boot Sector 時一定將此行註解掉!將此行打開後用 nasm Boot.asm -o Boot.com 做成一個.COM檔案易於測試
%ifdef _BOOT_DEBUG_
org 0100h ; 測試狀態, 做成 .COM 檔案, 可測試
%else
org 07c00h ; Boot 狀態, Bios 將把 Boot Sector 加載到 0:7C00 處並開始執行
%endif
;================================================================================================
%ifdef _BOOT_DEBUG_
BaseOfStack equ 0100h ; 測試狀態下堆疊基位址(堆疊底, 從這個位置向低位址生長)
%else
BaseOfStack equ 07c00h ; Boot狀態下堆疊基位址(堆疊底, 從這個位置向低位址生長)
%endif
%include "load.inc"
;================================================================================================
jmp short LABEL_START ; Start to boot.
nop ; 這個 nop 不可少
; 下面是 FAT12 磁碟的頭, 之所以包含它是因為下面用到了磁碟的一些訊息
%include "fat12hdr.inc"
LABEL_START:
mov ax, cs
mov ds, ax
mov es, ax
mov ss, ax
mov sp, BaseOfStack
; 清屏
mov ax, 0600h ; AH = 6, AL = 0h
mov bx, 0700h ; 黑底白字(BL = 07h)
mov cx, 0 ; 左上角: (0, 0)
mov dx, 0184fh ; 右下角: (80, 50)
int 10h ; int 10h
mov dh, 0 ; "Booting "
call DispStr ; 顯示字元串
xor ah, ah ; ┓
xor dl, dl ; ┣ 軟體驅動復位
int 13h ; ┛
; 下面在 A 碟的根目錄尋找 LOADER.BIN
mov word [wSectorNo], SectorNoOfRootDirectory
LABEL_SEARCH_IN_ROOT_DIR_BEGIN:
cmp word [wRootDirSizeForLoop], 0 ; ┓
jz LABEL_NO_LOADERBIN ; ┣ 判斷根目錄區是不是已經讀完
dec word [wRootDirSizeForLoop] ; ┛ 如果讀完表示沒有找到 LOADER.BIN
mov ax, LOADER_SEG
mov es, ax ; es <- LOADER_SEG
mov bx, LOADER_OFF ; bx <- LOADER_OFF 於是, es:bx = LOADER_SEG:LOADER_OFF
mov ax, [wSectorNo] ; ax <- Root Directory 中的某 Sector 號
mov cl, 1
call ReadSector
mov si, LoaderFileName ; ds:si -> "LOADER BIN"
mov di, LOADER_OFF ; es:di -> LOADER_SEG:0100 = LOADER_SEG*10h+100
cld
mov dx, 10h
LABEL_SEARCH_FOR_LOADERBIN:
cmp dx, 0 ; ┓循環次數控制,
jz LABEL_GOTO_NEXT_SECTOR_IN_ROOT_DIR ; ┣如果已經讀完了一個 Sector,
dec dx ; ┛就跳到下一個 Sector
mov cx, 11
LABEL_CMP_FILENAME:
cmp cx, 0
jz LABEL_FILENAME_FOUND ; 如果比較了 11 個字元都相等, 表示找到
dec cx
lodsb ; ds:si -> al
cmp al, byte [es:di]
jz LABEL_GO_ON
jmp LABEL_DIFFERENT ; 只要發現不一樣的字元就表明本 DirectoryEntry 不是
; 我們要找的 LOADER.BIN
LABEL_GO_ON:
inc di
jmp LABEL_CMP_FILENAME ; 繼續循環
LABEL_DIFFERENT:
and di, 0FFE0h ; else ┓ di &= E0 為了讓它指向本項目開頭
add di, 20h ; ┃
mov si, LoaderFileName ; ┣ di += 20h 下一個目錄項目
jmp LABEL_SEARCH_FOR_LOADERBIN; ┛
LABEL_GOTO_NEXT_SECTOR_IN_ROOT_DIR:
add word [wSectorNo], 1
jmp LABEL_SEARCH_IN_ROOT_DIR_BEGIN
LABEL_NO_LOADERBIN:
mov dh, 2 ; "No LOADER."
call DispStr ; 顯示字元串
%ifdef _BOOT_DEBUG_
mov ax, 4c00h ; ┓
int 21h ; ┛沒有找到 LOADER.BIN, 回到 DOS
%else
jmp $ ; 沒有找到 LOADER.BIN, 死循環在這裡
%endif
LABEL_FILENAME_FOUND: ; 找到 LOADER.BIN 後便來到這裡繼續
mov ax, RootDirSectors
and di, 0FFE0h ; di -> 當前項目的開始
add di, 01Ah ; di -> 首 Sector
mov cx, word [es:di]
push cx ; 保存此 Sector 在 FAT 中的序號
add cx, ax
add cx, DeltaSectorNo ; 這句完成時 cl 裡面變成 LOADER.BIN 的起始磁區號 (從 0 開始數的序號)
mov ax, LOADER_SEG
mov es, ax ; es <- LOADER_SEG
mov bx, LOADER_OFF ; bx <- LOADER_OFF 於是, es:bx = LOADER_SEG:LOADER_OFF = LOADER_SEG * 10h + LOADER_OFF
mov ax, cx ; ax <- Sector 號
LABEL_GOON_LOADING_FILE:
push ax ; ┓
push bx ; ┃
mov ah, 0Eh ; ┃ 每讀一個磁區就在 "Booting " 後面打一個點, 形成這樣的效果:
mov al, '.' ; ┃
mov bl, 0Fh ; ┃ Booting ......
int 10h ; ┃
pop bx ; ┃
pop ax ; ┛
mov cl, 1
call ReadSector
pop ax ; 取出此 Sector 在 FAT 中的序號
call GetFATEntry
cmp ax, 0FFFh
jz LABEL_FILE_LOADED
push ax ; 保存 Sector 在 FAT 中的序號
mov dx, RootDirSectors
add ax, dx
add ax, DeltaSectorNo
add bx, [BPB_BytsPerSec]
jmp LABEL_GOON_LOADING_FILE
LABEL_FILE_LOADED:
mov dh, 1 ; "Ready."
call DispStr ; 顯示字元串
; *****************************************************************************************************
jmp LOADER_SEG:LOADER_OFF ; 這一句正式跳轉到已加載到記憶體中的 LOADER.BIN 的開始處
; 開始執行 LOADER.BIN 的程式碼
; Boot Sector 的使命到此結束
; *****************************************************************************************************
;============================================================================
;變量
;----------------------------------------------------------------------------
wRootDirSizeForLoop dw RootDirSectors ; Root Directory 占用的磁區數, 在循環中會遞減至零.
wSectorNo dw 0 ; 要讀取的磁區號
bOdd db 0 ; 奇數還是偶數
;============================================================================
;字元串
;----------------------------------------------------------------------------
LoaderFileName db "LOADER BIN", 0 ; LOADER.BIN 之檔案名
; 為簡化程式碼, 下面每個字元串的長度均為 MessageLength
MessageLength equ 9
BootMessage: db "Booting "; 9字元, 不夠則用空格補齊. 序號 0
Message1 db "Ready. "; 9字元, 不夠則用空格補齊. 序號 1
Message2 db "No LOADER"; 9字元, 不夠則用空格補齊. 序號 2
;============================================================================
;----------------------------------------------------------------------------
; 函數名: DispStr
;----------------------------------------------------------------------------
; 作用:
; 顯示一個字元串, 函數開始時 dh 中應該是字元串序號(0-based)
DispStr:
mov ax, MessageLength
mul dh
add ax, BootMessage
mov bp, ax ; ┓
mov ax, ds ; ┣ ES:BP = 串位址
mov es, ax ; ┛
mov cx, MessageLength ; CX = 串長度
mov ax, 01301h ; AH = 13, AL = 01h
mov bx, 0007h ; 頁號為0(BH = 0) 黑底白字(BL = 07h)
mov dl, 0
int 10h ; int 10h
ret
;----------------------------------------------------------------------------
; 函數名: ReadSector
;----------------------------------------------------------------------------
; 作用:
; 從第 ax 個 Sector 開始, 將 cl 個 Sector 讀入 es:bx 中
ReadSector:
; -----------------------------------------------------------------------
; 怎樣由磁區號求磁區在磁碟中的位置 (磁區號 -> 柱面號, 起始磁區, 磁頭號)
; -----------------------------------------------------------------------
; 設磁區號為 x
; ┌ 柱面號 = y >> 1
; x ┌ 商 y ┤
; -------------- => ┤ └ 磁頭號 = y & 1
; 每磁道磁區數 │
; └ 余 z => 起始磁區號 = z + 1
push bp
mov bp, sp
sub esp, 2 ; 辟出兩個字元的堆疊區域保存要讀的磁區數: byte [bp-2]
mov byte [bp-2], cl
push bx ; 保存 bx
mov bl, [BPB_SecPerTrk] ; bl: 除數
div bl ; y 在 al 中, z 在 ah 中
inc ah ; z ++
mov cl, ah ; cl <- 起始磁區號
mov dh, al ; dh <- y
shr al, 1 ; y >> 1 (其實是 y/BPB_NumHeads, 這裡BPB_NumHeads=2)
mov ch, al ; ch <- 柱面號
and dh, 1 ; dh & 1 = 磁頭號
pop bx ; 恢復 bx
; 至此, "柱面號, 起始磁區, 磁頭號" 全部得到 ^^^^^^^^^^^^^^^^^^^^^^^^
mov dl, [BS_DrvNum] ; 驅動器號 (0 表示 A 碟)
.GoOnReading:
mov ah, 2 ; 讀
mov al, byte [bp-2] ; 讀 al 個磁區
int 13h
jc .GoOnReading ; 如果讀取錯誤 CF 會被置為 1, 這時就不停地讀, 直到正確為止
add esp, 2
pop bp
ret
;----------------------------------------------------------------------------
; 函數名: GetFATEntry
;----------------------------------------------------------------------------
; 作用:
; 找到序號為 ax 的 Sector 在 FAT 中的項目, 結果放在 ax 中
; 需要注意的是, 中間需要讀 FAT 的磁區到 es:bx 處, 所以函數一開始保存了 es 和 bx
GetFATEntry:
push es
push bx
push ax
mov ax, LOADER_SEG ; ┓
sub ax, 0100h ; ┣ 在 LOADER_SEG 後面留出 4K 空間用於存放 FAT
mov es, ax ; ┛
pop ax
mov byte [bOdd], 0
mov bx, 3
mul bx ; dx:ax = ax * 3
mov bx, 2
div bx ; dx:ax / 2 ==> ax <- 商, dx <- 餘數
cmp dx, 0
jz LABEL_EVEN
mov byte [bOdd], 1
LABEL_EVEN:;偶數
xor dx, dx ; 現在 ax 中是 FATEntry 在 FAT 中的偏移量. 下面來計算 FATEntry 在哪個磁區中(FAT占用不止一個磁區)
mov bx, [BPB_BytsPerSec]
div bx ; dx:ax / BPB_BytsPerSec ==> ax <- 商 (FATEntry 所在的磁區相對於 FAT 來說的磁區號)
; dx <- 餘數 (FATEntry 在磁區內的偏移)。
push dx
mov bx, 0 ; bx <- 0 於是, es:bx = (LOADER_SEG - 100):00 = (LOADER_SEG - 100) * 10h
add ax, SectorNoOfFAT1 ; 此句執行之後的 ax 就是 FATEntry 所在的磁區號
mov cl, 2
call ReadSector ; 讀取 FATEntry 所在的磁區, 一次讀兩個, 避免在邊界發生錯誤, 因為一個 FATEntry 可能跨越兩個磁區
pop dx
add bx, dx
mov ax, [es:bx]
cmp byte [bOdd], 1
jnz LABEL_EVEN_2
shr ax, 4
LABEL_EVEN_2:
and ax, 0FFFh
LABEL_GET_FAT_ENRY_OK:
pop bx
pop es
ret
;----------------------------------------------------------------------------
times 510-($-$$) db 0 ; 填充剩下的空間,使生成的二進制程式碼恰好為512字元
dw 0xaa55 ; 結束標誌
boot/loader.asm
; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; loader.asm
; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; Forrest Yu, 2005
; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
org 0100h
jmp LABEL_START ; Start
; 下面是 FAT12 磁碟的頭, 之所以包含它是因為下面用到了磁碟的一些訊息
%include "fat12hdr.inc"
%include "load.inc"
%include "pm.inc"
; GDT ------------------------------------------------------------------------------------------------------------------------------------------------------------
; 段基址 段界限 , 屬性
LABEL_GDT: Descriptor 0, 0, 0 ; 空描述符
LABEL_DESC_FLAT_C: Descriptor 0, 0fffffh, DA_CR | DA_32 | DA_LIMIT_4K ; 0 ~ 4G
LABEL_DESC_FLAT_RW: Descriptor 0, 0fffffh, DA_DRW | DA_32 | DA_LIMIT_4K ; 0 ~ 4G
LABEL_DESC_VIDEO: Descriptor 0B8000h, 0ffffh, DA_DRW | DA_DPL3 ; 顯示卡記憶體首位址
; GDT ------------------------------------------------------------------------------------------------------------------------------------------------------------
GdtLen equ $ - LABEL_GDT
GdtPtr dw GdtLen - 1 ; 段界限
dd LOADER_PHY_ADDR + LABEL_GDT ; 基位址 (讓基位址八字元對齊將起到優化速度之效果,目前懶得改)
; The GDT is not a segment itself; instead, it is a data structure in linear address space.
; The base linear address and limit of the GDT must be loaded into the GDTR register. -- IA-32 Software Developer’s Manual, Vol.3A
; GDT 選擇子 ----------------------------------------------------------------------------------
SelectorFlatC equ LABEL_DESC_FLAT_C - LABEL_GDT
SelectorFlatRW equ LABEL_DESC_FLAT_RW - LABEL_GDT
SelectorVideo equ LABEL_DESC_VIDEO - LABEL_GDT + SA_RPL3
; GDT 選擇子 ----------------------------------------------------------------------------------
BaseOfStack equ 0100h
LABEL_START: ; <--- 從這裡開始 *************
mov ax, cs
mov ds, ax
mov es, ax
mov ss, ax
mov sp, BaseOfStack
mov dh, 0 ; "Loading "
call DispStrRealMode ; 顯示字元串
; 得到記憶體數
mov ebx, 0 ; ebx = 後續值, 開始時需為 0
mov di, _MemChkBuf ; es:di 指向一個位址範圍描述符結構(Address Range Descriptor Structure)
.MemChkLoop:
mov eax, 0E820h ; eax = 0000E820h
mov ecx, 20 ; ecx = 位址範圍描述符結構的大小
mov edx, 0534D4150h ; edx = 'SMAP'
int 15h ; int 15h
jc .MemChkFail
add di, 20
inc dword [_dwMCRNumber] ; dwMCRNumber = ARDS 的個數
cmp ebx, 0
jne .MemChkLoop
jmp .MemChkOK
.MemChkFail:
mov dword [_dwMCRNumber], 0
.MemChkOK:
; 下面在 A 碟的根目錄尋找 KERNEL.BIN
mov word [wSectorNo], SectorNoOfRootDirectory
xor ah, ah ; ┓
xor dl, dl ; ┣ 軟體驅動復位
int 13h ; ┛
LABEL_SEARCH_IN_ROOT_DIR_BEGIN:
cmp word [wRootDirSizeForLoop], 0 ; ┓
jz LABEL_NO_KERNELBIN ; ┣ 判斷根目錄區是不是已經讀完, 如果讀完表示沒有找到 KERNEL.BIN
dec word [wRootDirSizeForLoop] ; ┛
mov ax, KERNEL_FILE_SEG
mov es, ax ; es <- KERNEL_FILE_SEG
mov bx, KERNEL_FILE_OFF ; bx <- KERNEL_FILE_OFF 於是, es:bx = KERNEL_FILE_SEG:KERNEL_FILE_OFF = KERNEL_FILE_SEG * 10h + KERNEL_FILE_OFF
mov ax, [wSectorNo] ; ax <- Root Directory 中的某 Sector 號
mov cl, 1
call ReadSector
mov si, KernelFileName ; ds:si -> "KERNEL BIN"
mov di, KERNEL_FILE_OFF ; es:di -> KERNEL_FILE_SEG:???? = KERNEL_FILE_SEG*10h+????
cld
mov dx, 10h
LABEL_SEARCH_FOR_KERNELBIN:
cmp dx, 0 ; ┓
jz LABEL_GOTO_NEXT_SECTOR_IN_ROOT_DIR ; ┣ 循環次數控制, 如果已經讀完了一個 Sector, 就跳到下一個 Sector
dec dx ; ┛
mov cx, 11
LABEL_CMP_FILENAME:
cmp cx, 0 ; ┓
jz LABEL_FILENAME_FOUND ; ┣ 循環次數控制, 如果比較了 11 個字元都相等, 表示找到
dec cx ; ┛
lodsb ; ds:si -> al
cmp al, byte [es:di] ; if al == es:di
jz LABEL_GO_ON
jmp LABEL_DIFFERENT
LABEL_GO_ON:
inc di
jmp LABEL_CMP_FILENAME ; 繼續循環
LABEL_DIFFERENT:
and di, 0FFE0h ; else┓ 這時di的值不知道是什麼, di &= e0 為了讓它是 20h 的倍數
add di, 20h ; ┃
mov si, KernelFileName ; ┣ di += 20h 下一個目錄項目
jmp LABEL_SEARCH_FOR_KERNELBIN; ┛
LABEL_GOTO_NEXT_SECTOR_IN_ROOT_DIR:
add word [wSectorNo], 1
jmp LABEL_SEARCH_IN_ROOT_DIR_BEGIN
LABEL_NO_KERNELBIN:
mov dh, 3 ; "No KERNEL."
call DispStrRealMode ; 顯示字元串
jmp $ ; 沒有找到 KERNEL.BIN, 死循環在這裡
LABEL_FILENAME_FOUND: ; 找到 KERNEL.BIN 後便來到這裡繼續
mov ax, RootDirSectors
and di, 0FFF0h ; di -> 當前項目的開始
push eax
mov eax, [es : di + 01Ch] ; ┓
mov dword [dwKernelSize], eax ; ┛保存 KERNEL.BIN 檔案大小
cmp eax, KERNEL_VALID_SPACE
ja .1
pop eax
jmp .2
.1:
mov dh, 4 ; "Too Large"
call DispStrRealMode ; 顯示字元串
jmp $ ; KERNEL.BIN 太大,死循環在這裡
.2:
add di, 01Ah ; di -> 首 Sector
mov cx, word [es:di]
push cx ; 保存此 Sector 在 FAT 中的序號
add cx, ax
add cx, DeltaSectorNo ; 這時 cl 裡面是 LOADER.BIN 的起始磁區號 (從 0 開始數的序號)
mov ax, KERNEL_FILE_SEG
mov es, ax ; es <- KERNEL_FILE_SEG
mov bx, KERNEL_FILE_OFF ; bx <- KERNEL_FILE_OFF 於是, es:bx = KERNEL_FILE_SEG:KERNEL_FILE_OFF = KERNEL_FILE_SEG * 10h + KERNEL_FILE_OFF
mov ax, cx ; ax <- Sector 號
LABEL_GOON_LOADING_FILE:
push ax ; `.
push bx ; |
mov ah, 0Eh ; | 每讀一個磁區就在 "Loading " 後面
mov al, '.' ; | 打一個點, 形成這樣的效果:
mov bl, 0Fh ; | Loading ......
int 10h ; |
pop bx ; |
pop ax ; /
mov cl, 1
call ReadSector
pop ax ; 取出此 Sector 在 FAT 中的序號
call GetFATEntry
cmp ax, 0FFFh
jz LABEL_FILE_LOADED
push ax ; 保存 Sector 在 FAT 中的序號
mov dx, RootDirSectors
add ax, dx
add ax, DeltaSectorNo
add bx, [BPB_BytsPerSec]
jc .1 ; 如果 bx 重新變成 0,說明內核大於 64KB
jmp .2
.1:
push ax ; es += 0x1000 ← es 指向下一個段
mov ax, es
add ax, 1000h
mov es, ax
pop ax
.2:
jmp LABEL_GOON_LOADING_FILE
LABEL_FILE_LOADED:
call KillMotor ; 關閉軟體驅動馬達
;;; ;; 取硬碟訊息
;;; xor eax, eax
;;; mov ah, 08h ; Code for drive parameters
;;; mov dx, 80h ; hard drive
;;; int 0x13
;;; jb .hderr ; No such drive?
;;; ;; cylinder number
;;; xor ax, ax ; ax <- 0
;;; mov ah, cl ; ax <- cl
;;; shr ah, 6
;;; and ah, 3 ; cl bits 7-6: high two bits of maximum cylinder number
;;; mov al, ch ; CH = low eight bits of maximum cylinder number
;;; ;; sector number
;;; and cl, 3Fh ; cl bits 5-0: max sector number (1-origin)
;;; ;; head number
;;; inc dh ; dh = 1 + max head number (0-origin)
;;; mov [_dwNrHead], dh
;;; mov [_dwNrSector], cl
;;; mov [_dwNrCylinder], ax
;;; jmp .hdok
;;; .hderr:
;;; mov dword [_dwNrHead], 0FFFFh
;;; .hdok:
;; 將硬碟引導磁區內容讀入記憶體 0500h 處
xor ax, ax
mov es, ax
mov ax, 0201h ; AH = 02
; AL = number of sectors to read (must be nonzero)
mov cx, 1 ; CH = low eight bits of cylinder number
; CL = sector number 1-63 (bits 0-5)
; high two bits of cylinder (bits 6-7, hard disk only)
mov dx, 80h ; DH = head number
; DL = drive number (bit 7 set for hard disk)
mov bx, 500h ; ES:BX -> data buffer
int 13h
;; 硬碟操作完畢
mov dh, 2 ; "Ready."
call DispStrRealMode ; 顯示字元串
; 下面準備跳入保護模式 -------------------------------------------
; 加載 GDTR
lgdt [GdtPtr]
; 關中斷
cli
; 打開位址線A20
in al, 92h
or al, 00000010b
out 92h, al
; 準備切換到保護模式
mov eax, cr0
or eax, 1
mov cr0, eax
; 真正進入保護模式
jmp dword SelectorFlatC:(LOADER_PHY_ADDR+LABEL_PM_START)
;============================================================================
;變量
;----------------------------------------------------------------------------
wRootDirSizeForLoop dw RootDirSectors ; Root Directory 占用的磁區數
wSectorNo dw 0 ; 要讀取的磁區號
bOdd db 0 ; 奇數還是偶數
dwKernelSize dd 0 ; KERNEL.BIN 檔案大小
;============================================================================
;字元串
;----------------------------------------------------------------------------
KernelFileName db "KERNEL BIN", 0 ; KERNEL.BIN 之檔案名
; 為簡化程式碼, 下面每個字元串的長度均為 MessageLength
MessageLength equ 9
LoadMessage: db "Loading "
Message1 db " "
Message2 db "Ready. "
Message3 db "No KERNEL"
Message4 db "Too Large"
;============================================================================
;----------------------------------------------------------------------------
; 函數名: DispStrRealMode
;----------------------------------------------------------------------------
; 運行環境:
; 實模式(保護模式下顯示字元串由函數 DispStr 完成)
; 作用:
; 顯示一個字元串, 函數開始時 dh 中應該是字元串序號(0-based)
DispStrRealMode:
mov ax, MessageLength
mul dh
add ax, LoadMessage
mov bp, ax ; ┓
mov ax, ds ; ┣ ES:BP = 串位址
mov es, ax ; ┛
mov cx, MessageLength ; CX = 串長度
mov ax, 01301h ; AH = 13, AL = 01h
mov bx, 0007h ; 頁號為0(BH = 0) 黑底白字(BL = 07h)
mov dl, 0
add dh, 3 ; 從第 3 行往下顯示
int 10h ; int 10h
ret
;----------------------------------------------------------------------------
; 函數名: ReadSector
;----------------------------------------------------------------------------
; 作用:
; 從序號(Directory Entry 中的 Sector 號)為 ax 的的 Sector 開始, 將 cl 個 Sector 讀入 es:bx 中
ReadSector:
; -----------------------------------------------------------------------
; 怎樣由磁區號求磁區在磁碟中的位置 (磁區號 -> 柱面號, 起始磁區, 磁頭號)
; -----------------------------------------------------------------------
; 設磁區號為 x
; ┌ 柱面號 = y >> 1
; x ┌ 商 y ┤
; -------------- => ┤ └ 磁頭號 = y & 1
; 每磁道磁區數 │
; └ 余 z => 起始磁區號 = z + 1
push bp
mov bp, sp
sub esp, 2 ; 辟出兩個字元的堆疊區域保存要讀的磁區數: byte [bp-2]
mov byte [bp-2], cl
push bx ; 保存 bx
mov bl, [BPB_SecPerTrk] ; bl: 除數
div bl ; y 在 al 中, z 在 ah 中
inc ah ; z ++
mov cl, ah ; cl <- 起始磁區號
mov dh, al ; dh <- y
shr al, 1 ; y >> 1 (其實是 y/BPB_NumHeads, 這裡BPB_NumHeads=2)
mov ch, al ; ch <- 柱面號
and dh, 1 ; dh & 1 = 磁頭號
pop bx ; 恢復 bx
; 至此, "柱面號, 起始磁區, 磁頭號" 全部得到 ^^^^^^^^^^^^^^^^^^^^^^^^
mov dl, [BS_DrvNum] ; 驅動器號 (0 表示 A 碟)
.GoOnReading:
mov ah, 2 ; 讀
mov al, byte [bp-2] ; 讀 al 個磁區
int 13h
jc .GoOnReading ; 如果讀取錯誤 CF 會被置為 1, 這時就不停地讀, 直到正確為止
add esp, 2
pop bp
ret
;----------------------------------------------------------------------------
; 函數名: GetFATEntry
;----------------------------------------------------------------------------
; 作用:
; 找到序號為 ax 的 Sector 在 FAT 中的項目, 結果放在 ax 中
; 需要注意的是, 中間需要讀 FAT 的磁區到 es:bx 處, 所以函數一開始保存了 es 和 bx
GetFATEntry:
push es
push bx
push ax
mov ax, KERNEL_FILE_SEG ; ┓
sub ax, 0100h ; ┣ 在 KERNEL_FILE_SEG 後面留出 4K 空間用於存放 FAT
mov es, ax ; ┛
pop ax
mov byte [bOdd], 0
mov bx, 3
mul bx ; dx:ax = ax * 3
mov bx, 2
div bx ; dx:ax / 2 ==> ax <- 商, dx <- 餘數
cmp dx, 0
jz LABEL_EVEN
mov byte [bOdd], 1
LABEL_EVEN:;偶數
xor dx, dx ; 現在 ax 中是 FATEntry 在 FAT 中的偏移量. 下面來計算 FATEntry 在哪個磁區中(FAT占用不止一個磁區)
mov bx, [BPB_BytsPerSec]
div bx ; dx:ax / BPB_BytsPerSec ==> ax <- 商 (FATEntry 所在的磁區相對於 FAT 來說的磁區號)
; dx <- 餘數 (FATEntry 在磁區內的偏移)。
push dx
mov bx, 0 ; bx <- 0 於是, es:bx = (KERNEL_FILE_SEG - 100):00 = (KERNEL_FILE_SEG - 100) * 10h
add ax, SectorNoOfFAT1 ; 此句執行之後的 ax 就是 FATEntry 所在的磁區號
mov cl, 2
call ReadSector ; 讀取 FATEntry 所在的磁區, 一次讀兩個, 避免在邊界發生錯誤, 因為一個 FATEntry 可能跨越兩個磁區
pop dx
add bx, dx
mov ax, [es:bx]
cmp byte [bOdd], 1
jnz LABEL_EVEN_2
shr ax, 4
LABEL_EVEN_2:
and ax, 0FFFh
LABEL_GET_FAT_ENRY_OK:
pop bx
pop es
ret
;----------------------------------------------------------------------------
;----------------------------------------------------------------------------
; 函數名: KillMotor
;----------------------------------------------------------------------------
; 作用:
; 關閉軟體驅動馬達
KillMotor:
push dx
mov dx, 03F2h
mov al, 0
out dx, al
pop dx
ret
;----------------------------------------------------------------------------
; 從此以後的程式碼在保護模式下執行 ----------------------------------------------------
; 32 位程式碼段. 由實模式跳入 ---------------------------------------------------------
[SECTION .s32]
ALIGN 32
[BITS 32]
LABEL_PM_START:
mov ax, SelectorVideo
mov gs, ax
mov ax, SelectorFlatRW
mov ds, ax
mov es, ax
mov fs, ax
mov ss, ax
mov esp, TopOfStack
call DispMemInfo
;;; call DispReturn
;;; call DispHDInfo ; int 13h 讀出的硬碟 geometry 好像有點不對頭,不知道為什麼,乾脆不管它了
call SetupPaging
;mov ah, 0Fh ; 0000: 黑底 1111: 白字
;mov al, 'P'
;mov [gs:((80 * 0 + 39) * 2)], ax ; 螢幕第 0 行, 第 39 列。
call InitKernel
;jmp $
mov dword [BOOT_PARAM_ADDR], BOOT_PARAM_MAGIC ; BootParam[0] = BootParamMagic;
mov eax, [dwMemSize] ;
mov [BOOT_PARAM_ADDR + 4], eax ; BootParam[1] = MemSize;
mov eax, KERNEL_FILE_SEG
shl eax, 4
add eax, KERNEL_FILE_OFF
mov [BOOT_PARAM_ADDR + 8], eax ; BootParam[2] = KernelFilePhyAddr;
;***************************************************************
jmp SelectorFlatC:KRNL_ENT_PT_PHY_ADDR ; 正式进入内核 *
;***************************************************************
; 内存看上去是这样的:
; ┃ ┃
; ┃ . ┃
; ┃ . ┃
; ┃ . ┃
; ┣━━━━━━━━━━━━━━━━━━┫
; ┃■■■■■■■■■■■■■■■■■■┃
; ┃■■■■■■Page Tables■■■■■■┃
; ┃■■■■■(大小由LOADER决定)■■■■┃
; 00101000h ┃■■■■■■■■■■■■■■■■■■┃ PAGE_TBL_BASE
; ┣━━━━━━━━━━━━━━━━━━┫
; ┃■■■■■■■■■■■■■■■■■■┃
; 00100000h ┃■■■■Page Directory Table■■■■┃ PAGE_DIR_BASE <- 1M
; ┣━━━━━━━━━━━━━━━━━━┫
; ┃□□□□□□□□□□□□□□□□□□┃
; F0000h ┃□□□□□□□System ROM□□□□□□┃
; ┣━━━━━━━━━━━━━━━━━━┫
; ┃□□□□□□□□□□□□□□□□□□┃
; E0000h ┃□□□□Expansion of system ROM □□┃
; ┣━━━━━━━━━━━━━━━━━━┫
; ┃□□□□□□□□□□□□□□□□□□┃
; C0000h ┃□□□Reserved for ROM expansion□□┃
; ┣━━━━━━━━━━━━━━━━━━┫
; ┃□□□□□□□□□□□□□□□□□□┃ B8000h ← gs
; A0000h ┃□□□Display adapter reserved□□□┃
; ┣━━━━━━━━━━━━━━━━━━┫
; ┃□□□□□□□□□□□□□□□□□□┃
; 9FC00h ┃□□extended BIOS data area (EBDA)□┃
; ┣━━━━━━━━━━━━━━━━━━┫
; ┃■■■■■■■■■■■■■■■■■■┃
; 90000h ┃■■■■■■■LOADER.BIN■■■■■■┃ somewhere in LOADER ← esp
; ┣━━━━━━━━━━━━━━━━━━┫
; ┃■■■■■■■■■■■■■■■■■■┃
; ┃■■■■■■■■■■■■■■■■■■┃
; 70000h ┃■■■■■■■KERNEL.BIN■■■■■■┃
; ┣━━━━━━━━━━━━━━━━━━┫
; ┃■■■■■■■■■■■■■■■■■■┃
; ┃■■■■■■■■■■■■■■■■■■┃
; ┃■■■■■■■■■■■■■■■■■■┃
; ┃■■■■■■■■■■■■■■■■■■┃
; ┃■■■■■■■■■■■■■■■■■■┃
; ┃■■■■■■■■■■■■■■■■■■┃
; ┃■■■■■■■■■■■■■■■■■■┃ 7C00h~7DFFh : BOOT SECTOR, overwritten by the kernel
; ┃■■■■■■■■■■■■■■■■■■┃
; ┃■■■■■■■■■■■■■■■■■■┃
; ┃■■■■■■■■■■■■■■■■■■┃
; 1000h ┃■■■■■■■■KERNEL■■■■■■■┃ 1000h ← KERNEL 入口 (KRNL_ENT_PT_PHY_ADDR)
; ┣━━━━━━━━━━━━━━━━━━┫
; ┃ ┃
; 500h ┃ F R E E ┃
; ┣━━━━━━━━━━━━━━━━━━┫
; ┃□□□□□□□□□□□□□□□□□□┃
; 400h ┃□□□□ROM BIOS parameter area □□┃
; ┣━━━━━━━━━━━━━━━━━━┫
; ┃◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇┃
; 0h ┃◇◇◇◇◇◇Int Vectors◇◇◇◇◇◇┃
; ┗━━━━━━━━━━━━━━━━━━┛ ← cs, ds, es, fs, ss
;
;
; ┏━━━┓ ┏━━━┓
; ┃■■■┃ 我们使用 ┃□□□┃ 不能使用的内存
; ┗━━━┛ ┗━━━┛
; ┏━━━┓ ┏━━━┓
; ┃ ┃ 未使用空间 ┃◇◇◇┃ 可以覆盖的内存
; ┗━━━┛ ┗━━━┛
;
; 注:KERNEL 的位置实际上是很灵活的,可以通过同时改变 LOAD.INC 中的 KRNL_ENT_PT_PHY_ADDR 和 MAKEFILE 中参数 -Ttext 的值来改变。
; 比如,如果把 KRNL_ENT_PT_PHY_ADDR 和 -Ttext 的值都改为 0x400400,则 KERNEL 就会被加载到内存 0x400000(4M) 处,入口在 0x400400。
;
; ------------------------------------------------------------------------
; 显示 AL 中的数字
; ------------------------------------------------------------------------
DispAL:
push ecx
push edx
push edi
mov edi, [dwDispPos]
mov ah, 0Fh ; 0000b: 黑底 1111b: 白字
mov dl, al
shr al, 4
mov ecx, 2
.begin:
and al, 01111b
cmp al, 9
ja .1
add al, '0'
jmp .2
.1:
sub al, 0Ah
add al, 'A'
.2:
mov [gs:edi], ax
add edi, 2
mov al, dl
loop .begin
;add edi, 2
mov [dwDispPos], edi
pop edi
pop edx
pop ecx
ret
; DispAL 结束-------------------------------------------------------------
; ------------------------------------------------------------------------
; 显示一个整形数
; ------------------------------------------------------------------------
DispInt:
mov eax, [esp + 4]
shr eax, 24
call DispAL
mov eax, [esp + 4]
shr eax, 16
call DispAL
mov eax, [esp + 4]
shr eax, 8
call DispAL
mov eax, [esp + 4]
call DispAL
mov ah, 07h ; 0000b: 黑底 0111b: 灰字
mov al, 'h'
push edi
mov edi, [dwDispPos]
mov [gs:edi], ax
add edi, 4
mov [dwDispPos], edi
pop edi
ret
; DispInt 结束------------------------------------------------------------
; ------------------------------------------------------------------------
; 显示一个字元串
; ------------------------------------------------------------------------
DispStr:
push ebp
mov ebp, esp
push ebx
push esi
push edi
mov esi, [ebp + 8] ; pszInfo
mov edi, [dwDispPos]
mov ah, 0Fh
.1:
lodsb
test al, al
jz .2
cmp al, 0Ah ; 是回车吗?
jnz .3
push eax
mov eax, edi
mov bl, 160
div bl
and eax, 0FFh
inc eax
mov bl, 160
mul bl
mov edi, eax
pop eax
jmp .1
.3:
mov [gs:edi], ax
add edi, 2
jmp .1
.2:
mov [dwDispPos], edi
pop edi
pop esi
pop ebx
pop ebp
ret
; DispStr 结束------------------------------------------------------------
; ------------------------------------------------------------------------
; 换行
; ------------------------------------------------------------------------
DispReturn:
push szReturn
call DispStr ;printf("\n");
add esp, 4
ret
; DispReturn 结束---------------------------------------------------------
; ------------------------------------------------------------------------
; 内存拷贝,仿 memcpy
; ------------------------------------------------------------------------
; void* MemCpy(void* es:pDest, void* ds:pSrc, int iSize);
; ------------------------------------------------------------------------
MemCpy:
push ebp
mov ebp, esp
push esi
push edi
push ecx
mov edi, [ebp + 8] ; Destination
mov esi, [ebp + 12] ; Source
mov ecx, [ebp + 16] ; Counter
.1:
cmp ecx, 0 ; 判断计数器
jz .2 ; 计数器为零时跳出
mov al, [ds:esi] ; ┓
inc esi ; ┃
; ┣ 逐字节移动
mov byte [es:edi], al ; ┃
inc edi ; ┛
dec ecx ; 计数器减一
jmp .1 ; 循环
.2:
mov eax, [ebp + 8] ; 返回值
pop ecx
pop edi
pop esi
mov esp, ebp
pop ebp
ret ; 函数结束,返回
; MemCpy 结束-------------------------------------------------------------
; 显示内存訊息 --------------------------------------------------------------
DispMemInfo:
push esi
push edi
push ecx
push szMemChkTitle
call DispStr
add esp, 4
mov esi, MemChkBuf
mov ecx, [dwMCRNumber] ;for(int i=0;i<[MCRNumber];i++) // 每次得到一个ARDS(Address Range Descriptor Structure)结构
.loop: ;{
mov edx, 5 ; for(int j=0;j<5;j++) // 每次得到一个ARDS中的成员,共5个成员
mov edi, ARDStruct ; { // 依次显示:BaseAddrLow,BaseAddrHigh,LengthLow,LengthHigh,Type
.1: ;
push dword [esi] ;
call DispInt ; DispInt(MemChkBuf[j*4]); // 显示一个成员
pop eax ;
stosd ; ARDStruct[j*4] = MemChkBuf[j*4];
add esi, 4 ;
dec edx ;
cmp edx, 0 ;
jnz .1 ; }
call DispReturn ; printf("\n");
cmp dword [dwType], 1 ; if(Type == AddressRangeMemory) // AddressRangeMemory : 1, AddressRangeReserved : 2
jne .2 ; {
mov eax, [dwBaseAddrLow] ;
add eax, [dwLengthLow] ;
cmp eax, [dwMemSize] ; if(BaseAddrLow + LengthLow > MemSize)
jb .2 ;
mov [dwMemSize], eax ; MemSize = BaseAddrLow + LengthLow;
.2: ; }
loop .loop ;}
;
call DispReturn ;printf("\n");
push szRAMSize ;
call DispStr ;printf("RAM size:");
add esp, 4 ;
;
push dword [dwMemSize] ;
call DispInt ;DispInt(MemSize);
add esp, 4 ;
pop ecx
pop edi
pop esi
ret
; ---------------------------------------------------------------------------
;;; ; 显示内存訊息 --------------------------------------------------------------
;;; DispHDInfo:
;;; push eax
;;; cmp dword [dwNrHead], 0FFFFh
;;; je .nohd
;;; push szCylinder
;;; call DispStr ; printf("C:");
;;; add esp, 4
;;; push dword [dwNrCylinder] ; NR Cylinder
;;; call DispInt
;;; pop eax
;;; push szHead
;;; call DispStr ; printf(" H:");
;;; add esp, 4
;;; push dword [dwNrHead] ; NR Head
;;; call DispInt
;;; pop eax
;;; push szSector
;;; call DispStr ; printf(" S:");
;;; add esp, 4
;;; push dword [dwNrSector] ; NR Sector
;;; call DispInt
;;; pop eax
;;; jmp .hdinfo_finish
;;; .nohd:
;;; push szNOHD
;;; call DispStr ; printf("No hard drive. System halt.");
;;; add esp, 4
;;; jmp $ ; 没有硬盘,死在这里
;;; .hdinfo_finish:
;;; call DispReturn
;;; pop eax
;;; ret
;;; ; ---------------------------------------------------------------------------
; 启动分页机制 --------------------------------------------------------------
SetupPaging:
; 根据内存大小计算应初始化多少PDE以及多少页表
xor edx, edx
mov eax, [dwMemSize]
mov ebx, 400000h ; 400000h = 4M = 4096 * 1024, 一个页表对应的内存大小
div ebx
mov ecx, eax ; 此时 ecx 为页表的个数,也即 PDE 应该的个数
test edx, edx
jz .no_remainder
inc ecx ; 如果余数不为 0 就需增加一个页表
.no_remainder:
push ecx ; 暂存页表个数
; 为简化处理, 所有线性位址对应相等的物理位址. 并且不考虑内存空洞.
; 首先初始化页目录
mov ax, SelectorFlatRW
mov es, ax
mov edi, PAGE_DIR_BASE ; 此段首位址为 PAGE_DIR_BASE
xor eax, eax
mov eax, PAGE_TBL_BASE | PG_P | PG_USU | PG_RWW
.1:
stosd
add eax, 4096 ; 为了简化, 所有页表在内存中是连续的.
loop .1
; 再初始化所有页表
pop eax ; 页表个数
mov ebx, 1024 ; 每个页表 1024 个 PTE
mul ebx
mov ecx, eax ; PTE个数 = 页表个数 * 1024
mov edi, PAGE_TBL_BASE ; 此段首位址为 PAGE_TBL_BASE
xor eax, eax
mov eax, PG_P | PG_USU | PG_RWW
.2:
stosd
add eax, 4096 ; 每一页指向 4K 的空间
loop .2
mov eax, PAGE_DIR_BASE
mov cr3, eax
mov eax, cr0
or eax, 80000000h
mov cr0, eax
jmp short .3
.3:
nop
ret
; 分页机制启动完毕 ----------------------------------------------------------
; InitKernel ---------------------------------------------------------------------------------
; 将 KERNEL.BIN 的内容经过整理对齐后放到新的位置
; --------------------------------------------------------------------------------------------
InitKernel: ; 遍历每一个 Program Header,根据 Program Header 中的訊息来确定把什么放进内存,放到什么位置,以及放多少。
xor esi, esi
mov cx, word [KERNEL_FILE_PHY_ADDR + 2Ch]; ┓ ecx <- pELFHdr->e_phnum
movzx ecx, cx ; ┛
mov esi, [KERNEL_FILE_PHY_ADDR + 1Ch] ; esi <- pELFHdr->e_phoff
add esi, KERNEL_FILE_PHY_ADDR ; esi <- OffsetOfKernel + pELFHdr->e_phoff
.Begin:
mov eax, [esi + 0]
cmp eax, 0 ; PT_NULL
jz .NoAction
push dword [esi + 010h] ; size ┓
mov eax, [esi + 04h] ; ┃
add eax, KERNEL_FILE_PHY_ADDR ; ┣ ::memcpy( (void*)(pPHdr->p_vaddr),
push eax ; src ┃ uchCode + pPHdr->p_offset,
push dword [esi + 08h] ; dst ┃ pPHdr->p_filesz;
call MemCpy ; ┃
add esp, 12 ; ┛
.NoAction:
add esi, 020h ; esi += pELFHdr->e_phentsize
dec ecx
jnz .Begin
ret
; InitKernel ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
; SECTION .data1 之开始 ---------------------------------------------------------------------------------------------
[SECTION .data1]
ALIGN 32
LABEL_DATA:
; 实模式下使用这些符号
; 字元串
_szMemChkTitle: db "BaseAddrL BaseAddrH LengthLow LengthHigh Type", 0Ah, 0
_szRAMSize: db "RAM size: ", 0
;;; _szCylinder db "HD Info : C=", 0
;;; _szHead db " H=", 0
;;; _szSector db " S=", 0
;;; _szNOHD db "No hard drive. System halt.", 0
_szReturn: db 0Ah, 0
;; 变量
;;; _dwNrCylinder dd 0
;;; _dwNrHead dd 0
;;; _dwNrSector dd 0
_dwMCRNumber: dd 0 ; Memory Check Result
_dwDispPos: dd (80 * 7 + 0) * 2 ; 螢幕第 7 行, 第 0 列。
_dwMemSize: dd 0
_ARDStruct: ; Address Range Descriptor Structure
_dwBaseAddrLow: dd 0
_dwBaseAddrHigh: dd 0
_dwLengthLow: dd 0
_dwLengthHigh: dd 0
_dwType: dd 0
_MemChkBuf: times 256 db 0
;
;; 保护模式下使用这些符号
szMemChkTitle equ LOADER_PHY_ADDR + _szMemChkTitle
szRAMSize equ LOADER_PHY_ADDR + _szRAMSize
;;; szCylinder equ LOADER_PHY_ADDR + _szCylinder
;;; szHead equ LOADER_PHY_ADDR + _szHead
;;; szSector equ LOADER_PHY_ADDR + _szSector
;;; szNOHD equ LOADER_PHY_ADDR + _szNOHD
szReturn equ LOADER_PHY_ADDR + _szReturn
;;; dwNrCylinder equ LOADER_PHY_ADDR + _dwNrCylinder
;;; dwNrHead equ LOADER_PHY_ADDR + _dwNrHead
;;; dwNrSector equ LOADER_PHY_ADDR + _dwNrSector
dwDispPos equ LOADER_PHY_ADDR + _dwDispPos
dwMemSize equ LOADER_PHY_ADDR + _dwMemSize
dwMCRNumber equ LOADER_PHY_ADDR + _dwMCRNumber
ARDStruct equ LOADER_PHY_ADDR + _ARDStruct
dwBaseAddrLow equ LOADER_PHY_ADDR + _dwBaseAddrLow
dwBaseAddrHigh equ LOADER_PHY_ADDR + _dwBaseAddrHigh
dwLengthLow equ LOADER_PHY_ADDR + _dwLengthLow
dwLengthHigh equ LOADER_PHY_ADDR + _dwLengthHigh
dwType equ LOADER_PHY_ADDR + _dwType
MemChkBuf equ LOADER_PHY_ADDR + _MemChkBuf
; 堆栈就在数据段的末尾
StackSpace: times 1000h db 0
TopOfStack equ LOADER_PHY_ADDR + $ ; 栈顶
; SECTION .data1 之结束 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
boot/include/load.inc
BaseOfLoader equ 09000h ; LOADER.BIN 被加載到的位置 ---- 段地址
OffsetOfLoader equ 0100h ; LOADER.BIN 被加載到的位置 ---- 偏移地址
BaseOfLoaderPhyAddr equ BaseOfLoader * 10h ; LOADER.BIN 被加載到的位置 ---- 物理地址 (= BaseOfLoader * 10h)
BaseOfKernelFile equ 08000h ; KERNEL.BIN 被加載到的位置 ---- 段地址
OffsetOfKernelFile equ 0h ; KERNEL.BIN 被加載到的位置 ---- 偏移地址
BaseOfKernelFilePhyAddr equ BaseOfKernelFile * 10h
KernelEntryPointPhyAddr equ 030400h ; 注意:1、必須與 MAKEFILE 中參數 -Ttext 的值相等!!
; 2、這是個地址而非僅僅是個偏移,如果 -Ttext 的值為 0x400400,則它的值也應該是 0x400400。
PageDirBase equ 200000h ; 頁目錄開始地址: 2M
PageTblBase equ 201000h ; 頁表開始地址: 2M + 4K
fs/disklog.c
/*************************************************************************//**
*****************************************************************************
* @file disklog.c
* @brief
* @author Forrest Y. Yu
* @date Thu Nov 20 16:22:45 2008
*****************************************************************************
*****************************************************************************/
#include "type.h"
#include "config.h"
#include "stdio.h"
#include "const.h"
#include "protect.h"
#include "string.h"
#include "fs.h"
#include "proc.h"
#include "tty.h"
#include "console.h"
#include "global.h"
#include "keyboard.h"
#include "proto.h"
#include "hd.h"
#include "fs.h"
static char _buf[SECTOR_SIZE];
/*****************************************************************************
* do_disklog
*****************************************************************************/
/**
* Perform syslog() system call .
*
* @return
*****************************************************************************/
PUBLIC int do_disklog()
{
char buf[STR_DEFAULT_LEN];
/* get parameters from the message */
int str_len = fs_msg.CNT; /* length of filename */
int src = fs_msg.source; /* caller proc nr. */
assert(str_len < STR_DEFAULT_LEN);
phys_copy((void*)va2la(TASK_FS, buf), /* to */
(void*)va2la(src, fs_msg.BUF), /* from */
str_len);
buf[str_len] = 0; /* terminate the string */
return disklog(buf);
}
/*****************************************************************************
* disklog
*****************************************************************************/
/**
* <Ring 1> This routine handles the DEV_LOG message.
*
* @param p Ptr to the MESSAGE.
*****************************************************************************/
PUBLIC int disklog(char * logstr)
{
int device = root_inode->i_dev;
struct super_block * sb = get_super_block(device);
int nr_log_blk0_nr = sb->nr_sects - NR_SECTS_FOR_LOG; /* 0x9D41-0x800=0x9541 */
static int pos = 0;
if (!pos) { /* first time invoking this routine */
#ifdef SET_LOG_SECT_SMAP_AT_STARTUP
/*
* set sector-map so that other files cannot use the log sectors
*/
int bits_per_sect = SECTOR_SIZE * 8; /* 4096 */
int smap_blk0_nr = 1 + 1 + sb->nr_imap_sects; /* 3 */
int sect_nr = smap_blk0_nr + nr_log_blk0_nr / bits_per_sect; /* 3+9=12 */
int byte_off = (nr_log_blk0_nr % bits_per_sect) / 8; /* 168 */
int bit_off = (nr_log_blk0_nr % bits_per_sect) % 8; /* 1 */
int sect_cnt = NR_SECTS_FOR_LOG / bits_per_sect + 2; /* 1 */
int bits_left= NR_SECTS_FOR_LOG; /* 2048 */
int i;
for (i = 0; i < sect_cnt; i++) {
RD_SECT(device, sect_nr + i); /* RD_SECT(?, 12) */
for (; byte_off < SECTOR_SIZE && bits_left > 0; byte_off++) {
for (; bit_off < 8; bit_off++) { /* repeat till enough bits are set */
assert(((fsbuf[byte_off] >> bit_off) & 1) == 0);
fsbuf[byte_off] |= (1 << bit_off);
if (--bits_left == 0)
break;
}
bit_off = 0;
}
byte_off = 0;
bit_off = 0;
WR_SECT(device, sect_nr + i);
if (bits_left == 0)
break;
}
assert(bits_left == 0);
#endif /* SET_LOG_SECT_SMAP_AT_STARTUP */
pos = 0x40;
#ifdef MEMSET_LOG_SECTS
/* write padding stuff to log sectors */
int chunk = min(MAX_IO_BYTES, FSBUF_SIZE >> SECTOR_SIZE_SHIFT);
assert(chunk == 256);
int sects_left = NR_SECTS_FOR_LOG;
for (i = nr_log_blk0_nr;
i < nr_log_blk0_nr + NR_SECTS_FOR_LOG;
i += chunk) {
memset(fsbuf, 0x20, chunk*SECTOR_SIZE);
rw_sector(DEV_WRITE,
device,
i * SECTOR_SIZE,
chunk * SECTOR_SIZE,
TASK_FS,
fsbuf);
sects_left -= chunk;
}
if (sects_left != 0)
panic("sects_left should be 0, current: %d.", sects_left);
#endif /* MEMSET_LOG_SECTS */
}
char * p = logstr;
int bytes_left = strlen(logstr);
int sect_nr = nr_log_blk0_nr + (pos >> SECTOR_SIZE_SHIFT);
while (bytes_left) {
RD_SECT(device, sect_nr);
int off = pos % SECTOR_SIZE;
int bytes = min(bytes_left, SECTOR_SIZE - off);
memcpy(&fsbuf[off], p, bytes);
off += bytes;
bytes_left -= bytes;
WR_SECT(device, sect_nr);
sect_nr++;
pos += bytes;
p += bytes;
}
/* write `pos' into the log file header */
RD_SECT(device, nr_log_blk0_nr);
sprintf((char*)fsbuf, "%8d\n", pos);
memset(fsbuf+9, ' ', 22);
fsbuf[31] = '\n';
memset(fsbuf+32, ' ', 31);
fsbuf[63] = '\n';
WR_SECT(device, nr_log_blk0_nr);
memset(fsbuf+64, fsbuf[32+19], 512-64);
WR_SECT(device, nr_log_blk0_nr + NR_SECTS_FOR_LOG - 1);
return pos;
}
/*****************************************************************************
* dump_fd_graph
*****************************************************************************/
/**
* Output a dot graph.
*
*****************************************************************************/
PUBLIC void dump_fd_graph(const char * fmt, ...)
{
int i;
char title[STR_DEFAULT_LEN];
va_list arg = (va_list)((char*)(&fmt) + 4); /**
* 4: size of `fmt' in
* the stack
*/
i = vsprintf(title, fmt, arg);
assert(strlen(title) == i);
static int graph_idx = 0;
char filename[MAX_FILENAME_LEN+1];
char * proc_flags[32];
proc_flags[0x02] = "SENDING";
proc_flags[0x04] = "RECEIVING";
proc_flags[0x08] = "WAITING";
proc_flags[0x10] = "FREE_SLOT";
struct proc_fdesc_map {
int pid; /* PID */
int filp; /* idx of proc_table[pid].filp[] */
int desc; /* idx of f_desc_table[] */
} pfm[256];
int pfm_idx = 0;
struct fdesc_inode_map {
int desc; /* idx of f_desc_table[] */
int inode; /* idx of inode_table[] */
} fim[256];
int fim_idx = 0;
/* head */
SYSLOG("digraph filedesc%02d {\n", graph_idx++);
SYSLOG("\tgraph [\n");
SYSLOG(" rankdir = \"LR\"\n");
SYSLOG(" ];\n");
SYSLOG(" node [\n");
SYSLOG(" fontsize = \"16\"\n");
SYSLOG(" shape = \"ellipse\"\n");
SYSLOG(" ];\n");
SYSLOG(" edge [\n");
SYSLOG(" ];\n");
int k;
struct proc* p_proc = proc_table;
SYSLOG("\n\tsubgraph cluster_0 {\n");
for (i = 0; i < NR_TASKS + NR_PROCS; i++,p_proc++) {
/* skip procs which open no files */
for (k = 0; k < NR_FILES; k++) {
if (p_proc->filp[k] != 0)
break;
}
if (k == NR_FILES)
continue;
SYSLOG("\t\t\"proc%d\" [\n", i);
SYSLOG("\t\t\tlabel = \"<f0>%s (%d) "
"|<f1> p_flags:%d(%s)",
p_proc->name,
i,
p_proc->p_flags,
proc_flags[p_proc->p_flags]);
int fnr = 3;
for (k = 0; k < NR_FILES; k++) {
if (p_proc->filp[k] == 0)
continue;
int fdesc_tbl_idx = p_proc->filp[k] - f_desc_table;
SYSLOG("\t|<f%d> filp[%d]: %d",
fnr,
k,
fdesc_tbl_idx);
pfm[pfm_idx].pid = i;
pfm[pfm_idx].filp = fnr;
pfm[pfm_idx].desc = fdesc_tbl_idx;
fnr++;
pfm_idx++;
}
SYSLOG("\t\"\n");
SYSLOG("\t\t\tshape = \"record\"\n");
SYSLOG("\t\t];\n");
}
SYSLOG("\t\tlabel = \"procs\";\n");
SYSLOG("\t}\n");
SYSLOG("\n\tsubgraph cluster_1 {\n");
for (i = 0; i < NR_FILE_DESC; i++) {
if (f_desc_table[i].fd_inode == 0)
continue;
int inode_tbl_idx = f_desc_table[i].fd_inode - inode_table;
SYSLOG("\t\t\"filedesc%d\" [\n", i);
SYSLOG("\t\t\tlabel = \"<f0>filedesc %d"
"|<f1> fd_mode:%d"
"|<f2> fd_pos:%d"
"|<f4> fd_inode:%d",
i,
f_desc_table[i].fd_mode,
f_desc_table[i].fd_pos,
inode_tbl_idx);
fim[fim_idx].desc = i;
fim[fim_idx].inode = inode_tbl_idx;
fim_idx++;
SYSLOG("\t\"\n");
SYSLOG("\t\t\tshape = \"record\"\n");
SYSLOG("\t\t];\n");
}
SYSLOG("\t\tlabel = \"filedescs\";\n");
SYSLOG("\t}\n");
SYSLOG("\n\tsubgraph cluster_2 {\n");
for (i = 0; i < NR_INODE; i++) {
if (inode_table[i].i_cnt == 0)
continue;
SYSLOG("\t\t\"inode%d\" [\n", i);
SYSLOG("\t\t\tlabel = \"<f0>inode %d"
"|<f1> i_mode:0x%x"
"|<f2> i_size:0x%x"
"|<f3> i_start_sect:0x%x"
"|<f4> i_nr_sects:0x%x"
"|<f5> i_dev:0x%x"
"|<f6> i_cnt:%d"
"|<f7> i_num:%d",
inode_table[i].i_num,
inode_table[i].i_mode,
inode_table[i].i_size,
inode_table[i].i_start_sect,
inode_table[i].i_nr_sects,
inode_table[i].i_dev,
inode_table[i].i_cnt,
inode_table[i].i_num);
assert(filename != 0);
SYSLOG("\t\"\n");
SYSLOG("\t\t\tshape = \"record\"\n");
SYSLOG("\t\t];\n");
}
SYSLOG("\t\tlabel = \"inodes\";\n");
SYSLOG("\t}\n");
SYSLOG("\n\tsubgraph cluster_3 {\n");
SYSLOG("\n\t\tstyle=filled;\n");
SYSLOG("\n\t\tcolor=lightgrey;\n");
int smap_flag = 0;
int bit_start = 0;
/* i: sector index */
int j; /* byte index */
/* k: bit index */
struct super_block * sb = get_super_block(root_inode->i_dev);
int smap_blk0_nr = 1 + 1 + sb->nr_imap_sects;
for (i = 0; i < sb->nr_smap_sects; i++) { /* smap_blk0_nr + i : current sect nr. */
RD_SECT(root_inode->i_dev, smap_blk0_nr + i);
memcpy(_buf, fsbuf, SECTOR_SIZE);
for (j = 0; j < SECTOR_SIZE; j++) {
for (k = 0; k < 8; k++) {
if (!smap_flag) {
if ((_buf[j] >> k ) & 1) {
smap_flag = 1;
bit_start = (i * SECTOR_SIZE + j) * 8 + k;
}
else {
continue;
}
}
else {
if ((_buf[j] >> k ) & 1) {
continue;
}
else {
smap_flag = 0;
int bit_end = (i * SECTOR_SIZE + j) * 8 + k - 1;
SYSLOG("\t\t\"sector %xh\" [\n", bit_start);
SYSLOG("\t\t\tlabel = \"<f0>sect %xh-%xh",
bit_start,
bit_end);
SYSLOG("\t\"\n");
SYSLOG("\t\t\tshape = \"record\"\n");
SYSLOG("\t\t];\n");
}
}
}
}
}
SYSLOG("\t\tlabel = \"sector map (dev size: %xh)\";\n", sb->nr_sects);
SYSLOG("\t}\n");
SYSLOG("\n\tsubgraph cluster_4 {\n");
SYSLOG("\n\t\tstyle=filled;\n");
SYSLOG("\n\t\tcolor=lightgrey;\n");
SYSLOG("\t\t\"imap\" [\n");
SYSLOG("\t\t\tlabel = \"<f0>bits");
/* i: sector index */
/* j: byte index */
/* k: bit index */
int imap_blk0_nr = 1 + 1;
for (i = 0; i < sb->nr_imap_sects; i++) { /* smap_blk0_nr + i : current sect nr. */
RD_SECT(root_inode->i_dev, imap_blk0_nr + i);
memcpy(_buf, fsbuf, SECTOR_SIZE);
for (j = 0; j < SECTOR_SIZE; j++) {
for (k = 0; k < 8; k++) {
if ((_buf[j] >> k ) & 1) {
int bit_nr = (i * SECTOR_SIZE + j) * 8 + k;
SYSLOG("| %xh ", bit_nr);
}
}
}
}
SYSLOG("\t\"\n");
SYSLOG("\t\t\tshape = \"record\"\n");
SYSLOG("\t\t];\n");
SYSLOG("\t\tlabel = \"inode map\";\n");
SYSLOG("\t}\n");
SYSLOG("\n\tsubgraph cluster_5 {\n");
SYSLOG("\n\t\tstyle=filled;\n");
SYSLOG("\n\t\tcolor=lightgrey;\n");
sb = get_super_block(root_inode->i_dev);
int blk_nr = 1 + 1 + sb->nr_imap_sects + sb->nr_smap_sects;
RD_SECT(root_inode->i_dev, blk_nr);
memcpy(_buf, fsbuf, SECTOR_SIZE);
char * p = _buf;
for (i = 0; i < SECTOR_SIZE / sizeof(struct inode); i++,p+=INODE_SIZE) {
struct inode * pinode = (struct inode*)p;
if (pinode->i_start_sect == 0)
continue;
int start_sect;
int end_sect;
if (pinode->i_mode != I_CHAR_SPECIAL) {
if (pinode->i_start_sect < sb->n_1st_sect) {
panic("should not happen: %x < %x.",
pinode->i_start_sect,
sb->n_1st_sect);
}
start_sect = pinode->i_start_sect - sb->n_1st_sect + 1;
end_sect = start_sect + pinode->i_nr_sects - 1;
SYSLOG("\t\t\"inodearray%d\" [\n", i+1);
SYSLOG("\t\t\tlabel = \"<f0> %d"
"|<f2> i_size:0x%x"
"|<f3> sect: %xh-%xh",
i+1,
pinode->i_size,
start_sect,
end_sect);
SYSLOG("\t\"\n");
SYSLOG("\t\t\tshape = \"record\"\n");
SYSLOG("\t\t];\n");
}
else {
start_sect = MAJOR(pinode->i_start_sect);
end_sect = MINOR(pinode->i_start_sect);
SYSLOG("\t\t\"inodearray%d\" [\n", i+1);
SYSLOG("\t\t\tlabel = \"<f0> %d"
"|<f2> i_size:0x%x"
"|<f3> dev nr: (%xh,%xh)",
i+1,
pinode->i_size,
start_sect,
end_sect);
SYSLOG("\t\"\n");
SYSLOG("\t\t\tshape = \"record\"\n");
SYSLOG("\t\t];\n");
}
}
SYSLOG("\t\tlabel = \"inode array\";\n");
SYSLOG("\t}\n");
SYSLOG("\n\tsubgraph cluster_6 {\n");
SYSLOG("\n\t\tstyle=filled;\n");
SYSLOG("\n\t\tcolor=lightgrey;\n");
sb = get_super_block(root_inode->i_dev);
int dir_blk0_nr = root_inode->i_start_sect;
int nr_dir_blks = (root_inode->i_size + SECTOR_SIZE - 1) / SECTOR_SIZE;
int nr_dir_entries =
root_inode->i_size / DIR_ENTRY_SIZE; /**
* including unused slots
* (the file has been deleted
* but the slot is still there)
*/
int m = 0;
struct dir_entry * pde;
for (i = 0; i < nr_dir_blks; i++) {
RD_SECT(root_inode->i_dev, dir_blk0_nr + i);
memcpy(_buf, fsbuf, SECTOR_SIZE);
pde = (struct dir_entry *)_buf;
for (j = 0; j < SECTOR_SIZE / DIR_ENTRY_SIZE; j++,pde++) {
if (pde->inode_nr) {
memcpy(filename, pde->name, MAX_FILENAME_LEN);
if (filename[0] == '.')
filename[0] = '/';
SYSLOG("\t\t\"rootdirent%d\" [\n", pde->inode_nr);
SYSLOG("\t\t\tlabel = \"<f0> %d"
"|<f2> %s",
pde->inode_nr,
filename);
SYSLOG("\t\"\n");
SYSLOG("\t\t\tshape = \"record\"\n");
SYSLOG("\t\t];\n");
SYSLOG("\t"
"\"inodearray%d\":f0"
" -> "
"\"rootdirent%d\":f0"
";\n",
pde->inode_nr, pde->inode_nr);
}
}
if (m > nr_dir_entries) /* all entries have been iterated */
break;
}
SYSLOG("\t\tlabel = \"root dir\";\n");
SYSLOG("\t}\n");
for (i = 0; i < pfm_idx; i++) {
SYSLOG("\t\"proc%d\":f%d -> \"filedesc%d\":f0;\n",
pfm[i].pid,
pfm[i].filp,
pfm[i].desc);
}
for (i = 0; i < fim_idx; i++) {
SYSLOG("\t\"filedesc%d\":f4 -> \"inode%d\":f6;\n",
fim[i].desc,
fim[i].inode);
}
for (i = 0; i < NR_INODE; i++) {
if (inode_table[i].i_cnt != 0)
SYSLOG("\t\"inode%d\":f7 -> \"inodearray%d\":f0;\n",
i,
inode_table[i].i_num);
}
/* tail */
SYSLOG("\tlabel = \"%s\";\n", title);
SYSLOG("}\n");
/* separator */
SYSLOG("--separator--\n");
/* int pos = SYSLOG("--separator--\n"); */
/* printl("dump_fd_graph(%s)::logpos:%d\n", title, pos); */
}
fs/link.c
/*************************************************************************//**
*****************************************************************************
* @file link.c
* @brief
* @author Forrest Y. Yu
* @date Tue Jun 3 17:05:10 2008
*****************************************************************************
*****************************************************************************/
#include "type.h"
#include "stdio.h"
#include "const.h"
#include "protect.h"
#include "string.h"
#include "fs.h"
#include "proc.h"
#include "tty.h"
#include "console.h"
#include "global.h"
#include "keyboard.h"
#include "proto.h"
/*****************************************************************************
* do_unlink
*****************************************************************************/
/**
* Remove a file.
*
* @note We clear the i-node in inode_array[] although it is not really needed.
* We don't clear the data bytes so the file is recoverable.
*
* @return On success, zero is returned. On error, -1 is returned.
*****************************************************************************/
PUBLIC int do_unlink()
{
char pathname[MAX_PATH];
/* get parameters from the message */
int name_len = fs_msg.NAME_LEN; /* length of filename */
int src = fs_msg.source; /* caller proc nr. */
assert(name_len < MAX_PATH);
phys_copy((void*)va2la(TASK_FS, pathname),
(void*)va2la(src, fs_msg.PATHNAME),
name_len);
pathname[name_len] = 0;
if (strcmp(pathname , "/") == 0) {
printl("FS:do_unlink():: cannot unlink the root\n");
return -1;
}
int inode_nr = search_file(pathname);
if (inode_nr == INVALID_INODE) { /* file not found */
printl("FS::do_unlink():: search_file() returns "
"invalid inode: %s\n", pathname);
return -1;
}
char filename[MAX_PATH];
struct inode * dir_inode;
if (strip_path(filename, pathname, &dir_inode) != 0)
return -1;
struct inode * pin = get_inode(dir_inode->i_dev, inode_nr);
if (pin->i_mode != I_REGULAR) { /* can only remove regular files */
printl("cannot remove file %s, because "
"it is not a regular file.\n",
pathname);
return -1;
}
if (pin->i_cnt > 1) { /* the file was opened */
printl("cannot remove file %s, because pin->i_cnt is %d.\n",
pathname, pin->i_cnt);
return -1;
}
struct super_block * sb = get_super_block(pin->i_dev);
/*************************/
/* free the bit in i-map */
/*************************/
int byte_idx = inode_nr / 8;
int bit_idx = inode_nr % 8;
assert(byte_idx < SECTOR_SIZE); /* we have only one i-map sector */
/* read sector 2 (skip bootsect and superblk): */
RD_SECT(pin->i_dev, 2);
assert(fsbuf[byte_idx % SECTOR_SIZE] & (1 << bit_idx));
fsbuf[byte_idx % SECTOR_SIZE] &= ~(1 << bit_idx);
WR_SECT(pin->i_dev, 2);
/**************************/
/* free the bits in s-map */
/**************************/
/*
* bit_idx: bit idx in the entire i-map
* ... ____|____
* \ .-- byte_cnt: how many bytes between
* \ | the first and last byte
* +-+-+-+-+-+-+-+-+ V +-+-+-+-+-+-+-+-+
* ... | | | | | |*|*|*|...|*|*|*|*| | | | |
* +-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+
* 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7
* ...__/
* byte_idx: byte idx in the entire i-map
*/
bit_idx = pin->i_start_sect - sb->n_1st_sect + 1;
byte_idx = bit_idx / 8;
int bits_left = pin->i_nr_sects;
int byte_cnt = (bits_left - (8 - (bit_idx % 8))) / 8;
/* current sector nr. */
int s = 2 /* 2: bootsect + superblk */
+ sb->nr_imap_sects + byte_idx / SECTOR_SIZE;
RD_SECT(pin->i_dev, s);
int i;
/* clear the first byte */
for (i = bit_idx % 8; (i < 8) && bits_left; i++,bits_left--) {
assert((fsbuf[byte_idx % SECTOR_SIZE] >> i & 1) == 1);
fsbuf[byte_idx % SECTOR_SIZE] &= ~(1 << i);
}
/* clear bytes from the second byte to the second to last */
int k;
i = (byte_idx % SECTOR_SIZE) + 1; /* the second byte */
for (k = 0; k < byte_cnt; k++,i++,bits_left-=8) {
if (i == SECTOR_SIZE) {
i = 0;
WR_SECT(pin->i_dev, s);
RD_SECT(pin->i_dev, ++s);
}
assert(fsbuf[i] == 0xFF);
fsbuf[i] = 0;
}
/* clear the last byte */
if (i == SECTOR_SIZE) {
i = 0;
WR_SECT(pin->i_dev, s);
RD_SECT(pin->i_dev, ++s);
}
unsigned char mask = ~((unsigned char)(~0) << bits_left);
assert((fsbuf[i] & mask) == mask);
fsbuf[i] &= (~0) << bits_left;
WR_SECT(pin->i_dev, s);
/***************************/
/* clear the i-node itself */
/***************************/
pin->i_mode = 0;
pin->i_size = 0;
pin->i_start_sect = 0;
pin->i_nr_sects = 0;
sync_inode(pin);
/* release slot in inode_table[] */
put_inode(pin);
/************************************************/
/* set the inode-nr to 0 in the directory entry */
/************************************************/
int dir_blk0_nr = dir_inode->i_start_sect;
int nr_dir_blks = (dir_inode->i_size + SECTOR_SIZE) / SECTOR_SIZE;
int nr_dir_entries =
dir_inode->i_size / DIR_ENTRY_SIZE; /* including unused slots
* (the file has been
* deleted but the slot
* is still there)
*/
int m = 0;
struct dir_entry * pde = 0;
int flg = 0;
int dir_size = 0;
for (i = 0; i < nr_dir_blks; i++) {
RD_SECT(dir_inode->i_dev, dir_blk0_nr + i);
pde = (struct dir_entry *)fsbuf;
int j;
for (j = 0; j < SECTOR_SIZE / DIR_ENTRY_SIZE; j++,pde++) {
if (++m > nr_dir_entries)
break;
if (pde->inode_nr == inode_nr) {
/* pde->inode_nr = 0; */
memset(pde, 0, DIR_ENTRY_SIZE);
WR_SECT(dir_inode->i_dev, dir_blk0_nr + i);
flg = 1;
break;
}
if (pde->inode_nr != INVALID_INODE)
dir_size += DIR_ENTRY_SIZE;
}
if (m > nr_dir_entries || /* all entries have been iterated OR */
flg) /* file is found */
break;
}
assert(flg);
if (m == nr_dir_entries) { /* the file is the last one in the dir */
dir_inode->i_size = dir_size;
sync_inode(dir_inode);
}
return 0;
}
fs/main.c
/*************************************************************************//**
*****************************************************************************
* @file main.c
* @brief
* @author Forrest Y. Yu
* @date 2007
*****************************************************************************
*****************************************************************************/
#include "type.h"
#include "config.h"
#include "stdio.h"
#include "const.h"
#include "protect.h"
#include "string.h"
#include "fs.h"
#include "proc.h"
#include "tty.h"
#include "console.h"
#include "global.h"
#include "proto.h"
#include "hd.h"
PRIVATE void init_fs();
PRIVATE void mkfs();
PRIVATE void read_super_block(int dev);
/*****************************************************************************
* task_fs
*****************************************************************************/
/**
* <Ring 1> The main loop of TASK FS.
*
*****************************************************************************/
PUBLIC void task_fs()
{
printl("Task FS begins.\n");
init_fs();
while (1) {
send_recv(RECEIVE, ANY, &fs_msg);
int msgtype = fs_msg.type;
int src = fs_msg.source;
pcaller = &proc_table[src];
switch (msgtype) {
case OPEN:
fs_msg.FD = do_open();
break;
case CLOSE:
fs_msg.RETVAL = do_close();
break;
case READ:
case WRITE:
fs_msg.CNT = do_rdwt();
break;
case UNLINK:
fs_msg.RETVAL = do_unlink();
break;
/* case LSEEK: */
/* fs_msg.OFFSET = do_lseek(); */
/* break; */
/* case RESUME_PROC: */
/* src = fs_msg.PROC_NR; */
/* break; */
/* case FORK: */
/* fs_msg.RETVAL = fs_fork(); */
/* break; */
/* case EXIT: */
/* fs_msg.RETVAL = fs_exit(); */
/* break; */
/* case STAT: */
/* fs_msg.RETVAL = do_stat(); */
/* break; */
default:
dump_msg("FS::unknown message:", &fs_msg);
assert(0);
break;
}
#ifdef ENABLE_DISK_LOG
char * msg_name[128];
msg_name[OPEN] = "OPEN";
msg_name[CLOSE] = "CLOSE";
msg_name[READ] = "READ";
msg_name[WRITE] = "WRITE";
msg_name[LSEEK] = "LSEEK";
msg_name[UNLINK] = "UNLINK";
/* msg_name[FORK] = "FORK"; */
/* msg_name[EXIT] = "EXIT"; */
/* msg_name[STAT] = "STAT"; */
switch (msgtype) {
case CLOSE:
case UNLINK:
//dump_fd_graph("%s just finished.", msg_name[msgtype]);
//panic("");
case OPEN:
case READ:
case WRITE:
/* case FORK: */
/* case LSEEK: */
/* case EXIT: */
/* case STAT: */
break;
/* case RESUME_PROC: */
case DISK_LOG:
break;
default:
assert(0);
}
#endif
/* reply */
fs_msg.type = SYSCALL_RET;
send_recv(SEND, src, &fs_msg);
}
}
/*****************************************************************************
* init_fs
*****************************************************************************/
/**
* <Ring 1> Do some preparation.
*
*****************************************************************************/
PRIVATE void init_fs()
{
int i;
/* f_desc_table[] */
for (i = 0; i < NR_FILE_DESC; i++)
memset(&f_desc_table[i], 0, sizeof(struct file_desc));
/* inode_table[] */
for (i = 0; i < NR_INODE; i++)
memset(&inode_table[i], 0, sizeof(struct inode));
/* super_block[] */
struct super_block * sb = super_block;
for (; sb < &super_block[NR_SUPER_BLOCK]; sb++)
sb->sb_dev = NO_DEV;
/* open the device: hard disk */
MESSAGE driver_msg;
driver_msg.type = DEV_OPEN;
driver_msg.DEVICE = MINOR(ROOT_DEV);
assert(dd_map[MAJOR(ROOT_DEV)].driver_nr != INVALID_DRIVER);
send_recv(BOTH, dd_map[MAJOR(ROOT_DEV)].driver_nr, &driver_msg);
/* make FS */
mkfs();
/* load super block of ROOT */
read_super_block(ROOT_DEV);
sb = get_super_block(ROOT_DEV);
assert(sb->magic == MAGIC_V1);
root_inode = get_inode(ROOT_DEV, ROOT_INODE);
}
/*****************************************************************************
* mkfs
*****************************************************************************/
/**
* <Ring 1> Make a available Orange'S FS in the disk. It will
* - Write a super block to sector 1.
* - Create three special files: dev_tty0, dev_tty1, dev_tty2
* - Create the inode map
* - Create the sector map
* - Create the inodes of the files
* - Create `/', the root directory
*****************************************************************************/
PRIVATE void mkfs()
{
MESSAGE driver_msg;
int i, j;
int bits_per_sect = SECTOR_SIZE * 8; /* 8 bits per byte */
/* get the geometry of ROOTDEV */
struct part_info geo;
driver_msg.type = DEV_IOCTL;
driver_msg.DEVICE = MINOR(ROOT_DEV);
driver_msg.REQUEST = DIOCTL_GET_GEO;
driver_msg.BUF = &geo;
driver_msg.PROC_NR = TASK_FS;
assert(dd_map[MAJOR(ROOT_DEV)].driver_nr != INVALID_DRIVER);
send_recv(BOTH, dd_map[MAJOR(ROOT_DEV)].driver_nr, &driver_msg);
printl("dev size: 0x%x sectors\n", geo.size);
/************************/
/* super block */
/************************/
struct super_block sb;
sb.magic = MAGIC_V1;
sb.nr_inodes = bits_per_sect;
sb.nr_inode_sects = sb.nr_inodes * INODE_SIZE / SECTOR_SIZE;
sb.nr_sects = geo.size; /* partition size in sector */
sb.nr_imap_sects = 1;
sb.nr_smap_sects = sb.nr_sects / bits_per_sect + 1;
sb.n_1st_sect = 1 + 1 + /* boot sector & super block */
sb.nr_imap_sects + sb.nr_smap_sects + sb.nr_inode_sects;
sb.root_inode = ROOT_INODE;
sb.inode_size = INODE_SIZE;
struct inode x;
sb.inode_isize_off= (int)&x.i_size - (int)&x;
sb.inode_start_off= (int)&x.i_start_sect - (int)&x;
sb.dir_ent_size = DIR_ENTRY_SIZE;
struct dir_entry de;
sb.dir_ent_inode_off = (int)&de.inode_nr - (int)&de;
sb.dir_ent_fname_off = (int)&de.name - (int)&de;
memset(fsbuf, 0x90, SECTOR_SIZE);
memcpy(fsbuf, &sb, SUPER_BLOCK_SIZE);
/* write the super block */
WR_SECT(ROOT_DEV, 1);
printl("devbase:0x%x00, sb:0x%x00, imap:0x%x00, smap:0x%x00\n"
" inodes:0x%x00, 1st_sector:0x%x00\n",
geo.base * 2,
(geo.base + 1) * 2,
(geo.base + 1 + 1) * 2,
(geo.base + 1 + 1 + sb.nr_imap_sects) * 2,
(geo.base + 1 + 1 + sb.nr_imap_sects + sb.nr_smap_sects) * 2,
(geo.base + sb.n_1st_sect) * 2);
/************************/
/* inode map */
/************************/
memset(fsbuf, 0, SECTOR_SIZE);
for (i = 0; i < (NR_CONSOLES + 2); i++)
fsbuf[0] |= 1 << i;
assert(fsbuf[0] == 0x1F);/* 0001 1111 :
* | ||||
* | |||`--- bit 0 : reserved
* | ||`---- bit 1 : the first inode,
* | || which indicates `/'
* | |`----- bit 2 : /dev_tty0
* | `------ bit 3 : /dev_tty1
* `-------- bit 4 : /dev_tty2
*/
WR_SECT(ROOT_DEV, 2);
/************************/
/* secter map */
/************************/
memset(fsbuf, 0, SECTOR_SIZE);
int nr_sects = NR_DEFAULT_FILE_SECTS + 1;
/* ~~~~~~~~~~~~~~~~~~~|~ |
* | `--- bit 0 is reserved
* `-------- for `/'
*/
for (i = 0; i < nr_sects / 8; i++)
fsbuf[i] = 0xFF;
for (j = 0; j < nr_sects % 8; j++)
fsbuf[i] |= (1 << j);
WR_SECT(ROOT_DEV, 2 + sb.nr_imap_sects);
/* zeromemory the rest sector-map */
memset(fsbuf, 0, SECTOR_SIZE);
for (i = 1; i < sb.nr_smap_sects; i++)
WR_SECT(ROOT_DEV, 2 + sb.nr_imap_sects + i);
/************************/
/* inodes */
/************************/
/* inode of `/' */
memset(fsbuf, 0, SECTOR_SIZE);
struct inode * pi = (struct inode*)fsbuf;
pi->i_mode = I_DIRECTORY;
pi->i_size = DIR_ENTRY_SIZE * 4; /* 4 files:
* `.',
* `dev_tty0', `dev_tty1', `dev_tty2',
*/
pi->i_start_sect = sb.n_1st_sect;
pi->i_nr_sects = NR_DEFAULT_FILE_SECTS;
/* inode of `/dev_tty0~2' */
for (i = 0; i < NR_CONSOLES; i++) {
pi = (struct inode*)(fsbuf + (INODE_SIZE * (i + 1)));
pi->i_mode = I_CHAR_SPECIAL;
pi->i_size = 0;
pi->i_start_sect = MAKE_DEV(DEV_CHAR_TTY, i);
pi->i_nr_sects = 0;
}
WR_SECT(ROOT_DEV, 2 + sb.nr_imap_sects + sb.nr_smap_sects);
/************************/
/* `/' */
/************************/
memset(fsbuf, 0, SECTOR_SIZE);
struct dir_entry * pde = (struct dir_entry *)fsbuf;
pde->inode_nr = 1;
strcpy(pde->name, ".");
/* dir entries of `/dev_tty0~2' */
for (i = 0; i < NR_CONSOLES; i++) {
pde++;
pde->inode_nr = i + 2; /* dev_tty0's inode_nr is 2 */
sprintf(pde->name, "dev_tty%d", i);
}
WR_SECT(ROOT_DEV, sb.n_1st_sect);
}
/*****************************************************************************
* rw_sector
*****************************************************************************/
/**
* <Ring 1> R/W a sector via messaging with the corresponding driver.
*
* @param io_type DEV_READ or DEV_WRITE
* @param dev device nr
* @param pos Byte offset from/to where to r/w.
* @param bytes r/w count in bytes.
* @param proc_nr To whom the buffer belongs.
* @param buf r/w buffer.
*
* @return Zero if success.
*****************************************************************************/
PUBLIC int rw_sector(int io_type, int dev, u64 pos, int bytes, int proc_nr,
void* buf)
{
MESSAGE driver_msg;
driver_msg.type = io_type;
driver_msg.DEVICE = MINOR(dev);
driver_msg.POSITION = pos;
driver_msg.BUF = buf;
driver_msg.CNT = bytes;
driver_msg.PROC_NR = proc_nr;
assert(dd_map[MAJOR(dev)].driver_nr != INVALID_DRIVER);
send_recv(BOTH, dd_map[MAJOR(dev)].driver_nr, &driver_msg);
return 0;
}
/*****************************************************************************
* read_super_block
*****************************************************************************/
/**
* <Ring 1> Read super block from the given device then write it into a free
* super_block[] slot.
*
* @param dev From which device the super block comes.
*****************************************************************************/
PRIVATE void read_super_block(int dev)
{
int i;
MESSAGE driver_msg;
driver_msg.type = DEV_READ;
driver_msg.DEVICE = MINOR(dev);
driver_msg.POSITION = SECTOR_SIZE * 1;
driver_msg.BUF = fsbuf;
driver_msg.CNT = SECTOR_SIZE;
driver_msg.PROC_NR = TASK_FS;
assert(dd_map[MAJOR(dev)].driver_nr != INVALID_DRIVER);
send_recv(BOTH, dd_map[MAJOR(dev)].driver_nr, &driver_msg);
/* find a free slot in super_block[] */
for (i = 0; i < NR_SUPER_BLOCK; i++)
if (super_block[i].sb_dev == NO_DEV)
break;
if (i == NR_SUPER_BLOCK)
panic("super_block slots used up");
assert(i == 0); /* currently we use only the 1st slot */
struct super_block * psb = (struct super_block *)fsbuf;
super_block[i] = *psb;
super_block[i].sb_dev = dev;
}
/*****************************************************************************
* get_super_block
*****************************************************************************/
/**
* <Ring 1> Get the super block from super_block[].
*
* @param dev Device nr.
*
* @return Super block ptr.
*****************************************************************************/
PUBLIC struct super_block * get_super_block(int dev)
{
struct super_block * sb = super_block;
for (; sb < &super_block[NR_SUPER_BLOCK]; sb++)
if (sb->sb_dev == dev)
return sb;
panic("super block of devie %d not found.\n", dev);
return 0;
}
/*****************************************************************************
* get_inode
*****************************************************************************/
/**
* <Ring 1> Get the inode ptr of given inode nr. A cache -- inode_table[] -- is
* maintained to make things faster. If the inode requested is already there,
* just return it. Otherwise the inode will be read from the disk.
*
* @param dev Device nr.
* @param num I-node nr.
*
* @return The inode ptr requested.
*****************************************************************************/
PUBLIC struct inode * get_inode(int dev, int num)
{
if (num == 0)
return 0;
struct inode * p;
struct inode * q = 0;
for (p = &inode_table[0]; p < &inode_table[NR_INODE]; p++) {
if (p->i_cnt) { /* not a free slot */
if ((p->i_dev == dev) && (p->i_num == num)) {
/* this is the inode we want */
p->i_cnt++;
return p;
}
}
else { /* a free slot */
if (!q) /* q hasn't been assigned yet */
q = p; /* q <- the 1st free slot */
}
}
if (!q)
panic("the inode table is full");
q->i_dev = dev;
q->i_num = num;
q->i_cnt = 1;
struct super_block * sb = get_super_block(dev);
int blk_nr = 1 + 1 + sb->nr_imap_sects + sb->nr_smap_sects +
((num - 1) / (SECTOR_SIZE / INODE_SIZE));
RD_SECT(dev, blk_nr);
struct inode * pinode =
(struct inode*)((u8*)fsbuf +
((num - 1 ) % (SECTOR_SIZE / INODE_SIZE))
* INODE_SIZE);
q->i_mode = pinode->i_mode;
q->i_size = pinode->i_size;
q->i_start_sect = pinode->i_start_sect;
q->i_nr_sects = pinode->i_nr_sects;
return q;
}
/*****************************************************************************
* put_inode
*****************************************************************************/
/**
* Decrease the reference nr of a slot in inode_table[]. When the nr reaches
* zero, it means the inode is not used any more and can be overwritten by
* a new inode.
*
* @param pinode I-node ptr.
*****************************************************************************/
PUBLIC void put_inode(struct inode * pinode)
{
assert(pinode->i_cnt > 0);
pinode->i_cnt--;
}
/*****************************************************************************
* sync_inode
*****************************************************************************/
/**
* <Ring 1> Write the inode back to the disk. Commonly invoked as soon as the
* inode is changed.
*
* @param p I-node ptr.
*****************************************************************************/
PUBLIC void sync_inode(struct inode * p)
{
struct inode * pinode;
struct super_block * sb = get_super_block(p->i_dev);
int blk_nr = 1 + 1 + sb->nr_imap_sects + sb->nr_smap_sects +
((p->i_num - 1) / (SECTOR_SIZE / INODE_SIZE));
RD_SECT(p->i_dev, blk_nr);
pinode = (struct inode*)((u8*)fsbuf +
(((p->i_num - 1) % (SECTOR_SIZE / INODE_SIZE))
* INODE_SIZE));
pinode->i_mode = p->i_mode;
pinode->i_size = p->i_size;
pinode->i_start_sect = p->i_start_sect;
pinode->i_nr_sects = p->i_nr_sects;
WR_SECT(p->i_dev, blk_nr);
}
fs/misc.c
/*************************************************************************//**
*****************************************************************************
* @file misc.c
* @brief
* @author Forrest Y. Yu
* @date 2008
*****************************************************************************
*****************************************************************************/
/* Orange'S FS */
#include "type.h"
#include "stdio.h"
#include "const.h"
#include "protect.h"
#include "string.h"
#include "fs.h"
#include "proc.h"
#include "tty.h"
#include "console.h"
#include "global.h"
#include "keyboard.h"
#include "proto.h"
#include "hd.h"
#include "fs.h"
/*****************************************************************************
* search_file
*****************************************************************************/
/**
* Search the file and return the inode_nr.
*
* @param[in] path The full path of the file to search.
* @return Ptr to the i-node of the file if successful, otherwise zero.
*
* @see open()
* @see do_open()
*****************************************************************************/
PUBLIC int search_file(char * path)
{
int i, j;
char filename[MAX_PATH];
memset(filename, 0, MAX_FILENAME_LEN);
struct inode * dir_inode;
if (strip_path(filename, path, &dir_inode) != 0)
return 0;
if (filename[0] == 0) /* path: "/" */
return dir_inode->i_num;
/**
* Search the dir for the file.
*/
int dir_blk0_nr = dir_inode->i_start_sect;
int nr_dir_blks = (dir_inode->i_size + SECTOR_SIZE - 1) / SECTOR_SIZE;
int nr_dir_entries =
dir_inode->i_size / DIR_ENTRY_SIZE; /**
* including unused slots
* (the file has been deleted
* but the slot is still there)
*/
int m = 0;
struct dir_entry * pde;
for (i = 0; i < nr_dir_blks; i++) {
RD_SECT(dir_inode->i_dev, dir_blk0_nr + i);
pde = (struct dir_entry *)fsbuf;
for (j = 0; j < SECTOR_SIZE / DIR_ENTRY_SIZE; j++,pde++) {
if (memcmp(filename, pde->name, MAX_FILENAME_LEN) == 0)
return pde->inode_nr;
if (++m > nr_dir_entries)
break;
}
if (m > nr_dir_entries) /* all entries have been iterated */
break;
}
/* file not found */
return 0;
}
/*****************************************************************************
* strip_path
*****************************************************************************/
/**
* Get the basename from the fullpath.
*
* In Orange'S FS v1.0, all files are stored in the root directory.
* There is no sub-folder thing.
*
* This routine should be called at the very beginning of file operations
* such as open(), read() and write(). It accepts the full path and returns
* two things: the basename and a ptr of the root dir's i-node.
*
* e.g. After stip_path(filename, "/blah", ppinode) finishes, we get:
* - filename: "blah"
* - *ppinode: root_inode
* - ret val: 0 (successful)
*
* Currently an acceptable pathname should begin with at most one `/'
* preceding a filename.
*
* Filenames may contain any character except '/' and '\\0'.
*
* @param[out] filename The string for the result.
* @param[in] pathname The full pathname.
* @param[out] ppinode The ptr of the dir's inode will be stored here.
*
* @return Zero if success, otherwise the pathname is not valid.
*****************************************************************************/
PUBLIC int strip_path(char * filename, const char * pathname,
struct inode** ppinode)
{
const char * s = pathname;
char * t = filename;
if (s == 0)
return -1;
if (*s == '/')
s++;
while (*s) { /* check each character */
if (*s == '/')
return -1;
*t++ = *s++;
/* if filename is too long, just truncate it */
if (t - filename >= MAX_FILENAME_LEN)
break;
}
*t = 0;
*ppinode = root_inode;
return 0;
}
fs/open.c
/*************************************************************************//**
*****************************************************************************
* @file fs/open.c
* The file contains:
* - do_open()
* - do_close()
* - do_lseek()
* - create_file()
* @author Forrest Yu
* @date 2007
*****************************************************************************
*****************************************************************************/
#include "type.h"
#include "stdio.h"
#include "const.h"
#include "protect.h"
#include "string.h"
#include "fs.h"
#include "proc.h"
#include "tty.h"
#include "console.h"
#include "global.h"
#include "keyboard.h"
#include "proto.h"
PRIVATE struct inode * create_file(char * path, int flags);
PRIVATE int alloc_imap_bit(int dev);
PRIVATE int alloc_smap_bit(int dev, int nr_sects_to_alloc);
PRIVATE struct inode * new_inode(int dev, int inode_nr, int start_sect);
PRIVATE void new_dir_entry(struct inode * dir_inode, int inode_nr, char * filename);
/*****************************************************************************
* do_open
*****************************************************************************/
/**
* Open a file and return the file descriptor.
*
* @return File descriptor if successful, otherwise a negative error code.
*****************************************************************************/
PUBLIC int do_open()
{
int fd = -1; /* return value */
char pathname[MAX_PATH];
/* get parameters from the message */
int flags = fs_msg.FLAGS; /* access mode */
int name_len = fs_msg.NAME_LEN; /* length of filename */
int src = fs_msg.source; /* caller proc nr. */
assert(name_len < MAX_PATH);
phys_copy((void*)va2la(TASK_FS, pathname),
(void*)va2la(src, fs_msg.PATHNAME),
name_len);
pathname[name_len] = 0;
/* find a free slot in PROCESS::filp[] */
int i;
for (i = 0; i < NR_FILES; i++) {
if (pcaller->filp[i] == 0) {
fd = i;
break;
}
}
if ((fd < 0) || (fd >= NR_FILES))
panic("filp[] is full (PID:%d)", proc2pid(pcaller));
/* find a free slot in f_desc_table[] */
for (i = 0; i < NR_FILE_DESC; i++)
if (f_desc_table[i].fd_inode == 0)
break;
if (i >= NR_FILE_DESC)
panic("f_desc_table[] is full (PID:%d)", proc2pid(pcaller));
int inode_nr = search_file(pathname);
struct inode * pin = 0;
if (flags & O_CREAT) {
if (inode_nr) {
printl("file exists.\n");
return -1;
}
else {
pin = create_file(pathname, flags);
}
}
else {
assert(flags & O_RDWR);
char filename[MAX_PATH];
struct inode * dir_inode;
if (strip_path(filename, pathname, &dir_inode) != 0)
return -1;
pin = get_inode(dir_inode->i_dev, inode_nr);
}
if (pin) {
/* connects proc with file_descriptor */
pcaller->filp[fd] = &f_desc_table[i];
/* connects file_descriptor with inode */
f_desc_table[i].fd_inode = pin;
f_desc_table[i].fd_mode = flags;
/* f_desc_table[i].fd_cnt = 1; */
f_desc_table[i].fd_pos = 0;
int imode = pin->i_mode & I_TYPE_MASK;
if (imode == I_CHAR_SPECIAL) {
MESSAGE driver_msg;
driver_msg.type = DEV_OPEN;
int dev = pin->i_start_sect;
driver_msg.DEVICE = MINOR(dev);
assert(MAJOR(dev) == 4);
assert(dd_map[MAJOR(dev)].driver_nr != INVALID_DRIVER);
send_recv(BOTH,
dd_map[MAJOR(dev)].driver_nr,
&driver_msg);
}
else if (imode == I_DIRECTORY) {
assert(pin->i_num == ROOT_INODE);
}
else {
assert(pin->i_mode == I_REGULAR);
}
}
else {
return -1;
}
return fd;
}
/*****************************************************************************
* create_file
*****************************************************************************/
/**
* Create a file and return it's inode ptr.
*
* @param[in] path The full path of the new file
* @param[in] flags Attribiutes of the new file
*
* @return Ptr to i-node of the new file if successful, otherwise 0.
*
* @see open()
* @see do_open()
*
* @todo return values of routines called, return values of self.
*****************************************************************************/
PRIVATE struct inode * create_file(char * path, int flags)
{
char filename[MAX_PATH];
struct inode * dir_inode;
if (strip_path(filename, path, &dir_inode) != 0)
return 0;
int inode_nr = alloc_imap_bit(dir_inode->i_dev);
int free_sect_nr = alloc_smap_bit(dir_inode->i_dev,
NR_DEFAULT_FILE_SECTS);
struct inode *newino = new_inode(dir_inode->i_dev, inode_nr,
free_sect_nr);
new_dir_entry(dir_inode, newino->i_num, filename);
return newino;
}
/*****************************************************************************
* do_close
*****************************************************************************/
/**
* Handle the message CLOSE.
*
* @return Zero if success.
*****************************************************************************/
PUBLIC int do_close()
{
int fd = fs_msg.FD;
put_inode(pcaller->filp[fd]->fd_inode);
pcaller->filp[fd]->fd_inode = 0;
pcaller->filp[fd] = 0;
return 0;
}
/*****************************************************************************
* do_lseek
*****************************************************************************/
/**
* Handle the message LSEEK.
*
* @return The new offset in bytes from the beginning of the file if successful,
* otherwise a negative number.
*****************************************************************************/
PUBLIC int do_lseek()
{
int fd = fs_msg.FD;
int off = fs_msg.OFFSET;
int whence = fs_msg.WHENCE;
int pos = pcaller->filp[fd]->fd_pos;
int f_size = pcaller->filp[fd]->fd_inode->i_size;
switch (whence) {
case SEEK_SET:
pos = off;
break;
case SEEK_CUR:
pos += off;
break;
case SEEK_END:
pos = f_size + off;
break;
default:
return -1;
break;
}
if ((pos > f_size) || (pos < 0)) {
return -1;
}
pcaller->filp[fd]->fd_pos = pos;
return pos;
}
/*****************************************************************************
* alloc_imap_bit
*****************************************************************************/
/**
* Allocate a bit in inode-map.
*
* @param dev In which device the inode-map is located.
*
* @return I-node nr.
*****************************************************************************/
PRIVATE int alloc_imap_bit(int dev)
{
int inode_nr = 0;
int i, j, k;
int imap_blk0_nr = 1 + 1; /* 1 boot sector & 1 super block */
struct super_block * sb = get_super_block(dev);
for (i = 0; i < sb->nr_imap_sects; i++) {
RD_SECT(dev, imap_blk0_nr + i);
for (j = 0; j < SECTOR_SIZE; j++) {
/* skip `11111111' bytes */
if (fsbuf[j] == 0xFF)
continue;
/* skip `1' bits */
for (k = 0; ((fsbuf[j] >> k) & 1) != 0; k++) {}
/* i: sector index; j: byte index; k: bit index */
inode_nr = (i * SECTOR_SIZE + j) * 8 + k;
fsbuf[j] |= (1 << k);
/* write the bit to imap */
WR_SECT(dev, imap_blk0_nr + i);
break;
}
return inode_nr;
}
/* no free bit in imap */
panic("inode-map is probably full.\n");
return 0;
}
/*****************************************************************************
* alloc_smap_bit
*****************************************************************************/
/**
* Allocate a bit in sector-map.
*
* @param dev In which device the sector-map is located.
* @param nr_sects_to_alloc How many sectors are allocated.
*
* @return The 1st sector nr allocated.
*****************************************************************************/
PRIVATE int alloc_smap_bit(int dev, int nr_sects_to_alloc)
{
/* int nr_sects_to_alloc = NR_DEFAULT_FILE_SECTS; */
int i; /* sector index */
int j; /* byte index */
int k; /* bit index */
struct super_block * sb = get_super_block(dev);
int smap_blk0_nr = 1 + 1 + sb->nr_imap_sects;
int free_sect_nr = 0;
for (i = 0; i < sb->nr_smap_sects; i++) { /* smap_blk0_nr + i :
current sect nr. */
RD_SECT(dev, smap_blk0_nr + i);
/* byte offset in current sect */
for (j = 0; j < SECTOR_SIZE && nr_sects_to_alloc > 0; j++) {
k = 0;
if (!free_sect_nr) {
/* loop until a free bit is found */
if (fsbuf[j] == 0xFF) continue;
for (; ((fsbuf[j] >> k) & 1) != 0; k++) {}
free_sect_nr = (i * SECTOR_SIZE + j) * 8 +
k - 1 + sb->n_1st_sect;
}
for (; k < 8; k++) { /* repeat till enough bits are set */
assert(((fsbuf[j] >> k) & 1) == 0);
fsbuf[j] |= (1 << k);
if (--nr_sects_to_alloc == 0)
break;
}
}
if (free_sect_nr) /* free bit found, write the bits to smap */
WR_SECT(dev, smap_blk0_nr + i);
if (nr_sects_to_alloc == 0)
break;
}
assert(nr_sects_to_alloc == 0);
return free_sect_nr;
}
/*****************************************************************************
* new_inode
*****************************************************************************/
/**
* Generate a new i-node and write it to disk.
*
* @param dev Home device of the i-node.
* @param inode_nr I-node nr.
* @param start_sect Start sector of the file pointed by the new i-node.
*
* @return Ptr of the new i-node.
*****************************************************************************/
PRIVATE struct inode * new_inode(int dev, int inode_nr, int start_sect)
{
struct inode * new_inode = get_inode(dev, inode_nr);
new_inode->i_mode = I_REGULAR;
new_inode->i_size = 0;
new_inode->i_start_sect = start_sect;
new_inode->i_nr_sects = NR_DEFAULT_FILE_SECTS;
new_inode->i_dev = dev;
new_inode->i_cnt = 1;
new_inode->i_num = inode_nr;
/* write to the inode array */
sync_inode(new_inode);
return new_inode;
}
/*****************************************************************************
* new_dir_entry
*****************************************************************************/
/**
* Write a new entry into the directory.
*
* @param dir_inode I-node of the directory.
* @param inode_nr I-node nr of the new file.
* @param filename Filename of the new file.
*****************************************************************************/
PRIVATE void new_dir_entry(struct inode *dir_inode,int inode_nr,char *filename)
{
/* write the dir_entry */
int dir_blk0_nr = dir_inode->i_start_sect;
int nr_dir_blks = (dir_inode->i_size + SECTOR_SIZE) / SECTOR_SIZE;
int nr_dir_entries =
dir_inode->i_size / DIR_ENTRY_SIZE; /**
* including unused slots
* (the file has been
* deleted but the slot
* is still there)
*/
int m = 0;
struct dir_entry * pde;
struct dir_entry * new_de = 0;
int i, j;
for (i = 0; i < nr_dir_blks; i++) {
RD_SECT(dir_inode->i_dev, dir_blk0_nr + i);
pde = (struct dir_entry *)fsbuf;
for (j = 0; j < SECTOR_SIZE / DIR_ENTRY_SIZE; j++,pde++) {
if (++m > nr_dir_entries)
break;
if (pde->inode_nr == 0) { /* it's a free slot */
new_de = pde;
break;
}
}
if (m > nr_dir_entries ||/* all entries have been iterated or */
new_de) /* free slot is found */
break;
}
if (!new_de) { /* reached the end of the dir */
new_de = pde;
dir_inode->i_size += DIR_ENTRY_SIZE;
}
new_de->inode_nr = inode_nr;
strcpy(new_de->name, filename);
/* write dir block -- ROOT dir block */
WR_SECT(dir_inode->i_dev, dir_blk0_nr + i);
/* update dir inode */
sync_inode(dir_inode);
}
fs/read_write.c
/*************************************************************************//**
*****************************************************************************
* @file read_write.c
* @brief
* @author Forrest Y. Yu
* @date 2008
*****************************************************************************
*****************************************************************************/
#include "type.h"
#include "stdio.h"
#include "const.h"
#include "protect.h"
#include "string.h"
#include "fs.h"
#include "proc.h"
#include "tty.h"
#include "console.h"
#include "global.h"
#include "keyboard.h"
#include "proto.h"
/*****************************************************************************
* do_rdwt
*****************************************************************************/
/**
* Read/Write file and return byte count read/written.
*
* Sector map is not needed to update, since the sectors for the file have been
* allocated and the bits are set when the file was created.
*
* @return How many bytes have been read/written.
*****************************************************************************/
PUBLIC int do_rdwt()
{
int fd = fs_msg.FD; /**< file descriptor. */
void * buf = fs_msg.BUF;/**< r/w buffer */
int len = fs_msg.CNT; /**< r/w bytes */
int src = fs_msg.source; /* caller proc nr. */
assert((pcaller->filp[fd] >= &f_desc_table[0]) &&
(pcaller->filp[fd] < &f_desc_table[NR_FILE_DESC]));
if (!(pcaller->filp[fd]->fd_mode & O_RDWR))
return 0;
int pos = pcaller->filp[fd]->fd_pos;
struct inode * pin = pcaller->filp[fd]->fd_inode;
assert(pin >= &inode_table[0] && pin < &inode_table[NR_INODE]);
int imode = pin->i_mode & I_TYPE_MASK;
if (imode == I_CHAR_SPECIAL) {
int t = fs_msg.type == READ ? DEV_READ : DEV_WRITE;
fs_msg.type = t;
int dev = pin->i_start_sect;
assert(MAJOR(dev) == 4);
fs_msg.DEVICE = MINOR(dev);
fs_msg.BUF = buf;
fs_msg.CNT = len;
fs_msg.PROC_NR = src;
assert(dd_map[MAJOR(dev)].driver_nr != INVALID_DRIVER);
send_recv(BOTH, dd_map[MAJOR(dev)].driver_nr, &fs_msg);
assert(fs_msg.CNT == len);
return fs_msg.CNT;
}
else {
assert(pin->i_mode == I_REGULAR || pin->i_mode == I_DIRECTORY);
assert((fs_msg.type == READ) || (fs_msg.type == WRITE));
int pos_end;
if (fs_msg.type == READ)
pos_end = min(pos + len, pin->i_size);
else /* WRITE */
pos_end = min(pos + len, pin->i_nr_sects * SECTOR_SIZE);
int off = pos % SECTOR_SIZE;
int rw_sect_min=pin->i_start_sect+(pos>>SECTOR_SIZE_SHIFT);
int rw_sect_max=pin->i_start_sect+(pos_end>>SECTOR_SIZE_SHIFT);
int chunk = min(rw_sect_max - rw_sect_min + 1,
FSBUF_SIZE >> SECTOR_SIZE_SHIFT);
int bytes_rw = 0;
int bytes_left = len;
int i;
for (i = rw_sect_min; i <= rw_sect_max; i += chunk) {
/* read/write this amount of bytes every time */
int bytes = min(bytes_left, chunk * SECTOR_SIZE - off);
rw_sector(DEV_READ,
pin->i_dev,
i * SECTOR_SIZE,
chunk * SECTOR_SIZE,
TASK_FS,
fsbuf);
if (fs_msg.type == READ) {
phys_copy((void*)va2la(src, buf + bytes_rw),
(void*)va2la(TASK_FS, fsbuf + off),
bytes);
}
else { /* WRITE */
phys_copy((void*)va2la(TASK_FS, fsbuf + off),
(void*)va2la(src, buf + bytes_rw),
bytes);
rw_sector(DEV_WRITE,
pin->i_dev,
i * SECTOR_SIZE,
chunk * SECTOR_SIZE,
TASK_FS,
fsbuf);
}
off = 0;
bytes_rw += bytes;
pcaller->filp[fd]->fd_pos += bytes;
bytes_left -= bytes;
}
if (pcaller->filp[fd]->fd_pos > pin->i_size) {
/* update inode::size */
pin->i_size = pcaller->filp[fd]->fd_pos;
/* write the updated i-node back to disk */
sync_inode(pin);
}
return bytes_rw;
}
}
include/sys/const.h
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
const.h
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Forrest Yu, 2005
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
#ifndef _ORANGES_CONST_H_
#define _ORANGES_CONST_H_
/* max() & min() */
#define max(a,b) ((a) > (b) ? (a) : (b))
#define min(a,b) ((a) < (b) ? (a) : (b))
/* Color */
/*
* e.g. MAKE_COLOR(BLUE, RED)
* MAKE_COLOR(BLACK, RED) | BRIGHT
* MAKE_COLOR(BLACK, RED) | BRIGHT | FLASH
*/
#define BLACK 0x0 /* 0000 */
#define WHITE 0x7 /* 0111 */
#define RED 0x4 /* 0100 */
#define GREEN 0x2 /* 0010 */
#define BLUE 0x1 /* 0001 */
#define FLASH 0x80 /* 1000 0000 */
#define BRIGHT 0x08 /* 0000 1000 */
#define MAKE_COLOR(x,y) ((x<<4) | y) /* MAKE_COLOR(Background,Foreground) */
/* GDT 和 IDT 中描述符的個數 */
#define GDT_SIZE 128
#define IDT_SIZE 256
/* 權限 */
#define PRIVILEGE_KRNL 0
#define PRIVILEGE_TASK 1
#define PRIVILEGE_USER 3
/* RPL */
#define RPL_KRNL SA_RPL0
#define RPL_TASK SA_RPL1
#define RPL_USER SA_RPL3
/* Process */
#define SENDING 0x02 /* set when proc trying to send */
#define RECEIVING 0x04 /* set when proc trying to recv */
/* TTY */
#define NR_CONSOLES 3 /* consoles */
/* 8259A interrupt controller ports. */
#define INT_M_CTL 0x20 /* I/O port for interrupt controller <Master> */
#define INT_M_CTLMASK 0x21 /* setting bits in this port disables ints <Master> */
#define INT_S_CTL 0xA0 /* I/O port for second interrupt controller <Slave> */
#define INT_S_CTLMASK 0xA1 /* setting bits in this port disables ints <Slave> */
/* 8253/8254 PIT (Programmable Interval Timer) */
#define TIMER0 0x40 /* I/O port for timer channel 0 */
#define TIMER_MODE 0x43 /* I/O port for timer mode control */
#define RATE_GENERATOR 0x34 /* 00-11-010-0 :
* Counter0 - LSB then MSB - rate generator - binary
*/
#define TIMER_FREQ 1193182L/* clock frequency for timer in PC and AT */
#define HZ 100 /* clock freq (software settable on IBM-PC) */
/* AT keyboard */
/* 8042 ports */
#define KB_DATA 0x60 /* I/O port for keyboard data
Read : Read Output Buffer
Write: Write Input Buffer(8042 Data&8048 Command) */
#define KB_CMD 0x64 /* I/O port for keyboard command
Read : Read Status Register
Write: Write Input Buffer(8042 Command) */
#define LED_CODE 0xED
#define KB_ACK 0xFA
/* VGA */
#define CRTC_ADDR_REG 0x3D4 /* CRT Controller Registers - Addr Register */
#define CRTC_DATA_REG 0x3D5 /* CRT Controller Registers - Data Register */
#define START_ADDR_H 0xC /* reg index of video mem start addr (MSB) */
#define START_ADDR_L 0xD /* reg index of video mem start addr (LSB) */
#define CURSOR_H 0xE /* reg index of cursor position (MSB) */
#define CURSOR_L 0xF /* reg index of cursor position (LSB) */
#define V_MEM_BASE 0xB8000 /* base of color video memory */
#define V_MEM_SIZE 0x8000 /* 32K: B8000H -> BFFFFH */
/* Hardware interrupts */
#define NR_IRQ 16 /* Number of IRQs */
#define CLOCK_IRQ 0
#define KEYBOARD_IRQ 1
#define CASCADE_IRQ 2 /* cascade enable for 2nd AT controller */
#define ETHER_IRQ 3 /* default ethernet interrupt vector */
#define SECONDARY_IRQ 3 /* RS232 interrupt vector for port 2 */
#define RS232_IRQ 4 /* RS232 interrupt vector for port 1 */
#define XT_WINI_IRQ 5 /* xt winchester */
#define FLOPPY_IRQ 6 /* floppy disk */
#define PRINTER_IRQ 7
#define AT_WINI_IRQ 14 /* at winchester */
/* tasks */
/* 注意 TASK_XXX 的定義要與 global.c 中對應 */
#define INVALID_DRIVER -20
#define INTERRUPT -10
#define TASK_TTY 0
#define TASK_SYS 1
#define TASK_HD 2
#define TASK_FS 3
/* #define TASK_MM 4 */
#define ANY (NR_TASKS + NR_PROCS + 10)
#define NO_TASK (NR_TASKS + NR_PROCS + 20)
/* system call */
#define NR_SYS_CALL 3
/* ipc */
#define SEND 1
#define RECEIVE 2
#define BOTH 3 /* BOTH = (SEND | RECEIVE) */
/* magic chars used by `printx' */
#define MAG_CH_PANIC '\002'
#define MAG_CH_ASSERT '\003'
/**
* @enum msgtype
* @brief MESSAGE types
*/
enum msgtype {
/*
* when hard interrupt occurs, a msg (with type==HARD_INT) will
* be sent to some tasks
*/
HARD_INT = 1,
/* SYS task */
GET_TICKS, GET_PID,
/* FS */
OPEN, CLOSE, READ, WRITE, LSEEK, STAT, UNLINK,
/* TTY, SYS, FS, MM, etc */
SYSCALL_RET,
/* message type for drivers */
DEV_OPEN = 1001,
DEV_CLOSE,
DEV_READ,
DEV_WRITE,
DEV_IOCTL,
/* for debug */
DISK_LOG
};
/* macros for messages */
#define FD u.m3.m3i1
#define PATHNAME u.m3.m3p1
#define FLAGS u.m3.m3i1
#define NAME_LEN u.m3.m3i2
#define CNT u.m3.m3i2
#define REQUEST u.m3.m3i2
#define PROC_NR u.m3.m3i3
#define DEVICE u.m3.m3i4
#define POSITION u.m3.m3l1
#define BUF u.m3.m3p2
#define OFFSET u.m3.m3i2
#define WHENCE u.m3.m3i3
#define PID u.m3.m3i2
/* #define STATUS u.m3.m3i1 */
#define RETVAL u.m3.m3i1
#define DIOCTL_GET_GEO 1
/* Hard Drive */
#define SECTOR_SIZE 512
#define SECTOR_BITS (SECTOR_SIZE * 8)
#define SECTOR_SIZE_SHIFT 9
/* major device numbers (corresponding to kernel/global.c::dd_map[]) */
#define NO_DEV 0
#define DEV_FLOPPY 1
#define DEV_CDROM 2
#define DEV_HD 3
#define DEV_CHAR_TTY 4
#define DEV_SCSI 5
/* make device number from major and minor numbers */
#define MAJOR_SHIFT 8
#define MAKE_DEV(a,b) ((a << MAJOR_SHIFT) | b)
/* separate major and minor numbers from device number */
#define MAJOR(x) ((x >> MAJOR_SHIFT) & 0xFF)
#define MINOR(x) (x & 0xFF)
#define INVALID_INODE 0
#define ROOT_INODE 1
#define MAX_DRIVES 2
#define NR_PART_PER_DRIVE 4
#define NR_SUB_PER_PART 16
#define NR_SUB_PER_DRIVE (NR_SUB_PER_PART * NR_PART_PER_DRIVE)
#define NR_PRIM_PER_DRIVE (NR_PART_PER_DRIVE + 1)
/**
* @def MAX_PRIM
* Defines the max minor number of the primary partitions.
* If there are 2 disks, prim_dev ranges in hd[0-9], this macro will
* equals 9.
*/
#define MAX_PRIM (MAX_DRIVES * NR_PRIM_PER_DRIVE - 1)
#define MAX_SUBPARTITIONS (NR_SUB_PER_DRIVE * MAX_DRIVES)
/* device numbers of hard disk */
#define MINOR_hd1a 0x10
#define MINOR_hd2a (MINOR_hd1a+NR_SUB_PER_PART)
#define ROOT_DEV MAKE_DEV(DEV_HD, MINOR_BOOT)
#define P_PRIMARY 0
#define P_EXTENDED 1
#define ORANGES_PART 0x99 /* Orange'S partition */
#define NO_PART 0x00 /* unused entry */
#define EXT_PART 0x05 /* extended partition */
#define NR_FILES 64
#define NR_FILE_DESC 64 /* FIXME */
#define NR_INODE 64 /* FIXME */
#define NR_SUPER_BLOCK 8
/* INODE::i_mode (octal, lower 12 bits reserved) */
#define I_TYPE_MASK 0170000
#define I_REGULAR 0100000
#define I_BLOCK_SPECIAL 0060000
#define I_DIRECTORY 0040000
#define I_CHAR_SPECIAL 0020000
#define I_NAMED_PIPE 0010000
#define is_special(m) ((((m) & I_TYPE_MASK) == I_BLOCK_SPECIAL) || \
(((m) & I_TYPE_MASK) == I_CHAR_SPECIAL))
#define NR_DEFAULT_FILE_SECTS 2048 /* 2048 * 512 = 1MB */
#endif /* _ORANGES_CONST_H_ */
include/sys/proc.h
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
proc.h
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Forrest Yu, 2005
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
struct stackframe { /* proc_ptr points here ↑ Low */
u32 gs; /* ┓ │ */
u32 fs; /* ┃ │ */
u32 es; /* ┃ │ */
u32 ds; /* ┃ │ */
u32 edi; /* ┃ │ */
u32 esi; /* ┣ pushed by save() │ */
u32 ebp; /* ┃ │ */
u32 kernel_esp; /* <- 'popad' will ignore it │ */
u32 ebx; /* ┃ ↑棧從高地址往低地址增長*/
u32 edx; /* ┃ │ */
u32 ecx; /* ┃ │ */
u32 eax; /* ┛ │ */
u32 retaddr; /* return address for assembly code save() │ */
u32 eip; /* ┓ │ */
u32 cs; /* ┃ │ */
u32 eflags; /* ┣ these are pushed by CPU during interrupt │ */
u32 esp; /* ┃ │ */
u32 ss; /* ┛ ┷High */
};
struct proc {
struct stackframe regs; /* process registers saved in stack frame */
u16 ldt_sel; /* gdt selector giving ldt base and limit */
struct descriptor ldts[LDT_SIZE]; /* local descs for code and data */
int ticks; /* remained ticks */
int priority;
u32 pid; /* process id passed in from MM */
char name[16]; /* name of the process */
int p_flags; /**
* process flags.
* A proc is runnable iff p_flags==0
*/
MESSAGE * p_msg;
int p_recvfrom;
int p_sendto;
int has_int_msg; /**
* nonzero if an INTERRUPT occurred when
* the task is not ready to deal with it.
*/
struct proc * q_sending; /**
* queue of procs sending messages to
* this proc
*/
struct proc * next_sending;/**
* next proc in the sending
* queue (q_sending)
*/
int nr_tty;
struct file_desc * filp[NR_FILES];
};
struct task {
task_f initial_eip;
int stacksize;
char name[32];
};
#define proc2pid(x) (x - proc_table)
/* Number of tasks & procs */
#define NR_TASKS 4
#define NR_PROCS 3
#define FIRST_PROC proc_table[0]
#define LAST_PROC proc_table[NR_TASKS + NR_PROCS - 1]
/* stacks of tasks */
#define STACK_SIZE_TTY 0x8000
#define STACK_SIZE_SYS 0x8000
#define STACK_SIZE_HD 0x8000
#define STACK_SIZE_FS 0x8000
#define STACK_SIZE_TESTA 0x8000
#define STACK_SIZE_TESTB 0x8000
#define STACK_SIZE_TESTC 0x8000
#define STACK_SIZE_TOTAL (STACK_SIZE_TTY + \
STACK_SIZE_SYS + \
STACK_SIZE_HD + \
STACK_SIZE_FS + \
STACK_SIZE_TESTA + \
STACK_SIZE_TESTB + \
STACK_SIZE_TESTC)
include/sys/proto.h
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
proto.h
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Forrest Yu, 2005
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
/* kliba.asm */
PUBLIC void out_byte(u16 port, u8 value);
PUBLIC u8 in_byte(u16 port);
PUBLIC void disp_str(char * info);
PUBLIC void disp_color_str(char * info, int color);
PUBLIC void disable_irq(int irq);
PUBLIC void enable_irq(int irq);
PUBLIC void disable_int();
PUBLIC void enable_int();
PUBLIC void port_read(u16 port, void* buf, int n);
PUBLIC void port_write(u16 port, void* buf, int n);
PUBLIC void glitter(int row, int col);
/* string.asm */
PUBLIC char* strcpy(char* dst, const char* src);
/* protect.c */
PUBLIC void init_prot();
PUBLIC u32 seg2phys(u16 seg);
/* klib.c */
PUBLIC void delay(int time);
PUBLIC void disp_int(int input);
PUBLIC char * itoa(char * str, int num);
/* kernel.asm */
PUBLIC void restart();
/* main.c */
PUBLIC int get_ticks();
PUBLIC void TestA();
PUBLIC void TestB();
PUBLIC void TestC();
PUBLIC void panic(const char *fmt, ...);
/* i8259.c */
PUBLIC void init_8259A();
PUBLIC void put_irq_handler(int irq, irq_handler handler);
PUBLIC void spurious_irq(int irq);
/* clock.c */
PUBLIC void clock_handler(int irq);
PUBLIC void init_clock();
PUBLIC void milli_delay(int milli_sec);
/* kernel/hd.c */
PUBLIC void task_hd();
PUBLIC void hd_handler(int irq);
/* keyboard.c */
PUBLIC void init_keyboard();
PUBLIC void keyboard_read(TTY* p_tty);
/* tty.c */
PUBLIC void task_tty();
PUBLIC void in_process(TTY* p_tty, u32 key);
/* systask.c */
PUBLIC void task_sys();
/* fs/main.c */
PUBLIC void task_fs();
PUBLIC int rw_sector(int io_type, int dev, u64 pos,
int bytes, int proc_nr, void * buf);
PUBLIC struct inode * get_inode(int dev, int num);
PUBLIC void put_inode(struct inode * pinode);
PUBLIC void sync_inode(struct inode * p);
PUBLIC struct super_block * get_super_block(int dev);
/* fs/open.c */
PUBLIC int do_open();
PUBLIC int do_close();
/* fs/read_write.c */
PUBLIC int do_rdwt();
/* fs/link.c */
PUBLIC int do_unlink();
/* fs/misc.c */
PUBLIC int do_stat();
PUBLIC int strip_path(char * filename, const char * pathname,
struct inode** ppinode);
PUBLIC int search_file(char * path);
/* fs/disklog.c */
PUBLIC int do_disklog();
PUBLIC int disklog(char * logstr); /* for debug */
PUBLIC void dump_fd_graph(const char * fmt, ...);
/* console.c */
PUBLIC void out_char(CONSOLE* p_con, char ch);
PUBLIC void scroll_screen(CONSOLE* p_con, int direction);
PUBLIC void select_console(int nr_console);
PUBLIC void init_screen(TTY* p_tty);
PUBLIC int is_current_console(CONSOLE* p_con);
/* printf.c */
PUBLIC int printf(const char *fmt, ...);
#define printl printf
/* vsprintf.c */
PUBLIC int vsprintf(char *buf, const char *fmt, va_list args);
PUBLIC int sprintf(char *buf, const char *fmt, ...);
/* proc.c */
PUBLIC void schedule();
PUBLIC void* va2la(int pid, void* va);
PUBLIC int ldt_seg_linear(struct proc* p, int idx);
PUBLIC void reset_msg(MESSAGE* p);
PUBLIC void dump_msg(const char * title, MESSAGE* m);
PUBLIC void dump_proc(struct proc * p);
PUBLIC int send_recv(int function, int src_dest, MESSAGE* msg);
PUBLIC void inform_int(int task_nr);
/* lib/misc.c */
PUBLIC void spin(char * func_name);
/* 以下是系統調用相關 */
/* 系統調用 - 系統級 */
/* proc.c */
PUBLIC int sys_sendrec(int function, int src_dest, MESSAGE* m, struct proc* p);
PUBLIC int sys_printx(int _unused1, int _unused2, char* s, struct proc * p_proc);
/* syscall.asm */
PUBLIC void sys_call(); /* int_handler */
/* 系統調用 - 用戶級 */
PUBLIC int sendrec(int function, int src_dest, MESSAGE* p_msg);
PUBLIC int printx(char* str);
kernel/main.c
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
main.c
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Forrest Yu, 2005
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
#include "type.h"
#include "stdio.h"
#include "const.h"
#include "protect.h"
#include "string.h"
#include "fs.h"
#include "proc.h"
#include "tty.h"
#include "console.h"
#include "global.h"
#include "proto.h"
/*======================================================================*
kernel_main
*======================================================================*/
PUBLIC int kernel_main()
{
disp_str("-----\"kernel_main\" begins-----\n");
struct task* p_task;
struct proc* p_proc= proc_table;
char* p_task_stack = task_stack + STACK_SIZE_TOTAL;
u16 selector_ldt = SELECTOR_LDT_FIRST;
u8 privilege;
u8 rpl;
int eflags;
int i, j;
int prio;
for (i = 0; i < NR_TASKS+NR_PROCS; i++) {
if (i < NR_TASKS) { /* 任務 */
p_task = task_table + i;
privilege = PRIVILEGE_TASK;
rpl = RPL_TASK;
eflags = 0x1202; /* IF=1, IOPL=1, bit 2 is always 1 */
prio = 15;
}
else { /* 用戶進程 */
p_task = user_proc_table + (i - NR_TASKS);
privilege = PRIVILEGE_USER;
rpl = RPL_USER;
eflags = 0x202; /* IF=1, bit 2 is always 1 */
prio = 5;
}
strcpy(p_proc->name, p_task->name); /* name of the process */
p_proc->pid = i; /* pid */
p_proc->ldt_sel = selector_ldt;
memcpy(&p_proc->ldts[0], &gdt[SELECTOR_KERNEL_CS >> 3],
sizeof(struct descriptor));
p_proc->ldts[0].attr1 = DA_C | privilege << 5;
memcpy(&p_proc->ldts[1], &gdt[SELECTOR_KERNEL_DS >> 3],
sizeof(struct descriptor));
p_proc->ldts[1].attr1 = DA_DRW | privilege << 5;
p_proc->regs.cs = (0 & SA_RPL_MASK & SA_TI_MASK) | SA_TIL | rpl;
p_proc->regs.ds = (8 & SA_RPL_MASK & SA_TI_MASK) | SA_TIL | rpl;
p_proc->regs.es = (8 & SA_RPL_MASK & SA_TI_MASK) | SA_TIL | rpl;
p_proc->regs.fs = (8 & SA_RPL_MASK & SA_TI_MASK) | SA_TIL | rpl;
p_proc->regs.ss = (8 & SA_RPL_MASK & SA_TI_MASK) | SA_TIL | rpl;
p_proc->regs.gs = (SELECTOR_KERNEL_GS & SA_RPL_MASK) | rpl;
p_proc->regs.eip = (u32)p_task->initial_eip;
p_proc->regs.esp = (u32)p_task_stack;
p_proc->regs.eflags = eflags;
p_proc->nr_tty = 0;
p_proc->p_flags = 0;
p_proc->p_msg = 0;
p_proc->p_recvfrom = NO_TASK;
p_proc->p_sendto = NO_TASK;
p_proc->has_int_msg = 0;
p_proc->q_sending = 0;
p_proc->next_sending = 0;
for (j = 0; j < NR_FILES; j++)
p_proc->filp[j] = 0;
p_proc->ticks = p_proc->priority = prio;
p_task_stack -= p_task->stacksize;
p_proc++;
p_task++;
selector_ldt += 1 << 3;
}
proc_table[NR_TASKS + 0].nr_tty = 0;
proc_table[NR_TASKS + 1].nr_tty = 1;
proc_table[NR_TASKS + 2].nr_tty = 1;
k_reenter = 0;
ticks = 0;
p_proc_ready = proc_table;
init_clock();
init_keyboard();
restart();
while(1){}
}
/*****************************************************************************
* get_ticks
*****************************************************************************/
PUBLIC int get_ticks()
{
MESSAGE msg;
reset_msg(&msg);
msg.type = GET_TICKS;
send_recv(BOTH, TASK_SYS, &msg);
return msg.RETVAL;
}
/*======================================================================*
TestA
*======================================================================*/
void TestA()
{
int fd;
int i, n;
char filename[MAX_FILENAME_LEN+1] = "blah";
const char bufw[] = "abcde";
const int rd_bytes = 3;
char bufr[rd_bytes];
assert(rd_bytes <= strlen(bufw));
/* create */
fd = open(filename, O_CREAT | O_RDWR);
assert(fd != -1);
printf("File created: %s (fd %d)\n", filename, fd);
/* write */
n = write(fd, bufw, strlen(bufw));
assert(n == strlen(bufw));
/* close */
close(fd);
/* open */
fd = open(filename, O_RDWR);
assert(fd != -1);
printf("File opened. fd: %d\n", fd);
/* read */
n = read(fd, bufr, rd_bytes);
assert(n == rd_bytes);
bufr[n] = 0;
printf("%d bytes read: %s\n", n, bufr);
/* close */
close(fd);
char * filenames[] = {"/foo", "/bar", "/baz"};
/* create files */
for (i = 0; i < sizeof(filenames) / sizeof(filenames[0]); i++) {
fd = open(filenames[i], O_CREAT | O_RDWR);
assert(fd != -1);
printf("File created: %s (fd %d)\n", filenames[i], fd);
close(fd);
}
char * rfilenames[] = {"/bar", "/foo", "/baz", "/dev_tty0"};
/* remove files */
for (i = 0; i < sizeof(rfilenames) / sizeof(rfilenames[0]); i++) {
if (unlink(rfilenames[i]) == 0)
printf("File removed: %s\n", rfilenames[i]);
else
printf("Failed to remove file: %s\n", rfilenames[i]);
}
spin("TestA");
}
/*======================================================================*
TestB
*======================================================================*/
void TestB()
{
while(1){
printf("B");
milli_delay(200);
}
}
/*======================================================================*
TestB
*======================================================================*/
void TestC()
{
/* assert(0); */
while(1){
printf("C");
milli_delay(200);
}
}
/*****************************************************************************
* panic
*****************************************************************************/
PUBLIC void panic(const char *fmt, ...)
{
int i;
char buf[256];
/* 4 is the size of fmt in the stack */
va_list arg = (va_list)((char*)&fmt + 4);
i = vsprintf(buf, fmt, arg);
printl("%c !!panic!! %s", MAG_CH_PANIC, buf);
/* should never arrive here */
__asm__ __volatile__("ud2");
}
kernel/systask.c
/*************************************************************************//**
*****************************************************************************
* @file systask.c
* @brief
* @author Forrest Y. Yu
* @date 2007
*****************************************************************************
*****************************************************************************/
#include "type.h"
#include "stdio.h"
#include "const.h"
#include "protect.h"
#include "string.h"
#include "fs.h"
#include "proc.h"
#include "tty.h"
#include "console.h"
#include "global.h"
#include "keyboard.h"
#include "proto.h"
/*****************************************************************************
* task_sys
*****************************************************************************/
/**
* <Ring 1> The main loop of TASK SYS.
*
*****************************************************************************/
PUBLIC void task_sys()
{
MESSAGE msg;
while (1) {
send_recv(RECEIVE, ANY, &msg);
int src = msg.source;
switch (msg.type) {
case GET_TICKS:
msg.RETVAL = ticks;
send_recv(SEND, src, &msg);
break;
case GET_PID:
msg.type = SYSCALL_RET;
msg.PID = src;
send_recv(SEND, src, &msg);
break;
default:
panic("unknown msg type");
break;
}
}
}
lib/close.c
/*************************************************************************//**
*****************************************************************************
* @file close.c
* @brief
* @author Forrest Y. Yu
* @date Mon Apr 21 17:08:19 2008
*****************************************************************************
*****************************************************************************/
#include "type.h"
#include "stdio.h"
#include "const.h"
#include "protect.h"
#include "string.h"
#include "fs.h"
#include "proc.h"
#include "tty.h"
#include "console.h"
#include "global.h"
#include "proto.h"
/*****************************************************************************
* close
*****************************************************************************/
/**
* Close a file descriptor.
*
* @param fd File descriptor.
*
* @return Zero if successful, otherwise -1.
*****************************************************************************/
PUBLIC int close(int fd)
{
MESSAGE msg;
msg.type = CLOSE;
msg.FD = fd;
send_recv(BOTH, TASK_FS, &msg);
return msg.RETVAL;
}
lib/getpid.c
/*************************************************************************//**
*****************************************************************************
* @file getpid.c
* @brief getpid()
* @author Forrest Y. Yu
* @date Mon Nov 10 19:04:07 2008
*****************************************************************************
*****************************************************************************/
#include "type.h"
#include "stdio.h"
#include "const.h"
#include "protect.h"
#include "string.h"
#include "fs.h"
#include "proc.h"
#include "tty.h"
#include "console.h"
#include "global.h"
#include "proto.h"
/*****************************************************************************
* getpid
*****************************************************************************/
/**
* Get the PID.
*
* @return The PID.
*****************************************************************************/
PUBLIC int getpid()
{
MESSAGE msg;
msg.type = GET_PID;
send_recv(BOTH, TASK_SYS, &msg);
assert(msg.type == SYSCALL_RET);
return msg.PID;
}
lib/misc.c
/*************************************************************************//**
*****************************************************************************
* @file misc.c
* @brief
* @author Forrest Y. Yu
* @date 2008
*****************************************************************************
*****************************************************************************/
#include "type.h"
#include "stdio.h"
#include "const.h"
#include "protect.h"
#include "string.h"
#include "fs.h"
#include "proc.h"
#include "tty.h"
#include "console.h"
#include "global.h"
#include "keyboard.h"
#include "proto.h"
/*****************************************************************************
* memcmp
*****************************************************************************/
/**
* Compare memory areas.
*
* @param s1 The 1st area.
* @param s2 The 2nd area.
* @param n The first n bytes will be compared.
*
* @return an integer less than, equal to, or greater than zero if the first
* n bytes of s1 is found, respectively, to be less than, to match,
* or be greater than the first n bytes of s2.
*****************************************************************************/
PUBLIC int memcmp(const void * s1, const void *s2, int n)
{
if ((s1 == 0) || (s2 == 0)) { /* for robustness */
return (s1 - s2);
}
const char * p1 = (const char *)s1;
const char * p2 = (const char *)s2;
int i;
for (i = 0; i < n; i++,p1++,p2++) {
if (*p1 != *p2) {
return (*p1 - *p2);
}
}
return 0;
}
/*****************************************************************************
* strcmp
*****************************************************************************/
/**
* Compare two strings.
*
* @param s1 The 1st string.
* @param s2 The 2nd string.
*
* @return an integer less than, equal to, or greater than zero if s1 (or the
* first n bytes thereof) is found, respectively, to be less than,
* to match, or be greater than s2.
*****************************************************************************/
PUBLIC int strcmp(const char * s1, const char *s2)
{
if ((s1 == 0) || (s2 == 0)) { /* for robustness */
return (s1 - s2);
}
const char * p1 = s1;
const char * p2 = s2;
for (; *p1 && *p2; p1++,p2++) {
if (*p1 != *p2) {
break;
}
}
return (*p1 - *p2);
}
/*****************************************************************************
* strcat
*****************************************************************************/
/**
* Concatenate two strings.
*
* @param s1 The 1st string.
* @param s2 The 2nd string.
*
* @return Ptr to the 1st string.
*****************************************************************************/
PUBLIC char * strcat(char * s1, const char *s2)
{
if ((s1 == 0) || (s2 == 0)) { /* for robustness */
return 0;
}
char * p1 = s1;
for (; *p1; p1++) {}
const char * p2 = s2;
for (; *p2; p1++,p2++) {
*p1 = *p2;
}
*p1 = 0;
return s1;
}
/*****************************************************************************
* spin
*****************************************************************************/
PUBLIC void spin(char * func_name)
{
printl("\nspinning in %s ...\n", func_name);
while (1) {}
}
/*****************************************************************************
* assertion_failure
*************************************************************************//**
* Invoked by assert().
*
* @param exp The failure expression itself.
* @param file __FILE__
* @param base_file __BASE_FILE__
* @param line __LINE__
*****************************************************************************/
PUBLIC void assertion_failure(char *exp, char *file, char *base_file, int line)
{
printl("%c assert(%s) failed: file: %s, base_file: %s, ln%d",
MAG_CH_ASSERT,
exp, file, base_file, line);
/**
* If assertion fails in a TASK, the system will halt before
* printl() returns. If it happens in a USER PROC, printl() will
* return like a common routine and arrive here.
* @see sys_printx()
*
* We use a forever loop to prevent the proc from going on:
*/
spin("assertion_failure()");
/* should never arrive here */
__asm__ __volatile__("ud2");
}
lib/open.c
/*************************************************************************//**
*****************************************************************************
* @file open.c
* @brief open()
* @author Forrest Y. Yu
* @date 2008
*****************************************************************************
*****************************************************************************/
#include "type.h"
#include "stdio.h"
#include "const.h"
#include "protect.h"
#include "string.h"
#include "fs.h"
#include "proc.h"
#include "tty.h"
#include "console.h"
#include "global.h"
#include "proto.h"
/*****************************************************************************
* open
*****************************************************************************/
/**
* open/create a file.
*
* @param pathname The full path of the file to be opened/created.
* @param flags O_CREAT, O_RDWR, etc.
*
* @return File descriptor if successful, otherwise -1.
*****************************************************************************/
PUBLIC int open(const char *pathname, int flags)
{
MESSAGE msg;
msg.type = OPEN;
msg.PATHNAME = (void*)pathname;
msg.FLAGS = flags;
msg.NAME_LEN = strlen(pathname);
send_recv(BOTH, TASK_FS, &msg);
assert(msg.type == SYSCALL_RET);
return msg.FD;
}
lib/printf.c
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
printf.c
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Forrest Yu, 2005
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
#include "type.h"
#include "stdio.h"
#include "const.h"
#include "protect.h"
#include "string.h"
#include "fs.h"
#include "proc.h"
#include "tty.h"
#include "console.h"
#include "global.h"
#include "keyboard.h"
#include "proto.h"
/******************************************************************************************
可變參數函數調用原理(其中涉及的數字皆為舉例)
===========================================================================================
i = 0x23;
j = 0x78;
char fmt[] = "%x%d";
printf(fmt, i, j);
push j
push i
push fmt
call printf
add esp, 3 * 4
┃ HIGH ┃ ┃ HIGH ┃
┃ ... ┃ ┃ ... ┃
┣━━━━━━━━━━┫ ┣━━━━━━━━━━┫
┃ ┃ 0x32010┃ '\0' ┃
┣━━━━━━━━━━┫ ┣━━━━━━━━━━┫
0x3046C┃ 0x78 ┃ 0x3200c┃ d ┃
┣━━━━━━━━━━┫ ┣━━━━━━━━━━┫
arg = 0x30468┃ 0x23 ┃ 0x32008┃ % ┃
┣━━━━━━━━━━┫ ┣━━━━━━━━━━┫
0x30464┃ 0x32000 ───╂────┐ 0x32004┃ x ┃
┣━━━━━━━━━━┫ │ ┣━━━━━━━━━━┫
┃ ┃ └──→ 0x32000┃ % ┃
┣━━━━━━━━━━┫ ┣━━━━━━━━━━┫
┃ ... ┃ ┃ ... ┃
┃ LOW ┃ ┃ LOW ┃
實際上,調用 vsprintf 的情形是這樣的:
vsprintf(buf, 0x32000, 0x30468);
******************************************************************************************/
/*======================================================================*
printf
*======================================================================*/
int printf(const char *fmt, ...)
{
int i;
char buf[256];
va_list arg = (va_list)((char*)(&fmt) + 4); /*4是參數fmt所占堆棧中的大小*/
i = vsprintf(buf, fmt, arg);
buf[i] = 0;
printx(buf);
return i;
}
lib/read.c
/*************************************************************************//**
*****************************************************************************
* @file read.c
* @brief read()
* @author Forrest Y. Yu
* @date 2008
*****************************************************************************
*****************************************************************************/
#include "type.h"
#include "stdio.h"
#include "const.h"
#include "protect.h"
#include "string.h"
#include "fs.h"
#include "proc.h"
#include "tty.h"
#include "console.h"
#include "global.h"
#include "proto.h"
/*****************************************************************************
* read
*****************************************************************************/
/**
* Read from a file descriptor.
*
* @param fd File descriptor.
* @param buf Buffer to accept the bytes read.
* @param count How many bytes to read.
*
* @return On success, the number of bytes read are returned.
* On error, -1 is returned.
*****************************************************************************/
PUBLIC int read(int fd, void *buf, int count)
{
MESSAGE msg;
msg.type = READ;
msg.FD = fd;
msg.BUF = buf;
msg.CNT = count;
send_recv(BOTH, TASK_FS, &msg);
return msg.CNT;
}
lib/syscall.asm
; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; syscall.asm
; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; Forrest Yu, 2005
; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
%include "sconst.inc"
INT_VECTOR_SYS_CALL equ 0x90
_NR_printx equ 0
_NR_sendrec equ 1
; 導出符號
global printx
global sendrec
bits 32
[section .text]
; ====================================================================================
; sendrec(int function, int src_dest, MESSAGE* msg);
; ====================================================================================
; Never call sendrec() directly, call send_recv() instead.
sendrec:
mov eax, _NR_sendrec
mov ebx, [esp + 4] ; function
mov ecx, [esp + 8] ; src_dest
mov edx, [esp + 12] ; p_msg
int INT_VECTOR_SYS_CALL
ret
; ====================================================================================
; void printx(char* s);
; ====================================================================================
printx:
mov eax, _NR_printx
mov edx, [esp + 4]
int INT_VECTOR_SYS_CALL
ret
lib/syslog.c
/*************************************************************************//**
*****************************************************************************
* @file syslog.c
* @brief
* @author Forrest Y. Yu
* @date Thu Nov 20 17:02:42 2008
*****************************************************************************
*****************************************************************************/
#include "type.h"
#include "stdio.h"
#include "const.h"
#include "protect.h"
#include "string.h"
#include "fs.h"
#include "proc.h"
#include "tty.h"
#include "console.h"
#include "global.h"
#include "proto.h"
/*****************************************************************************
* syslog
*****************************************************************************/
/**
* Write log directly to the disk by sending message to FS.
*
* @param fmt The format string.
*
* @return How many chars have been printed.
*****************************************************************************/
PUBLIC int syslog(const char *fmt, ...)
{
int i;
char buf[STR_DEFAULT_LEN];
va_list arg = (va_list)((char*)(&fmt) + 4); /**
* 4: size of `fmt' in
* the stack
*/
i = vsprintf(buf, fmt, arg);
assert(strlen(buf) == i);
if (getpid() == TASK_FS) { /* in FS */
return disklog(buf);
}
else { /* any proc which is not FS */
MESSAGE msg;
msg.type = DISK_LOG;
msg.BUF= buf;
msg.CNT = i;
send_recv(BOTH, TASK_FS, &msg);
if (i != msg.CNT) {
panic("failed to write log");
}
return msg.RETVAL;
}
}
lib/unlink.c
/*************************************************************************//**
*****************************************************************************
* @file unlink.c
* @brief
* @author Forrest Y. Yu
* @date Tue Jun 3 16:12:05 2008
*****************************************************************************
*****************************************************************************/
#include "type.h"
#include "stdio.h"
#include "const.h"
#include "protect.h"
#include "string.h"
#include "fs.h"
#include "proc.h"
#include "tty.h"
#include "console.h"
#include "global.h"
#include "proto.h"
/*****************************************************************************
* unlink
*****************************************************************************/
/**
* Delete a file.
*
* @param pathname The full path of the file to delete.
*
* @return Zero if successful, otherwise -1.
*****************************************************************************/
PUBLIC int unlink(const char * pathname)
{
MESSAGE msg;
msg.type = UNLINK;
msg.PATHNAME = (void*)pathname;
msg.NAME_LEN = strlen(pathname);
send_recv(BOTH, TASK_FS, &msg);
return msg.RETVAL;
}
lib/vsprintf.c
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vsprintf.c
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Forrest Yu, 2005
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
#include "type.h"
#include "stdio.h"
#include "const.h"
#include "protect.h"
#include "string.h"
#include "fs.h"
#include "proc.h"
#include "tty.h"
#include "console.h"
#include "global.h"
#include "keyboard.h"
#include "proto.h"
/*======================================================================*
i2a
*======================================================================*/
PRIVATE char* i2a(int val, int base, char ** ps)
{
int m = val % base;
int q = val / base;
if (q) {
i2a(q, base, ps);
}
*(*ps)++ = (m < 10) ? (m + '0') : (m - 10 + 'A');
return *ps;
}
/*======================================================================*
vsprintf
*======================================================================*/
/*
* 為更好地理解此函數的原理,可參考 printf 的注釋部分。
*/
PUBLIC int vsprintf(char *buf, const char *fmt, va_list args)
{
char* p;
va_list p_next_arg = args;
int m;
char inner_buf[STR_DEFAULT_LEN];
char cs;
int align_nr;
for (p=buf;*fmt;fmt++) {
if (*fmt != '%') {
*p++ = *fmt;
continue;
}
else { /* a format string begins */
align_nr = 0;
}
fmt++;
if (*fmt == '%') {
*p++ = *fmt;
continue;
}
else if (*fmt == '0') {
cs = '0';
fmt++;
}
else {
cs = ' ';
}
while (((unsigned char)(*fmt) >= '0') && ((unsigned char)(*fmt) <= '9')) {
align_nr *= 10;
align_nr += *fmt - '0';
fmt++;
}
char * q = inner_buf;
memset(q, 0, sizeof(inner_buf));
switch (*fmt) {
case 'c':
*q++ = *((char*)p_next_arg);
p_next_arg += 4;
break;
case 'x':
m = *((int*)p_next_arg);
i2a(m, 16, &q);
p_next_arg += 4;
break;
case 'd':
m = *((int*)p_next_arg);
if (m < 0) {
m = m * (-1);
*q++ = '-';
}
i2a(m, 10, &q);
p_next_arg += 4;
break;
case 's':
strcpy(q, (*((char**)p_next_arg)));
q += strlen(*((char**)p_next_arg));
p_next_arg += 4;
break;
default:
break;
}
int k;
for (k = 0; k < ((align_nr > strlen(inner_buf)) ? (align_nr - strlen(inner_buf)) : 0); k++) {
*p++ = cs;
}
q = inner_buf;
while (*q) {
*p++ = *q++;
}
}
*p = 0;
return (p - buf);
}
/*======================================================================*
sprintf
*======================================================================*/
int sprintf(char *buf, const char *fmt, ...)
{
va_list arg = (va_list)((char*)(&fmt) + 4); /* 4 是參數 fmt 所占堆棧中的大小 */
return vsprintf(buf, fmt, arg);
}
lib/write.c
/*************************************************************************//**
*****************************************************************************
* @file write.c
* @brief write()
* @author Forrest Y. Yu
* @date 2008
*****************************************************************************
*****************************************************************************/
#include "type.h"
#include "stdio.h"
#include "const.h"
#include "protect.h"
#include "string.h"
#include "fs.h"
#include "proc.h"
#include "tty.h"
#include "console.h"
#include "global.h"
#include "proto.h"
/*****************************************************************************
* write
*****************************************************************************/
/**
* Write to a file descriptor.
*
* @param fd File descriptor.
* @param buf Buffer including the bytes to write.
* @param count How many bytes to write.
*
* @return On success, the number of bytes written are returned.
* On error, -1 is returned.
*****************************************************************************/
PUBLIC int write(int fd, const void *buf, int count)
{
MESSAGE msg;
msg.type = WRITE;
msg.FD = fd;
msg.BUF = (void*)buf;
msg.CNT = count;
send_recv(BOTH, TASK_FS, &msg);
return msg.CNT;
}
include/sys/config.h
#define ENABLE_DISK_LOG // 以下新增
#define SET_LOG_SECT_SMAP_AT_STARTUP
#define MEMSET_LOG_SECTS
#define NR_SECTS_FOR_LOG NR_DEFAULT_FILE_SECTS
include/sys/global.h
EXTERN struct file_desc f_desc_table[NR_FILE_DESC]; // 以下新增
EXTERN struct inode inode_table[NR_INODE];
EXTERN struct super_block super_block[NR_SUPER_BLOCK];
EXTERN MESSAGE fs_msg;
EXTERN struct proc * pcaller;
EXTERN struct inode * root_inode;
include/sys/hd.h
// 新增
#define MAX_IO_BYTES 256 /* how many sectors does one IO can handle */
include/string.h
PUBLIC int strlen(char* p_str); // 刪除
PUBLIC int strlen(const char* p_str); // 以下新增
PUBLIC int memcmp(const void * s1, const void *s2, int n);
PUBLIC int strcmp(const char * s1, const char *s2);
PUBLIC char* strcat(char * s1, const char *s2);
include/type.h
// 以下新增
/* routine types */
#define PUBLIC /* PUBLIC is the opposite of PRIVATE */
#define PRIVATE static /* PRIVATE x limits the scope of x */
kernel/clock.c, kernel/console.c, kernel/global.c, kernel/hd.c, kernel/i8259.c, kernel/keyboard.c, kernel/proc.c, kernel/protect.c, kernel/start.c, kernel/tty.c, lib/klib.c
#include "stdio.h" // 新增
刪除檔案:kernel/printf.c, kernel/syscall.asm, kernel/vsprintf.c
 |
執行結果 |
留言
張貼留言