111
This commit is contained in:
parent
7166483892
commit
93a432ec36
|
@ -0,0 +1,113 @@
|
|||
#########################
|
||||
# Makefile for Orange'S #
|
||||
#########################
|
||||
|
||||
# Entry point of Orange'S
|
||||
# It must have the same value with 'KernelEntryPointPhyAddr' in load.inc!
|
||||
ENTRYPOINT = 0x30400
|
||||
|
||||
# Offset of entry point in kernel file
|
||||
# It depends on ENTRYPOINT
|
||||
ENTRYOFFSET = 0x400
|
||||
|
||||
# Programs, flags, etc.
|
||||
ASM = nasm
|
||||
DASM = ndisasm
|
||||
CC = gcc
|
||||
LD = ld
|
||||
ASMBFLAGS = -I boot/include/
|
||||
ASMKFLAGS = -I include/ -f elf32
|
||||
CFLAGS = -I include/ -c -fno-builtin -m32 -fno-stack-protector -std=c99
|
||||
LDFLAGS = -s -Ttext $(ENTRYPOINT) -m elf_i386
|
||||
DASMFLAGS = -u -o $(ENTRYPOINT) -e $(ENTRYOFFSET)
|
||||
|
||||
# This Program
|
||||
ORANGESBOOT = boot/boot.bin boot/loader.bin
|
||||
ORANGESKERNEL = kernel.bin
|
||||
OBJS = kernel/kernel.o kernel/syscall.o kernel/start.o kernel/main.o kernel/clock.o\
|
||||
kernel/i8259.o kernel/global.o kernel/protect.o kernel/proc.o\
|
||||
lib/kliba.o lib/klib.o lib/string.o
|
||||
DASMOUTPUT = kernel.bin.asm
|
||||
|
||||
# All Phony Targets
|
||||
.PHONY : everything final image clean realclean disasm all buildimg
|
||||
|
||||
# Default starting position
|
||||
nop :
|
||||
@echo "why not \`make image' huh? :)"
|
||||
|
||||
everything : $(ORANGESBOOT) $(ORANGESKERNEL)
|
||||
|
||||
all : realclean everything
|
||||
|
||||
image : realclean everything clean buildimg
|
||||
|
||||
run:
|
||||
make image
|
||||
|
||||
clean :
|
||||
rm -f $(OBJS)
|
||||
|
||||
realclean :
|
||||
rm -f $(OBJS) $(ORANGESBOOT) $(ORANGESKERNEL)
|
||||
|
||||
disasm :
|
||||
$(DASM) $(DASMFLAGS) $(ORANGESKERNEL) > $(DASMOUTPUT)
|
||||
|
||||
# We assume that "a.img" exists in current folder
|
||||
buildimg :
|
||||
dd if=boot/boot.bin of=a.img bs=512 count=1 conv=notrunc
|
||||
sudo mount -o loop a.img /home/lighthouse/tmp/mount
|
||||
sudo cp -fv boot/loader.bin /home/lighthouse/tmp/mount
|
||||
sudo cp -fv kernel.bin /home/lighthouse/tmp/mount
|
||||
sudo umount /home/lighthouse/tmp/mount
|
||||
|
||||
boot/boot.bin : boot/boot.asm boot/include/load.inc boot/include/fat12hdr.inc
|
||||
$(ASM) $(ASMBFLAGS) -o $@ $<
|
||||
|
||||
boot/loader.bin : boot/loader.asm boot/include/load.inc boot/include/fat12hdr.inc boot/include/pm.inc
|
||||
$(ASM) $(ASMBFLAGS) -o $@ $<
|
||||
|
||||
$(ORANGESKERNEL) : $(OBJS)
|
||||
$(LD) $(LDFLAGS) -o $(ORANGESKERNEL) $(OBJS)
|
||||
|
||||
kernel/kernel.o : kernel/kernel.asm include/sconst.inc
|
||||
$(ASM) $(ASMKFLAGS) -o $@ $<
|
||||
|
||||
kernel/syscall.o : kernel/syscall.asm include/sconst.inc
|
||||
$(ASM) $(ASMKFLAGS) -o $@ $<
|
||||
|
||||
kernel/start.o: kernel/start.c include/type.h include/const.h include/protect.h include/string.h include/proc.h include/proto.h \
|
||||
include/global.h
|
||||
$(CC) $(CFLAGS) -o $@ $<
|
||||
|
||||
kernel/main.o: kernel/main.c include/type.h include/const.h include/protect.h include/string.h include/proc.h include/proto.h \
|
||||
include/global.h
|
||||
$(CC) $(CFLAGS) -o $@ $<
|
||||
|
||||
kernel/clock.o: kernel/clock.c
|
||||
$(CC) $(CFLAGS) -o $@ $<
|
||||
|
||||
kernel/i8259.o: kernel/i8259.c include/type.h include/const.h include/protect.h include/proto.h
|
||||
$(CC) $(CFLAGS) -o $@ $<
|
||||
|
||||
kernel/global.o: kernel/global.c include/type.h include/const.h include/protect.h include/proc.h \
|
||||
include/global.h include/proto.h
|
||||
$(CC) $(CFLAGS) -o $@ $<
|
||||
|
||||
kernel/protect.o: kernel/protect.c include/type.h include/const.h include/protect.h include/proc.h include/proto.h \
|
||||
include/global.h
|
||||
$(CC) $(CFLAGS) -o $@ $<
|
||||
|
||||
kernel/proc.o: kernel/proc.c
|
||||
$(CC) $(CFLAGS) -o $@ $<
|
||||
|
||||
lib/klib.o: lib/klib.c include/type.h include/const.h include/protect.h include/string.h include/proc.h include/proto.h \
|
||||
include/global.h
|
||||
$(CC) $(CFLAGS) -o $@ $<
|
||||
|
||||
lib/kliba.o : lib/kliba.asm
|
||||
$(ASM) $(ASMKFLAGS) -o $@ $<
|
||||
|
||||
lib/string.o : lib/string.asm
|
||||
$(ASM) $(ASMKFLAGS) -o $@ $<
|
|
@ -0,0 +1,25 @@
|
|||
###############################################################
|
||||
# Configuration file for Bochs
|
||||
###############################################################
|
||||
|
||||
# how much memory the emulated machine will have
|
||||
megs: 32
|
||||
|
||||
# filename of ROM images
|
||||
romimage: file=/usr/share/bochs/BIOS-bochs-latest
|
||||
vgaromimage: file=/usr/share/vgabios/vgabios.bin
|
||||
|
||||
# what disk images will be used
|
||||
floppya: 1_44=a.img, status=inserted
|
||||
|
||||
# choose the boot disk.
|
||||
boot: a
|
||||
|
||||
# where do we send log messages?
|
||||
# log: bochsout.txt
|
||||
|
||||
# disable the mouse
|
||||
mouse: enabled=0
|
||||
|
||||
# enable key mapping, using US layout as default.
|
||||
keyboard_mapping: enabled=1, map=/usr/share/bochs/keymaps/x11-pc-us.map
|
|
@ -0,0 +1,288 @@
|
|||
|
||||
; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
; 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, BaseOfLoader
|
||||
mov es, ax ; es <- BaseOfLoader
|
||||
mov bx, OffsetOfLoader ; bx <- OffsetOfLoader 于是, es:bx = BaseOfLoader:OffsetOfLoader
|
||||
mov ax, [wSectorNo] ; ax <- Root Directory 中的某 Sector 号
|
||||
mov cl, 1
|
||||
call ReadSector
|
||||
|
||||
mov si, LoaderFileName ; ds:si -> "LOADER BIN"
|
||||
mov di, OffsetOfLoader ; es:di -> BaseOfLoader:0100 = BaseOfLoader*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, BaseOfLoader
|
||||
mov es, ax ; es <- BaseOfLoader
|
||||
mov bx, OffsetOfLoader ; bx <- OffsetOfLoader 于是, es:bx = BaseOfLoader:OffsetOfLoader = BaseOfLoader * 10h + OffsetOfLoader
|
||||
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 BaseOfLoader:OffsetOfLoader ; 这一句正式跳转到已加载到内存中的 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, BaseOfLoader ; ┓
|
||||
sub ax, 0100h ; ┣ 在 BaseOfLoader 后面留出 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 = (BaseOfLoader - 100):00 = (BaseOfLoader - 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 ; 结束标志
|
|
@ -0,0 +1,43 @@
|
|||
|
||||
; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
; fat12hdr.inc
|
||||
; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
; Forrest Yu, 2005
|
||||
; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
|
||||
|
||||
; FAT12 磁盘的头
|
||||
; ----------------------------------------------------------------------
|
||||
BS_OEMName DB 'ForrestY' ; OEM String, 必须 8 个字节
|
||||
|
||||
BPB_BytsPerSec DW 512 ; 每扇区字节数
|
||||
BPB_SecPerClus DB 1 ; 每簇多少扇区
|
||||
BPB_RsvdSecCnt DW 1 ; Boot 记录占用多少扇区
|
||||
BPB_NumFATs DB 2 ; 共有多少 FAT 表
|
||||
BPB_RootEntCnt DW 224 ; 根目录文件数最大值
|
||||
BPB_TotSec16 DW 2880 ; 逻辑扇区总数
|
||||
BPB_Media DB 0xF0 ; 媒体描述符
|
||||
BPB_FATSz16 DW 9 ; 每FAT扇区数
|
||||
BPB_SecPerTrk DW 18 ; 每磁道扇区数
|
||||
BPB_NumHeads DW 2 ; 磁头数(面数)
|
||||
BPB_HiddSec DD 0 ; 隐藏扇区数
|
||||
BPB_TotSec32 DD 0 ; 如果 wTotalSectorCount 是 0 由这个值记录扇区数
|
||||
|
||||
BS_DrvNum DB 0 ; 中断 13 的驱动器号
|
||||
BS_Reserved1 DB 0 ; 未使用
|
||||
BS_BootSig DB 29h ; 扩展引导标记 (29h)
|
||||
BS_VolID DD 0 ; 卷序列号
|
||||
BS_VolLab DB 'OrangeS0.02'; 卷标, 必须 11 个字节
|
||||
BS_FileSysType DB 'FAT12 ' ; 文件系统类型, 必须 8个字节
|
||||
;------------------------------------------------------------------------
|
||||
|
||||
|
||||
; -------------------------------------------------------------------------
|
||||
; 基于 FAT12 头的一些常量定义,如果头信息改变,下面的常量可能也要做相应改变
|
||||
; -------------------------------------------------------------------------
|
||||
FATSz equ 9 ; BPB_FATSz16
|
||||
RootDirSectors equ 14 ; 根目录占用空间: RootDirSectors = ((BPB_RootEntCnt * 32) + (BPB_BytsPerSec – 1)) / BPB_BytsPerSec; 但如果按照此公式代码过长
|
||||
SectorNoOfRootDirectory equ 19 ; Root Directory 的第一个扇区号 = BPB_RsvdSecCnt + (BPB_NumFATs * FATSz)
|
||||
SectorNoOfFAT1 equ 1 ; FAT1 的第一个扇区号 = BPB_RsvdSecCnt
|
||||
DeltaSectorNo equ 17 ; DeltaSectorNo = BPB_RsvdSecCnt + (BPB_NumFATs * FATSz) - 2
|
||||
; 文件的开始Sector号 = DirEntry中的开始Sector号 + 根目录占用Sector数目 + DeltaSectorNo
|
|
@ -0,0 +1,24 @@
|
|||
|
||||
; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
; load.inc
|
||||
; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
; Forrest Yu, 2005
|
||||
; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
|
||||
|
||||
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
|
||||
|
|
@ -0,0 +1,322 @@
|
|||
|
||||
; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
; pm.inc
|
||||
; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
; Forrest Yu, 2005
|
||||
; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
|
||||
|
||||
; 描述符图示
|
||||
|
||||
; 图示一
|
||||
;
|
||||
; ------ ┏━━┳━━┓高地址
|
||||
; ┃ 7 ┃ 段 ┃
|
||||
; ┣━━┫ ┃
|
||||
; 基
|
||||
; 字节 7 ┆ ┆ ┆
|
||||
; 址
|
||||
; ┣━━┫ ② ┃
|
||||
; ┃ 0 ┃ ┃
|
||||
; ------ ┣━━╋━━┫
|
||||
; ┃ 7 ┃ G ┃
|
||||
; ┣━━╉──┨
|
||||
; ┃ 6 ┃ D ┃
|
||||
; ┣━━╉──┨
|
||||
; ┃ 5 ┃ 0 ┃
|
||||
; ┣━━╉──┨
|
||||
; ┃ 4 ┃ AVL┃
|
||||
; 字节 6 ┣━━╉──┨
|
||||
; ┃ 3 ┃ ┃
|
||||
; ┣━━┫ 段 ┃
|
||||
; ┃ 2 ┃ 界 ┃
|
||||
; ┣━━┫ 限 ┃
|
||||
; ┃ 1 ┃ ┃
|
||||
; ┣━━┫ ② ┃
|
||||
; ┃ 0 ┃ ┃
|
||||
; ------ ┣━━╋━━┫
|
||||
; ┃ 7 ┃ P ┃
|
||||
; ┣━━╉──┨
|
||||
; ┃ 6 ┃ ┃
|
||||
; ┣━━┫ DPL┃
|
||||
; ┃ 5 ┃ ┃
|
||||
; ┣━━╉──┨
|
||||
; ┃ 4 ┃ S ┃
|
||||
; 字节 5 ┣━━╉──┨
|
||||
; ┃ 3 ┃ ┃
|
||||
; ┣━━┫ T ┃
|
||||
; ┃ 2 ┃ Y ┃
|
||||
; ┣━━┫ P ┃
|
||||
; ┃ 1 ┃ E ┃
|
||||
; ┣━━┫ ┃
|
||||
; ┃ 0 ┃ ┃
|
||||
; ------ ┣━━╋━━┫
|
||||
; ┃ 23 ┃ ┃
|
||||
; ┣━━┫ ┃
|
||||
; ┃ 22 ┃ ┃
|
||||
; ┣━━┫ 段 ┃
|
||||
;
|
||||
; 字节 ┆ ┆ 基 ┆
|
||||
; 2, 3, 4
|
||||
; ┣━━┫ 址 ┃
|
||||
; ┃ 1 ┃ ① ┃
|
||||
; ┣━━┫ ┃
|
||||
; ┃ 0 ┃ ┃
|
||||
; ------ ┣━━╋━━┫
|
||||
; ┃ 15 ┃ ┃
|
||||
; ┣━━┫ ┃
|
||||
; ┃ 14 ┃ ┃
|
||||
; ┣━━┫ 段 ┃
|
||||
;
|
||||
; 字节 0,1┆ ┆ 界 ┆
|
||||
;
|
||||
; ┣━━┫ 限 ┃
|
||||
; ┃ 1 ┃ ① ┃
|
||||
; ┣━━┫ ┃
|
||||
; ┃ 0 ┃ ┃
|
||||
; ------ ┗━━┻━━┛低地址
|
||||
;
|
||||
|
||||
|
||||
; 图示二
|
||||
|
||||
; 高地址………………………………………………………………………低地址
|
||||
|
||||
; | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
|
||||
; |7654321076543210765432107654321076543210765432107654321076543210| <- 共 8 字节
|
||||
; |--------========--------========--------========--------========|
|
||||
; ┏━━━┳━━━━━━━┳━━━━━━━━━━━┳━━━━━━━┓
|
||||
; ┃31..24┃ (见下图) ┃ 段基址(23..0) ┃ 段界限(15..0)┃
|
||||
; ┃ ┃ ┃ ┃ ┃
|
||||
; ┃ 基址2┃③│②│ ①┃基址1b│ 基址1a ┃ 段界限1 ┃
|
||||
; ┣━━━╋━━━┳━━━╋━━━━━━━━━━━╋━━━━━━━┫
|
||||
; ┃ %6 ┃ %5 ┃ %4 ┃ %3 ┃ %2 ┃ %1 ┃
|
||||
; ┗━━━┻━━━┻━━━┻━━━┻━━━━━━━┻━━━━━━━┛
|
||||
; │ \_________
|
||||
; │ \__________________
|
||||
; │ \________________________________________________
|
||||
; │ \
|
||||
; ┏━━┳━━┳━━┳━━┳━━┳━━┳━━┳━━┳━━┳━━┳━━┳━━┳━━┳━━┳━━┳━━┓
|
||||
; ┃ 7 ┃ 6 ┃ 5 ┃ 4 ┃ 3 ┃ 2 ┃ 1 ┃ 0 ┃ 7 ┃ 6 ┃ 5 ┃ 4 ┃ 3 ┃ 2 ┃ 1 ┃ 0 ┃
|
||||
; ┣━━╋━━╋━━╋━━╋━━┻━━┻━━┻━━╋━━╋━━┻━━╋━━╋━━┻━━┻━━┻━━┫
|
||||
; ┃ G ┃ D ┃ 0 ┃ AVL┃ 段界限 2 (19..16) ┃ P ┃ DPL ┃ S ┃ TYPE ┃
|
||||
; ┣━━┻━━┻━━┻━━╋━━━━━━━━━━━╋━━┻━━━━━┻━━┻━━━━━━━━━━━┫
|
||||
; ┃ ③: 属性 2 ┃ ②: 段界限 2 ┃ ①: 属性1 ┃
|
||||
; ┗━━━━━━━━━━━┻━━━━━━━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━┛
|
||||
; 高地址 低地址
|
||||
;
|
||||
;
|
||||
|
||||
; 说明:
|
||||
;
|
||||
; (1) P: 存在(Present)位。
|
||||
; P=1 表示描述符对地址转换是有效的,或者说该描述符所描述的段存在,即在内存中;
|
||||
; P=0 表示描述符对地址转换无效,即该段不存在。使用该描述符进行内存访问时会引起异常。
|
||||
;
|
||||
; (2) DPL: 表示描述符特权级(Descriptor Privilege level),共2位。它规定了所描述段的特权级,用于特权检查,以决定对该段能否访问。
|
||||
;
|
||||
; (3) S: 说明描述符的类型。
|
||||
; 对于存储段描述符而言,S=1,以区别与系统段描述符和门描述符(S=0)。
|
||||
;
|
||||
; (4) TYPE: 说明存储段描述符所描述的存储段的具体属性。
|
||||
;
|
||||
;
|
||||
; 数据段类型 类型值 说明
|
||||
; ----------------------------------
|
||||
; 0 只读
|
||||
; 1 只读、已访问
|
||||
; 2 读/写
|
||||
; 3 读/写、已访问
|
||||
; 4 只读、向下扩展
|
||||
; 5 只读、向下扩展、已访问
|
||||
; 6 读/写、向下扩展
|
||||
; 7 读/写、向下扩展、已访问
|
||||
;
|
||||
;
|
||||
; 类型值 说明
|
||||
; 代码段类型 ----------------------------------
|
||||
; 8 只执行
|
||||
; 9 只执行、已访问
|
||||
; A 执行/读
|
||||
; B 执行/读、已访问
|
||||
; C 只执行、一致码段
|
||||
; D 只执行、一致码段、已访问
|
||||
; E 执行/读、一致码段
|
||||
; F 执行/读、一致码段、已访问
|
||||
;
|
||||
;
|
||||
; 系统段类型 类型编码 说明
|
||||
; ----------------------------------
|
||||
; 0 <未定义>
|
||||
; 1 可用286TSS
|
||||
; 2 LDT
|
||||
; 3 忙的286TSS
|
||||
; 4 286调用门
|
||||
; 5 任务门
|
||||
; 6 286中断门
|
||||
; 7 286陷阱门
|
||||
; 8 未定义
|
||||
; 9 可用386TSS
|
||||
; A <未定义>
|
||||
; B 忙的386TSS
|
||||
; C 386调用门
|
||||
; D <未定义>
|
||||
; E 386中断门
|
||||
; F 386陷阱门
|
||||
;
|
||||
; (5) G: 段界限粒度(Granularity)位。
|
||||
; G=0 表示界限粒度为字节;
|
||||
; G=1 表示界限粒度为4K 字节。
|
||||
; 注意,界限粒度只对段界限有效,对段基地址无效,段基地址总是以字节为单位。
|
||||
;
|
||||
; (6) D: D位是一个很特殊的位,在描述可执行段、向下扩展数据段或由SS寄存器寻址的段(通常是堆栈段)的三种描述符中的意义各不相同。
|
||||
; ⑴ 在描述可执行段的描述符中,D位决定了指令使用的地址及操作数所默认的大小。
|
||||
; ① D=1表示默认情况下指令使用32位地址及32位或8位操作数,这样的代码段也称为32位代码段;
|
||||
; ② D=0 表示默认情况下,使用16位地址及16位或8位操作数,这样的代码段也称为16位代码段,它与80286兼容。可以使用地址大小前缀和操作数大小前缀分别改变默认的地址或操作数的大小。
|
||||
; ⑵ 在向下扩展数据段的描述符中,D位决定段的上部边界。
|
||||
; ① D=1表示段的上部界限为4G;
|
||||
; ② D=0表示段的上部界限为64K,这是为了与80286兼容。
|
||||
; ⑶ 在描述由SS寄存器寻址的段描述符中,D位决定隐式的堆栈访问指令(如PUSH和POP指令)使用何种堆栈指针寄存器。
|
||||
; ① D=1表示使用32位堆栈指针寄存器ESP;
|
||||
; ② D=0表示使用16位堆栈指针寄存器SP,这与80286兼容。
|
||||
;
|
||||
; (7) AVL: 软件可利用位。80386对该位的使用未左规定,Intel公司也保证今后开发生产的处理器只要与80386兼容,就不会对该位的使用做任何定义或规定。
|
||||
;
|
||||
|
||||
|
||||
;----------------------------------------------------------------------------
|
||||
; 描述符类型值说明
|
||||
; 其中:
|
||||
; DA_ : Descriptor Attribute
|
||||
; D : 数据段
|
||||
; C : 代码段
|
||||
; S : 系统段
|
||||
; R : 只读
|
||||
; RW : 读写
|
||||
; A : 已访问
|
||||
; 其它 : 可按照字面意思理解
|
||||
;----------------------------------------------------------------------------
|
||||
DA_32 EQU 4000h ; 32 位段
|
||||
DA_LIMIT_4K EQU 8000h ; 段界限粒度为 4K 字节
|
||||
|
||||
DA_DPL0 EQU 00h ; DPL = 0
|
||||
DA_DPL1 EQU 20h ; DPL = 1
|
||||
DA_DPL2 EQU 40h ; DPL = 2
|
||||
DA_DPL3 EQU 60h ; DPL = 3
|
||||
;----------------------------------------------------------------------------
|
||||
; 存储段描述符类型值说明
|
||||
;----------------------------------------------------------------------------
|
||||
DA_DR EQU 90h ; 存在的只读数据段类型值
|
||||
DA_DRW EQU 92h ; 存在的可读写数据段属性值
|
||||
DA_DRWA EQU 93h ; 存在的已访问可读写数据段类型值
|
||||
DA_C EQU 98h ; 存在的只执行代码段属性值
|
||||
DA_CR EQU 9Ah ; 存在的可执行可读代码段属性值
|
||||
DA_CCO EQU 9Ch ; 存在的只执行一致代码段属性值
|
||||
DA_CCOR EQU 9Eh ; 存在的可执行可读一致代码段属性值
|
||||
;----------------------------------------------------------------------------
|
||||
; 系统段描述符类型值说明
|
||||
;----------------------------------------------------------------------------
|
||||
DA_LDT EQU 82h ; 局部描述符表段类型值
|
||||
DA_TaskGate EQU 85h ; 任务门类型值
|
||||
DA_386TSS EQU 89h ; 可用 386 任务状态段类型值
|
||||
DA_386CGate EQU 8Ch ; 386 调用门类型值
|
||||
DA_386IGate EQU 8Eh ; 386 中断门类型值
|
||||
DA_386TGate EQU 8Fh ; 386 陷阱门类型值
|
||||
;----------------------------------------------------------------------------
|
||||
|
||||
|
||||
; 选择子图示:
|
||||
; ┏━━┳━━┳━━┳━━┳━━┳━━┳━━┳━━┳━━┳━━┳━━┳━━┳━━┳━━┳━━┳━━┓
|
||||
; ┃ 15 ┃ 14 ┃ 13 ┃ 12 ┃ 11 ┃ 10 ┃ 9 ┃ 8 ┃ 7 ┃ 6 ┃ 5 ┃ 4 ┃ 3 ┃ 2 ┃ 1 ┃ 0 ┃
|
||||
; ┣━━┻━━┻━━┻━━┻━━┻━━┻━━┻━━┻━━┻━━┻━━┻━━┻━━╋━━╋━━┻━━┫
|
||||
; ┃ 描述符索引 ┃ TI ┃ RPL ┃
|
||||
; ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┻━━┻━━━━━┛
|
||||
;
|
||||
; RPL(Requested Privilege Level): 请求特权级,用于特权检查。
|
||||
;
|
||||
; TI(Table Indicator): 引用描述符表指示位
|
||||
; TI=0 指示从全局描述符表GDT中读取描述符;
|
||||
; TI=1 指示从局部描述符表LDT中读取描述符。
|
||||
;
|
||||
|
||||
;----------------------------------------------------------------------------
|
||||
; 选择子类型值说明
|
||||
; 其中:
|
||||
; SA_ : Selector Attribute
|
||||
|
||||
SA_RPL0 EQU 0 ; ┓
|
||||
SA_RPL1 EQU 1 ; ┣ RPL
|
||||
SA_RPL2 EQU 2 ; ┃
|
||||
SA_RPL3 EQU 3 ; ┛
|
||||
|
||||
SA_TIG EQU 0 ; ┓TI
|
||||
SA_TIL EQU 4 ; ┛
|
||||
;----------------------------------------------------------------------------
|
||||
|
||||
|
||||
;----------------------------------------------------------------------------
|
||||
; 分页机制使用的常量说明
|
||||
;----------------------------------------------------------------------------
|
||||
PG_P EQU 1 ; 页存在属性位
|
||||
PG_RWR EQU 0 ; R/W 属性位值, 读/执行
|
||||
PG_RWW EQU 2 ; R/W 属性位值, 读/写/执行
|
||||
PG_USS EQU 0 ; U/S 属性位值, 系统级
|
||||
PG_USU EQU 4 ; U/S 属性位值, 用户级
|
||||
;----------------------------------------------------------------------------
|
||||
|
||||
|
||||
; =========================================
|
||||
; FLAGS - Intel 8086 Family Flags Register
|
||||
; =========================================
|
||||
;
|
||||
; |11|10|F|E|D|C|B|A|9|8|7|6|5|4|3|2|1|0|
|
||||
; | | | | | | | | | | | | | | | | | '--- CF……Carry Flag
|
||||
; | | | | | | | | | | | | | | | | '--- 1
|
||||
; | | | | | | | | | | | | | | | '--- PF……Parity Flag
|
||||
; | | | | | | | | | | | | | | '--- 0
|
||||
; | | | | | | | | | | | | | '--- AF……Auxiliary Flag
|
||||
; | | | | | | | | | | | | '--- 0
|
||||
; | | | | | | | | | | | '--- ZF……Zero Flag
|
||||
; | | | | | | | | | | '--- SF……Sign Flag
|
||||
; | | | | | | | | | '--- TF……Trap Flag (Single Step)
|
||||
; | | | | | | | | '--- IF……Interrupt Flag
|
||||
; | | | | | | | '--- DF……Direction Flag
|
||||
; | | | | | | '--- OF……Overflow flag
|
||||
; | | | | '----- IOPL……I/O Privilege Level (286+ only)
|
||||
; | | | '----- NT……Nested Task Flag (286+ only)
|
||||
; | | '----- 0
|
||||
; | '----- RF……Resume Flag (386+ only)
|
||||
; '------ VM……Virtual Mode Flag (386+ only)
|
||||
;
|
||||
; 注: see PUSHF POPF STI CLI STD CLD
|
||||
;
|
||||
|
||||
|
||||
; 宏 ------------------------------------------------------------------------------------------------------
|
||||
;
|
||||
; 描述符
|
||||
; usage: Descriptor Base, Limit, Attr
|
||||
; Base: dd
|
||||
; Limit: dd (low 20 bits available)
|
||||
; Attr: dw (lower 4 bits of higher byte are always 0)
|
||||
%macro Descriptor 3
|
||||
dw %2 & 0FFFFh ; 段界限 1 (2 字节)
|
||||
dw %1 & 0FFFFh ; 段基址 1 (2 字节)
|
||||
db (%1 >> 16) & 0FFh ; 段基址 2 (1 字节)
|
||||
dw ((%2 >> 8) & 0F00h) | (%3 & 0F0FFh) ; 属性 1 + 段界限 2 + 属性 2 (2 字节)
|
||||
db (%1 >> 24) & 0FFh ; 段基址 3 (1 字节)
|
||||
%endmacro ; 共 8 字节
|
||||
;
|
||||
; 门
|
||||
; usage: Gate Selector, Offset, DCount, Attr
|
||||
; Selector: dw
|
||||
; Offset: dd
|
||||
; DCount: db
|
||||
; Attr: db
|
||||
%macro Gate 4
|
||||
dw (%2 & 0FFFFh) ; 偏移 1 (2 字节)
|
||||
dw %1 ; 选择子 (2 字节)
|
||||
dw (%3 & 1Fh) | ((%4 << 8) & 0FF00h) ; 属性 (2 字节)
|
||||
dw ((%2 >> 16) & 0FFFFh) ; 偏移 2 (2 字节)
|
||||
%endmacro ; 共 8 字节
|
||||
; ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
@ -0,0 +1,787 @@
|
|||
|
||||
; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
; 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 BaseOfLoaderPhyAddr + LABEL_GDT ; 基地址
|
||||
|
||||
; 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, BaseOfKernelFile
|
||||
mov es, ax ; es <- BaseOfKernelFile
|
||||
mov bx, OffsetOfKernelFile ; bx <- OffsetOfKernelFile 于是, es:bx = BaseOfKernelFile:OffsetOfKernelFile = BaseOfKernelFile * 10h + OffsetOfKernelFile
|
||||
mov ax, [wSectorNo] ; ax <- Root Directory 中的某 Sector 号
|
||||
mov cl, 1
|
||||
call ReadSector
|
||||
|
||||
mov si, KernelFileName ; ds:si -> "KERNEL BIN"
|
||||
mov di, OffsetOfKernelFile ; es:di -> BaseOfKernelFile:???? = BaseOfKernelFile*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, 2 ; "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 文件大小
|
||||
pop eax
|
||||
|
||||
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, BaseOfKernelFile
|
||||
mov es, ax ; es <- BaseOfKernelFile
|
||||
mov bx, OffsetOfKernelFile ; bx <- OffsetOfKernelFile 于是, es:bx = BaseOfKernelFile:OffsetOfKernelFile = BaseOfKernelFile * 10h + OffsetOfKernelFile
|
||||
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]
|
||||
jmp LABEL_GOON_LOADING_FILE
|
||||
LABEL_FILE_LOADED:
|
||||
|
||||
call KillMotor ; 关闭软驱马达
|
||||
|
||||
mov dh, 1 ; "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:(BaseOfLoaderPhyAddr+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 "Ready. "
|
||||
Message2 db "No KERNEL"
|
||||
;============================================================================
|
||||
|
||||
;----------------------------------------------------------------------------
|
||||
; 函数名: 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, BaseOfKernelFile ; ┓
|
||||
sub ax, 0100h ; ┣ 在 BaseOfKernelFile 后面留出 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 = (BaseOfKernelFile - 100):00 = (BaseOfKernelFile - 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
|
||||
|
||||
push szMemChkTitle
|
||||
call DispStr
|
||||
add esp, 4
|
||||
|
||||
call DispMemInfo
|
||||
call SetupPaging
|
||||
|
||||
;mov ah, 0Fh ; 0000: 黑底 1111: 白字
|
||||
;mov al, 'P'
|
||||
;mov [gs:((80 * 0 + 39) * 2)], ax ; 屏幕第 0 行, 第 39 列。
|
||||
|
||||
call InitKernel
|
||||
|
||||
;jmp $
|
||||
|
||||
;***************************************************************
|
||||
jmp SelectorFlatC:KernelEntryPointPhyAddr ; 正式进入内核 *
|
||||
;***************************************************************
|
||||
; 内存看上去是这样的:
|
||||
; ┃ ┃
|
||||
; ┃ . ┃
|
||||
; ┃ . ┃
|
||||
; ┃ . ┃
|
||||
; ┣━━━━━━━━━━━━━━━━━━┫
|
||||
; ┃■■■■■■■■■■■■■■■■■■┃
|
||||
; ┃■■■■■■Page Tables■■■■■■┃
|
||||
; ┃■■■■■(大小由LOADER决定)■■■■┃
|
||||
; 00101000h ┃■■■■■■■■■■■■■■■■■■┃ PageTblBase
|
||||
; ┣━━━━━━━━━━━━━━━━━━┫
|
||||
; ┃■■■■■■■■■■■■■■■■■■┃
|
||||
; 00100000h ┃■■■■Page Directory Table■■■■┃ PageDirBase <- 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
|
||||
; ┣━━━━━━━━━━━━━━━━━━┫
|
||||
; ┃■■■■■■■■■■■■■■■■■■┃
|
||||
; 80000h ┃■■■■■■■KERNEL.BIN■■■■■■┃
|
||||
; ┣━━━━━━━━━━━━━━━━━━┫
|
||||
; ┃■■■■■■■■■■■■■■■■■■┃
|
||||
; 30000h ┃■■■■■■■■KERNEL■■■■■■■┃ 30400h ← KERNEL 入口 (KernelEntryPointPhyAddr)
|
||||
; ┣━━━━━━━━━━━━━━━━━━┫
|
||||
; ┃ ┃
|
||||
; 7E00h ┃ F R E E ┃
|
||||
; ┣━━━━━━━━━━━━━━━━━━┫
|
||||
; ┃■■■■■■■■■■■■■■■■■■┃
|
||||
; 7C00h ┃■■■■■■BOOT SECTOR■■■■■■┃
|
||||
; ┣━━━━━━━━━━━━━━━━━━┫
|
||||
; ┃ ┃
|
||||
; 500h ┃ F R E E ┃
|
||||
; ┣━━━━━━━━━━━━━━━━━━┫
|
||||
; ┃□□□□□□□□□□□□□□□□□□┃
|
||||
; 400h ┃□□□□ROM BIOS parameter area □□┃
|
||||
; ┣━━━━━━━━━━━━━━━━━━┫
|
||||
; ┃◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇┃
|
||||
; 0h ┃◇◇◇◇◇◇Int Vectors◇◇◇◇◇◇┃
|
||||
; ┗━━━━━━━━━━━━━━━━━━┛ ← cs, ds, es, fs, ss
|
||||
;
|
||||
;
|
||||
; ┏━━━┓ ┏━━━┓
|
||||
; ┃■■■┃ 我们使用 ┃□□□┃ 不能使用的内存
|
||||
; ┗━━━┛ ┗━━━┛
|
||||
; ┏━━━┓ ┏━━━┓
|
||||
; ┃ ┃ 未使用空间 ┃◇◇◇┃ 可以覆盖的内存
|
||||
; ┗━━━┛ ┗━━━┛
|
||||
;
|
||||
; 注:KERNEL 的位置实际上是很灵活的,可以通过同时改变 LOAD.INC 中的 KernelEntryPointPhyAddr 和 MAKEFILE 中参数 -Ttext 的值来改变。
|
||||
; 比如,如果把 KernelEntryPointPhyAddr 和 -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
|
||||
|
||||
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
|
||||
; ---------------------------------------------------------------------------
|
||||
|
||||
; 启动分页机制 --------------------------------------------------------------
|
||||
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, PageDirBase ; 此段首地址为 PageDirBase
|
||||
xor eax, eax
|
||||
mov eax, PageTblBase | 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, PageTblBase ; 此段首地址为 PageTblBase
|
||||
xor eax, eax
|
||||
mov eax, PG_P | PG_USU | PG_RWW
|
||||
.2:
|
||||
stosd
|
||||
add eax, 4096 ; 每一页指向 4K 的空间
|
||||
loop .2
|
||||
|
||||
mov eax, PageDirBase
|
||||
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 [BaseOfKernelFilePhyAddr + 2Ch]; ┓ ecx <- pELFHdr->e_phnum
|
||||
movzx ecx, cx ; ┛
|
||||
mov esi, [BaseOfKernelFilePhyAddr + 1Ch] ; esi <- pELFHdr->e_phoff
|
||||
add esi, BaseOfKernelFilePhyAddr ; 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, BaseOfKernelFilePhyAddr ; ┣ ::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
|
||||
_szReturn: db 0Ah, 0
|
||||
;; 变量
|
||||
_dwMCRNumber: dd 0 ; Memory Check Result
|
||||
_dwDispPos: dd (80 * 6 + 0) * 2 ; 屏幕第 6 行, 第 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 BaseOfLoaderPhyAddr + _szMemChkTitle
|
||||
szRAMSize equ BaseOfLoaderPhyAddr + _szRAMSize
|
||||
szReturn equ BaseOfLoaderPhyAddr + _szReturn
|
||||
dwDispPos equ BaseOfLoaderPhyAddr + _dwDispPos
|
||||
dwMemSize equ BaseOfLoaderPhyAddr + _dwMemSize
|
||||
dwMCRNumber equ BaseOfLoaderPhyAddr + _dwMCRNumber
|
||||
ARDStruct equ BaseOfLoaderPhyAddr + _ARDStruct
|
||||
dwBaseAddrLow equ BaseOfLoaderPhyAddr + _dwBaseAddrLow
|
||||
dwBaseAddrHigh equ BaseOfLoaderPhyAddr + _dwBaseAddrHigh
|
||||
dwLengthLow equ BaseOfLoaderPhyAddr + _dwLengthLow
|
||||
dwLengthHigh equ BaseOfLoaderPhyAddr + _dwLengthHigh
|
||||
dwType equ BaseOfLoaderPhyAddr + _dwType
|
||||
MemChkBuf equ BaseOfLoaderPhyAddr + _MemChkBuf
|
||||
|
||||
|
||||
; 堆栈就在数据段的末尾
|
||||
StackSpace: times 1000h db 0
|
||||
TopOfStack equ BaseOfLoaderPhyAddr + $ ; 栈顶
|
||||
; SECTION .data1 之结束 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
@ -0,0 +1,69 @@
|
|||
|
||||
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
const.h
|
||||
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
Forrest Yu, 2005
|
||||
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
|
||||
|
||||
#ifndef _ORANGES_CONST_H_
|
||||
#define _ORANGES_CONST_H_
|
||||
|
||||
|
||||
/* EXTERN */
|
||||
#define EXTERN extern /* EXTERN is defined as extern except in global.c */
|
||||
|
||||
/* 函数类型 */
|
||||
#define PUBLIC /* PUBLIC is the opposite of PRIVATE */
|
||||
#define PRIVATE static /* PRIVATE x limits the scope of x */
|
||||
|
||||
/* Boolean */
|
||||
#define TRUE 1
|
||||
#define FALSE 0
|
||||
|
||||
/* 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
|
||||
|
||||
/* 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) */
|
||||
|
||||
/* 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 */
|
||||
|
||||
/* system call */
|
||||
//TODO 系统调用数量
|
||||
//不被分配时间片的系统调用、打印字符串的系统调用、PV操作的系统调用
|
||||
#define NR_SYS_CALL 5
|
||||
|
||||
#endif /* _ORANGES_CONST_H_ */
|
|
@ -0,0 +1,31 @@
|
|||
|
||||
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
global.h
|
||||
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
Forrest Yu, 2005
|
||||
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
|
||||
|
||||
/* EXTERN is defined as extern except in global.c */
|
||||
#ifdef GLOBAL_VARIABLES_HERE
|
||||
#undef EXTERN
|
||||
#define EXTERN
|
||||
#endif
|
||||
|
||||
EXTERN int ticks;
|
||||
|
||||
EXTERN int disp_pos;
|
||||
EXTERN u8 gdt_ptr[6]; // 0~15:Limit 16~47:Base
|
||||
EXTERN DESCRIPTOR gdt[GDT_SIZE];
|
||||
EXTERN u8 idt_ptr[6]; // 0~15:Limit 16~47:Base
|
||||
EXTERN GATE idt[IDT_SIZE];
|
||||
|
||||
EXTERN u32 k_reenter;
|
||||
|
||||
EXTERN TSS tss;
|
||||
EXTERN PROCESS* p_proc_ready;
|
||||
|
||||
extern PROCESS proc_table[];
|
||||
extern char task_stack[];
|
||||
extern TASK task_table[];
|
||||
extern irq_handler irq_table[];
|
||||
|
|
@ -0,0 +1,94 @@
|
|||
|
||||
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
proc.h
|
||||
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
Forrest Yu, 2005
|
||||
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
|
||||
|
||||
|
||||
typedef struct s_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 */
|
||||
}STACK_FRAME;
|
||||
|
||||
|
||||
//相互持有引用的定义
|
||||
typedef struct s_proc PROCESS;
|
||||
typedef struct semaphore SEMAPHORE;
|
||||
|
||||
//TODO 信号量
|
||||
struct semaphore{
|
||||
int value; //当前资源最大允许个数
|
||||
int s; //头指针
|
||||
int e; //尾指针
|
||||
PROCESS *queue[1000]; //进程队列
|
||||
};
|
||||
|
||||
|
||||
//TODO
|
||||
struct s_proc {
|
||||
STACK_FRAME regs; /* process registers saved in stack frame */
|
||||
|
||||
u16 ldt_sel; /* gdt selector giving ldt base and limit */
|
||||
DESCRIPTOR ldts[LDT_SIZE]; /* local descriptors for code and data */
|
||||
|
||||
int ticks; /* remained ticks */
|
||||
int priority;
|
||||
|
||||
u32 pid; /* process id passed in from MM */
|
||||
char p_name[16]; /* name of the process */
|
||||
|
||||
int wake; //TODO 进程睡眠到什么时间
|
||||
SEMAPHORE *waiting_semaphore; //等待信号量
|
||||
|
||||
};
|
||||
|
||||
typedef struct s_task {
|
||||
task_f initial_eip;
|
||||
int stacksize;
|
||||
char name[32];
|
||||
}TASK;
|
||||
|
||||
|
||||
//TODO 6个任务
|
||||
/* Number of tasks */
|
||||
#define NR_TASKS 6
|
||||
|
||||
/* stacks of tasks */
|
||||
// #define STACK_SIZE_TESTA 0x8000
|
||||
// #define STACK_SIZE_TESTB 0x8000
|
||||
// #define STACK_SIZE_TESTC 0x8000
|
||||
#define STACK_SIZE_A 0x8000
|
||||
#define STACK_SIZE_READER_B 0x8000
|
||||
#define STACK_SIZE_READER_C 0x8000
|
||||
#define STACK_SIZE_READER_D 0x8000
|
||||
#define STACK_SIZE_WRITER_E 0x8000
|
||||
#define STACK_SIZE_WRITER_F 0x8000
|
||||
|
||||
|
||||
// #define STACK_SIZE_TOTAL (STACK_SIZE_TESTA + \
|
||||
// STACK_SIZE_TESTB + \
|
||||
// STACK_SIZE_TESTC)
|
||||
|
||||
#define STACK_SIZE_TOTAL (STACK_SIZE_A + \
|
||||
STACK_SIZE_READER_B + \
|
||||
STACK_SIZE_READER_C + \
|
||||
STACK_SIZE_READER_D + \
|
||||
STACK_SIZE_WRITER_E + \
|
||||
STACK_SIZE_WRITER_F)
|
|
@ -0,0 +1,154 @@
|
|||
|
||||
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
protect.h
|
||||
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
Forrest Yu, 2005
|
||||
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
|
||||
|
||||
#ifndef _ORANGES_PROTECT_H_
|
||||
#define _ORANGES_PROTECT_H_
|
||||
|
||||
|
||||
/* 存储段描述符/系统段描述符 */
|
||||
typedef struct s_descriptor /* 共 8 个字节 */
|
||||
{
|
||||
u16 limit_low; /* Limit */
|
||||
u16 base_low; /* Base */
|
||||
u8 base_mid; /* Base */
|
||||
u8 attr1; /* P(1) DPL(2) DT(1) TYPE(4) */
|
||||
u8 limit_high_attr2; /* G(1) D(1) 0(1) AVL(1) LimitHigh(4) */
|
||||
u8 base_high; /* Base */
|
||||
}DESCRIPTOR;
|
||||
|
||||
/* 门描述符 */
|
||||
typedef struct s_gate
|
||||
{
|
||||
u16 offset_low; /* Offset Low */
|
||||
u16 selector; /* Selector */
|
||||
u8 dcount; /* 该字段只在调用门描述符中有效。
|
||||
如果在利用调用门调用子程序时引起特权级的转换和堆栈的改变,需要将外层堆栈中的参数复制到内层堆栈。
|
||||
该双字计数字段就是用于说明这种情况发生时,要复制的双字参数的数量。 */
|
||||
u8 attr; /* P(1) DPL(2) DT(1) TYPE(4) */
|
||||
u16 offset_high; /* Offset High */
|
||||
}GATE;
|
||||
|
||||
typedef struct s_tss {
|
||||
u32 backlink;
|
||||
u32 esp0; /* stack pointer to use during interrupt */
|
||||
u32 ss0; /* " segment " " " " */
|
||||
u32 esp1;
|
||||
u32 ss1;
|
||||
u32 esp2;
|
||||
u32 ss2;
|
||||
u32 cr3;
|
||||
u32 eip;
|
||||
u32 flags;
|
||||
u32 eax;
|
||||
u32 ecx;
|
||||
u32 edx;
|
||||
u32 ebx;
|
||||
u32 esp;
|
||||
u32 ebp;
|
||||
u32 esi;
|
||||
u32 edi;
|
||||
u32 es;
|
||||
u32 cs;
|
||||
u32 ss;
|
||||
u32 ds;
|
||||
u32 fs;
|
||||
u32 gs;
|
||||
u32 ldt;
|
||||
u16 trap;
|
||||
u16 iobase; /* I/O位图基址大于或等于TSS段界限,就表示没有I/O许可位图 */
|
||||
/*u8 iomap[2];*/
|
||||
}TSS;
|
||||
|
||||
/* GDT */
|
||||
/* 描述符索引 */
|
||||
#define INDEX_DUMMY 0 // ┓
|
||||
#define INDEX_FLAT_C 1 // ┣ LOADER 里面已经确定了的.
|
||||
#define INDEX_FLAT_RW 2 // ┃
|
||||
#define INDEX_VIDEO 3 // ┛
|
||||
#define INDEX_TSS 4
|
||||
#define INDEX_LDT_FIRST 5
|
||||
/* 选择子 */
|
||||
#define SELECTOR_DUMMY 0 // ┓
|
||||
#define SELECTOR_FLAT_C 0x08 // ┣ LOADER 里面已经确定了的.
|
||||
#define SELECTOR_FLAT_RW 0x10 // ┃
|
||||
#define SELECTOR_VIDEO (0x18+3) // ┛<-- RPL=3
|
||||
#define SELECTOR_TSS 0x20 // TSS. 从外层跳到内存时 SS 和 ESP 的值从里面获得.
|
||||
#define SELECTOR_LDT_FIRST 0x28
|
||||
|
||||
#define SELECTOR_KERNEL_CS SELECTOR_FLAT_C
|
||||
#define SELECTOR_KERNEL_DS SELECTOR_FLAT_RW
|
||||
#define SELECTOR_KERNEL_GS SELECTOR_VIDEO
|
||||
|
||||
/* 每个任务有一个单独的 LDT, 每个 LDT 中的描述符个数: */
|
||||
#define LDT_SIZE 2
|
||||
|
||||
/* 描述符类型值说明 */
|
||||
#define DA_32 0x4000 /* 32 位段 */
|
||||
#define DA_LIMIT_4K 0x8000 /* 段界限粒度为 4K 字节 */
|
||||
#define DA_DPL0 0x00 /* DPL = 0 */
|
||||
#define DA_DPL1 0x20 /* DPL = 1 */
|
||||
#define DA_DPL2 0x40 /* DPL = 2 */
|
||||
#define DA_DPL3 0x60 /* DPL = 3 */
|
||||
/* 存储段描述符类型值说明 */
|
||||
#define DA_DR 0x90 /* 存在的只读数据段类型值 */
|
||||
#define DA_DRW 0x92 /* 存在的可读写数据段属性值 */
|
||||
#define DA_DRWA 0x93 /* 存在的已访问可读写数据段类型值 */
|
||||
#define DA_C 0x98 /* 存在的只执行代码段属性值 */
|
||||
#define DA_CR 0x9A /* 存在的可执行可读代码段属性值 */
|
||||
#define DA_CCO 0x9C /* 存在的只执行一致代码段属性值 */
|
||||
#define DA_CCOR 0x9E /* 存在的可执行可读一致代码段属性值 */
|
||||
/* 系统段描述符类型值说明 */
|
||||
#define DA_LDT 0x82 /* 局部描述符表段类型值 */
|
||||
#define DA_TaskGate 0x85 /* 任务门类型值 */
|
||||
#define DA_386TSS 0x89 /* 可用 386 任务状态段类型值 */
|
||||
#define DA_386CGate 0x8C /* 386 调用门类型值 */
|
||||
#define DA_386IGate 0x8E /* 386 中断门类型值 */
|
||||
#define DA_386TGate 0x8F /* 386 陷阱门类型值 */
|
||||
|
||||
/* 选择子类型值说明 */
|
||||
/* 其中, SA_ : Selector Attribute */
|
||||
#define SA_RPL_MASK 0xFFFC
|
||||
#define SA_RPL0 0
|
||||
#define SA_RPL1 1
|
||||
#define SA_RPL2 2
|
||||
#define SA_RPL3 3
|
||||
|
||||
#define SA_TI_MASK 0xFFFB
|
||||
#define SA_TIG 0
|
||||
#define SA_TIL 4
|
||||
|
||||
/* 中断向量 */
|
||||
#define INT_VECTOR_DIVIDE 0x0
|
||||
#define INT_VECTOR_DEBUG 0x1
|
||||
#define INT_VECTOR_NMI 0x2
|
||||
#define INT_VECTOR_BREAKPOINT 0x3
|
||||
#define INT_VECTOR_OVERFLOW 0x4
|
||||
#define INT_VECTOR_BOUNDS 0x5
|
||||
#define INT_VECTOR_INVAL_OP 0x6
|
||||
#define INT_VECTOR_COPROC_NOT 0x7
|
||||
#define INT_VECTOR_DOUBLE_FAULT 0x8
|
||||
#define INT_VECTOR_COPROC_SEG 0x9
|
||||
#define INT_VECTOR_INVAL_TSS 0xA
|
||||
#define INT_VECTOR_SEG_NOT 0xB
|
||||
#define INT_VECTOR_STACK_FAULT 0xC
|
||||
#define INT_VECTOR_PROTECTION 0xD
|
||||
#define INT_VECTOR_PAGE_FAULT 0xE
|
||||
#define INT_VECTOR_COPROC_ERR 0x10
|
||||
|
||||
/* 中断向量 */
|
||||
#define INT_VECTOR_IRQ0 0x20
|
||||
#define INT_VECTOR_IRQ8 0x28
|
||||
|
||||
/* 系统调用 */
|
||||
#define INT_VECTOR_SYS_CALL 0x90
|
||||
|
||||
/* 宏 */
|
||||
/* 线性地址 → 物理地址 */
|
||||
#define vir2phys(seg_base, vir) (u32)(((u32)seg_base) + (u32)(vir))
|
||||
|
||||
|
||||
#endif /* _ORANGES_PROTECT_H_ */
|
|
@ -0,0 +1,75 @@
|
|||
|
||||
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
proto.h
|
||||
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
Forrest Yu, 2005
|
||||
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
|
||||
|
||||
#include "proc.h"
|
||||
|
||||
|
||||
/* klib.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);
|
||||
|
||||
/* protect.c */
|
||||
PUBLIC void init_prot();
|
||||
PUBLIC u32 seg2phys(u16 seg);
|
||||
|
||||
/* klib.c */
|
||||
PUBLIC void delay(int time);
|
||||
|
||||
/* kernel.asm */
|
||||
void restart();
|
||||
|
||||
/* main.c */
|
||||
void TestA();
|
||||
void TestB();
|
||||
void TestC();
|
||||
|
||||
/* i8259.c */
|
||||
PUBLIC void put_irq_handler(int irq, irq_handler handler);
|
||||
PUBLIC void spurious_irq(int irq);
|
||||
|
||||
/* clock.c */
|
||||
PUBLIC void clock_handler(int irq);
|
||||
|
||||
|
||||
/* 以下是系统调用相关 */
|
||||
|
||||
/* proc.c */
|
||||
PUBLIC int sys_get_ticks(); /* sys_call */
|
||||
PUBLIC void sys_ms_delay_proc(int); /* TODO 被分配的时间片的操作*/
|
||||
|
||||
/* syscall.asm */
|
||||
PUBLIC void sys_call(); /* int_handler */
|
||||
PUBLIC int get_ticks();
|
||||
PUBLIC void sys_p_impl(SEMAPHORE *);
|
||||
PUBLIC void sys_v_impl(SEMAPHORE *);
|
||||
|
||||
|
||||
//TODO 新增的系统调用
|
||||
//打印字符串的系统调用,封装内核函数disp_str
|
||||
PUBLIC void print_str(char *);
|
||||
PUBLIC void sys_print_str(char *);
|
||||
|
||||
|
||||
//不被分配时间片的系统调用
|
||||
PUBLIC void sys_ms_delay(int);
|
||||
PUBLIC void ms_delay(int);
|
||||
|
||||
//pv实现
|
||||
PUBLIC void sys_p(SEMAPHORE *);
|
||||
PUBLIC void sys_v(SEMAPHORE *);
|
||||
PUBLIC void p(SEMAPHORE *);
|
||||
PUBLIC void v(SEMAPHORE *);
|
||||
|
||||
//TODO 读者写者问题调用
|
||||
void A();
|
||||
void READER_B();
|
||||
void READER_C();
|
||||
void READER_D();
|
||||
void WRITER_E();
|
||||
void WRITER_F();
|
|
@ -0,0 +1,44 @@
|
|||
|
||||
; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
; sconst.inc
|
||||
; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
; Forrest Yu, 2005
|
||||
; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
|
||||
P_STACKBASE equ 0
|
||||
GSREG equ P_STACKBASE
|
||||
FSREG equ GSREG + 4
|
||||
ESREG equ FSREG + 4
|
||||
DSREG equ ESREG + 4
|
||||
EDIREG equ DSREG + 4
|
||||
ESIREG equ EDIREG + 4
|
||||
EBPREG equ ESIREG + 4
|
||||
KERNELESPREG equ EBPREG + 4
|
||||
EBXREG equ KERNELESPREG + 4
|
||||
EDXREG equ EBXREG + 4
|
||||
ECXREG equ EDXREG + 4
|
||||
EAXREG equ ECXREG + 4
|
||||
RETADR equ EAXREG + 4
|
||||
EIPREG equ RETADR + 4
|
||||
CSREG equ EIPREG + 4
|
||||
EFLAGSREG equ CSREG + 4
|
||||
ESPREG equ EFLAGSREG + 4
|
||||
SSREG equ ESPREG + 4
|
||||
P_STACKTOP equ SSREG + 4
|
||||
P_LDT_SEL equ P_STACKTOP
|
||||
P_LDT equ P_LDT_SEL + 4
|
||||
|
||||
TSS3_S_SP0 equ 4
|
||||
|
||||
INT_M_CTL equ 0x20 ; I/O port for interrupt controller <Master>
|
||||
INT_M_CTLMASK equ 0x21 ; setting bits in this port disables ints <Master>
|
||||
INT_S_CTL equ 0xA0 ; I/O port for second interrupt controller <Slave>
|
||||
INT_S_CTLMASK equ 0xA1 ; setting bits in this port disables ints <Slave>
|
||||
|
||||
EOI equ 0x20
|
||||
|
||||
; 以下选择子值必须与 protect.h 中保持一致!!!
|
||||
SELECTOR_FLAT_C equ 0x08 ; LOADER 里面已经确定了的.
|
||||
SELECTOR_TSS equ 0x20 ; TSS. 从外层跳到内存时 SS 和 ESP 的值从里面获得.
|
||||
SELECTOR_KERNEL_CS equ SELECTOR_FLAT_C
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
|
||||
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
string.h
|
||||
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
Forrest Yu, 2005
|
||||
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
|
||||
|
||||
PUBLIC void* memcpy(void* p_dst, void* p_src, int size);
|
||||
PUBLIC void memset(void* p_dst, char ch, int size);
|
|
@ -0,0 +1,24 @@
|
|||
|
||||
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
type.h
|
||||
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
Forrest Yu, 2005
|
||||
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
|
||||
|
||||
#ifndef _ORANGES_TYPE_H_
|
||||
#define _ORANGES_TYPE_H_
|
||||
|
||||
|
||||
typedef unsigned int u32;
|
||||
typedef unsigned short u16;
|
||||
typedef unsigned char u8;
|
||||
|
||||
|
||||
typedef void (*int_handler) ();
|
||||
typedef void (*task_f) ();
|
||||
typedef void (*irq_handler) (int irq);
|
||||
|
||||
typedef void* system_call;
|
||||
|
||||
|
||||
#endif /* _ORANGES_TYPE_H_ */
|
|
@ -0,0 +1,45 @@
|
|||
|
||||
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
clock.c
|
||||
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
Forrest Yu, 2005
|
||||
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
|
||||
|
||||
#include "type.h"
|
||||
#include "const.h"
|
||||
#include "protect.h"
|
||||
#include "proto.h"
|
||||
#include "string.h"
|
||||
#include "global.h"
|
||||
|
||||
|
||||
/*======================================================================*
|
||||
clock_handler
|
||||
*======================================================================*/
|
||||
PUBLIC void clock_handler(int irq)
|
||||
{
|
||||
ticks++;
|
||||
p_proc_ready->ticks--;
|
||||
|
||||
if (k_reenter != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (p_proc_ready->ticks > 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
schedule();
|
||||
|
||||
}
|
||||
|
||||
/*======================================================================*
|
||||
milli_delay
|
||||
*======================================================================*/
|
||||
PUBLIC void milli_delay(int milli_sec)
|
||||
{
|
||||
int t = get_ticks();
|
||||
|
||||
while(((get_ticks() - t) * 1000 / HZ) < milli_sec) {}
|
||||
}
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
|
||||
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
global.c
|
||||
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
Forrest Yu, 2005
|
||||
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
|
||||
|
||||
#define GLOBAL_VARIABLES_HERE
|
||||
|
||||
#include "type.h"
|
||||
#include "const.h"
|
||||
#include "protect.h"
|
||||
#include "proto.h"
|
||||
#include "global.h"
|
||||
|
||||
|
||||
PUBLIC PROCESS proc_table[NR_TASKS];
|
||||
|
||||
PUBLIC char task_stack[STACK_SIZE_TOTAL];
|
||||
|
||||
// PUBLIC TASK task_table[NR_TASKS] = {{TestA, STACK_SIZE_TESTA, "TestA"},
|
||||
// {TestB, STACK_SIZE_TESTB, "TestB"},
|
||||
// {TestC, STACK_SIZE_TESTC, "TestC"}};
|
||||
|
||||
PUBLIC TASK
|
||||
task_table[NR_TASKS] = {
|
||||
{READER_B,STACK_SIZE_READER_B,"READER_B"},
|
||||
{READER_C,STACK_SIZE_READER_C,"READER_C"},
|
||||
{READER_D,STACK_SIZE_READER_D,"READER_D"},
|
||||
{WRITER_E,STACK_SIZE_WRITER_E,"WRITER_E"},
|
||||
{WRITER_F,STACK_SIZE_WRITER_F,"WRITER_F"},
|
||||
{A,STACK_SIZE_A,"A"}
|
||||
};
|
||||
|
||||
PUBLIC irq_handler irq_table[NR_IRQ];
|
||||
|
||||
//TODO系统调用表中的顺序要和asm文件中的系统调用好保持一致
|
||||
PUBLIC system_call
|
||||
sys_call_table[NR_SYS_CALL] = {
|
||||
sys_get_ticks,
|
||||
sys_print_str,
|
||||
sys_ms_delay,
|
||||
sys_p,
|
||||
sys_v
|
||||
};
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
|
||||
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
i8259.c
|
||||
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
Forrest Yu, 2005
|
||||
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
|
||||
|
||||
|
||||
#include "type.h"
|
||||
#include "const.h"
|
||||
#include "protect.h"
|
||||
#include "proto.h"
|
||||
#include "global.h"
|
||||
|
||||
|
||||
/*======================================================================*
|
||||
init_8259A
|
||||
*======================================================================*/
|
||||
PUBLIC void init_8259A()
|
||||
{
|
||||
out_byte(INT_M_CTL, 0x11); // Master 8259, ICW1.
|
||||
out_byte(INT_S_CTL, 0x11); // Slave 8259, ICW1.
|
||||
out_byte(INT_M_CTLMASK, INT_VECTOR_IRQ0); // Master 8259, ICW2. 设置 '主8259' 的中断入口地址为 0x20.
|
||||
out_byte(INT_S_CTLMASK, INT_VECTOR_IRQ8); // Slave 8259, ICW2. 设置 '从8259' 的中断入口地址为 0x28
|
||||
out_byte(INT_M_CTLMASK, 0x4); // Master 8259, ICW3. IR2 对应 '从8259'.
|
||||
out_byte(INT_S_CTLMASK, 0x2); // Slave 8259, ICW3. 对应 '主8259' 的 IR2.
|
||||
out_byte(INT_M_CTLMASK, 0x1); // Master 8259, ICW4.
|
||||
out_byte(INT_S_CTLMASK, 0x1); // Slave 8259, ICW4.
|
||||
|
||||
out_byte(INT_M_CTLMASK, 0xFF); // Master 8259, OCW1.
|
||||
out_byte(INT_S_CTLMASK, 0xFF); // Slave 8259, OCW1.
|
||||
|
||||
int i;
|
||||
for (i = 0; i < NR_IRQ; i++) {
|
||||
irq_table[i] = spurious_irq;
|
||||
}
|
||||
}
|
||||
|
||||
/*======================================================================*
|
||||
spurious_irq
|
||||
*======================================================================*/
|
||||
PUBLIC void spurious_irq(int irq)
|
||||
{
|
||||
disp_str("spurious_irq: ");
|
||||
disp_int(irq);
|
||||
disp_str("\n");
|
||||
}
|
||||
|
||||
/*======================================================================*
|
||||
put_irq_handler
|
||||
*======================================================================*/
|
||||
PUBLIC void put_irq_handler(int irq, irq_handler handler)
|
||||
{
|
||||
disable_irq(irq);
|
||||
irq_table[irq] = handler;
|
||||
}
|
|
@ -0,0 +1,371 @@
|
|||
|
||||
; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
; kernel.asm
|
||||
; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
; Forrest Yu, 2005
|
||||
; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
|
||||
|
||||
%include "sconst.inc"
|
||||
|
||||
; 导入函数
|
||||
extern cstart
|
||||
extern kernel_main
|
||||
extern exception_handler
|
||||
extern spurious_irq
|
||||
extern clock_handler
|
||||
extern disp_str
|
||||
extern delay
|
||||
extern irq_table
|
||||
|
||||
; 导入全局变量
|
||||
extern gdt_ptr
|
||||
extern idt_ptr
|
||||
extern p_proc_ready
|
||||
extern tss
|
||||
extern disp_pos
|
||||
extern k_reenter
|
||||
extern sys_call_table
|
||||
|
||||
bits 32
|
||||
|
||||
[SECTION .data]
|
||||
clock_int_msg db "^", 0
|
||||
|
||||
[SECTION .bss]
|
||||
StackSpace resb 2 * 1024
|
||||
StackTop: ; 栈顶
|
||||
|
||||
[section .text] ; 代码在此
|
||||
|
||||
global _start ; 导出 _start
|
||||
|
||||
global restart
|
||||
global sys_call
|
||||
|
||||
global divide_error
|
||||
global single_step_exception
|
||||
global nmi
|
||||
global breakpoint_exception
|
||||
global overflow
|
||||
global bounds_check
|
||||
global inval_opcode
|
||||
global copr_not_available
|
||||
global double_fault
|
||||
global copr_seg_overrun
|
||||
global inval_tss
|
||||
global segment_not_present
|
||||
global stack_exception
|
||||
global general_protection
|
||||
global page_fault
|
||||
global copr_error
|
||||
global hwint00
|
||||
global hwint01
|
||||
global hwint02
|
||||
global hwint03
|
||||
global hwint04
|
||||
global hwint05
|
||||
global hwint06
|
||||
global hwint07
|
||||
global hwint08
|
||||
global hwint09
|
||||
global hwint10
|
||||
global hwint11
|
||||
global hwint12
|
||||
global hwint13
|
||||
global hwint14
|
||||
global hwint15
|
||||
|
||||
|
||||
_start:
|
||||
; 此时内存看上去是这样的(更详细的内存情况在 LOADER.ASM 中有说明):
|
||||
; ┃ ┃
|
||||
; ┃ ... ┃
|
||||
; ┣━━━━━━━━━━━━━━━━━━┫
|
||||
; ┃■■■■■■Page Tables■■■■■■┃
|
||||
; ┃■■■■■(大小由LOADER决定)■■■■┃ PageTblBase
|
||||
; 00101000h ┣━━━━━━━━━━━━━━━━━━┫
|
||||
; ┃■■■■Page Directory Table■■■■┃ PageDirBase = 1M
|
||||
; 00100000h ┣━━━━━━━━━━━━━━━━━━┫
|
||||
; ┃□□□□ Hardware Reserved □□□□┃ B8000h ← gs
|
||||
; 9FC00h ┣━━━━━━━━━━━━━━━━━━┫
|
||||
; ┃■■■■■■■LOADER.BIN■■■■■■┃ somewhere in LOADER ← esp
|
||||
; 90000h ┣━━━━━━━━━━━━━━━━━━┫
|
||||
; ┃■■■■■■■KERNEL.BIN■■■■■■┃
|
||||
; 80000h ┣━━━━━━━━━━━━━━━━━━┫
|
||||
; ┃■■■■■■■■KERNEL■■■■■■■┃ 30400h ← KERNEL 入口 (KernelEntryPointPhyAddr)
|
||||
; 30000h ┣━━━━━━━━━━━━━━━━━━┫
|
||||
; ┋ ... ┋
|
||||
; ┋ ┋
|
||||
; 0h ┗━━━━━━━━━━━━━━━━━━┛ ← cs, ds, es, fs, ss
|
||||
;
|
||||
;
|
||||
; GDT 以及相应的描述符是这样的:
|
||||
;
|
||||
; Descriptors Selectors
|
||||
; ┏━━━━━━━━━━━━━━━━━━┓
|
||||
; ┃ Dummy Descriptor ┃
|
||||
; ┣━━━━━━━━━━━━━━━━━━┫
|
||||
; ┃ DESC_FLAT_C (0~4G) ┃ 8h = cs
|
||||
; ┣━━━━━━━━━━━━━━━━━━┫
|
||||
; ┃ DESC_FLAT_RW (0~4G) ┃ 10h = ds, es, fs, ss
|
||||
; ┣━━━━━━━━━━━━━━━━━━┫
|
||||
; ┃ DESC_VIDEO ┃ 1Bh = gs
|
||||
; ┗━━━━━━━━━━━━━━━━━━┛
|
||||
;
|
||||
; 注意! 在使用 C 代码的时候一定要保证 ds, es, ss 这几个段寄存器的值是一样的
|
||||
; 因为编译器有可能编译出使用它们的代码, 而编译器默认它们是一样的. 比如串拷贝操作会用到 ds 和 es.
|
||||
;
|
||||
;
|
||||
|
||||
|
||||
; 把 esp 从 LOADER 挪到 KERNEL
|
||||
mov esp, StackTop ; 堆栈在 bss 段中
|
||||
|
||||
mov dword [disp_pos], 0
|
||||
|
||||
sgdt [gdt_ptr] ; cstart() 中将会用到 gdt_ptr
|
||||
call cstart ; 在此函数中改变了gdt_ptr,让它指向新的GDT
|
||||
lgdt [gdt_ptr] ; 使用新的GDT
|
||||
|
||||
lidt [idt_ptr]
|
||||
|
||||
jmp SELECTOR_KERNEL_CS:csinit
|
||||
csinit: ; “这个跳转指令强制使用刚刚初始化的结构”——<<OS:D&I 2nd>> P90.
|
||||
|
||||
;jmp 0x40:0
|
||||
;ud2
|
||||
|
||||
|
||||
xor eax, eax
|
||||
mov ax, SELECTOR_TSS
|
||||
ltr ax
|
||||
|
||||
;sti
|
||||
jmp kernel_main
|
||||
|
||||
;hlt
|
||||
|
||||
|
||||
; 中断和异常 -- 硬件中断
|
||||
; ---------------------------------
|
||||
%macro hwint_master 1
|
||||
call save
|
||||
in al, INT_M_CTLMASK ; `.
|
||||
or al, (1 << %1) ; | 屏蔽当前中断
|
||||
out INT_M_CTLMASK, al ; /
|
||||
mov al, EOI ; `. 置EOI位
|
||||
out INT_M_CTL, al ; /
|
||||
sti ; CPU在响应中断的过程中会自动关中断,这句之后就允许响应新的中断
|
||||
push %1 ; `.
|
||||
call [irq_table + 4 * %1] ; | 中断处理程序
|
||||
pop ecx ; /
|
||||
cli
|
||||
in al, INT_M_CTLMASK ; `.
|
||||
and al, ~(1 << %1) ; | 恢复接受当前中断
|
||||
out INT_M_CTLMASK, al ; /
|
||||
ret
|
||||
%endmacro
|
||||
|
||||
|
||||
ALIGN 16
|
||||
hwint00: ; Interrupt routine for irq 0 (the clock).
|
||||
hwint_master 0
|
||||
|
||||
ALIGN 16
|
||||
hwint01: ; Interrupt routine for irq 1 (keyboard)
|
||||
hwint_master 1
|
||||
|
||||
ALIGN 16
|
||||
hwint02: ; Interrupt routine for irq 2 (cascade!)
|
||||
hwint_master 2
|
||||
|
||||
ALIGN 16
|
||||
hwint03: ; Interrupt routine for irq 3 (second serial)
|
||||
hwint_master 3
|
||||
|
||||
ALIGN 16
|
||||
hwint04: ; Interrupt routine for irq 4 (first serial)
|
||||
hwint_master 4
|
||||
|
||||
ALIGN 16
|
||||
hwint05: ; Interrupt routine for irq 5 (XT winchester)
|
||||
hwint_master 5
|
||||
|
||||
ALIGN 16
|
||||
hwint06: ; Interrupt routine for irq 6 (floppy)
|
||||
hwint_master 6
|
||||
|
||||
ALIGN 16
|
||||
hwint07: ; Interrupt routine for irq 7 (printer)
|
||||
hwint_master 7
|
||||
|
||||
; ---------------------------------
|
||||
%macro hwint_slave 1
|
||||
push %1
|
||||
call spurious_irq
|
||||
add esp, 4
|
||||
hlt
|
||||
%endmacro
|
||||
; ---------------------------------
|
||||
|
||||
ALIGN 16
|
||||
hwint08: ; Interrupt routine for irq 8 (realtime clock).
|
||||
hwint_slave 8
|
||||
|
||||
ALIGN 16
|
||||
hwint09: ; Interrupt routine for irq 9 (irq 2 redirected)
|
||||
hwint_slave 9
|
||||
|
||||
ALIGN 16
|
||||
hwint10: ; Interrupt routine for irq 10
|
||||
hwint_slave 10
|
||||
|
||||
ALIGN 16
|
||||
hwint11: ; Interrupt routine for irq 11
|
||||
hwint_slave 11
|
||||
|
||||
ALIGN 16
|
||||
hwint12: ; Interrupt routine for irq 12
|
||||
hwint_slave 12
|
||||
|
||||
ALIGN 16
|
||||
hwint13: ; Interrupt routine for irq 13 (FPU exception)
|
||||
hwint_slave 13
|
||||
|
||||
ALIGN 16
|
||||
hwint14: ; Interrupt routine for irq 14 (AT winchester)
|
||||
hwint_slave 14
|
||||
|
||||
ALIGN 16
|
||||
hwint15: ; Interrupt routine for irq 15
|
||||
hwint_slave 15
|
||||
|
||||
|
||||
|
||||
; 中断和异常 -- 异常
|
||||
divide_error:
|
||||
push 0xFFFFFFFF ; no err code
|
||||
push 0 ; vector_no = 0
|
||||
jmp exception
|
||||
single_step_exception:
|
||||
push 0xFFFFFFFF ; no err code
|
||||
push 1 ; vector_no = 1
|
||||
jmp exception
|
||||
nmi:
|
||||
push 0xFFFFFFFF ; no err code
|
||||
push 2 ; vector_no = 2
|
||||
jmp exception
|
||||
breakpoint_exception:
|
||||
push 0xFFFFFFFF ; no err code
|
||||
push 3 ; vector_no = 3
|
||||
jmp exception
|
||||
overflow:
|
||||
push 0xFFFFFFFF ; no err code
|
||||
push 4 ; vector_no = 4
|
||||
jmp exception
|
||||
bounds_check:
|
||||
push 0xFFFFFFFF ; no err code
|
||||
push 5 ; vector_no = 5
|
||||
jmp exception
|
||||
inval_opcode:
|
||||
push 0xFFFFFFFF ; no err code
|
||||
push 6 ; vector_no = 6
|
||||
jmp exception
|
||||
copr_not_available:
|
||||
push 0xFFFFFFFF ; no err code
|
||||
push 7 ; vector_no = 7
|
||||
jmp exception
|
||||
double_fault:
|
||||
push 8 ; vector_no = 8
|
||||
jmp exception
|
||||
copr_seg_overrun:
|
||||
push 0xFFFFFFFF ; no err code
|
||||
push 9 ; vector_no = 9
|
||||
jmp exception
|
||||
inval_tss:
|
||||
push 10 ; vector_no = A
|
||||
jmp exception
|
||||
segment_not_present:
|
||||
push 11 ; vector_no = B
|
||||
jmp exception
|
||||
stack_exception:
|
||||
push 12 ; vector_no = C
|
||||
jmp exception
|
||||
general_protection:
|
||||
push 13 ; vector_no = D
|
||||
jmp exception
|
||||
page_fault:
|
||||
push 14 ; vector_no = E
|
||||
jmp exception
|
||||
copr_error:
|
||||
push 0xFFFFFFFF ; no err code
|
||||
push 16 ; vector_no = 10h
|
||||
jmp exception
|
||||
|
||||
exception:
|
||||
call exception_handler
|
||||
add esp, 4*2 ; 让栈顶指向 EIP,堆栈中从顶向下依次是:EIP、CS、EFLAGS
|
||||
hlt
|
||||
|
||||
; ====================================================================================
|
||||
; save
|
||||
; ====================================================================================
|
||||
save:
|
||||
pushad ; `.
|
||||
push ds ; |
|
||||
push es ; | 保存原寄存器值
|
||||
push fs ; |
|
||||
push gs ; /
|
||||
mov dx, ss
|
||||
mov ds, dx
|
||||
mov es, dx
|
||||
|
||||
mov esi, esp ;esi = 进程表起始地址
|
||||
|
||||
inc dword [k_reenter] ;k_reenter++;
|
||||
cmp dword [k_reenter], 0 ;if(k_reenter ==0)
|
||||
jne .1 ;{
|
||||
mov esp, StackTop ; mov esp, StackTop <--切换到内核栈
|
||||
push restart ; push restart
|
||||
jmp [esi + RETADR - P_STACKBASE]; return;
|
||||
.1: ;} else { 已经在内核栈,不需要再切换
|
||||
push restart_reenter ; push restart_reenter
|
||||
jmp [esi + RETADR - P_STACKBASE]; return;
|
||||
;}
|
||||
|
||||
|
||||
; ====================================================================================
|
||||
; sys_call
|
||||
; ====================================================================================
|
||||
sys_call:
|
||||
call save
|
||||
|
||||
sti
|
||||
|
||||
call [sys_call_table + eax * 4]
|
||||
mov [esi + EAXREG - P_STACKBASE], eax
|
||||
|
||||
cli
|
||||
|
||||
ret
|
||||
|
||||
|
||||
; ====================================================================================
|
||||
; restart
|
||||
; ====================================================================================
|
||||
restart:
|
||||
mov esp, [p_proc_ready]
|
||||
lldt [esp + P_LDT_SEL]
|
||||
lea eax, [esp + P_STACKTOP]
|
||||
mov dword [tss + TSS3_S_SP0], eax
|
||||
restart_reenter:
|
||||
dec dword [k_reenter]
|
||||
pop gs
|
||||
pop fs
|
||||
pop es
|
||||
pop ds
|
||||
popad
|
||||
add esp, 4
|
||||
iretd
|
||||
|
|
@ -0,0 +1,387 @@
|
|||
|
||||
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
main.c
|
||||
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
Forrest Yu, 2005
|
||||
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
|
||||
|
||||
#include "type.h"
|
||||
#include "const.h"
|
||||
#include "protect.h"
|
||||
#include "proto.h"
|
||||
#include "string.h"
|
||||
#include "global.h"
|
||||
|
||||
//TODO 所有要改动的超参数
|
||||
//0读者优先,1写者优先,2读写公平
|
||||
#define STRATEGY 2
|
||||
#define READERS_ALLOWED 3
|
||||
#define B_SLEEP_TIME 1
|
||||
#define C_SLEEP_TIME 2
|
||||
#define D_SLEEP_TIME 1
|
||||
#define E_SLEEP_TIME 1
|
||||
#define F_SLEEP_TIME 2
|
||||
#define B_PROC_TIME 2
|
||||
#define C_PROC_TIME 3
|
||||
#define D_PROC_TIME 3
|
||||
#define E_PROC_TIME 3
|
||||
#define F_PROC_TIME 4
|
||||
|
||||
//TODO 声明
|
||||
//每个进程的状态,需要进程维护,由A来输出,0表示正在使用,1表示等待使用,2表示休眠
|
||||
#define TIME_SEG (500) //时间片
|
||||
int proc_state[5]={1,1,1,1,1};
|
||||
int thread_sleep_time[5];
|
||||
int thread_proc_time[5];
|
||||
//两个信号量
|
||||
SEMAPHORE w_mutex;
|
||||
SEMAPHORE r_mutex;
|
||||
//额外的信号量
|
||||
SEMAPHORE S;
|
||||
int readers_cnt;//目前在线的读者数量
|
||||
int writers_cnt;//目前在线的写者数量
|
||||
int mode;//模式
|
||||
|
||||
/*======================================================================*
|
||||
TODO clearScreen
|
||||
*======================================================================*/
|
||||
void clearScreen(){
|
||||
u8 *base=(u8 *)0xB8000;
|
||||
for(int i=0;i<0x8000;i+=2){
|
||||
base[i]=' ';
|
||||
}
|
||||
disp_pos=0;
|
||||
}
|
||||
|
||||
/*======================================================================*
|
||||
TODO init_semaphore
|
||||
*======================================================================*/
|
||||
void init_semaphore(SEMAPHORE *semaphore, int value)
|
||||
{
|
||||
semaphore->s=0;
|
||||
semaphore->e=0;
|
||||
semaphore->value=value;
|
||||
|
||||
}
|
||||
|
||||
/*======================================================================*
|
||||
kernel_main
|
||||
*======================================================================*/
|
||||
PUBLIC int kernel_main()
|
||||
{
|
||||
disp_str("-----\"kernel_main\" begins-----\n");
|
||||
|
||||
TASK* p_task = task_table;
|
||||
PROCESS* p_proc = proc_table;
|
||||
char* p_task_stack = task_stack + STACK_SIZE_TOTAL;
|
||||
u16 selector_ldt = SELECTOR_LDT_FIRST;
|
||||
int i;
|
||||
for (i = 0; i < NR_TASKS; i++) {
|
||||
strcpy(p_proc->p_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(DESCRIPTOR));
|
||||
p_proc->ldts[0].attr1 = DA_C | PRIVILEGE_TASK << 5;
|
||||
memcpy(&p_proc->ldts[1], &gdt[SELECTOR_KERNEL_DS >> 3],
|
||||
sizeof(DESCRIPTOR));
|
||||
p_proc->ldts[1].attr1 = DA_DRW | PRIVILEGE_TASK << 5;
|
||||
p_proc->regs.cs = ((8 * 0) & SA_RPL_MASK & SA_TI_MASK)
|
||||
| SA_TIL | RPL_TASK;
|
||||
p_proc->regs.ds = ((8 * 1) & SA_RPL_MASK & SA_TI_MASK)
|
||||
| SA_TIL | RPL_TASK;
|
||||
p_proc->regs.es = ((8 * 1) & SA_RPL_MASK & SA_TI_MASK)
|
||||
| SA_TIL | RPL_TASK;
|
||||
p_proc->regs.fs = ((8 * 1) & SA_RPL_MASK & SA_TI_MASK)
|
||||
| SA_TIL | RPL_TASK;
|
||||
p_proc->regs.ss = ((8 * 1) & SA_RPL_MASK & SA_TI_MASK)
|
||||
| SA_TIL | RPL_TASK;
|
||||
p_proc->regs.gs = (SELECTOR_KERNEL_GS & SA_RPL_MASK)
|
||||
| RPL_TASK;
|
||||
|
||||
p_proc->regs.eip = (u32)p_task->initial_eip;
|
||||
p_proc->regs.esp = (u32)p_task_stack;
|
||||
p_proc->regs.eflags = 0x1202; /* IF=1, IOPL=1 */
|
||||
|
||||
p_task_stack -= p_task->stacksize;
|
||||
p_proc++;
|
||||
p_task++;
|
||||
selector_ldt += 1 << 3;
|
||||
}
|
||||
|
||||
proc_table[0].ticks = proc_table[0].priority = 15;
|
||||
proc_table[1].ticks = proc_table[1].priority = 5;
|
||||
proc_table[2].ticks = proc_table[2].priority = 3;
|
||||
|
||||
k_reenter = 0;
|
||||
ticks = 0;
|
||||
|
||||
p_proc_ready = proc_table;
|
||||
|
||||
/* 初始化 8253 PIT */
|
||||
out_byte(TIMER_MODE, RATE_GENERATOR);
|
||||
out_byte(TIMER0, (u8) (TIMER_FREQ/HZ) );
|
||||
out_byte(TIMER0, (u8) ((TIMER_FREQ/HZ) >> 8));
|
||||
|
||||
put_irq_handler(CLOCK_IRQ, clock_handler); /* 设定时钟中断处理程序 */
|
||||
enable_irq(CLOCK_IRQ); /* 让8259A可以接收时钟中断 */
|
||||
|
||||
|
||||
//TODO 初始化超参数
|
||||
init_semaphore(&r_mutex, READERS_ALLOWED);
|
||||
init_semaphore(&w_mutex, 1);
|
||||
init_semaphore(&S, 1);
|
||||
|
||||
thread_sleep_time[0]=B_SLEEP_TIME*TIME_SEG;
|
||||
thread_sleep_time[1]=C_SLEEP_TIME*TIME_SEG;
|
||||
thread_sleep_time[2]=D_SLEEP_TIME*TIME_SEG;
|
||||
thread_sleep_time[3]=E_SLEEP_TIME*TIME_SEG;
|
||||
thread_sleep_time[4]=F_SLEEP_TIME*TIME_SEG;
|
||||
|
||||
thread_proc_time[0]=B_PROC_TIME*TIME_SEG;
|
||||
thread_proc_time[1]=C_PROC_TIME*TIME_SEG;
|
||||
thread_proc_time[2]=D_PROC_TIME*TIME_SEG;
|
||||
thread_proc_time[3]=E_PROC_TIME*TIME_SEG;
|
||||
thread_proc_time[4]=F_PROC_TIME*TIME_SEG;
|
||||
|
||||
readers_cnt=0;
|
||||
writers_cnt=0;
|
||||
mode=STRATEGY;
|
||||
clearScreen();
|
||||
restart();
|
||||
|
||||
while(1){}
|
||||
}
|
||||
|
||||
/*======================================================================*
|
||||
TestA
|
||||
*======================================================================*/
|
||||
// void TestA()
|
||||
// {
|
||||
// int i = 0;
|
||||
// while (1) {
|
||||
// disp_str("A.");
|
||||
// milli_delay(10);
|
||||
// }
|
||||
// }
|
||||
|
||||
/*======================================================================*
|
||||
TestB
|
||||
*======================================================================*/
|
||||
// void TestB()
|
||||
// {
|
||||
// int i = 0x1000;
|
||||
// while(1){
|
||||
// disp_str("B.");
|
||||
// milli_delay(10);
|
||||
// }
|
||||
// }
|
||||
|
||||
/*======================================================================*
|
||||
TestC
|
||||
*======================================================================*/
|
||||
// void TestC()
|
||||
// {
|
||||
// int i = 0x2000;
|
||||
// while(1){
|
||||
// disp_str("C.");
|
||||
// milli_delay(10);
|
||||
// }
|
||||
// }
|
||||
|
||||
|
||||
/*======================================================================*
|
||||
A
|
||||
*======================================================================*/
|
||||
void A()
|
||||
{
|
||||
int i = 1;
|
||||
while (1) {
|
||||
if (i > 20) { while (1); }
|
||||
char *str;
|
||||
if (i < 10) {
|
||||
str = " \0";
|
||||
str[0] = (char) ('0' + i);
|
||||
}
|
||||
else {
|
||||
str = " \0";
|
||||
str[0] = (char) ('0' + i / 10);
|
||||
str[1] = (char) ('0' + i % 10);
|
||||
}
|
||||
print_str(str);
|
||||
for (int j = 0; j < 6; ++j) {
|
||||
//每个进程的状态,需要每个进程维护,并且由A来输出 0-正在使用 1-等待使用 2-休眠
|
||||
//int proc_state[5] = {-1, 0, 1, 2, -1};
|
||||
if (j == 5) {
|
||||
print_str("\n");
|
||||
break;
|
||||
}
|
||||
if (proc_state[j] == -1) print_str("None ");
|
||||
else if (proc_state[j] == 0) disp_color_str("O ", 0x0A);
|
||||
else if (proc_state[j] == 1) disp_color_str("X ", 0x0C);
|
||||
else if (proc_state[j] == 2) disp_color_str("Z ", 0x03);
|
||||
}
|
||||
i++;
|
||||
milli_delay(TIME_SEG);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*======================================================================*
|
||||
READER_B
|
||||
*======================================================================*/
|
||||
void READER_B()
|
||||
{
|
||||
reader(0);
|
||||
}
|
||||
|
||||
/*======================================================================*
|
||||
READER_C
|
||||
*======================================================================*/
|
||||
void READER_C()
|
||||
{
|
||||
reader(1);
|
||||
}
|
||||
|
||||
/*======================================================================*
|
||||
READER_D
|
||||
*======================================================================*/
|
||||
void READER_D()
|
||||
{
|
||||
reader(2);
|
||||
}
|
||||
|
||||
/*======================================================================*
|
||||
WRITER_E
|
||||
*======================================================================*/
|
||||
void WRITER_E()
|
||||
{
|
||||
writer(3);
|
||||
}
|
||||
|
||||
/*======================================================================*
|
||||
WRITER_F
|
||||
*======================================================================*/
|
||||
void WRITER_F()
|
||||
{
|
||||
writer(4);
|
||||
}
|
||||
|
||||
/*======================================================================*
|
||||
writer
|
||||
|
||||
读者优先使用两个信号量,一个用于管理写者w_mutex,一个用于管理读者r_mutex
|
||||
写者进行pv操作,维护proc_state[]
|
||||
读者先把写者锁死,再进行pv,再放开写者,维护proc_state[]
|
||||
|
||||
写者优先使用三个信号量,一个用于管理写者w_mutex,一个用于管理读者r_mutex,一个用于读者能不能读
|
||||
写者要把读者锁死
|
||||
读者要看有没有被锁死
|
||||
|
||||
读写公平使用三个信号量,一个用于管理写者w_mutex,一个用于管理读者r_mutex,一个互斥信号量S
|
||||
写者进行pv操作(互斥信号量)
|
||||
读者进行pv操作(互斥信号量)
|
||||
*======================================================================*/
|
||||
void writer(int i)
|
||||
{
|
||||
if(mode ==0){
|
||||
while(1){
|
||||
p(&w_mutex);
|
||||
proc_state[i]=0;
|
||||
milli_delay(thread_proc_time[i]);
|
||||
v(&w_mutex);
|
||||
proc_state[i]=2;
|
||||
milli_delay(thread_sleep_time[i]);
|
||||
proc_state[i]=1;
|
||||
}
|
||||
}
|
||||
else if(mode == 1){
|
||||
while(1){
|
||||
if(writers_cnt==0) p(&S);
|
||||
writers_cnt++;
|
||||
p(&w_mutex);
|
||||
proc_state[i]=0;
|
||||
milli_delay(thread_proc_time[i]);
|
||||
writers_cnt--;
|
||||
v(&w_mutex);
|
||||
if(writers_cnt==0) v(&S);
|
||||
proc_state[i]=2;
|
||||
milli_delay(thread_sleep_time[i]);
|
||||
proc_state[i]=1;
|
||||
}
|
||||
}
|
||||
else if(mode == 2){
|
||||
while(1){
|
||||
p(&S);
|
||||
p(&w_mutex);
|
||||
proc_state[i]=0;
|
||||
milli_delay(thread_proc_time[i]);
|
||||
v(&w_mutex);
|
||||
v(&S);
|
||||
proc_state[i]=2;
|
||||
milli_delay(thread_sleep_time[i]);
|
||||
proc_state[i]=1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*======================================================================*
|
||||
reader
|
||||
*======================================================================*/
|
||||
void reader(int i)
|
||||
{
|
||||
if(mode ==0){
|
||||
while(1){
|
||||
if(readers_cnt==0) p(&w_mutex);
|
||||
readers_cnt++;
|
||||
p(&r_mutex);
|
||||
proc_state[i]=0;
|
||||
milli_delay(thread_proc_time[i]);
|
||||
v(&r_mutex);
|
||||
readers_cnt--;
|
||||
if(readers_cnt==0) v(&w_mutex);
|
||||
proc_state[i]=2;
|
||||
milli_delay(thread_sleep_time[i]);
|
||||
proc_state[i]=1;
|
||||
}
|
||||
}
|
||||
else if(mode ==1){
|
||||
while(1){
|
||||
p(&r_mutex);
|
||||
p(&S);
|
||||
v(&S);
|
||||
if(readers_cnt==0) p(&w_mutex);
|
||||
readers_cnt++;
|
||||
proc_state[i]=0;
|
||||
milli_delay(thread_proc_time[i]);
|
||||
readers_cnt--;
|
||||
if(readers_cnt==0) v(&w_mutex);
|
||||
v(&r_mutex);
|
||||
proc_state[i]=2;
|
||||
milli_delay(thread_sleep_time[i]);
|
||||
proc_state[i]=1;
|
||||
}
|
||||
}
|
||||
else if(mode ==2){
|
||||
while(1){
|
||||
p(&S);
|
||||
p(&r_mutex);
|
||||
if(readers_cnt==0) p(&w_mutex);
|
||||
readers_cnt++;
|
||||
proc_state[i]=0;
|
||||
v(&S);
|
||||
milli_delay(thread_proc_time[i]);
|
||||
readers_cnt--;
|
||||
if(readers_cnt==0) v(&w_mutex);
|
||||
v(&r_mutex);
|
||||
proc_state[i]=2;
|
||||
milli_delay(thread_sleep_time[i]);
|
||||
proc_state[i]=1;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,80 @@
|
|||
|
||||
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
proc.c
|
||||
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
Forrest Yu, 2005
|
||||
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
|
||||
|
||||
#include "type.h"
|
||||
#include "const.h"
|
||||
#include "protect.h"
|
||||
#include "proto.h"
|
||||
#include "string.h"
|
||||
#include "global.h"
|
||||
|
||||
/*======================================================================*
|
||||
schedule TODO 助教的版本
|
||||
*======================================================================*/
|
||||
PUBLIC void schedule()
|
||||
{
|
||||
PROCESS* p; // 修改此结构体
|
||||
int current_tick = get_ticks();
|
||||
while (1) {
|
||||
p_proc_ready++;
|
||||
if (p_proc_ready >= proc_table + NR_TASKS) {
|
||||
p_proc_ready = proc_table;
|
||||
}
|
||||
if (p_proc_ready->waiting_semaphore == 0 &&
|
||||
p_proc_ready->wake <= current_tick) {
|
||||
break; // 寻找到进程
|
||||
}
|
||||
// if (p_proc_ready->wake_tick <= current_tick) {
|
||||
// break; // 寻找到进程
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
/*======================================================================*
|
||||
sys_get_ticks
|
||||
*======================================================================*/
|
||||
PUBLIC int sys_get_ticks()
|
||||
{
|
||||
return ticks;
|
||||
}
|
||||
|
||||
/*======================================================================*
|
||||
TODO sys_ms_delay_proc
|
||||
*======================================================================*/
|
||||
PUBLIC void sys_ms_delay_proc(int milli_seconds)
|
||||
{
|
||||
p_proc_ready->wake = get_ticks() + (milli_seconds*(1000/HZ));
|
||||
schedule();
|
||||
}
|
||||
|
||||
|
||||
/*======================================================================*
|
||||
TODO sys_p_impl sys_v_impl
|
||||
*======================================================================*/
|
||||
|
||||
PUBLIC void sys_p_impl(SEMAPHORE *semaphore)
|
||||
{
|
||||
semaphore->value--;
|
||||
if(semaphore->value<0){
|
||||
p_proc_ready->waiting_semaphore = semaphore;
|
||||
semaphore->queue[semaphore->e] = p_proc_ready;
|
||||
semaphore->e++;
|
||||
semaphore->e%=1000;
|
||||
schedule();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
PUBLIC void sys_v_impl(SEMAPHORE *semaphore)
|
||||
{
|
||||
semaphore->value++;
|
||||
if(semaphore->value<=0){
|
||||
semaphore->queue[semaphore->s]->waiting_semaphore = 0;
|
||||
semaphore->s++;
|
||||
semaphore->s%=1000;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,287 @@
|
|||
|
||||
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
protect.c
|
||||
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
Forrest Yu, 2005
|
||||
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
|
||||
|
||||
#include "type.h"
|
||||
#include "const.h"
|
||||
#include "protect.h"
|
||||
#include "proto.h"
|
||||
#include "global.h"
|
||||
|
||||
|
||||
/* 本文件内函数声明 */
|
||||
PRIVATE void init_idt_desc(unsigned char vector, u8 desc_type, int_handler handler, unsigned char privilege);
|
||||
PRIVATE void init_descriptor(DESCRIPTOR * p_desc, u32 base, u32 limit, u16 attribute);
|
||||
|
||||
|
||||
/* 中断处理函数 */
|
||||
void divide_error();
|
||||
void single_step_exception();
|
||||
void nmi();
|
||||
void breakpoint_exception();
|
||||
void overflow();
|
||||
void bounds_check();
|
||||
void inval_opcode();
|
||||
void copr_not_available();
|
||||
void double_fault();
|
||||
void copr_seg_overrun();
|
||||
void inval_tss();
|
||||
void segment_not_present();
|
||||
void stack_exception();
|
||||
void general_protection();
|
||||
void page_fault();
|
||||
void copr_error();
|
||||
void hwint00();
|
||||
void hwint01();
|
||||
void hwint02();
|
||||
void hwint03();
|
||||
void hwint04();
|
||||
void hwint05();
|
||||
void hwint06();
|
||||
void hwint07();
|
||||
void hwint08();
|
||||
void hwint09();
|
||||
void hwint10();
|
||||
void hwint11();
|
||||
void hwint12();
|
||||
void hwint13();
|
||||
void hwint14();
|
||||
void hwint15();
|
||||
|
||||
|
||||
/*======================================================================*
|
||||
init_prot
|
||||
*----------------------------------------------------------------------*
|
||||
初始化 IDT
|
||||
*======================================================================*/
|
||||
PUBLIC void init_prot()
|
||||
{
|
||||
init_8259A();
|
||||
|
||||
// 全部初始化成中断门(没有陷阱门)
|
||||
init_idt_desc(INT_VECTOR_DIVIDE, DA_386IGate,
|
||||
divide_error, PRIVILEGE_KRNL);
|
||||
|
||||
init_idt_desc(INT_VECTOR_DEBUG, DA_386IGate,
|
||||
single_step_exception, PRIVILEGE_KRNL);
|
||||
|
||||
init_idt_desc(INT_VECTOR_NMI, DA_386IGate,
|
||||
nmi, PRIVILEGE_KRNL);
|
||||
|
||||
init_idt_desc(INT_VECTOR_BREAKPOINT, DA_386IGate,
|
||||
breakpoint_exception, PRIVILEGE_USER);
|
||||
|
||||
init_idt_desc(INT_VECTOR_OVERFLOW, DA_386IGate,
|
||||
overflow, PRIVILEGE_USER);
|
||||
|
||||
init_idt_desc(INT_VECTOR_BOUNDS, DA_386IGate,
|
||||
bounds_check, PRIVILEGE_KRNL);
|
||||
|
||||
init_idt_desc(INT_VECTOR_INVAL_OP, DA_386IGate,
|
||||
inval_opcode, PRIVILEGE_KRNL);
|
||||
|
||||
init_idt_desc(INT_VECTOR_COPROC_NOT, DA_386IGate,
|
||||
copr_not_available, PRIVILEGE_KRNL);
|
||||
|
||||
init_idt_desc(INT_VECTOR_DOUBLE_FAULT, DA_386IGate,
|
||||
double_fault, PRIVILEGE_KRNL);
|
||||
|
||||
init_idt_desc(INT_VECTOR_COPROC_SEG, DA_386IGate,
|
||||
copr_seg_overrun, PRIVILEGE_KRNL);
|
||||
|
||||
init_idt_desc(INT_VECTOR_INVAL_TSS, DA_386IGate,
|
||||
inval_tss, PRIVILEGE_KRNL);
|
||||
|
||||
init_idt_desc(INT_VECTOR_SEG_NOT, DA_386IGate,
|
||||
segment_not_present, PRIVILEGE_KRNL);
|
||||
|
||||
init_idt_desc(INT_VECTOR_STACK_FAULT, DA_386IGate,
|
||||
stack_exception, PRIVILEGE_KRNL);
|
||||
|
||||
init_idt_desc(INT_VECTOR_PROTECTION, DA_386IGate,
|
||||
general_protection, PRIVILEGE_KRNL);
|
||||
|
||||
init_idt_desc(INT_VECTOR_PAGE_FAULT, DA_386IGate,
|
||||
page_fault, PRIVILEGE_KRNL);
|
||||
|
||||
init_idt_desc(INT_VECTOR_COPROC_ERR, DA_386IGate,
|
||||
copr_error, PRIVILEGE_KRNL);
|
||||
|
||||
init_idt_desc(INT_VECTOR_IRQ0 + 0, DA_386IGate,
|
||||
hwint00, PRIVILEGE_KRNL);
|
||||
|
||||
init_idt_desc(INT_VECTOR_IRQ0 + 1, DA_386IGate,
|
||||
hwint01, PRIVILEGE_KRNL);
|
||||
|
||||
init_idt_desc(INT_VECTOR_IRQ0 + 2, DA_386IGate,
|
||||
hwint02, PRIVILEGE_KRNL);
|
||||
|
||||
init_idt_desc(INT_VECTOR_IRQ0 + 3, DA_386IGate,
|
||||
hwint03, PRIVILEGE_KRNL);
|
||||
|
||||
init_idt_desc(INT_VECTOR_IRQ0 + 4, DA_386IGate,
|
||||
hwint04, PRIVILEGE_KRNL);
|
||||
|
||||
init_idt_desc(INT_VECTOR_IRQ0 + 5, DA_386IGate,
|
||||
hwint05, PRIVILEGE_KRNL);
|
||||
|
||||
init_idt_desc(INT_VECTOR_IRQ0 + 6, DA_386IGate,
|
||||
hwint06, PRIVILEGE_KRNL);
|
||||
|
||||
init_idt_desc(INT_VECTOR_IRQ0 + 7, DA_386IGate,
|
||||
hwint07, PRIVILEGE_KRNL);
|
||||
|
||||
init_idt_desc(INT_VECTOR_IRQ8 + 0, DA_386IGate,
|
||||
hwint08, PRIVILEGE_KRNL);
|
||||
|
||||
init_idt_desc(INT_VECTOR_IRQ8 + 1, DA_386IGate,
|
||||
hwint09, PRIVILEGE_KRNL);
|
||||
|
||||
init_idt_desc(INT_VECTOR_IRQ8 + 2, DA_386IGate,
|
||||
hwint10, PRIVILEGE_KRNL);
|
||||
|
||||
init_idt_desc(INT_VECTOR_IRQ8 + 3, DA_386IGate,
|
||||
hwint11, PRIVILEGE_KRNL);
|
||||
|
||||
init_idt_desc(INT_VECTOR_IRQ8 + 4, DA_386IGate,
|
||||
hwint12, PRIVILEGE_KRNL);
|
||||
|
||||
init_idt_desc(INT_VECTOR_IRQ8 + 5, DA_386IGate,
|
||||
hwint13, PRIVILEGE_KRNL);
|
||||
|
||||
init_idt_desc(INT_VECTOR_IRQ8 + 6, DA_386IGate,
|
||||
hwint14, PRIVILEGE_KRNL);
|
||||
|
||||
init_idt_desc(INT_VECTOR_IRQ8 + 7, DA_386IGate,
|
||||
hwint15, PRIVILEGE_KRNL);
|
||||
|
||||
init_idt_desc(INT_VECTOR_SYS_CALL, DA_386IGate,
|
||||
sys_call, PRIVILEGE_USER);
|
||||
|
||||
/* 填充 GDT 中 TSS 这个描述符 */
|
||||
memset(&tss, 0, sizeof(tss));
|
||||
tss.ss0 = SELECTOR_KERNEL_DS;
|
||||
init_descriptor(&gdt[INDEX_TSS],
|
||||
vir2phys(seg2phys(SELECTOR_KERNEL_DS), &tss),
|
||||
sizeof(tss) - 1,
|
||||
DA_386TSS);
|
||||
tss.iobase = sizeof(tss); /* 没有I/O许可位图 */
|
||||
|
||||
// 填充 GDT 中进程的 LDT 的描述符
|
||||
int i;
|
||||
PROCESS* p_proc = proc_table;
|
||||
u16 selector_ldt = INDEX_LDT_FIRST << 3;
|
||||
for(i=0;i<NR_TASKS;i++){
|
||||
init_descriptor(&gdt[selector_ldt>>3],
|
||||
vir2phys(seg2phys(SELECTOR_KERNEL_DS),
|
||||
proc_table[i].ldts),
|
||||
LDT_SIZE * sizeof(DESCRIPTOR) - 1,
|
||||
DA_LDT);
|
||||
p_proc++;
|
||||
selector_ldt += 1 << 3;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*======================================================================*
|
||||
init_idt_desc
|
||||
*----------------------------------------------------------------------*
|
||||
初始化 386 中断门
|
||||
*======================================================================*/
|
||||
PUBLIC void init_idt_desc(unsigned char vector, u8 desc_type, int_handler handler, unsigned char privilege)
|
||||
{
|
||||
GATE * p_gate = &idt[vector];
|
||||
u32 base = (u32)handler;
|
||||
p_gate->offset_low = base & 0xFFFF;
|
||||
p_gate->selector = SELECTOR_KERNEL_CS;
|
||||
p_gate->dcount = 0;
|
||||
p_gate->attr = desc_type | (privilege << 5);
|
||||
p_gate->offset_high = (base >> 16) & 0xFFFF;
|
||||
}
|
||||
|
||||
|
||||
/*======================================================================*
|
||||
seg2phys
|
||||
*----------------------------------------------------------------------*
|
||||
由段名求绝对地址
|
||||
*======================================================================*/
|
||||
PUBLIC u32 seg2phys(u16 seg)
|
||||
{
|
||||
DESCRIPTOR* p_dest = &gdt[seg >> 3];
|
||||
|
||||
return (p_dest->base_high << 24) | (p_dest->base_mid << 16) | (p_dest->base_low);
|
||||
}
|
||||
|
||||
/*======================================================================*
|
||||
init_descriptor
|
||||
*----------------------------------------------------------------------*
|
||||
初始化段描述符
|
||||
*======================================================================*/
|
||||
PRIVATE void init_descriptor(DESCRIPTOR * p_desc, u32 base, u32 limit, u16 attribute)
|
||||
{
|
||||
p_desc->limit_low = limit & 0x0FFFF; // 段界限 1 (2 字节)
|
||||
p_desc->base_low = base & 0x0FFFF; // 段基址 1 (2 字节)
|
||||
p_desc->base_mid = (base >> 16) & 0x0FF; // 段基址 2 (1 字节)
|
||||
p_desc->attr1 = attribute & 0xFF; // 属性 1
|
||||
p_desc->limit_high_attr2 = ((limit >> 16) & 0x0F) |
|
||||
(attribute >> 8) & 0xF0;// 段界限 2 + 属性 2
|
||||
p_desc->base_high = (base >> 24) & 0x0FF; // 段基址 3 (1 字节)
|
||||
}
|
||||
|
||||
/*======================================================================*
|
||||
exception_handler
|
||||
*----------------------------------------------------------------------*
|
||||
异常处理
|
||||
*======================================================================*/
|
||||
PUBLIC void exception_handler(int vec_no, int err_code, int eip, int cs, int eflags)
|
||||
{
|
||||
int i;
|
||||
int text_color = 0x74; /* 灰底红字 */
|
||||
char err_description[][64] = { "#DE Divide Error",
|
||||
"#DB RESERVED",
|
||||
"— NMI Interrupt",
|
||||
"#BP Breakpoint",
|
||||
"#OF Overflow",
|
||||
"#BR BOUND Range Exceeded",
|
||||
"#UD Invalid Opcode (Undefined Opcode)",
|
||||
"#NM Device Not Available (No Math Coprocessor)",
|
||||
"#DF Double Fault",
|
||||
" Coprocessor Segment Overrun (reserved)",
|
||||
"#TS Invalid TSS",
|
||||
"#NP Segment Not Present",
|
||||
"#SS Stack-Segment Fault",
|
||||
"#GP General Protection",
|
||||
"#PF Page Fault",
|
||||
"— (Intel reserved. Do not use.)",
|
||||
"#MF x87 FPU Floating-Point Error (Math Fault)",
|
||||
"#AC Alignment Check",
|
||||
"#MC Machine Check",
|
||||
"#XF SIMD Floating-Point Exception"
|
||||
};
|
||||
|
||||
/* 通过打印空格的方式清空屏幕的前五行,并把 disp_pos 清零 */
|
||||
disp_pos = 0;
|
||||
for(i=0;i<80*5;i++){
|
||||
disp_str(" ");
|
||||
}
|
||||
disp_pos = 0;
|
||||
|
||||
disp_color_str("Exception! --> ", text_color);
|
||||
disp_color_str(err_description[vec_no], text_color);
|
||||
disp_color_str("\n\n", text_color);
|
||||
disp_color_str("EFLAGS:", text_color);
|
||||
disp_int(eflags);
|
||||
disp_color_str("CS:", text_color);
|
||||
disp_int(cs);
|
||||
disp_color_str("EIP:", text_color);
|
||||
disp_int(eip);
|
||||
|
||||
if(err_code != 0xFFFFFFFF){
|
||||
disp_color_str("Error code:", text_color);
|
||||
disp_int(err_code);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
|
||||
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
start.c
|
||||
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
Forrest Yu, 2005
|
||||
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
|
||||
|
||||
#include "type.h"
|
||||
#include "const.h"
|
||||
#include "protect.h"
|
||||
#include "proto.h"
|
||||
#include "string.h"
|
||||
#include "global.h"
|
||||
|
||||
|
||||
/*======================================================================*
|
||||
cstart
|
||||
*======================================================================*/
|
||||
PUBLIC void cstart()
|
||||
{
|
||||
disp_str("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n-----\"cstart\" begins-----\n");
|
||||
|
||||
// 将 LOADER 中的 GDT 复制到新的 GDT 中
|
||||
memcpy( &gdt, // New GDT
|
||||
(void*)(*((u32*)(&gdt_ptr[2]))), // Base of Old GDT
|
||||
*((u16*)(&gdt_ptr[0])) + 1 // Limit of Old GDT
|
||||
);
|
||||
// gdt_ptr[6] 共 6 个字节:0~15:Limit 16~47:Base。用作 sgdt 以及 lgdt 的参数。
|
||||
u16* p_gdt_limit = (u16*)(&gdt_ptr[0]);
|
||||
u32* p_gdt_base = (u32*)(&gdt_ptr[2]);
|
||||
*p_gdt_limit = GDT_SIZE * sizeof(DESCRIPTOR) - 1;
|
||||
*p_gdt_base = (u32)&gdt;
|
||||
|
||||
// idt_ptr[6] 共 6 个字节:0~15:Limit 16~47:Base。用作 sidt 以及 lidt 的参数。
|
||||
u16* p_idt_limit = (u16*)(&idt_ptr[0]);
|
||||
u32* p_idt_base = (u32*)(&idt_ptr[2]);
|
||||
*p_idt_limit = IDT_SIZE * sizeof(GATE) - 1;
|
||||
*p_idt_base = (u32)&idt;
|
||||
|
||||
init_prot();
|
||||
|
||||
disp_str("-----\"cstart\" finished-----\n");
|
||||
}
|
|
@ -0,0 +1,133 @@
|
|||
|
||||
; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
; syscall.asm
|
||||
; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
; Forrest Yu, 2005
|
||||
; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
|
||||
%include "sconst.inc"
|
||||
|
||||
; TODO 系统调用的设置
|
||||
_NR_get_ticks equ 0 ; 要跟 global.c 中 sys_call_table 的定义相对应!
|
||||
_NR_print_str equ 1 ; 要跟 global.c 中 sys_call_table 的定义相对应!
|
||||
_NR_ms_delay equ 2 ; 要跟 global.c 中 sys_call_table 的定义相对应!
|
||||
_NR_p equ 3 ; 要跟 global.c 中 sys_call_table 的定义相对应!
|
||||
_NR_v equ 4 ; 要跟 global.c 中 sys_call_table 的定义相对应!
|
||||
INT_VECTOR_SYS_CALL equ 0x90
|
||||
|
||||
; TODO 系统调用的导出符号
|
||||
global get_ticks
|
||||
global print_str
|
||||
global sys_print_str
|
||||
global ms_delay ;外部调用,准备现场,发出中断
|
||||
global sys_ms_delay ;具体实现,将ebx压入内核栈,调用sys_ms_delay_proc(int)
|
||||
global sys_p
|
||||
global sys_v
|
||||
global p
|
||||
global v
|
||||
|
||||
; TODO 导入外部函数
|
||||
extern sys_ms_delay_proc
|
||||
extern disp_str
|
||||
extern sys_p_impl
|
||||
extern sys_v_impl
|
||||
|
||||
bits 32
|
||||
[section .text]
|
||||
|
||||
; ====================================================================
|
||||
; get_ticks
|
||||
; ====================================================================
|
||||
get_ticks:
|
||||
mov eax, _NR_get_ticks
|
||||
int INT_VECTOR_SYS_CALL
|
||||
ret
|
||||
|
||||
; ====================================================================
|
||||
; TODO 不分配时间片sys_ms_delay
|
||||
; ====================================================================
|
||||
ms_delay:
|
||||
;准备现场,发出中断
|
||||
mov eax, _NR_ms_delay
|
||||
push ebx
|
||||
mov ebx, [esp+8]
|
||||
int INT_VECTOR_SYS_CALL
|
||||
pop ebx
|
||||
ret
|
||||
|
||||
sys_ms_delay:
|
||||
;系统调用
|
||||
pusha
|
||||
push ebx
|
||||
call sys_ms_delay_proc ;保存ebx后调用sys_ms_delay_proc
|
||||
pop ebx
|
||||
popa
|
||||
ret
|
||||
|
||||
|
||||
; ====================================================================
|
||||
; TODO 打印字符串sys_print_str
|
||||
; ====================================================================
|
||||
print_str:
|
||||
;准备现场,发出中断
|
||||
mov eax, _NR_print_str
|
||||
push ebx
|
||||
mov ebx, [esp+8]
|
||||
int INT_VECTOR_SYS_CALL
|
||||
pop ebx
|
||||
ret
|
||||
|
||||
sys_print_str:
|
||||
;系统调用
|
||||
pusha
|
||||
push ebx
|
||||
call disp_str
|
||||
pop ebx
|
||||
popa
|
||||
ret
|
||||
|
||||
|
||||
; ====================================================================
|
||||
; TODO PV
|
||||
; ====================================================================
|
||||
p:
|
||||
;准备现场,发出中断
|
||||
mov eax, _NR_p
|
||||
push ebx
|
||||
mov ebx, [esp+8]
|
||||
int INT_VECTOR_SYS_CALL
|
||||
pop ebx
|
||||
ret
|
||||
|
||||
|
||||
v:
|
||||
;准备现场,发出中断
|
||||
mov eax, _NR_v
|
||||
push ebx
|
||||
mov ebx, [esp+8]
|
||||
int INT_VECTOR_SYS_CALL
|
||||
pop ebx
|
||||
ret
|
||||
|
||||
sys_p:
|
||||
;系统调用
|
||||
pusha
|
||||
push ebx
|
||||
call sys_p_impl
|
||||
pop ebx
|
||||
popa
|
||||
ret
|
||||
|
||||
sys_v:
|
||||
;系统调用
|
||||
pusha
|
||||
push ebx
|
||||
call sys_v_impl
|
||||
pop ebx
|
||||
popa
|
||||
ret
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
|
||||
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
klib.c
|
||||
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
Forrest Yu, 2005
|
||||
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
|
||||
|
||||
#include "type.h"
|
||||
#include "const.h"
|
||||
#include "protect.h"
|
||||
#include "proto.h"
|
||||
#include "string.h"
|
||||
#include "global.h"
|
||||
|
||||
|
||||
/*======================================================================*
|
||||
itoa
|
||||
*======================================================================*/
|
||||
PUBLIC char * itoa(char * str, int num)/* 数字前面的 0 不被显示出来, 比如 0000B800 被显示成 B800 */
|
||||
{
|
||||
char * p = str;
|
||||
char ch;
|
||||
int i;
|
||||
int flag = FALSE;
|
||||
|
||||
*p++ = '0';
|
||||
*p++ = 'x';
|
||||
|
||||
if(num == 0){
|
||||
*p++ = '0';
|
||||
}
|
||||
else{
|
||||
for(i=28;i>=0;i-=4){
|
||||
ch = (num >> i) & 0xF;
|
||||
if(flag || (ch > 0)){
|
||||
flag = TRUE;
|
||||
ch += '0';
|
||||
if(ch > '9'){
|
||||
ch += 7;
|
||||
}
|
||||
*p++ = ch;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*p = 0;
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
|
||||
/*======================================================================*
|
||||
disp_int
|
||||
*======================================================================*/
|
||||
PUBLIC void disp_int(int input)
|
||||
{
|
||||
char output[16];
|
||||
itoa(output, input);
|
||||
disp_str(output);
|
||||
}
|
||||
|
||||
/*======================================================================*
|
||||
delay
|
||||
*======================================================================*/
|
||||
PUBLIC void delay(int time)
|
||||
{
|
||||
int i, j, k;
|
||||
for(k=0;k<time;k++){
|
||||
/*for(i=0;i<10000;i++){ for Virtual PC */
|
||||
for(i=0;i<10;i++){/* for Bochs */
|
||||
for(j=0;j<10000;j++){}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,198 @@
|
|||
|
||||
; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
; klib.asm
|
||||
; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
; Forrest Yu, 2005
|
||||
; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
|
||||
%include "sconst.inc"
|
||||
|
||||
; 导入全局变量
|
||||
extern disp_pos
|
||||
|
||||
|
||||
[SECTION .text]
|
||||
|
||||
; 导出函数
|
||||
global disp_str
|
||||
global disp_color_str
|
||||
global out_byte
|
||||
global in_byte
|
||||
global enable_irq
|
||||
global disable_irq
|
||||
|
||||
|
||||
; ========================================================================
|
||||
; void disp_str(char * info);
|
||||
; ========================================================================
|
||||
disp_str:
|
||||
push ebp
|
||||
mov ebp, esp
|
||||
|
||||
mov esi, [ebp + 8] ; pszInfo
|
||||
mov edi, [disp_pos]
|
||||
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 [disp_pos], edi
|
||||
|
||||
pop ebp
|
||||
ret
|
||||
|
||||
; ========================================================================
|
||||
; void disp_color_str(char * info, int color);
|
||||
; ========================================================================
|
||||
disp_color_str:
|
||||
push ebp
|
||||
mov ebp, esp
|
||||
|
||||
mov esi, [ebp + 8] ; pszInfo
|
||||
mov edi, [disp_pos]
|
||||
mov ah, [ebp + 12] ; color
|
||||
.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 [disp_pos], edi
|
||||
|
||||
pop ebp
|
||||
ret
|
||||
|
||||
; ========================================================================
|
||||
; void out_byte(u16 port, u8 value);
|
||||
; ========================================================================
|
||||
out_byte:
|
||||
mov edx, [esp + 4] ; port
|
||||
mov al, [esp + 4 + 4] ; value
|
||||
out dx, al
|
||||
nop ; 一点延迟
|
||||
nop
|
||||
ret
|
||||
|
||||
; ========================================================================
|
||||
; u8 in_byte(u16 port);
|
||||
; ========================================================================
|
||||
in_byte:
|
||||
mov edx, [esp + 4] ; port
|
||||
xor eax, eax
|
||||
in al, dx
|
||||
nop ; 一点延迟
|
||||
nop
|
||||
ret
|
||||
|
||||
; ========================================================================
|
||||
; void disable_irq(int irq);
|
||||
; ========================================================================
|
||||
; Disable an interrupt request line by setting an 8259 bit.
|
||||
; Equivalent code:
|
||||
; if(irq < 8){
|
||||
; out_byte(INT_M_CTLMASK, in_byte(INT_M_CTLMASK) | (1 << irq));
|
||||
; }
|
||||
; else{
|
||||
; out_byte(INT_S_CTLMASK, in_byte(INT_S_CTLMASK) | (1 << irq));
|
||||
; }
|
||||
disable_irq:
|
||||
mov ecx, [esp + 4] ; irq
|
||||
pushf
|
||||
cli
|
||||
mov ah, 1
|
||||
rol ah, cl ; ah = (1 << (irq % 8))
|
||||
cmp cl, 8
|
||||
jae disable_8 ; disable irq >= 8 at the slave 8259
|
||||
disable_0:
|
||||
in al, INT_M_CTLMASK
|
||||
test al, ah
|
||||
jnz dis_already ; already disabled?
|
||||
or al, ah
|
||||
out INT_M_CTLMASK, al ; set bit at master 8259
|
||||
popf
|
||||
mov eax, 1 ; disabled by this function
|
||||
ret
|
||||
disable_8:
|
||||
in al, INT_S_CTLMASK
|
||||
test al, ah
|
||||
jnz dis_already ; already disabled?
|
||||
or al, ah
|
||||
out INT_S_CTLMASK, al ; set bit at slave 8259
|
||||
popf
|
||||
mov eax, 1 ; disabled by this function
|
||||
ret
|
||||
dis_already:
|
||||
popf
|
||||
xor eax, eax ; already disabled
|
||||
ret
|
||||
|
||||
; ========================================================================
|
||||
; void enable_irq(int irq);
|
||||
; ========================================================================
|
||||
; Enable an interrupt request line by clearing an 8259 bit.
|
||||
; Equivalent code:
|
||||
; if(irq < 8){
|
||||
; out_byte(INT_M_CTLMASK, in_byte(INT_M_CTLMASK) & ~(1 << irq));
|
||||
; }
|
||||
; else{
|
||||
; out_byte(INT_S_CTLMASK, in_byte(INT_S_CTLMASK) & ~(1 << irq));
|
||||
; }
|
||||
;
|
||||
enable_irq:
|
||||
mov ecx, [esp + 4] ; irq
|
||||
pushf
|
||||
cli
|
||||
mov ah, ~1
|
||||
rol ah, cl ; ah = ~(1 << (irq % 8))
|
||||
cmp cl, 8
|
||||
jae enable_8 ; enable irq >= 8 at the slave 8259
|
||||
enable_0:
|
||||
in al, INT_M_CTLMASK
|
||||
and al, ah
|
||||
out INT_M_CTLMASK, al ; clear bit at master 8259
|
||||
popf
|
||||
ret
|
||||
enable_8:
|
||||
in al, INT_S_CTLMASK
|
||||
and al, ah
|
||||
out INT_S_CTLMASK, al ; clear bit at slave 8259
|
||||
popf
|
||||
ret
|
||||
|
||||
|
|
@ -0,0 +1,116 @@
|
|||
|
||||
; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
; string.asm
|
||||
; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
; Forrest Yu, 2005
|
||||
; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
|
||||
[SECTION .text]
|
||||
|
||||
; 导出函数
|
||||
global memcpy
|
||||
global memset
|
||||
global strcpy
|
||||
|
||||
|
||||
; ------------------------------------------------------------------------
|
||||
; void* memcpy(void* es:p_dst, void* ds:p_src, int size);
|
||||
; ------------------------------------------------------------------------
|
||||
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 结束-------------------------------------------------------------
|
||||
|
||||
|
||||
; ------------------------------------------------------------------------
|
||||
; void memset(void* p_dst, char ch, int size);
|
||||
; ------------------------------------------------------------------------
|
||||
memset:
|
||||
push ebp
|
||||
mov ebp, esp
|
||||
|
||||
push esi
|
||||
push edi
|
||||
push ecx
|
||||
|
||||
mov edi, [ebp + 8] ; Destination
|
||||
mov edx, [ebp + 12] ; Char to be putted
|
||||
mov ecx, [ebp + 16] ; Counter
|
||||
.1:
|
||||
cmp ecx, 0 ; 判断计数器
|
||||
jz .2 ; 计数器为零时跳出
|
||||
|
||||
mov byte [edi], dl ; ┓
|
||||
inc edi ; ┛
|
||||
|
||||
dec ecx ; 计数器减一
|
||||
jmp .1 ; 循环
|
||||
.2:
|
||||
|
||||
pop ecx
|
||||
pop edi
|
||||
pop esi
|
||||
mov esp, ebp
|
||||
pop ebp
|
||||
|
||||
ret ; 函数结束,返回
|
||||
; ------------------------------------------------------------------------
|
||||
|
||||
|
||||
; ------------------------------------------------------------------------
|
||||
; char* strcpy(char* p_dst, char* p_src);
|
||||
; ------------------------------------------------------------------------
|
||||
strcpy:
|
||||
push ebp
|
||||
mov ebp, esp
|
||||
|
||||
mov esi, [ebp + 12] ; Source
|
||||
mov edi, [ebp + 8] ; Destination
|
||||
|
||||
.1:
|
||||
mov al, [esi] ; ┓
|
||||
inc esi ; ┃
|
||||
; ┣ 逐字节移动
|
||||
mov byte [edi], al ; ┃
|
||||
inc edi ; ┛
|
||||
|
||||
cmp al, 0 ; 是否遇到 '\0'
|
||||
jnz .1 ; 没遇到就继续循环,遇到就结束
|
||||
|
||||
mov eax, [ebp + 8] ; 返回值
|
||||
|
||||
pop ebp
|
||||
ret ; 函数结束,返回
|
||||
; strcpy 结束-------------------------------------------------------------
|
||||
|
||||
|
Loading…
Reference in New Issue