init commit

This commit is contained in:
catfood 2022-12-13 13:29:17 +08:00
commit 88ec7f1be2
98 changed files with 20046 additions and 0 deletions

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
obj/
iso/

182
Makefile Normal file
View File

@ -0,0 +1,182 @@
#
# make的主文件
#
# 文件夹
# OBJ用于存放编译出来的可重定位文件
OBJDIR := obj
# INC用于存放各种头文件(*.h)
INCDIR := include
# 编译以及日常工具
CC := gcc
# 汇编器
AS := nasm
# 静态库编辑器
AR := ar
# 链接器
LD := ld
# 复制文件
OBJCOPY := objcopy
# 反编译
OBJDUMP := objdump
# 查询可重定位文件符号表
NM := nm
DEFS :=
# gcc的相关命令参数
# $(DEFS) 定义一些可能的参数
# -O0 0优化保证程序按照代码语义走而不被优化方便调试
# -fno-builtin 静止使用gcc内置函数具体查手册
CFLAGS := $(CFLAGS) $(DEFS) -O0 -fno-builtin
# -I 编译时去指定文件夹查找头文件
# -MD 一个黑科技暂时可以不需要了解总之是在头文件依赖变动的时候能够及时更新target
CFLAGS += -I $(INCDIR) -MD
# -fno-stack-protector 禁止栈保护(金丝雀保护机制,内核代码扛不住)
CFLAGS += -fno-stack-protector
# -std=gnu99 规定编译的语言规范为gnu99
CFLAGS += -std=gnu99
# -fno-pie 不创建动态链接库
CFLAGS += -fno-pie
# -static 编译静态程序
# -m32 编译32位程序
CFLAGS += -static -m32
# -g 打开gdb调试信息能够允许gdb的时候调试
CFLAGS += -g
# 一车的warning在编译的时候可能会很有用
CFLAGS += -Wall -Wno-format -Wno-unused -Werror
# ld链接器的相关命令参数
# -m elf_i386 链接的格式为i386
LDFLAGS := -m elf_i386
# -nostdlib 不链接gcc的标准库用库只能用命令行的
LDFLAGS += -nostdlib
# 获取gcc的库文件除法取模会用到
GCC_LIB := $(shell $(CC) $(CFLAGS) -print-libgcc-file-name)
# 记录每个OBJDIR里存放的每个子文件夹
OBJDIRS :=
# 保证all是第一个target这样make的时候会先执行all
# all的依赖会在kern/Makefrag中填充
all:
.DELETE_ON_ERROR:
# xv6黑科技获取编译命令如果命令较新则重新编译所有文件
.PRECIOUS: $(OBJDIR)/.vars.% \
$(OBJDIR)/kernel/%.o $(OBJDIR)/kernel/%.d \
$(OBJDIR)/user/%.o $(OBJDIR)/user/%.d \
$(OBJDIR)/lib/%.o $(OBJDIR)/lib/%.d
$(OBJDIR)/.vars.%: FORCE
@echo "$($*)" | cmp -s $@ || echo "$($*)" > $@
.PHONY: FORCE
include boot/Makefrag
include lib/Makefrag
include kernel/Makefrag
include user/Makefrag
include fs_flags/Makefrag
# FAT32镜像文件
IMAGE = $(OBJDIR)/a.img
BUILD_IMAGE_SCRIPT = build_img.sh
# added by mingxuan 2020-9-12
# Offset of os_boot in hd
# 活动分区所在的扇区号
# OSBOOT_SEC = 4096
# 活动分区所在的扇区号对应的字节数
# OSBOOT_OFFSET = $(OSBOOT_SEC)*512
OSBOOT_OFFSET = 1048576
# FAT32规范规定os_boot的前89个字节是FAT32的配置信息
# OSBOOT_START_OFFSET = OSBOOT_OFFSET + 90
OSBOOT_START_OFFSET = 1048666 # for test12.img
# added by mingxuan 2020-10-29
# Offset of fs in hd
# 文件系统标志所在扇区号 = 文件系统所在分区的第1个扇区 + 1
# ORANGE_FS_SEC = 6144 + 1 = 6145
# 文件系统标志所在扇区 = $(ORANGE_FS_SEC)*512
ORANGE_FS_START_OFFSET = 3146240
# FAT32_FS_SEC = 53248 + 1 = 53249
# 文件系统标志所在扇区 = $(ORANGE_FS_SEC)*512
FAT32_FS_START_OFFSET = 27263488
# oranges文件系统在硬盘上的起始扇区
# PART_START_SECTOR = 92049
PART_START_SECTOR = 6144 # modified by mingxuan 2020-10-12
# 写入硬盘的起始位置
# INSTALL_PHY_SECTOR = PART_START_SECTOR + 951 # Why is 951 ?
INSTALL_PHY_SECTOR = 7095 # modified by mingxuan 2020-10-12
# assert(INSTALL_PHY_SECTOR > PART_START_SECTOR)
# 写入硬盘的文件大小
INSTALL_NR_SECTORS = 1000
INSTALL_START_SECTOR = $(shell echo $$(($(INSTALL_PHY_SECTOR)-$(PART_START_SECTOR))))
SUPER_BLOCK_ADDR = $(shell echo $$((($(PART_START_SECTOR)+1)*512)))
INSTALL_TYPE = INSTALL_TAR
INSTALL_FILENAME = app.tar
$(IMAGE): $(OBJDIR)/boot/mbr.bin \
$(OBJDIR)/boot/boot.bin \
$(OBJDIR)/boot/loader.bin \
$(OBJDIR)/kernel/kernel.bin \
$(BUILD_IMAGE_SCRIPT) \
$(OBJDIR)/user/$(USER_TAR) \
$(FS_FLAG_OBJFILES)
@./build_img.sh $@ $(OBJDIR) $(OSBOOT_START_OFFSET)
@dd if=$(OBJDIR)/user/$(USER_TAR) of=$@ bs=512 count=$(INSTALL_NR_SECTORS) seek=$(INSTALL_PHY_SECTOR) conv=notrunc
@dd if=$(OBJDIR)/fs_flags/orange_flag.bin of=$@ bs=1 count=1 seek=$(ORANGE_FS_START_OFFSET) conv=notrunc
@dd if=$(OBJDIR)/fs_flags/fat32_flag.bin of=$@ bs=1 count=11 seek=$(FAT32_FS_START_OFFSET) conv=notrunc
all: $(IMAGE)
clean:
@rm -rf $(OBJDIR)
run: $(IMAGE)
@qemu-system-i386 \
-boot order=a \
-drive file=$<,format=raw \
gdb: $(IMAGE)
@qemu-system-i386 \
-boot order=a \
-drive file=$<,format=raw \
-s -S \
gdb-no-graphic: $(IMAGE)
@qemu-system-i386 \
-nographic \
-boot order=a \
-drive file=$<,format=raw \
-s -S \
# 调试的内核代码elf
KERNDBG := $(OBJDIR)/kernel/kernel.dbg
monitor: $(IMAGE)
@gdb \
-ex 'set confirm off' \
-ex 'target remote localhost:1234' \
-ex 'file $(KERNDBG)'
disassemble: $(IMAGE)
@$(OBJDUMP) -S $(KERNDBG) | less
# 黑科技时间,获取每个.c对应的头文件依赖
# 挺难整明白的不建议一开始整明白反正从xv6上抄的不明觉厉
$(OBJDIR)/.deps: $(foreach dir, $(OBJDIRS), $(wildcard $(OBJDIR)/$(dir)/*.d))
@mkdir -p $(@D)
@perl mergedep.pl $@ $^
-include $(OBJDIR)/.deps
.PHONY: all clean run gdb gdb-no-graphic monitor disassemble

67
README.md Normal file
View File

@ -0,0 +1,67 @@
# MiniOS简介
---
MiniOS是一个面向操作系统开发学习者的、微型的操作系统内核可以运行在32位x86架构的CPU上。MiniOS专注于对操作系统开发中的核心概念和基础原理的学习与研究并基于通用硬件对操作系统中的各基本子系统或模块进行实现。
流行的[Linux](https://github.com/torvalds/linux)、 [FreeBSD](https://github.com/freebsd/freebsd) 等操作系统内核固然很好然而它们却并不适合内核开发的初学者。一方面这些操作系统内核已经发展了很多年积累了十分庞大的代码量发布于2005年的Linux内核早期版本v2.6.12就已经有大约400万行代码另一方面因为应用在生产环境中的需要这些内核代码中包含了大量和操作系统基本原理无关的细节初学者很难抓到其中的要领。因此从一个简单的、代码量较少的操作系统内核入手使用较短的时间熟悉并掌握操作系统内核开发领域的核心概念和基础原理等把这些基础性知识掌握到一定程度再投身于Linux等实用内核的开发对于内核初学者来说是一个比较现实可行的策略。即使不打算从事内核开发通过一个易于入手的内核学习一些操作系统相关的基础知识也会有利于写出更健壮、性能更好的应用程序。
查看MiniOS的[release_notes](https://github.com/doubleXnine/MiniOS/blob/master/release_notes.txt) 可了解MiniOS的当前开发进展。
# MiniOS开发工具
---
MiniOS主要基于C语言和x86汇编语言开发使用的开发工具包括
* 汇编器[nasm](https://www.nasm.us/)
* C语言编译器gcc
* GNU二进制工具集[Binutils](http://www.gnu.org/software/binutils/)
* 项目构建工具make
* 调试器gdb
其中Binutils是一套对二进制文件进行操作的工具集包括创建静态库的工具ar从二进制文件中去除符号表以减小文件体积的工具strip等。
# 运行MiniOS
---
MiniOS当前从软盘中启动启动流程为
1. BIOS自检完毕后从软盘引导扇区中加载引导程序boot.bin至内存并将控制权交给引导程序。
2. 引导程序从软盘中读取加载器loader.bin至内存并将控制器交给加载器。
3. 加载器运行时会从软盘中读取MiniOS内核kernel.bin至内存然后从CPU的实模式进入保护模式并将控制权交给内核。
4. MiniOS开始运行。
由于MiniOS是一个面向学习者的操作系统内核因此目前主要运行在虚拟机中可选的虚拟机有[Bochs](http://bochs.sourceforge.net/)和[Qemu](https://www.qemu.org/)。
**在Bochs中运行MiniOS**
1. 安装Bochs在Ubuntu系统下可以直接执行命令`sudo apt-get install bochs`进行安装也可以先下载Bochs的源码再进行编译安装通过源码进行安装可以选择想要的Bochs版本。
2. 进入MiniOS源目录执行`tar zxvf misc/80m.img.tar.gz .`,从硬盘镜像压缩包中解压出硬盘镜像。
3. 在当前目录下执行`bochs`命令启动Bochs虚拟机Bochs首先会从bochsrc文件中读取配置信息然后对Bochs给出的运行提示信息进行确认便可让MiniOS在Bochs内运行。
**在Qemu中运行MiniOS**
1. 按照Qemu在Ubuntu系统下可以直接执行命令`sudo apt-get install qemu-system-x86`进行按照也可以下载Qemu的源代码进行编译安装。
2. 进入MiniOS源目录执行`tar zxvf misc/80m.img.tar.gz .`,从硬盘镜像压缩包中解压出硬盘镜像。
3. 在当前目录下执行`./launch-qemu.sh`命令启动Qemu虚拟机之后MiniOS将直接在Qemu内开始运行。Qemu虚拟机没有使用像bochsrc一样的配置文件配置信息是通过命令行选项指定的脚本launch-qemu.sh中包含了当前使用的配置选项。
# 调试MiniOS
通过使用Bochs或Qemu中自带的调试功能可以对MiniOS进行汇编语言级的调试但由于汇编程序比较冗长且难以阅读这种调试方式使用起来不太方便。幸运的是Bochs和Qemu中都内置了gdb支持通过和gdb提供的远程调试功能配合可以对MiniOS进行C源码级的调试。
**使用Bochs+gdb调试MiniOS**
1. 从源代码编译安装Bochs并在编译时打开gdb支持选项。然后在Bochs配置文件中添加gdb配置信息MiniOS源目录下的bochsrc-gdb文件中已经包含了所需的配置选项。
2. 在MiniOS源目录下执行`./launch-bochs-gdb.sh`所运行的shell脚本会在一个新的终端窗口中运行gdb并加载debug版的内核二进制文件。
3. 在gdb命令界面执行命令`target remote :2345`和Bochs建立连接。
4. 用gdb像调试本地程序一样对MiniOS进行调试。
**使用Qemu+gdb调试MiniOS**
1. 在启动Qemu时添加命令行选项以启用gdb支持MiniOS源目录下的脚本文件launch-qemu-gdb.sh中已经添加了所需的配置选项。
2. 在MiniOS源目录下执行`./launch-bochs-gdb.sh`所运行的shell脚本会在一个新的终端窗口中运行gdb并加载debug版的内核二进制文件。
3. 在gdb命令界面执行命令`target remote :1234`和Qemu建立连接。
4. 用gdb像调试本地程序一样对MiniOS进行调试。
# 常用MiniOS构建选项
```
# 编译MiniOS内核和用户程序init并写入到软盘镜像a.img中
make image
# 清除所有.o目标文件
make clean
# 清除所有.o目标文件和可执行文件
make realclean
```
# 参考资料
* [Orange's](https://github.com/yyu/Oranges) 由于渊开发的一个微型操作系统在《一个操作系统的实现》这本书中讲述了Orange's的开发过程。MiniOS是基于Orange's进行开发的。
* [xv6](https://pdos.csail.mit.edu/6.828/2014/xv6.html) 由MIT开发的一个用于教学的微型操作系统xv6由Unix V6改写而来被应用在MIT的操作系统课程6.828: Operating System Engineering中。
* [Minix](http://www.minix3.org/) 最初由Andrew S. Tanenbaum教授开发的一个微内核操作系统Linus在开发早期的Linux的时候从Minix处继承了很多特性于渊在开发Orange's的时候也多次借鉴了Minix。

16
boot/Makefrag Normal file
View File

@ -0,0 +1,16 @@
OBJDIRS += boot
$(OBJDIR)/boot/mbr.bin: boot/mbr/mbr.asm
@echo + as bin $<
@mkdir -p $(@D)
@$(AS) -I ./boot/mbr/include -o $@ $<
$(OBJDIR)/boot/boot.bin: boot/mbr/boot.asm
@echo + as bin $<
@mkdir -p $(@D)
@$(AS) -I ./boot/mbr/include -o $@ $<
$(OBJDIR)/boot/loader.bin: boot/mbr/loader.asm
@echo + as bin $<
@mkdir -p $(@D)
@$(AS) -I ./boot/mbr/include -o $@ $<

288
boot/floppy/boot.asm Normal file
View File

@ -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 ; 结束标志

View File

@ -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

View File

@ -0,0 +1,34 @@
; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; load.inc
; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; Forrest Yu, 2005
; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
BaseOfLoader equ 09000h ; LOADER.BIN 被加载到的位置 ---- 段地址
OffsetOfLoader equ 0100h ; LOADER.BIN 被加载到的位置 ---- 偏移地址
BaseOfLoaderPhyAddr equ BaseOfLoader * 10h ; LOADER.BIN 被加载到的位置 ---- 物理地址 (= BaseOfLoader * 10h)
;modified by xw, 18/6/12
; BaseOfKernelFile equ 08000h ; KERNEL.BIN 被加载到的位置 ---- 段地址
BaseOfKernelFile equ 07000h ;
OffsetOfKernelFile equ 0h ; KERNEL.BIN 被加载到的位置 ---- 偏移地址
BaseOfEchoFile equ 07E0h ; KERNEL.BIN 被加载到的位置 ---- 段地址
OffsetOfEchoFile equ 0h ; KERNEL.BIN 被加载到的位置 ---- 偏移地址
BaseOfKernelFilePhyAddr equ BaseOfKernelFile * 10h
BaseOfEchoFilePhyAddr equ BaseOfKernelFile * 10h
KernelEntryPointPhyAddr equ 0C0030400h ; 注意1、必须与 MAKEFILE 中参数 -Ttext 的值相等!! edit by visual 2016.5.10
; 2、这是个地址而非仅仅是个偏移,如果 -Ttext 的值为 0x400400,则它的值也应该是 0x400400
PageDirBase equ 200000h ; 页目录开始地址: 2M
PageTblBase equ 201000h ; 页表开始地址: 2M + 4K
PageTblNumAddr equ 500h;页表数量放在这个位置 delete by visual 2016.4.28
FMIBuff equ 007ff000h

322
boot/floppy/include/pm.inc Normal file
View File

@ -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 字节
; ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

1061
boot/floppy/loader.asm Normal file

File diff suppressed because it is too large Load Diff

253
boot/grub/boot.asm Normal file
View File

@ -0,0 +1,253 @@
;==============================================================================================================================
BaseOfStack equ 0x07c00 ; Boot状态下堆栈基地址
DATA_BUF_OFF equ 0x2000 ; 目录被加载的缓冲区地址
STACK_ADDR equ 0x7bea ; 堆栈栈顶
OSLOADER_SEG equ 0x09000 ; 起始段地址
OSLOADER_SEG_OFF equ 0x0100
FAT_START_SECTOR equ 0x820 ; FAT表的起始扇区号 DWORD
DATA_START_SECTOR equ 0xd6a ; 数据区起始扇区号 DWORD
DIR_PER_SECTOR equ 0x10 ; 每个扇区所容纳的目录 BYTE
; 扩展磁盘服务所使用的地址包
DAP_SECTOR_HIGH equ 4 ; 起始扇区号的高32位 ( 每次调用需要重置 ) DWORD
DAP_SECTOR_LOW equ 8 ; 起始扇区号的低32位 ( 每次调用需要重置 ) DWORD
DAP_BUFFER_SEG equ 10 ; 缓冲区段地址 ( 每次调用需要重置 ) WORD
DAP_BUFFER_OFF equ 12 ; 缓冲区偏移 ( 每次调用需要重置 ) WORD
DAP_RESERVED2 equ 13 ; 保留字节
DAP_READ_SECTORS equ 14 ; 要处理的扇区数(1 - 127 )
DAP_RESERVED1 equ 15 ; 保留字节
DAP_PACKET_SIZE equ 16 ; 包的大小为16字节
CURRENT_CLUSTER equ 20 ; 当前正在处理的簇号 DWORD
; 目录项结构
OFF_START_CLUSTER_HIGH equ 20 ; 起始簇号高位 WORD
OFF_START_CLUSTER_LOW equ 26 ; 起始簇号低位 WORD
; 相关常量
DIR_NAME_FREE equ 0x00 ; 该项是空闲的
DIR_ENTRY_SIZE equ 32 ; 每个目录项的尺寸
; 簇属性
CLUSTER_MASK equ 0FFFFFFFH ; 簇号掩码
CLUSTER_LAST equ 0FFFFFF8H ;0xFFFFFFF8-0xFFFFFFFF表示文件的最后一个簇
;==============================================================================================================================
org 07c00h
jmp START
nop
BS_OEM DB 'mkfs.fat' ;文件系统标志
BPB_BytesPerSec DW 0x200 ;每扇区字节数
BPB_SecPerClu DB 1 ;每簇扇区数
BPB_RsvdSecCnt DW 0x20 ;保留扇区数
BPB_NumFATs DB 2 ;FAT表数
BPB_RootEntCnt DW 0 ;FAT32不使用
BPB_TotSec16 DW 0 ;扇区总数
BPB_Media DB 0xf8 ;介质描述符
BPB_FATSz16 DW 0 ;每个FAT表的大小扇区数
BPB_SecPerTrk DW 0x3f ;每磁道扇区数
BPB_NumHeads DW 0xff ;磁头数
BPB_HiddSec DD 0 ;分区已使用扇区数
BPB_TotSec32 DD 0x015791 ;文件系统大小扇区数
BS_SecPerFAT DD 0x02a5 ;每个FAT表大小扇区数
BS_Flag DW 0 ;标记
BS_Version DW 0 ;版本号
BS_RootClus DD 2 ;根目录簇号
BS_FsInfoSec DW 1 ;FSINFO扇区号
BS_BackBootSec DW 6 ;备份引导扇区位置
BS_Unuse1 DD 0 ;未使用
BS_Unuse2 DD 0 ;未使用
BS_Unuse3 DD 0 ;未使用
BS_DriveNum DB 0x80 ;设备号
BS_Unuse4 DB 0x01 ;未使用
BS_ExtBootFlag DB 0x29 ;扩展引导标志
BS_VolNum DD 0xbe3a8ff5 ;卷序列号
BS_VolName DB 'MZY hd boot' ;卷标
START:
cld
xor ax, ax
mov ds, ax
mov es, ax
mov ss, ax
mov sp, STACK_ADDR
mov bp, BaseOfStack
mov dword [bp - DAP_SECTOR_HIGH ], 00h
mov byte [bp - DAP_RESERVED1 ], 00h
mov byte [bp - DAP_RESERVED2 ], 00h
mov byte [bp - DAP_PACKET_SIZE ], 10h
mov byte [bp - DAP_READ_SECTORS], 01h
mov byte [bp - DAP_BUFFER_SEG ], 00h
jmp _SEARCH_LOADER
_MISSING_LOADER: ; 显示没有装载程序
_DISK_ERROR: ; 显示磁盘错误信息
JMP $
ReadSector:
pusha
mov ah, 42h
lea si, [BP - DAP_PACKET_SIZE]
mov dl, [BS_DriveNum]
int 13h
jc _DISK_ERROR
popa
ret
_SEARCH_LOADER:
mov word [bp - DAP_BUFFER_OFF], DATA_BUF_OFF
mov eax, dword [BS_RootClus]
mov dword [bp - CURRENT_CLUSTER], eax
_NEXT_ROOT_CLUSTER:
dec eax
dec eax
xor ebx, ebx
mov bl, byte [BPB_SecPerClu]
mul ebx
add eax, DATA_START_SECTOR
mov dword [BP - DAP_SECTOR_LOW], eax
mov dl, [BPB_SecPerClu]
_NEXT_ROOT_SECTOR:
call ReadSector
mov di, DATA_BUF_OFF
mov bl, DIR_PER_SECTOR
_NEXT_ROOT_ENTRY:
cmp byte [di], DIR_NAME_FREE
jz _MISSING_LOADER
push di;
mov si, LoaderName
mov cx, 10
repe cmpsb
jcxz _FOUND_LOADER
pop di
add di, DIR_ENTRY_SIZE
dec bl
jnz _NEXT_ROOT_ENTRY
dec dl
jz _CHECK_NEXT_ROOT_CLUSTER
inc dword [bp - DAP_SECTOR_LOW]
jmp _NEXT_ROOT_SECTOR
_CHECK_NEXT_ROOT_CLUSTER:
; 计算FAT所在的簇号和偏移
; FatOffset = ClusterNum*4
XOR EDX,EDX
MOV EAX,DWORD[BP - CURRENT_CLUSTER]
SHL EAX,2
XOR ECX,ECX
MOV CX,WORD [ BPB_BytesPerSec ]
DIV ECX ; EAX = Sector EDX = OFFSET
ADD EAX, FAT_START_SECTOR
MOV DWORD [ BP - DAP_SECTOR_LOW ], EAX
call ReadSector
; 检查下一个簇
MOV DI,DX
ADD DI,DATA_BUF_OFF
MOV EAX,DWORD[DI] ; EAX = 下一个要读的簇号
AND EAX,CLUSTER_MASK
MOV DWORD[ BP - CURRENT_CLUSTER ],EAX
CMP EAX,CLUSTER_LAST ; CX >= 0FFFFFF8H则意味着没有更多的簇了
JB _NEXT_ROOT_CLUSTER
JMP _MISSING_LOADER
_FOUND_LOADER:
; 目录结构地址放在DI中
pop di
xor eax, eax
mov ax, [di + OFF_START_CLUSTER_HIGH] ; 起始簇号高32位
shl ax, 16
mov ax, [di + OFF_START_CLUSTER_LOW] ; 起始簇号低32位
mov dword [ bp - CURRENT_CLUSTER ], eax
mov cx, OSLOADER_SEG ; CX = 缓冲区段地址
_NEXT_DATA_CLUSTER:
; 根据簇号计算扇区号
DEC EAX
DEC EAX
XOR EBX,EBX
MOV BL, BYTE [ BPB_SecPerClu ]
MUL EBX
ADD EAX, DATA_START_SECTOR
MOV DWORD[ BP - DAP_SECTOR_LOW ], EAX
MOV BL , BYTE [BPB_SecPerClu]
; 设置缓冲区
MOV WORD [ BP - DAP_BUFFER_SEG ], CX
MOV WORD [ BP - DAP_BUFFER_OFF ], OSLOADER_SEG_OFF
_NEXT_DATA_SECTOR:
; 读取簇中的每个扇区(内层循环)
; 注意 : 通过检查文件大小,可以避免读取最后一个不满簇的所有大小
call ReadSector
; 更新地址,继续读取
MOV AX, WORD [BPB_BytesPerSec]
ADD WORD [BP - DAP_BUFFER_OFF], ax
INC DWORD [BP - DAP_SECTOR_LOW] ; 递增扇区号
DEC BL ; 内层循环计数
JNZ _NEXT_DATA_SECTOR
; 更新读取下一个簇的缓冲区地址
MOV CL, BYTE [ BPB_SecPerClu ]
MOV AX, WORD [BPB_BytesPerSec]
SHR AX, 4
MUL CL
ADD AX, WORD [ BP - DAP_BUFFER_SEG ]
MOV CX, AX ; 保存下一个簇的缓冲区段地址
;====================================================================
; 检查是否还有下一个簇(读取FAT表的相关信息)
; LET N = 数据簇号
; THUS FAT_BYTES = N*4 (FAT32)
; FAT_SECTOR = FAT_BYTES / BPB_BytesPerSec
; FAT_OFFSET = FAT_BYTES % BPB_BytesPerSec
;====================================================================
; 计算FAT所在的簇号和偏移
MOV EAX,DWORD [BP - CURRENT_CLUSTER]
XOR EDX,EDX
SHL EAX,2
XOR EBX,EBX
MOV BX,WORD [ BPB_BytesPerSec ]
DIV EBX ; EAX = Sector EDX = Offset
; 设置缓冲区地址
ADD EAX, FAT_START_SECTOR
MOV DWORD [ BP - DAP_SECTOR_LOW ], EAX
MOV WORD [BP - DAP_BUFFER_SEG ], 00H
MOV WORD [BP - DAP_BUFFER_OFF ], DATA_BUF_OFF
; 读取扇区
CALL ReadSector
; 检查下一个簇
MOV DI,DX
ADD DI,DATA_BUF_OFF
MOV EAX,DWORD[DI] ; EAX = 下一个要读的簇号
AND EAX,CLUSTER_MASK
MOV DWORD[ BP - CURRENT_CLUSTER ],EAX
CMP EAX,CLUSTER_LAST ; CX >= 0FFFFFF8H则意味着没有更多的簇了
JB _NEXT_DATA_CLUSTER
_RUN_LOADER:
mov dl, [BS_DriveNum]
jmp OSLOADER_SEG:OSLOADER_SEG_OFF
LoaderName db "LOADER BIN" ; 第二阶段启动程序 FDOSLDR.BIN
times 510-($-$$) db 0 ; 填充剩下的空间使生成的二进制代码恰好为512字节
dw 0xaa55 ; 结束标志

8
boot/grub/grub.cfg Normal file
View File

@ -0,0 +1,8 @@
set default=0
set timeout=5
menuentry "myboot" {
set root=(hd0,msdos1)
chainloader +1
boot
}

View File

@ -0,0 +1,28 @@
BS_OEM DB 'mkfs.fat'
BPB_BytesPerSec DW 0x200
BPB_SecPerClu DB 1
BPB_RsvdSecCnt DW 0x20
BPB_NumFATs DB 2
BPB_RootEntCnt DW 0
BPB_TotSec16 DW 0
BPB_Media DB 0xf8
BPB_FATSz16 DW 0
BPB_SecPerTrk DW 0x20
BPB_NumHeads DW 0x40
BPB_HiddSec DD 0
BPB_TotSec32 DD 0x015791
BS_SecPerFAT DD 0x02a5
BS_Flag DW 0
BS_Version DW 0
BS_RootClus DD 2
BS_FsInfoSec DW 1
BS_BackBootSec DW 6
BS_Unuse1 DD 0
BS_Unuse2 DD 0
BS_Unuse3 DD 0
BS_DriveNum DB 0x80
BS_Unuse4 DB 0
BS_ExtBootFlag DB 0x29
BS_VolNum DD 0xbe3a8ff5
BS_VolName DB 'MZY hd boot'

170
boot/grub/include/lib.inc Normal file
View File

@ -0,0 +1,170 @@
; ------------------------------------------------------------------------
; 显示 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 结束-------------------------------------------------------------

View File

@ -0,0 +1,61 @@
;==============================================================================================================================
BaseOfStack equ 0x0100
STACK_ADDR equ 0x0ea
SEG_ADDR equ 0x09000
DATA_BUF_OFF equ 0x09000
FAT_START_SECTOR equ 0x820 ; FAT表的起始扇区号 DWORD
DATA_START_SECTOR equ 0xd6a ; 数据区起始扇区号 DWORD
DIR_PER_SECTOR equ 0x10 ; 每个扇区所容纳的目录 BYTE
; 扩展磁盘服务所使用的地址包
DAP_SECTOR_HIGH equ 4 ; 起始扇区号的高32位 ( 每次调用需要重置 ) DWORD
DAP_SECTOR_LOW equ 8 ; 起始扇区号的低32位 ( 每次调用需要重置 ) DWORD
DAP_BUFFER_SEG equ 10 ; 缓冲区段地址 ( 每次调用需要重置 ) WORD
DAP_BUFFER_OFF equ 12 ; 缓冲区偏移 ( 每次调用需要重置 ) WORD
DAP_RESERVED2 equ 13 ; 保留字节
DAP_READ_SECTORS equ 14 ; 要处理的扇区数(1 - 127 )
DAP_RESERVED1 equ 15 ; 保留字节
DAP_PACKET_SIZE equ 16 ; 包的大小为16字节
CURRENT_CLUSTER equ 20 ; 当前正在处理的簇号 DWORD
; 目录项结构
OFF_START_CLUSTER_HIGH equ 20 ; 起始簇号高位 WORD
OFF_START_CLUSTER_LOW equ 26 ; 起始簇号低位 WORD
; 相关常量
DIR_NAME_FREE equ 0x00 ; 该项是空闲的
DIR_ENTRY_SIZE equ 32 ; 每个目录项的尺寸
; 簇属性
CLUSTER_MASK equ 0FFFFFFFH ; 簇号掩码
CLUSTER_LAST equ 0FFFFFF8H ;0xFFFFFFF8-0xFFFFFFFF表示文件的最后一个簇
BaseOfLoader equ 09000h ; LOADER.BIN 被加载到的位置 ---- 段地址
OffsetOfLoader equ 0100h ; LOADER.BIN 被加载到的位置 ---- 偏移地址
BaseOfLoaderPhyAddr equ BaseOfLoader * 10h ; LOADER.BIN 被加载到的位置 ---- 物理地址 (= BaseOfLoader * 10h)
BaseOfKernelFile equ 06000h ; KERNEL.BIN 被加载到的位置 ---- 段地址
OffsetOfKernelFile equ 0h ; KERNEL.BIN 被加载到的位置 ---- 偏移地址
BaseOfKernelFilePhyAddr equ BaseOfKernelFile * 10h
BaseOfEchoFile equ 07E0h ; KERNEL.BIN 被加载到的位置 ---- 段地址
OffsetOfEchoFile equ 0h ; KERNEL.BIN 被加载到的位置 ---- 偏移地址
BaseOfEchoFilePhyAddr equ BaseOfKernelFile * 10h
KernelEntryPointPhyAddr equ 0xC0030400 ; 注意1、必须与 MAKEFILE 中参数 -Ttext 的值相等!!
; 2、这是个地址而非仅仅是个偏移
PageDirBase equ 200000h ; 页目录开始地址: 2M
PageTblBase equ 201000h ; 页表开始地址: 2M + 4K
PageTblNumAddr equ 500h;页表数量放在这个位置 delete by visual 2016.4.28
FMIBuff equ 007ff000h
;==============================================================================================================================

318
boot/grub/include/pm.inc Normal file
View File

@ -0,0 +1,318 @@
; 描述符图示
; 图示一
;
; ------ ┏━━┳━━┓高地址
; 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 字节
; ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

1064
boot/grub/loader.asm Normal file

File diff suppressed because it is too large Load Diff

543
boot/mbr/boot.asm Normal file
View File

@ -0,0 +1,543 @@
;==============================================================================================================================
BaseOfStack equ 0x07c00 ; Boot状态下堆栈基地址
STACK_ADDR equ 0x7bea ; 堆栈栈顶
BaseOfBoot equ 1000h ; added by mingxuan 2020-9-12
OffsetOfBoot equ 7c00h ; load Boot sector to BaseOfBoot:OffsetOfBoot
OffsetOfActiPartStartSec equ 7e00h ; 活动分区的起始扇区号相对于BaseOfBoot的偏移量 ;added by mingxuan 2020-9-12
; 该变量来自分区表保存在该内存地址用于在os_boot和loader中查找FAT32文件
BOOT_FAT32_INFO equ 0x5A ;位于boot中的FAT32配置信息的长度
;added by mingxuan 2020-9-16
DATA_BUF_OFF equ 0x2000 ; 目录 被加载的缓冲区地址
OSLOADER_SEG equ 0x09000 ; 起始段地址
OSLOADER_SEG_OFF equ 0x0100
;FAT_START_SECTOR equ 0x820 ; FAT表的起始扇区号 DWORD
;FAT_START_SECTOR equ 0x1020 ; FAT表的起始扇区号 DWORD ; for test 2020-9-10, mingxuan
;DATA_START_SECTOR equ 0xd6a ; 数据区起始扇区号 DWORD
;DATA_START_SECTOR equ 0x156a ; 数据区起始扇区号 DWORD ; for test 2020-9-10, mingxuan
;DATA_START_SECTOR equ 0x13a4 ; 数据区起始扇区号 DWORD ; for test 2020-9-13, mingxuan
DIR_PER_SECTOR equ 0x10 ; 每个扇区所容纳的目录 BYTE
; 扩展磁盘服务所使用的地址包
DAP_SECTOR_HIGH equ 4 ; 起始扇区号的高32位 ( 每次调用需要重置 ) DWORD
DAP_SECTOR_LOW equ 8 ; 起始扇区号的低32位 ( 每次调用需要重置 ) DWORD
DAP_BUFFER_SEG equ 10 ; 缓冲区段地址 ( 每次调用需要重置 ) WORD
DAP_BUFFER_OFF equ 12 ; 缓冲区偏移 ( 每次调用需要重置 ) WORD
DAP_RESERVED2 equ 13 ; 保留字节
DAP_READ_SECTORS equ 14 ; 要处理的扇区数(1 - 127 )
DAP_RESERVED1 equ 15 ; 保留字节
DAP_PACKET_SIZE equ 16 ; 包的大小为16字节
CURRENT_CLUSTER equ 20 ; 当前正在处理的簇号 DWORD
; 目录项结构
OFF_START_CLUSTER_HIGH equ 20 ; 起始簇号高位 WORD
OFF_START_CLUSTER_LOW equ 26 ; 起始簇号低位 WORD
; 相关常量
DIR_NAME_FREE equ 0x00 ; 该项是空闲的
DIR_ENTRY_SIZE equ 32 ; 每个目录项的尺寸
; 簇属性
CLUSTER_MASK equ 0FFFFFFFH ; 簇号掩码
CLUSTER_LAST equ 0FFFFFF8H ;0xFFFFFFF8-0xFFFFFFFF表示文件的最后一个簇
; added by mingxuan 2020-9-12
BPB_BytesPerSec equ (OffsetOfBoot + 0xb) ;每扇区字节数
BPB_SecPerClu equ (OffsetOfBoot + 0xd) ;每簇扇区数
BPB_RsvdSecCnt equ (OffsetOfBoot + 0xe) ;保留扇区数
BPB_NumFATs equ (OffsetOfBoot + 0x10) ;FAT表数
BPB_RootEntCnt equ (OffsetOfBoot + 0x11) ;FAT32不使用
BPB_TotSec16 equ (OffsetOfBoot + 0x13) ;扇区总数
BPB_Media equ (OffsetOfBoot + 0x15) ;介质描述符
BPB_FATSz16 equ (OffsetOfBoot + 0x16) ;每个FAT表的大小扇区数(FAT32不使用)
BPB_SecPerTrk equ (OffsetOfBoot + 0x18) ;每磁道扇区数
BPB_NumHeads equ (OffsetOfBoot + 0x1a) ;磁头数
BPB_HiddSec equ (OffsetOfBoot + 0x1c) ;分区已使用扇区数
BPB_TotSec32 equ (OffsetOfBoot + 0x20) ;文件系统大小扇区数
BS_SecPerFAT equ (OffsetOfBoot + 0x24) ;每个FAT表大小扇区数
BS_Flag equ (OffsetOfBoot + 0x28) ;标记
BS_Version equ (OffsetOfBoot + 0x2a) ;版本号
BS_RootClus equ (OffsetOfBoot + 0x2c) ;根目录簇号
BS_FsInfoSec equ (OffsetOfBoot + 0x30) ;FSINFO扇区号
BS_BackBootSec equ (OffsetOfBoot + 0x32) ;备份引导扇区位置
BS_Unuse1 equ (OffsetOfBoot + 0x34) ;未使用
;BS_Unuse2 equ (OffsetOfBoot + 0x40) ;未使用 ;deleted by mingxuan 2020-9-15
;BS_Unuse3 equ (OffsetOfBoot + 0x41) ;未使用 ;deleted by mingxuan 2020-9-15
BS_DriveNum equ (OffsetOfBoot + 0x40) ;设备号
BS_Unuse4 equ (OffsetOfBoot + 0x41) ;未使用
BS_ExtBootFlag equ (OffsetOfBoot + 0x42) ;扩展引导标志
BS_VolNum equ (OffsetOfBoot + 0x43) ;卷序列号
BS_VolName equ (OffsetOfBoot + 0x47) ;卷标
;==============================================================================================================================
;org 07c00h ;deleted by mingxuan 2020-9-16
org (07c00h + BOOT_FAT32_INFO) ;FAT322规范规定第90~512个字节(共423个字节)是引导程序
;modified by mingxuan 2020-9-16
;jmp START ;deleted by mingxuan 2020-9-15
;nop ;deleted by mingxuan 2020-9-15
FAT_START_SECTOR DD 0 ;FAT表的起始扇区号 ;added by mingxuan 2020-9-17
DATA_START_SECTOR DD 0 ;数据区起始扇区号 ;added by mingxuan 2020-9-17
;deleted by mingxuan 2020-9-12
;BS_OEM DB 'mkfs.fat' ;文件系统标志
;BPB_BytesPerSec DW 0x200 ;每扇区字节数
;BPB_SecPerClu DB 1 ;每簇扇区数
;BPB_RsvdSecCnt DW 0x20 ;保留扇区数
;BPB_NumFATs DB 2 ;FAT表数
;BPB_RootEntCnt DW 0 ;FAT32不使用
;BPB_TotSec16 DW 0 ;扇区总数
;BPB_Media DB 0xf8 ;介质描述符
;BPB_FATSz16 DW 0 ;每个FAT表的大小扇区数
;BPB_SecPerTrk DW 0x3f ;每磁道扇区数
;BPB_NumHeads DW 0xff ;磁头数
;BPB_HiddSec DD 0 ;分区已使用扇区数
;BPB_TotSec32 DD 0x015791 ;文件系统大小扇区数
;BS_SecPerFAT DD 0x02a5 ;每个FAT表大小扇区数
;BS_Flag DW 0 ;标记
;BS_Version DW 0 ;版本号
;BS_RootClus DD 2 ;根目录簇号
;BS_FsInfoSec DW 1 ;FSINFO扇区号
;BS_BackBootSec DW 6 ;备份引导扇区位置
;BS_Unuse1 DD 0 ;未使用
;BS_Unuse2 DD 0 ;未使用
;BS_Unuse3 DD 0 ;未使用
;BS_DriveNum DB 0x80 ;设备号
;BS_Unuse4 DB 0x01 ;未使用
;BS_ExtBootFlag DB 0x29 ;扩展引导标志
;BS_VolNum DD 0xbe3a8ff5 ;卷序列号
;BS_VolName DB 'MZY hd boot' ;卷标
START:
cld
mov ax, cs
mov ds, ax
mov es, ax ;deleted by mingxuan 2020-9-13
mov ss, ax
; 清屏
; for test, added by mingxuan 2020-9-15
; pusha
; mov dx, 0184fh ; 右下角: (80, 50)
; int 10h ; int 10h
; popa
;added by mingxuan 2020-9-13
;mov ax, BaseOfBoot
;mov fs, ax ;es存储BaseOfBoot用于查找FAT32的配置信息
;FAT_START_SECTOR DD ([fs:OffsetOfActiPartStartSec] + [fs:BPB_RsvdSecCnt])
; 计算FAT表的起始扇区号 ; added by mingxuan 2020-9-17
mov eax, [ OffsetOfActiPartStartSec]
add ax, [ BPB_RsvdSecCnt ]
mov [FAT_START_SECTOR], eax
; 计算数据区起始扇区号 ; added by mingxuan 2020-9-17
add eax, [BS_SecPerFAT]
add eax, [BS_SecPerFAT]
mov [DATA_START_SECTOR], eax
mov sp, STACK_ADDR
mov bp, BaseOfStack
mov dword [bp - DAP_SECTOR_HIGH ], 00h
;mov byte [bp - DAP_RESERVED1 ], 00h ;deleted by mingxuan 2020-9-17
;mov byte [bp - DAP_RESERVED2 ], 00h ;deleted by mingxuan 2020-9-17
mov byte [bp - DAP_PACKET_SIZE ], 10h
mov byte [bp - DAP_READ_SECTORS], 01h
mov word [bp - DAP_BUFFER_SEG ], 01000h
;for test, added by mingxuan 2020-9-4
;call DispStr ;
;jmp $
jmp _SEARCH_LOADER
_MISSING_LOADER: ; 显示没有装载程序
;for test, added by mingxuan 2020-9-10
;call DispStr ;
;JMP $ ;for test, added by mingxuan 2020-9-10
; 清屏
; for test, added by mingxuan 2020-9-15
;pusha
;mov dx, 0184fh ; 右下角: (80, 50)
;int 10h ; int 10h
;popa
_DISK_ERROR: ; 显示磁盘错误信息
;for test, added by mingxuan 2020-9-4
; 清屏
; for test, added by mingxuan 2020-9-15
;pusha
;mov dx, 0184fh ; 右下角: (80, 50)
;int 10h ; int 10h
;popa
JMP $
ReadSector:
pusha
mov ah, 42h ;ah是功能号扩展读对应0x42
lea si, [BP - DAP_PACKET_SIZE] ;使用扩展int13时DAP结构体首地址传给si
;mov dl, [BS_DriveNum] ;deleted by mingxuan 2020-9-13
;mov es, BaseOfBoot ;modified by mingxuan 2020-9-13
;mov dl, [fs:BS_DriveNum] ;modified by mingxuan 2020-9-13
mov dl, [BS_DriveNum] ;modified by mingxuan 2020-9-17
;mov dl, 0x80
;jmp $
int 13h
jc _DISK_ERROR
;jmp $
; 清屏
; for test, added by mingxuan 2020-9-15
;pusha
;mov dx, 0184fh ; 右下角: (80, 50)
;int 10h ; int 10h
;popa
popa
ret
_SEARCH_LOADER:
mov word [bp - DAP_BUFFER_OFF], DATA_BUF_OFF
;mov eax, dword [BS_RootClus] ;deleted by mingxuan 2020-9-13
;mov es, BaseOfBoot ;modified by mingxuan 2020-9-13
;mov eax, dword [fs:BS_RootClus] ;modified by mingxuan 2020-9-13
;mov eax, dword [BS_RootClus] ;modified by mingxuan 2020-9-17
mov eax, [BS_RootClus]
mov dword [bp - CURRENT_CLUSTER], eax
;for test, added by mingxuan 2020-9-4
;call DispStr ;
;jmp $
_NEXT_ROOT_CLUSTER:
; 根据簇号计算扇区号, mingxuan 2020-9-13
dec eax
dec eax
xor ebx, ebx
;mov bl, byte [BPB_SecPerClu] ;deleted by mingxuan 2020-9-13
;mov es, BaseOfBoot ;modified by mingxuan 2020-9-13
;mov bl, byte [fs:BPB_SecPerClu] ;modified by mingxuan 2020-9-13
mov bl, [BPB_SecPerClu] ;modified by mingxuan 2020-9-17
;jmp $
mul ebx
;add eax, DATA_START_SECTOR ;deleted by mingxuan 2020-9-17
add eax, [DATA_START_SECTOR] ;modified by mingxuan 2020-9-17
mov dword [BP - DAP_SECTOR_LOW], eax
;mov dl, [BPB_SecPerClu] ;deleted by mingxuan 2020-9-13
;mov dl, byte [es:BPB_SecPerClu] ;modified by mingxuan 2020-9-13
;mov dl, [fs:BPB_SecPerClu] ;modified by mingxuan 2020-9-15
mov dl, [BPB_SecPerClu] ;modified by mingxuan 2020-9-17
;jmp $
_NEXT_ROOT_SECTOR:
call ReadSector
;for test, added by mingxuan 2020-9-4
;call DispStr ;
;jmp $
mov di, DATA_BUF_OFF
mov bl, DIR_PER_SECTOR
_NEXT_ROOT_ENTRY:
cmp byte [di], DIR_NAME_FREE
jz _MISSING_LOADER
push di;
mov si, LoaderName
;add si, BOOT_FAT32_INFO ; added by mingxuan 2020-9-16
;mov si, 0x7df1 ; for test, added by mingxuan 2020-9-16
mov cx, 10
repe cmpsb
jcxz _FOUND_LOADER
pop di
add di, DIR_ENTRY_SIZE
dec bl
jnz _NEXT_ROOT_ENTRY
dec dl
jz _CHECK_NEXT_ROOT_CLUSTER
inc dword [bp - DAP_SECTOR_LOW]
jmp _NEXT_ROOT_SECTOR
; Comments, added by mingxuan 2020-9-10
;====================================================================
; 检查是否还有下一个簇(读取FAT表的相关信息)
; N = 数据簇号
; FAT_BYTES(在FAT表中的偏移) = N*4 (FAT32)
; FAT_SECTOR = FAT_BYTES / BPB_BytesPerSec
; FAT_OFFSET = FAT_BYTES % BPB_BytesPerSec
;====================================================================
_CHECK_NEXT_ROOT_CLUSTER: ; 检查是否还有下一个簇
; 计算FAT表项所在的簇号和偏移
; FatOffset(在FAT表中的偏移) = ClusterNum(簇号) * 4
XOR EDX, EDX
MOV EAX, DWORD[BP - CURRENT_CLUSTER]
SHL EAX, 2 ;FatOffset = ClusterNum * 4
XOR ECX, ECX
;MOV CX, WORD [ BPB_BytesPerSec ] ;deleted by mingxuan 2020-9-13
;mov es, BaseOfBoot ;modified by mingxuan 2020-9-13
;mov cx, word [fs:BPB_BytesPerSec] ;modified by mingxuan 2020-9-13
mov cx, word [BPB_BytesPerSec] ;modified by mingxuan 2020-9-17
DIV ECX ; EAX = Sector EDX = OFFSET
; 计算FAT表的起始扇区号
; added by mingxuan 2020-9-17
;mov ebx, dword [ fs:OffsetOfActiPartStartSec ]
;add bx, word [ fs:BPB_RsvdSecCnt ]
; 设置缓冲区地址
;ADD EAX, FAT_START_SECTOR ;deleted by mingxuan 2020-9-17
ADD EAX, [FAT_START_SECTOR] ;modified by mingxuan 2020-9-17
;add eax, ebx ;modified by mingxuan 2020-9-17
MOV DWORD [ BP - DAP_SECTOR_LOW ], EAX
call ReadSector
; 检查下一个簇
MOV DI,DX
ADD DI,DATA_BUF_OFF
MOV EAX, DWORD[DI] ; EAX = 下一个要读的簇号
AND EAX, CLUSTER_MASK
MOV DWORD[ BP - CURRENT_CLUSTER ],EAX
CMP EAX,CLUSTER_LAST ; CX >= 0FFFFFF8H则意味着没有更多的簇了
JB _NEXT_ROOT_CLUSTER
;for test, added by mingxuan 2020-9-10
;call DispStr ;
JMP _MISSING_LOADER
_FOUND_LOADER:
;for test, added by mingxuan 2020-9-10
;call DispStr ;
;JMP $ ;for test, added by mingxuan 2020-9-10
; 目录结构地址放在DI中
pop di
xor eax, eax
mov ax, [di + OFF_START_CLUSTER_HIGH] ; 起始簇号高32位
shl ax, 16
mov ax, [di + OFF_START_CLUSTER_LOW] ; 起始簇号低32位
mov dword [ bp - CURRENT_CLUSTER ], eax
mov cx, OSLOADER_SEG ; CX = 缓冲区段地址
; 清屏
; for test, added by mingxuan 2020-9-15
;pusha
;mov dx, 0184fh ; 右下角: (80, 50)
;int 10h ; int 10h
;popa
_NEXT_DATA_CLUSTER:
; 根据簇号计算扇区号
DEC EAX
DEC EAX
XOR EBX,EBX
;MOV BL, BYTE [ BPB_SecPerClu ] ;deleted by mingxuan 2020-9-13
;mov es, BaseOfBoot ;modified by mingxuan 2020-9-13
;mov bl, byte [fs:BPB_SecPerClu] ;modified by mingxuan 2020-9-13
mov bl, [BPB_SecPerClu] ;modified by mingxuan 2020-9-17
MUL EBX
;ADD EAX, DATA_START_SECTOR ;deleted by mingxuan 2020-9-17
ADD EAX, [DATA_START_SECTOR] ;modified by mingxuan 2020-9-17
MOV DWORD[ BP - DAP_SECTOR_LOW ], EAX
;MOV BL , BYTE [BPB_SecPerClu]
;mov bl, byte [fs:BPB_SecPerClu] ;modified by mingxuan 2020-9-13
mov bl, byte [BPB_SecPerClu] ;modified by mingxuan 2020-9-17
; 设置缓冲区
MOV WORD [ BP - DAP_BUFFER_SEG ], CX
MOV WORD [ BP - DAP_BUFFER_OFF ], OSLOADER_SEG_OFF
_NEXT_DATA_SECTOR:
; 读取簇中的每个扇区(内层循环)
; 注意 : 通过检查文件大小,可以避免读取最后一个不满簇的所有大小
call ReadSector
; 更新地址,继续读取
;MOV AX, WORD [BPB_BytesPerSec] ;deleted by mingxuan 2020-9-13
;mov es, BaseOfBoot ;modified by mingxuan 2020-9-13
;mov ax, word [fs:BPB_BytesPerSec] ;modified by mingxuan 2020-9-13
mov ax, word [BPB_BytesPerSec] ;modified by mingxuan 2020-9-17
ADD WORD [BP - DAP_BUFFER_OFF], ax
INC DWORD [BP - DAP_SECTOR_LOW] ; 递增扇区号
DEC BL ; 内层循环计数
JNZ _NEXT_DATA_SECTOR
;for test, added by mingxuan 2020-9-10
;call DispStr ;
;JMP $ ;for test, added by mingxuan 2020-9-10
; 更新读取下一个簇的缓冲区地址
;MOV CL, BYTE [ BPB_SecPerClu ]
;mov es, BaseOfBoot ;modified by mingxuan 2020-9-13
;mov cl, byte [fs:BPB_SecPerClu] ;modified by mingxuan 2020-9-13
mov cl, [BPB_SecPerClu] ;modified by mingxuan 2020-9-17
;MOV AX, WORD [BPB_BytesPerSec] ;deleted by mingxuan 2020-9-13
;mov es, BaseOfBoot ;modified by mingxuan 2020-9-13
;mov ax, word [fs:BPB_BytesPerSec] ;modified by mingxuan 2020-9-13
mov ax, [BPB_BytesPerSec] ;modified by mingxuan 2020-9-17
SHR AX, 4
MUL CL
ADD AX, WORD [ BP - DAP_BUFFER_SEG ]
MOV CX, AX ; 保存下一个簇的缓冲区段地址
;====================================================================
; 检查是否还有下一个簇(读取FAT表的相关信息)
; LET N = 数据簇号
; THUS FAT_BYTES = N*4 (FAT32)
; FAT_SECTOR = FAT_BYTES / BPB_BytesPerSec
; FAT_OFFSET = FAT_BYTES % BPB_BytesPerSec
;====================================================================
; 计算FAT所在的簇号和偏移
MOV EAX,DWORD [BP - CURRENT_CLUSTER]
XOR EDX,EDX
SHL EAX,2
XOR EBX,EBX
;MOV BX,WORD [ BPB_BytesPerSec ] ;deleted by mingxuan 2020-9-13
;mov es, BaseOfBoot ;modified by mingxuan 2020-9-13
; mov bx, word [fs:BPB_BytesPerSec] ;modified by mingxuan 2020-9-13
mov bx, [BPB_BytesPerSec] ;modified by mingxuan 2020-9-17
DIV EBX ; EAX = Sector EDX = Offset
; 计算FAT表的起始扇区号
; added by mingxuan 2020-9-17
;mov ebx, dword [ fs:OffsetOfActiPartStartSec ]
;add bx, word [ fs:BPB_RsvdSecCnt ]
; 设置int 13h读取的绝对扇区号
;ADD EAX, FAT_START_SECTOR ;deleted by mingxuan 2020-9-17
ADD EAX, [FAT_START_SECTOR] ;modified by mingxuan 2020-9-17
;add eax, ebx ;modified by mingxuan 2020-9-17
MOV DWORD [ BP - DAP_SECTOR_LOW ], EAX
; 设置int 13h写入内存的缓冲区地址
MOV WORD [BP - DAP_BUFFER_SEG ], 01000H
MOV WORD [BP - DAP_BUFFER_OFF ], DATA_BUF_OFF
; 读取扇区 ; 把FAT表读进内存
CALL ReadSector
; 检查下一个簇
MOV DI,DX
ADD DI,DATA_BUF_OFF
MOV EAX,DWORD[DI] ; EAX = 下一个要读的簇号
AND EAX,CLUSTER_MASK
MOV DWORD[ BP - CURRENT_CLUSTER ],EAX
CMP EAX,CLUSTER_LAST ; CX >= 0FFFFFF8H则意味着没有更多的簇了
;for test, added by mingxuan 2020-9-10
;call DispStr ;
;JMP $ ;for test, added by mingxuan 2020-9-10
; 清屏
; for test, added by mingxuan 2020-9-15
;pusha
;mov dx, 0184fh ; 右下角: (80, 50)
;int 10h ; int 10h
;popa
JB _NEXT_DATA_CLUSTER
_RUN_LOADER:
;mov dl, [BS_DriveNum] ;deleted by mingxuan 2020-9-13
;mov es, BaseOfBoot ;modified by mingxuan 2020-9-13
;mov dl, [fs:BS_DriveNum] ;modified by mingxuan 2020-9-13
mov dl, [BS_DriveNum] ;modified by mingxuan 2020-9-17
;for test, added by mingxuan 2020-9-10
;call DispStr ;
;jmp $ ;for test 2020-9-10, mingxuan
; 清屏
; for test, added by mingxuan 2020-9-15
;pusha
;mov dx, 0184fh ; 右下角: (80, 50)
;int 10h ; int 10h
;popa
jmp OSLOADER_SEG : OSLOADER_SEG_OFF
LoaderName db "LOADER BIN" ; 第二阶段启动程序 FDOSLDR.BIN
; for display
; added by mingxuan 2020-9-4
;TestMessage: db "#" ; 27字节, 不够则用空格补齐. 序号 0
; for display
; added by mingxuan 2020-9-4
;DispStr:
; pusha
; mov ax, TestMessage
; mov bp, ax
; mov cx, 1
; mov ax, 01301h ; AH = 13, AL = 01h
; mov bx, 0007h ; 页号为0(BH = 0) 黑底白字(BL = 07h)
; int 10h ; int 10h
; popa
; ret
times 510-($-$$) db 0 ; 填充剩下的空间使生成的二进制代码恰好为512字节
dw 0xaa55 ; 结束标志

8
boot/mbr/grub/grub.cfg Normal file
View File

@ -0,0 +1,8 @@
set default=0
set timeout=20
menuentry "hhh" {
set root=(hd0,msdos2)
chainloader +1
boot
}

View File

@ -0,0 +1,61 @@
;deleted by mingxuan 2020-9-16
;BS_OEM DB 'mkfs.fat'
;BPB_BytesPerSec DW 0x200
;BPB_SecPerClu DB 1
;BPB_RsvdSecCnt DW 0x20
;BPB_NumFATs DB 2
;BPB_RootEntCnt DW 0
;BPB_TotSec16 DW 0
;BPB_Media DB 0xf8
;BPB_FATSz16 DW 0
;BPB_SecPerTrk DW 0x20
;BPB_NumHeads DW 0x40
;BPB_HiddSec DD 0
;BPB_TotSec32 DD 0x015791
;BS_SecPerFAT DD 0x02a5
;BS_Flag DW 0
;BS_Version DW 0
;BS_RootClus DD 2
;BS_FsInfoSec DW 1
;BS_BackBootSec DW 6
;BS_Unuse1 DD 0
;BS_Unuse2 DD 0
;BS_Unuse3 DD 0
;BS_DriveNum DB 0x80
;BS_Unuse4 DB 0
;BS_ExtBootFlag DB 0x29
;BS_VolNum DD 0xbe3a8ff5
;BS_VolName DB 'MZY hd boot'
; added by mingxuan 2020-9-12
;BaseOfBoot equ 1000h ; added by mingxuan 2020-9-12
;OffsetOfBoot equ 7c00h ; load Boot sector to BaseOfBoot:OffsetOfBoot
BPB_BytesPerSec equ (OffsetOfBoot + 0xb) ;每扇区字节数
BPB_SecPerClu equ (OffsetOfBoot + 0xd) ;每簇扇区数
BPB_RsvdSecCnt equ (OffsetOfBoot + 0xe) ;保留扇区数
BPB_NumFATs equ (OffsetOfBoot + 0x10) ;FAT表数
BPB_RootEntCnt equ (OffsetOfBoot + 0x11) ;FAT32不使用
BPB_TotSec16 equ (OffsetOfBoot + 0x13) ;扇区总数
BPB_Media equ (OffsetOfBoot + 0x15) ;介质描述符
BPB_FATSz16 equ (OffsetOfBoot + 0x16) ;每个FAT表的大小扇区数(FAT32不使用)
BPB_SecPerTrk equ (OffsetOfBoot + 0x18) ;每磁道扇区数
BPB_NumHeads equ (OffsetOfBoot + 0x1a) ;磁头数
BPB_HiddSec equ (OffsetOfBoot + 0x1c) ;分区已使用扇区数
BPB_TotSec32 equ (OffsetOfBoot + 0x20) ;文件系统大小扇区数
BS_SecPerFAT equ (OffsetOfBoot + 0x24) ;每个FAT表大小扇区数
BS_Flag equ (OffsetOfBoot + 0x28) ;标记
BS_Version equ (OffsetOfBoot + 0x2a) ;版本号
BS_RootClus equ (OffsetOfBoot + 0x2c) ;根目录簇号
BS_FsInfoSec equ (OffsetOfBoot + 0x30) ;FSINFO扇区号
BS_BackBootSec equ (OffsetOfBoot + 0x32) ;备份引导扇区位置
BS_Unuse1 equ (OffsetOfBoot + 0x34) ;未使用
;BS_Unuse2 equ (OffsetOfBoot + 0x40) ;未使用 ;deleted by mingxuan 2020-9-15
;BS_Unuse3 equ (OffsetOfBoot + 0x41) ;未使用 ;deleted by mingxuan 2020-9-15
BS_DriveNum equ (OffsetOfBoot + 0x40) ;设备号
BS_Unuse4 equ (OffsetOfBoot + 0x41) ;未使用
BS_ExtBootFlag equ (OffsetOfBoot + 0x42) ;扩展引导标志
BS_VolNum equ (OffsetOfBoot + 0x43) ;卷序列号
BS_VolName equ (OffsetOfBoot + 0x47) ;卷标

170
boot/mbr/include/lib.inc Normal file
View File

@ -0,0 +1,170 @@
; ------------------------------------------------------------------------
; 显示 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 结束-------------------------------------------------------------

View File

@ -0,0 +1,70 @@
;==============================================================================================================================
BaseOfStack equ 0x0100
STACK_ADDR equ 0x0ea
SEG_ADDR equ 0x09000
DATA_BUF_OFF equ 0x09000
BaseOfBoot equ 1000h ; added by mingxuan 2020-9-17
OffsetOfBoot equ 7c00h ; load Boot sector to BaseOfBoot:OffsetOfBoot
OffsetOfActiPartStartSec equ 7e00h ; 活动分区的起始扇区号相对于BaseOfBoot的偏移量 ;added by mingxuan 2020-9-17
; 该变量来自分区表保存在该内存地址用于在os_boot和loader中查找FAT32文件
;FAT_START_SECTOR equ 0x820 ; FAT表的起始扇区号 DWORD
;FAT_START_SECTOR equ 0x1020 ; FAT表的起始扇区号 DWORD ; for test 2020-9-12, mingxuan
;DATA_START_SECTOR equ 0xd6a ; 数据区起始扇区号 DWORD
;DATA_START_SECTOR equ 0x156a ; 数据区起始扇区号 DWORD ; for test 2020-9-12, mingxuan
;DATA_START_SECTOR equ 0x13a4 ; 数据区起始扇区号 DWORD ; for test 2020-9-16, mingxuan
DIR_PER_SECTOR equ 0x10 ; 每个扇区所容纳的目录 BYTE
; 扩展磁盘服务所使用的地址包
DAP_SECTOR_HIGH equ 4 ; 起始扇区号的高32位 ( 每次调用需要重置 ) DWORD
DAP_SECTOR_LOW equ 8 ; 起始扇区号的低32位 ( 每次调用需要重置 ) DWORD
DAP_BUFFER_SEG equ 10 ; 缓冲区段地址 ( 每次调用需要重置 ) WORD
DAP_BUFFER_OFF equ 12 ; 缓冲区偏移 ( 每次调用需要重置 ) WORD
DAP_RESERVED2 equ 13 ; 保留字节
DAP_READ_SECTORS equ 14 ; 要处理的扇区数(1 - 127 )
DAP_RESERVED1 equ 15 ; 保留字节
DAP_PACKET_SIZE equ 16 ; 包的大小为16字节
CURRENT_CLUSTER equ 20 ; 当前正在处理的簇号 DWORD
; 目录项结构
OFF_START_CLUSTER_HIGH equ 20 ; 起始簇号高位 WORD
OFF_START_CLUSTER_LOW equ 26 ; 起始簇号低位 WORD
; 相关常量
DIR_NAME_FREE equ 0x00 ; 该项是空闲的
DIR_ENTRY_SIZE equ 32 ; 每个目录项的尺寸
; 簇属性
CLUSTER_MASK equ 0FFFFFFFH ; 簇号掩码
CLUSTER_LAST equ 0FFFFFF8H ;0xFFFFFFF8-0xFFFFFFFF表示文件的最后一个簇
BaseOfLoader equ 09000h ; LOADER.BIN 被加载到的位置 ---- 段地址
OffsetOfLoader equ 0100h ; LOADER.BIN 被加载到的位置 ---- 偏移地址
BaseOfLoaderPhyAddr equ BaseOfLoader * 10h ; LOADER.BIN 被加载到的位置 ---- 物理地址 (= BaseOfLoader * 10h)
BaseOfKernelFile equ 07000h ; KERNEL.BIN 被加载到的位置 ---- 段地址
OffsetOfKernelFile equ 0h ; KERNEL.BIN 被加载到的位置 ---- 偏移地址
BaseOfKernelFilePhyAddr equ BaseOfKernelFile * 10h
BaseOfEchoFile equ 07E0h ; KERNEL.BIN 被加载到的位置 ---- 段地址
OffsetOfEchoFile equ 0h ; KERNEL.BIN 被加载到的位置 ---- 偏移地址
BaseOfEchoFilePhyAddr equ BaseOfKernelFile * 10h
KernelEntryPointPhyAddr equ 0xC0030400 ; 注意1、必须与 MAKEFILE 中参数 -Ttext 的值相等!!
; 2、这是个地址而非仅仅是个偏移
PageDirBase equ 200000h ; 页目录开始地址: 2M
PageTblBase equ 201000h ; 页表开始地址: 2M + 4K
PageTblNumAddr equ 500h;页表数量放在这个位置 delete by visual 2016.4.28
FMIBuff equ 007ff000h
;==============================================================================================================================

318
boot/mbr/include/pm.inc Normal file
View File

@ -0,0 +1,318 @@
; 描述符图示
; 图示一
;
; ------ ┏━━┳━━┓高地址
; 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 字节
; ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

1013
boot/mbr/loader.asm Normal file

File diff suppressed because it is too large Load Diff

261
boot/mbr/mbr.asm Normal file
View File

@ -0,0 +1,261 @@
BaseOfBoot equ 1000h ; 段地址mbr加载loader到这个段
OffsetOfBoot equ 7c00h ; load Boot sector to BaseOfBoot:OffsetOfBoot
OffsetOfActiPartStartSec equ 7e00h ; 活动分区的起始扇区号相对于BaseOfBoot的偏移量 ;added by mingxuan 2020-9-12
; 该变量来自分区表保存在该内存地址用于在os_boot和loader中查找FAT32文件
org 07c00h
LABEL_START:
mov ax, cs
mov ds, ax
mov es, ax
mov ss, ax
mov sp, 7c00h
; 清屏
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 ;
call DispStr ;
xor ah, ah ; ┓
xor dl, dl ; ┣ 软驱复位
int 13h ; ┛
;循环读取分区表
mov bx, 0 ;每次循环累加16
mov dh, 1 ;每次循环累加1
jmp CHECK_PARTITION ;added by mingxuan 2020-9-29
;added by mingxuan 2020-9-29
LABLE_END_EXTENDED:
mov byte [EndInExt], 0 ;将EndInExt置0复位
; 检查扩展分区表的第二项是否是空项。如果是空项则表明当前逻辑分区就是最后一个。
add bx, 16
mov cl, [es:7c00h+446+bx+4] ;分区类型
;sub bx, 16 ;deleted by mingxuan 2020-9-30
cmp cl, 0
jz RESET_SecOffset_SELF
CHECK_PARTITION:
mov dl, [es:7c00h+446+bx] ;分区活跃标志地址
;mov ax, word [es:7c00h+446+bx+8] ;分区起始扇区地址 ;deletd by mingxuan 2020-9-12
mov eax, dword [es:7c00h+446+bx+8] ;分区起始扇区地址 ;modified by mingxuan 2020-9-12
;修改为eax的原因: 分区表用4个字节来表示起始扇区而不是2个字节, mingxuan
;add ax, [SecOffset] ;deletd by mingxuan 2020-9-12
;add eax, [SecOffset] ;modified by mingxuan 2020-9-29
;deleted by mingxuan 2020-9-29
mov cl, [es:7c00h+446+bx+4] ;分区类型
cmp cl, 5 ;extended partition type = 5
;jz LABLE_EXTENDED
jz LABLE_IN_EXTENDED ;modified by mingxuan 2020-9-29
add eax, [SecOffset_SELF] ;added by mingxuan 2020-9-29
add byte [CurPartNo], 1
add byte [CurPartNum], 1 ; added by mingxuan 2020-9-29 ;deleted by mingxuan 2020-9-30
cmp dl, 80h
jz LABLE_ACTIVE
; 检查当前的分区表是否是扩展分区的最后一个逻辑分区
mov cl, [EndInExt]
cmp cl, 1 ;added by mingxuan 2020-9-29
jz LABLE_END_EXTENDED ;added by mingxuan 2020-9-29
cmp dh, 4
jz LABLE_NOT_FOUND
inc dh
add bx, 16
jmp CHECK_PARTITION
RESET_SecOffset_SELF:
; SecOffset_SELF置0的目的是以后又恢复到搜索主分区
mov edx, 0
mov [SecOffset_SELF], edx
mov dl, [EXTNum]
mov al, 16
mul dl
mov bx, ax
mov ax, 0 ;added by mingxuan 2020-9-30
mov es, ax ;added by mingxuan 2020-9-30
jmp CHECK_PARTITION
; added by mingxuan 2020-9-29
LABLE_IN_EXTENDED: ;在分区表中发现扩展分区后,跳转到这里来执行
; 此时的eax有两种情况
; 1) 当第一次执行该程序时eax是从主分区表里获得的扩展分区起始的绝对地址
; 2) 之后的执行, eax是从扩展分区表的第二项获得的起始地址(相对于整个扩展分区起始地址偏移量)
; 从扩展分区表的第二项获得的起始地址是相对于整个扩展分区起始地址偏移量,所以要加上基地址
; 特殊情况: 当第一次进入该过程时SecOffset_EXT的值是0。此时是从主分区表里获得的起始地址这个地址是绝对地址。
add eax, [SecOffset_EXT] ;modified by mingxuan 2020-9-29
; FirstInExt是标志位判断是否是第一次进入该过程
mov cl, [FirstInExt]
; 若为1表示不是第一次进入该过程。
cmp cl, 1
jz LABLE_EXTENDED
; 以下是第一次进入该过程要执行的语句(仅执行一遍)
; 要记录下扩展分区是主分区表的第几项
add byte [CurPartNum], 1 ;added by mingxuan 2020-9-30
mov cl, [CurPartNum]
mov [EXTNum], cl
; 当第一次进入该过程时,要记录下扩展分区的起始地址,该地址是以后所有逻辑分区的偏移量的基地址
mov [SecOffset_EXT], eax
mov byte [FirstInExt], 1
LABLE_EXTENDED:
;mov [SecOffset], ax ;deleted by mingxuan 2020-9-12
;mov [SecOffset], eax ;deleted by mingxuan 2020-9-12
;要记录下每个逻辑分区的起始地址,因为每次找自身时需要用这个地址做基地址。(该变量每次都要更新)
mov [SecOffset_SELF], eax ;added by mingxuan 2020-9-29
add byte [EbrNum], 1
cmp byte [EbrNum], 1
jz ._add_CurPartNo
._read_ebr:
mov cl, 1
mov bx, BaseOfBoot
mov es, bx
mov bx, OffsetOfBoot
call ReadSector
mov bx, 0
mov dh, 1
; 将EndInExt置1表示此时正在扫描扩展分区用于之后程序判断当前是否是扩展分区的终点
mov [EndInExt], dh ;added by mingxuan 2020-9-29
jmp CHECK_PARTITION
._add_CurPartNo:
add byte [CurPartNo], 1
jmp ._read_ebr
LABLE_ACTIVE:
mov cl, 1 ;要读取的扇区个数
mov bx, BaseOfBoot
mov es, bx
mov dword [es:OffsetOfActiPartStartSec], eax ;此时eax中存放活动分区的起始扇区号
;added by mingxuan 2020-9-12
mov bx, OffsetOfBoot ;对应扇区会被加载到内存的 es:bx 处
call ReadSector
;mov dh, 1
;call DispStr
;mov dh, 2
;call DispStr
; mov ah,0h
; int 16h
jmp BaseOfBoot:OffsetOfBoot
LABLE_NOT_FOUND:
mov dh, 3
call DispStr
jmp $
;SecOffset dw 0 ;deletd by mingxuan 2020-9-12
;SecOffset dd 0 ;modifed by mingxuan 2020-9-29
SecOffset_SELF dd 0 ;modifed by mingxuan 2020-9-29
SecOffset_EXT dd 0 ;modifed by mingxuan 2020-9-29
EbrNum db 0
FirstInExt db 0 ;added by mingxuan 2020-9-29
EndInExt db 0 ;added by mingxuan 2020-9-29
EXTNum db 0 ;added by mingxuan 2020-9-29
CurPartNum db 0 ;added by mingxuan 2020-9-29
MessageLength equ 27
BootMessage: db "Finding active partition..." ; 27字节, 不够则用空格补齐. 序号 0
Message1 db " partition "
CurPartNo db "0"
db ": active"
;Message2 db "press any key to continue "
Message3 db "active partition not found!"
DispStr:
push ax
push dx
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
pop dx
pop ax
ret
;----------------------------------------------------------------------------
; 函数名: ReadSector (使用扩展int13 ah=42)
;----------------------------------------------------------------------------
; 作用:
; 从第 ax 个 Sector 开始, 将 cl 个 Sector 读入 es:bx 中
DAPS:
DB 0x10 ; size of packet
DB 0 ; Always 0
D_CL DW 1 ; number of sectors to transfer
D_BX DW OffsetOfBoot ; transfer buffer (16 bit segment:16 bit offset)
D_ES DW BaseOfBoot
LBA_Lo DD 1 ; lower 32-bits of 48-bit starting LBA
LBA_Hi DD 0 ; upper 32-bits of 48-bit starting LBAs
ReadSector:
mov [D_CL], cl
mov [D_BX], bx
mov [D_ES], es
;mov [LBA_Lo], ax ;deleted by mingxuan 2020-9-17
mov [LBA_Lo], eax ;modified by mingxuan 2020-9-17
;修改为eax的原因: 分区表用4个字节来表示起始扇区而不是2个字节, mingxuan
mov dl, 0x80
.GoOnReading:
mov ah, 42h
mov si, DAPS
int 13h
jc .GoOnReading ; 如果读取错误 CF 会被置为 1, 这时就不停地读, 直到正确为止
ret
times 444 -($-$$) db 0
dw 0x0000

24
build_img.sh Executable file
View File

@ -0,0 +1,24 @@
if [ $# -ne 3 ] ;then
echo "usage: $0 \$(IMAGE) \$(OBJDIR) \$(OSBOOT_START_OFFSET)"
exit 1
fi
IMAGE=$1
OBJDIR=$2
OSBOOT_START_OFFSET=$3
cp ./hd/test1.img ${IMAGE}
dd if=${OBJDIR}/boot/mbr.bin of=${IMAGE} bs=1 count=446 conv=notrunc
loop_device=`losetup -f`
sudo losetup -P ${loop_device} ${IMAGE}
sudo mkfs.vfat -F 32 ${loop_device}p1
dd if=${OBJDIR}/boot/boot.bin of=${IMAGE} bs=1 count=420 seek=${OSBOOT_START_OFFSET} conv=notrunc
mkdir -p iso
sudo mount ${loop_device}p1 iso/
sudo cp ${OBJDIR}/boot/loader.bin iso/ -v
sudo cp ${OBJDIR}/kernel/kernel.bin iso/ -v
sudo umount iso/
sudo losetup -d ${loop_device}

11
fs_flags/Makefrag Normal file
View File

@ -0,0 +1,11 @@
OBJDIRS += fs_flags
FS_FLAG_SRCFILES:= fs_flags/orange_flag.asm \
fs_flags/fat32_flag.asm
FS_FLAG_OBJFILES:= $(patsubst %.asm, $(OBJDIR)/%.bin, $(FS_FLAG_SRCFILES))
$(OBJDIR)/fs_flags/%.bin: fs_flags/%.asm
@echo + as obj $<
@mkdir -p $(@D)
@$(AS) -o $@ $<

6
fs_flags/fat32_flag.asm Normal file
View File

@ -0,0 +1,6 @@
BLANK1 DB 0
BLANK2 DB 0
BLANK3 DB 0
FAT32_FLAG1 DD 0x4f44534d
FAT32_FLAG2 DD 0x302e3553

1
fs_flags/orange_flag.asm Normal file
View File

@ -0,0 +1 @@
ORANGE_FLAG DB 0x11

BIN
hd/test1.img Normal file

Binary file not shown.

16
include/assert.h Normal file
View File

@ -0,0 +1,16 @@
#ifndef MINIOS_ASSERT_H
#define MINIOS_ASSERT_H
void _warn(const char*, int, const char*, ...);
void _panic(const char*, int, const char*, ...) __attribute__((noreturn));
#define warn(...) _warn(__FILE__, __LINE__, __VA_ARGS__)
#define panic(...) _panic(__FILE__, __LINE__, __VA_ARGS__)
#define assert(x) \
do { if (!(x)) panic("assertion failed: %s", #x); } while (0)
// 静态assert如果不符合条件就会直接在编译期报错
#define static_assert(x) switch (x) case 0: case (x):;
#endif /* MINIOS_ASSERT_H */

41
include/console.h Normal file
View File

@ -0,0 +1,41 @@
/*************************************************************************//**
*****************************************************************************
* @file console.h
* @brief
* @author Forrest Y. Yu
* @date 2005
*****************************************************************************
*****************************************************************************/
/**********************************************************
* console.h //added by mingxuan 2019-5-17
***********************************************************/
#ifndef _ORANGES_CONSOLE_H_
#define _ORANGES_CONSOLE_H_
/* CONSOLE */
typedef struct s_console
{
unsigned int crtc_start; /* set CRTC start addr reg */
unsigned int orig; /* start addr of the console */
unsigned int con_size; /* how many words does the console have */
unsigned int cursor;
int is_full;
unsigned int current_line;
}CONSOLE;
#define SCR_UP 1 /* scroll upward */
#define SCR_DN -1 /* scroll downward */
#define SCR_SIZE (80 * 25)
#define SCR_WIDTH 80
#define DEFAULT_CHAR_COLOR (MAKE_COLOR(BLACK, WHITE))
#define GRAY_CHAR (MAKE_COLOR(BLACK, BLACK) | BRIGHT)
#define RED_CHAR (MAKE_COLOR(BLUE, RED) | BRIGHT)
#endif /* _ORANGES_CONSOLE_H_ */

184
include/const.h Normal file
View File

@ -0,0 +1,184 @@
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
const.h
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Forrest Yu, 2005
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
#ifndef _ORANGES_CONST_H_
#define _ORANGES_CONST_H_
/*最大整数定义*/
#define MAX_UNSIGNED_INT 0xFFFFFFFF //最大的无符号整形
#define MAX_INT 0x7FFFFFFF //最大的整形数
/* Color */
/*
* e.g. MAKE_COLOR(BLUE, RED)
* MAKE_COLOR(BLACK, RED) | BRIGHT
* MAKE_COLOR(BLACK, RED) | BRIGHT | FLASH
*/
//added by mingxuan 2019-5-19
#define BLACK 0x0 /* 0000 */
#define WHITE 0x7 /* 0111 */
#define RED 0x4 /* 0100 */
#define GREEN 0x2 /* 0010 */
#define BLUE 0x1 /* 0001 */
#define FLASH 0x80 /* 1000 0000 */
#define BRIGHT 0x08 /* 0000 1000 */
#define MAKE_COLOR(x,y) ((x<<4) | y) /* MAKE_COLOR(Background,Foreground) */
/* 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 */
#define MOUSE_IRQ 12 //added by mingxuan 2019-5-19
/* system call */
//#define NR_SYS_CALL 23 //last modified by xw, 18/6/19
#define NR_SYS_CALL 28 //modified by mingxuan 2019-5-17
/* TTY */
//added by mingxuan 2019-5-19
#define NR_CONSOLES 3 /* consoles */
/*页表相关*/
#define PageTblNumAddr 0x500 //页表数量放在这个位置,必须与load.inc中一致 add by visual 2016.5.11
#define KernelPageTblAddr 0x200000 //内核页表物理地址必须与load.inc中一致 add by visual 2016.5.17
/*线性地址描述*/ //edit by visual 2016.5.25
#define KernelSize 0x800000 //内核的大小//add by visual 2016.5.10
#define K_PHY2LIN(x) ((x)+0xC0000000) //内核中物理地址转线性地址 //add by visual 2016.5.10
#define K_LIN2PHY(x) ((x)-0xC0000000) //added by xw, 18/8/27
#define num_4B 0x4 //4B大小
#define num_1K 0x400 //1k大小
#define num_4K 0x1000 //4k大小
#define num_4M 0x400000 //4M大小
#define TextLinBase ((u32)0x0) //进程代码的起始地址这是参考值具体以elf描述为准
#define TextLinLimitMAX (TextLinBase+0x20000000) //大小512M这是参考值具体以elf描述为准
#define DataLinBase TextLinLimitMAX //进程数据的起始地址这是参考值具体以elf描述为准
#define DataLinLimitMAX (DataLinBase+0x20000000) //大小512M这是参考值具体以elf描述为准但是代码和数据长度总和不能超过这个值
#define VpageLinBase DataLinLimitMAX //保留内存起始地址
#define VpageLinLimitMAX (VpageLinBase+0x8000000-num_4K) //大小128M-4k
#define SharePageBase VpageLinLimitMAX //共享页线性地址执行fork\pthread的时候用,共享页必须4K对齐
#define SharePageLimit (SharePageBase+num_4K) //大小4k
#define HeapLinBase SharePageLimit //堆的起始地址
#define HeapLinLimitMAX (HeapLinBase+0x40000000) //大小1G
#define StackLinLimitMAX HeapLinLimitMAX //栈的大小: 1G-128M-4K注意栈的基址和界限方向
#define StackLinBase (ArgLinBase-num_4B) //=(StackLinLimitMAX+1G-128M-4K-4B)栈的起始地址,放在参数位置之前(注意堆栈的增长方向)
#define ArgLinBase (KernelLinBase-0x1000) //参数存放位置起始地址放在3G前暂时还没没用到
#define ArgLinLimitMAX KernelLinBase //=(ArgLinBase+0x1000)大小4K。
#define KernelLinBase 0xC0000000 //内核线性起始地址(有0x30400的偏移)
#define KernelLinLimitMAX (KernelLinBase+0x40000000) //大小1G
/***************目前线性地址布局***************************** edit by visual 2016.5.25
* 0 ~ 512M ,512M
* 512M ~ 1G512M
* 1G ~ 1G+128M128M,
* 1G+128M ~ 2G+128M1G
* 2G+128M ~ 3G-4K, 1G-128M-4K
* 3G-4K~3G4K
* 3G~4G1G
***********************************************************/
//#define ShareTblLinAddr (KernelLinLimitMAX-0x1000) //公共临时共享页,放在内核最后一个页表的最后一项上
/*分页机制常量的定义,必须与load.inc中一致*/ //add by visual 2016.4.5
#define PG_P 1 // 页存在属性位
#define PG_RWR 0 // R/W 属性位值, 读/执行
#define PG_RWW 2 // R/W 属性位值, 读/写/执行
#define PG_USS 0 // U/S 属性位值, 系统级
#define PG_USU 4 // U/S 属性位值, 用户级
#define PG_PS 64 // PS属性位值4K页
/* AT keyboard */
/* 8042 ports */
//added by mingxuan 2019-5-19
#define KB_DATA 0x60 /* I/O port for keyboard data
* Read : Read Output Buffer
* Write: Write Input Buffer
* (8042 Data & 8048 Command)
*/
#define KB_CMD 0x64 /* I/O port for keyboard command
* Read : Read Status Register
* Write: Write Input Buffer
* (8042 Command)
*/
#define KB_STA 0x64
#define KEYSTA_SEND_NOTREADY 0x02
#define KBSTATUS_IBF 0x02
#define KBSTATUS_OBF 0x01
#define wait_KB_write() while(in_byte(KB_STA) & KBSTATUS_IBF)
#define wait_KB_read() while(in_byte(KB_STA) & KBSTATUS_OBF)
#define KEYCMD_WRITE_MODE 0x60
#define KBC_MODE 0x47
#define KEYCMD_SENDTO_MOUSE 0xd4
#define MOUSECMD_ENABLE 0xf4
#define KBCMD_EN_MOUSE_INTFACE 0xa8
#define LED_CODE 0xED
#define KB_ACK 0xFA
/* VGA */
//added by mingxuan 2019-5-19
#define CRTC_ADDR_REG 0x3D4 /* CRT Controller Registers - Addr Register */
#define CRTC_DATA_REG 0x3D5 /* CRT Controller Registers - Data Register */
#define START_ADDR_H 0xC /* reg index of video mem start addr (MSB) */
#define START_ADDR_L 0xD /* reg index of video mem start addr (LSB) */
#define CURSOR_H 0xE /* reg index of cursor position (MSB) */
#define CURSOR_L 0xF /* reg index of cursor position (LSB) */
#define V_MEM_BASE 0xB8000 /* base of color video memory */
#define V_MEM_SIZE 0x8000 /* 32K: B8000H -> BFFFFH */
#define STD_IN 0
#define STD_OUT 1
#define STD_ERR 2
/* max() & min() */
//added by mingxuan 2019-5-19
#define max(a,b) ((a) > (b) ? (a) : (b))
#define min(a,b) ((a) < (b) ? (a) : (b))
#endif /* _ORANGES_CONST_H_ */

61
include/elf.h Normal file
View File

@ -0,0 +1,61 @@
/**********************************************************
* elf.h //add by visual 2016.5.16
***********************************************************/
#define EI_NIDENT 16
/************************************
* elf
*****************************************/
typedef struct{
u8 e_ident[EI_NIDENT]; //ELF魔数ELF字长字节序ELF文件版本等
u16 e_type; //ELF文件类型REL, 可执行文件,共享目标文件等
u16 e_machine; //ELF的CPU平台属性
u32 e_version; //ELF版本号
u32 e_entry; //ELF程序的入口虚拟地址
u32 e_phoff; //program header table(program头)在文件中的偏移
u32 e_shoff; //section header table(section头)在文件中的偏移
u32 e_flags; //用于标识ELF文件平台相关的属性
u16 e_ehsize; //elf header本文件头的长度
u16 e_phentsize; //program header table 中每一个条目的长度
u16 e_phnum; //program header table 中有多少个条目
u16 e_shentsize; //section header table 中每一个条目的长度
u16 e_shnum; //section header table 中有多少个条目
u16 e_shstrndx; //section header table 中字符索引
}Elf32_Ehdr;
/*******************************************
* program头()
**********************************************/
typedef struct{
u32 p_type; //该program 类型
u32 p_offset; //该program 在文件中的偏移量
u32 p_vaddr; //该program 应该放在这个线性地址
u32 p_paddr; //该program 应该放在这个物理地址(对只使用物理地址的系统有效)
u32 p_filesz; //该program 在文件中的长度
u32 p_memsz; //该program 在内存中的长度不一定和filesz相等
u32 p_flags; //该program 读写权限
u32 p_align; //该program 对齐方式
}Elf32_Phdr;
/*********************************************
* section头()
************************************************/
typedef struct
{
u32 s_name; //该section 段的名字
u32 s_type; //该section 的类型,代码段,数据段,符号表等
u32 s_flags; //该section 在进程虚拟地址空间中的属性
u32 s_addr; //该section 的虚拟地址
u32 s_offset; //该section 在文件中的偏移
u32 s_size; //该section 的长度
u32 s_link; //该section 头部表符号链接
u32 s_info; //该section 附加信息
u32 s_addralign; //该section 对齐方式
u32 s_entsize; //该section 若有固定项目,则给出固定项目的大小,如符号表
}Elf32_Shdr;
void read_Ehdr(u32 fd,Elf32_Ehdr *File_Ehdr,u32 offset);
void read_Phdr(u32 fd,Elf32_Phdr *File_Phdr,u32 offset);
void read_Shdr(u32 fd,Elf32_Shdr *File_Shdr,u32 offset);

189
include/fat32.h Normal file
View File

@ -0,0 +1,189 @@
/**********************************************************
* fat32.h //added by mingxuan 2019-5-17
***********************************************************/
#ifndef FAT32_H
#define FAT32_H
#define TRUE 1//是
#define FALSE 0//否
#define OK 1//正常返回
#define SYSERROR 2//系统错误
#define VDISKERROR 3//虚拟磁盘错误
#define INSUFFICIENTSPACE 4//虚拟磁盘空间不足
#define WRONGPATH 5//路径有误
#define NAMEEXIST 6//文件或目录名已存在
#define ACCESSDENIED 7//读写权限不对拒绝访问
#define C 1//创建 //added by mingxuan 2019-5-18
#define R 5//读
#define W 6//写
#define RW 2 //读写 //added by mingxuan 2019-5-18
#define F 1//文件
#define D 0//目录
typedef int STATE;//函数返回状态
typedef unsigned char BYTE;//字节
typedef unsigned short WORD;//双字节
typedef unsigned long DWORD;//四字节
typedef unsigned int UINT;//无符号整型
typedef char CHAR;//字符类型
typedef unsigned char* PBYTE;
typedef unsigned short* PWORD;
typedef unsigned long* PDWORD;//四字节指针
typedef unsigned int* PUINT;//无符号整型指针
typedef char* PCHAR;//字符指针
typedef struct//定义目录项占32个字节
{
BYTE filename[8];//文件名占8个字节
BYTE extension[3];//扩展名占3个字节
BYTE proByte;//属性字节占1个字节
BYTE sysReserved;//系统保留占1个字节
BYTE createMsecond;//创建时间的10毫秒位占1个字节
WORD createTime;//文件创建时间占2个字节
WORD createDate;//文件创建日期占2个字节
WORD lastAccessDate;//文件最后访问日期占2个字节
WORD highClusterNum;//文件的起始簇号的高16位占2个字节
WORD lastModifiedTime;//文件的最近修改时间
WORD lastModifiedDate;//文件的最近修改日期
WORD lowClusterNum;//文件的起始簇号的低16位占2个字节
DWORD filelength;//文件的长度占4个字节
}Record,*PRecord;
typedef struct//定义长文件名目录项占32个字节
{
BYTE proByte;//属性字节
BYTE name1[10];//长文件名第1段
BYTE longNameFlag;//长文件名目录项标志取值0FH
BYTE sysReserved;//系统保留
BYTE name2[19];//长文件名第2段
}LONGNAME;
typedef struct{//文件类型
CHAR parent[256];//父路径
CHAR name[256];//文件名
DWORD start;//起始地址
DWORD off;//总偏移量,以字节为单位
DWORD size;//文件的大小,以字节为单位
UINT flag;//文件读写标志
}File,*PFile;
typedef struct{//动态数组元素类型,用于存储文件或目录的基本信息
CHAR fullpath[256];//绝对路径
CHAR name[256];//文件名或目录名
UINT tag;//1表示文件0表示目录
}DArrayElem;
typedef struct{//动态数组类型
DArrayElem *base;//数组基地址
UINT offset;//读取数组时的偏移量
UINT used;//数组当前已使用的容量
UINT capacity;//数组的总容量
UINT increment;//当数组容量不足时,动态增长的步长
}DArray;
typedef struct{//文件或目录属性类型
BYTE type;//0x10表示目录否则表示文件
CHAR name[256];//文件或目录名称
CHAR location[256];//文件或目录的位置,绝对路径
DWORD size;//文件的大小或整个目录中(包括子目录中)的文件总大小
CHAR createTime[20];//创建时间型如yyyy-MM-dd hh:mm:ss类型
CHAR lastModifiedTime[20];//最后修改时间
union{
CHAR lastAccessDate[11];//最后访问时间当type为文件值有效
UINT contain[2];//目录中的文件个数和子目录的个数当type为目录时有效
}share;
}Properties;
STATE CreateVDisk(DWORD size);
STATE FormatVDisk(PCHAR path,PCHAR volumelabel);
STATE LoadVDisk(PCHAR path);
STATE CreateDir(const char *dirname);
STATE CreateFile(const char *filename);
STATE OpenFile(const char *filename,int mode);
STATE CloseFile(int fd);
STATE OpenDir(const char *dirname);
STATE ReadFile(int fd,void *buf, int length);
STATE WriteFile(int fd, const void *buf, int length);
STATE CopyFileIn(PCHAR sfilename,PCHAR dfilename);
STATE CopyFileOut(PCHAR sfilename,PCHAR dfilename);
STATE DeleteFile(const char *filename);
STATE DeleteDir(const char *dirname);
STATE ListAll(PCHAR dirname,DArray *array);
STATE IsFile(PCHAR path,PUINT tag);
STATE GetFileLength(PCHAR filename,PDWORD length);
STATE Rename(PCHAR path,PCHAR newname);
STATE CopyFile(PCHAR sfilename,PCHAR dpath);
STATE CopyDir(PCHAR sdirname,PCHAR dpath);
STATE Move(PCHAR sfilename,PCHAR dpath);
STATE GetProperty(PCHAR filename,Properties *properties);
STATE GetParenetDir(PCHAR name,PCHAR parentDir);
STATE GetVDiskFreeSpace(PDWORD left);
STATE GetVDiskSize(PDWORD totalsize);
STATE GetCurrentPath(PCHAR path);
DArray* InitDArray(UINT initialCapacity,UINT capacityIncrement);
void AddElement(DArray *array,DArrayElem element);
DArrayElem* NextElement(DArray *array);
void DestroyDArray(DArray *array);
void TimeToBytes(WORD result[]);//t是一个WORD类型的数组长度为2第0个元素为日期第1个元素为时间
void BytesToTime(WORD date,WORD time,WORD result[]);//t是一个表示时间的WORD数组长度为6分别表示年、月、日、时、分、秒
void TimeToString(WORD result[],PCHAR timestring);
STATE IsFullPath(PCHAR path);//判断path是否是一个绝对路径
void ToFullPath(PCHAR path,PCHAR fullpath);//将path转换成绝对路径用fullpath返回
void GetParentFromPath(PCHAR fullpath,PCHAR parent);//从一个绝对路径中得到它的父路径(父目录)
void GetNameFromPath(PCHAR path,PCHAR name);//从一个路径中得到文件或目录的名称
void MakeFullPath(PCHAR parent,PCHAR name,PCHAR fullpath);//将父路径和文件名组合成一个绝对路径
void FormatFileNameAndExt(PCHAR filename,PCHAR name,PCHAR ext);//将一个文件名转换成带空格的文件名和后缀名的形式,为了写入目录项。
void FormatDirNameAndExt(PCHAR dirname,PCHAR name,PCHAR ext);//将一个目录名转换成带空格的目录名和后缀的形式,为了写入目录项。
void ChangeCurrentPath(PCHAR addpath);
void GetNameFromRecord(Record record,PCHAR fullname);//从目录项中得到文件或目录的全名
STATE PathToCluster(PCHAR path, PDWORD cluster);//将抽象的路径名转换成簇号
STATE FindSpaceInDir(DWORD parentCluster,PCHAR name,PDWORD sectorIndex,PDWORD off_in_sector);//在指定的目录中寻找空的目录项
STATE FindClusterForDir(PDWORD pcluster);//为目录分配簇
STATE ReadRecord(DWORD parentCluster,PCHAR name,PRecord record,PDWORD sectorIndex,PDWORD off_in_sector);//获得指定的目录项的位置(偏移量)
STATE WriteRecord(Record record,DWORD sectorIndex,DWORD off_in_sector);
STATE FindClusterForFile(DWORD totalClusters,PDWORD clusters);//为一个文件分配totalClusters个簇
STATE WriteFAT(DWORD totalClusters,PDWORD clusters);//写FAT1和FAT2
STATE GetNextCluster(DWORD curClusterIndex,PDWORD nextClusterIndex);
STATE AddCluster(DWORD startCluster,DWORD num);//cluster表示该文件或目录所在目录的簇,num表示增加几个簇
void CreateRecord(PCHAR filename,BYTE type,DWORD startCluster,DWORD size,PRecord precord);//创建一个目录项
void GetFileOffset(PFile pfile,PDWORD sectorIndex,PDWORD off_in_sector,PUINT isLastSector);//将文件当前位置转换成相对虚拟磁盘文件起始地址的偏移量,便于读写。
STATE AllotClustersForEmptyFile(PFile pfile,DWORD size);//为一个打开的空文件分配簇。
STATE NeedMoreCluster(PFile pfile,DWORD size,PDWORD number);//判断是否需要更多的簇,如果需要就返回需要的簇的个数
STATE ClearRecord(DWORD parentCluster,PCHAR name,PDWORD startCluster);//删除记录项
void ClearFATs(DWORD startcluster);//删除簇号
STATE FindNextRecord(PDWORD cluster,PDWORD off,PCHAR name,PUINT tag);
void DeleteAllRecord(DWORD startCluster);
void GetContent(DWORD startCluster,PDWORD size,PDWORD files,PDWORD folders);
void ClearClusters(DWORD cluster);
void ReadSector(BYTE*,DWORD sectorIndex);
void WriteSector(BYTE*,DWORD sectorIndex);
void GetNextSector(PFile pfile,DWORD curSectorIndex,PDWORD nextSectorIndex,PUINT isLastSector);
void init_fs_fat();
int rw_sector_fat(int io_type, int dev, unsigned long long pos, int bytes, int proc_nr, void* buf);
int rw_sector_sched_fat(int io_type, int dev, int pos, int bytes, int proc_nr, void* buf);
void DisErrorInfo(STATE state);
int sys_CreateFile(void *uesp);
int sys_DeleteFile(void *uesp);
int sys_OpenFile(void *uesp);
int sys_CloseFile(void *uesp);
int sys_WriteFile(void *uesp);
int sys_ReadFile(void *uesp);
int sys_OpenDir(void *uesp);
int sys_CreateDir(void *uesp);
int sys_DeleteDir(void *uesp);
int sys_ListDir(void *uesp);
#endif

37
include/fs.h Normal file
View File

@ -0,0 +1,37 @@
/**
* fs.h
* This file contains APIs of filesystem, it's used inside the kernel.
* There is a seperate header file for user program's use.
* This file is added by xw. 18/6/17
*/
#ifndef FS_H
#define FS_H
/* APIs of file operation */
#define O_CREAT 1
#define O_RDWR 2
#define SEEK_SET 1
#define SEEK_CUR 2
#define SEEK_END 3
#define MAX_PATH 128
#define MAX_FILENAME_LEN 12
void init_fs();
//added by mingxuan 2019-5-17
int real_open(const char *pathname, int flags);
int real_close(int fd);
int real_read(int fd, void *buf, int count);
int real_write(int fd, const void *buf, int count);
int real_unlink(const char *pathname);
int real_lseek(int fd, int offset, int whence);
//added by mingxuan 2020-10-30
void read_super_block(int dev);
struct super_block* get_super_block(int dev);
int get_fs_dev(int drive, int fs_type);
#endif /* FS_H */

120
include/fs_const.h Normal file
View File

@ -0,0 +1,120 @@
/**
* fs_const.h
* This file contains consts and macros associated with filesystem.
* The code is added by zcr, and the file is added by xw. 18/6/17
*/
/* TTY */
#define NR_CONSOLES 3 /* consoles */
/* max() & min() */
#define max(a,b) ((a) > (b) ? (a) : (b))
#define min(a,b) ((a) < (b) ? (a) : (b))
/* macros for messages */
#define FD u.m3.m3i1
#define PATHNAME u.m3.m3p1
#define FLAGS u.m3.m3i1
#define NAME_LEN u.m3.m3i2
#define CNT u.m3.m3i2
#define REQUEST u.m3.m3i2
#define PROC_NR u.m3.m3i3
#define DEVICE u.m3.m3i4
#define POSITION u.m3.m3l1
#define BUF u.m3.m3p2
#define OFFSET u.m3.m3i2
#define WHENCE u.m3.m3i3
#define RETVAL u.m3.m3i1
#define DIOCTL_GET_GEO 1
/* Hard Drive */
#define SECTOR_SIZE 512
#define SECTOR_BITS (SECTOR_SIZE * 8)
#define SECTOR_SIZE_SHIFT 9
/* major device numbers (corresponding to kernel/global.c::dd_map[]) */
#define NO_DEV 0
#define DEV_FLOPPY 1
#define DEV_CDROM 2
#define DEV_HD 3
#define DEV_CHAR_TTY 4
#define DEV_SCSI 5
/* make device number from major and minor numbers */
#define MAJOR_SHIFT 8
#define MAKE_DEV(a,b) ((a << MAJOR_SHIFT) | b)
/* separate major and minor numbers from device number */
#define MAJOR(x) ((x >> MAJOR_SHIFT) & 0xFF)
#define MINOR(x) (x & 0xFF)
#define INVALID_INODE 0
#define ROOT_INODE 1
#define MAX_DRIVES 2
#define NR_PART_PER_DRIVE 4 // 每块硬盘(驱动器)只能有4个主分区, mingxuan
#define NR_SUB_PER_PART 16 // 每个扩展分区最多有16个逻辑分区, mingxuan
#define NR_SUB_PER_DRIVE (NR_SUB_PER_PART * NR_PART_PER_DRIVE) //每块硬盘(驱动器)最多有16 * 4 = 64个逻辑分区, mingxuan
#define NR_PRIM_PER_DRIVE (NR_PART_PER_DRIVE + 1) // 表示的是hd[04]这5个分区因为有些代码中我们把整块硬盘hd0和主分区hd[14])放在一起看待, mingxuan
/**
* @def MAX_PRIM
* Defines the max minor number of the primary partitions.
* If there are 2 disks, prim_dev ranges in hd[0-9], this macro will
* equals 9.
*/
// MAX_PRIM定义的是主分区的最大值比如若有两块硬盘那第一块硬盘的主分区为hd[14]第二块硬盘的主分区为hd[69]
// 所以MAX_PRIM为9我们定义的hd1a的设备号应大于它这样通过与MAX_PRIM比较我们就可以知道一个设备是主分区还是逻辑分区
// mingxuan
#define MAX_PRIM (MAX_DRIVES * NR_PRIM_PER_DRIVE - 1) // MAX_PRIM = 2 * 4 - 1 = 9
#define MAX_SUBPARTITIONS (NR_SUB_PER_DRIVE * MAX_DRIVES) // MAX_SUBPARTITIONS = 64 * 2 = 128
/* name of drives */
// added by mingxuan 2020-10-27
#define PRIMARY_MASTER 0x0
#define PRIMARY_SLAVE 0x1
#define SECONDARY_MASTER 0x2
#define SECONDARY_SLAVE 0x3
/* device numbers of hard disk */
#define MINOR_hd0 0x0 // added by mingxuan 2020-10-9
#define MINOR_hd1 0x1 // added by mingxuan 2020-10-12
#define MINOR_hd2 0x2 // added by mingxuan 2020-10-12
#define MINOR_hd1a 0x10
#define MINOR_hd2a (MINOR_hd1a + NR_SUB_PER_PART) // MINOR_hd2a = 16 + 16
#define MAJOR_FAT 0x4 //modified by mingxuan 2020-10-22
#define MINOR_BOOT MINOR_hd2 //modified by mingxuan 2020-10-12
#define P_PRIMARY 0
#define P_EXTENDED 1
#define ORANGES_PART 0x99 /* Orange'S partition */
#define NO_PART 0x00 /* unused entry */
#define EXT_PART 0x05 /* extended partition */
#define NR_FILE_DESC 128 /* FIXME */ //modified by mingxuan 2019-5-19
#define NR_INODE 64 /* FIXME */
#define NR_SUPER_BLOCK 8
/* INODE::i_mode (octal, lower 32 bits reserved) */
#define I_TYPE_MASK 0170000
#define I_REGULAR 0100000
#define I_BLOCK_SPECIAL 0060000
#define I_DIRECTORY 0040000
#define I_CHAR_SPECIAL 0020000
#define I_NAMED_PIPE 0010000
#define is_special(m) ((((m) & I_TYPE_MASK) == I_BLOCK_SPECIAL) || \
(((m) & I_TYPE_MASK) == I_CHAR_SPECIAL))
#define NR_DEFAULT_FILE_SECTS 2048 /* 2048 * 512 = 1MB */
#define FSBUF_SIZE 0x100000 //added by mingxuan 2019-5-17

203
include/fs_misc.h Normal file
View File

@ -0,0 +1,203 @@
/**
* fs_misc.h
* This file contains miscellaneous defines and declarations associated with filesystem.
* The code is added by zcr, and the file is added by xw. 18/6/17
*/
#ifndef FS_MISC_H
#define FS_MISC_H
#include "fat32.h"
/**
* @struct dev_drv_map fs.h "include/sys/fs.h"
* @brief The Device_nr.\ - Driver_nr.\ MAP.
*/
struct dev_drv_map {
int driver_nr; /**< The proc nr.\ of the device driver. */
};
/**
* @def MAGIC_V1
* @brief Magic number of FS v1.0
*/
#define MAGIC_V1 0x111
/**
* @struct super_block fs.h "include/fs.h"
* @brief The 2nd sector of the FS
*
* Remember to change SUPER_BLOCK_SIZE if the members are changed.
*/
struct super_block {
u32 magic; /**< Magic number */
u32 nr_inodes; /**< How many inodes */
u32 nr_sects; /**< How many sectors */
u32 nr_imap_sects; /**< How many inode-map sectors */
u32 nr_smap_sects; /**< How many sector-map sectors */
u32 n_1st_sect; /**< Number of the 1st data sector */
u32 nr_inode_sects; /**< How many inode sectors */
u32 root_inode; /**< Inode nr of root directory */
u32 inode_size; /**< INODE_SIZE */
u32 inode_isize_off; /**< Offset of `struct inode::i_size' */
u32 inode_start_off; /**< Offset of `struct inode::i_start_sect' */
u32 dir_ent_size; /**< DIR_ENTRY_SIZE */
u32 dir_ent_inode_off;/**< Offset of `struct dir_entry::inode_nr' */
u32 dir_ent_fname_off;/**< Offset of `struct dir_entry::name' */
/*
* the following item(s) are only present in memory
*/
int sb_dev; /**< the super block's home device */
int fs_type; //added by mingxuan 2020-10-30
};
/**
* @def SUPER_BLOCK_SIZE
* @brief The size of super block \b in \b the \b device.
*
* Note that this is the size of the struct in the device, \b NOT in memory.
* The size in memory is larger because of some more members.
*/
//#define SUPER_BLOCK_SIZE 56
#define SUPER_BLOCK_SIZE 64 //modified by mingxuan 2020-10-30
/**
* @struct inode
* @brief i-node
*
* The \c start_sect and\c nr_sects locate the file in the device,
* and the size show how many bytes is used.
* If <tt> size < (nr_sects * SECTOR_SIZE) </tt>, the rest bytes
* are wasted and reserved for later writing.
*
* \b NOTE: Remember to change INODE_SIZE if the members are changed
*/
struct inode {
u32 i_mode; /**< Accsess mode */
u32 i_size; /**< File size */
u32 i_start_sect; /**< The first sector of the data */
u32 i_nr_sects; /**< How many sectors the file occupies */
u8 _unused[16]; /**< Stuff for alignment */
/* the following items are only present in memory */
int i_dev;
int i_cnt; /**< How many procs share this inode */
int i_num; /**< inode nr. */
};
/**
* @def INODE_SIZE
* @brief The size of i-node stored \b in \b the \b device.
*
* Note that this is the size of the struct in the device, \b NOT in memory.
* The size in memory is larger because of some more members.
*/
#define INODE_SIZE 32
/**
* @struct dir_entry
* @brief Directory Entry
*/
struct dir_entry {
int inode_nr; /**< inode nr. */
char name[MAX_FILENAME_LEN]; /**< Filename */
};
/**
* @def DIR_ENTRY_SIZE
* @brief The size of directory entry in the device.
*
* It is as same as the size in memory.
*/
#define DIR_ENTRY_SIZE sizeof(struct dir_entry)
/**
* @struct file_desc
* @brief File Descriptor
*/
//added by mingxuan 2019-5-17
union ptr_node{
struct inode* fd_inode; /**< Ptr to the i-node */
PFile fd_file; //指向fat32的file结构体
};
struct file_desc {
int fd_mode; /**< R or W */
int fd_pos; /**< Current position for R/W. */
//struct inode* fd_inode; /**< Ptr to the i-node */ //deleted by mingxuan 2019-5-17
//added by mingxuan 2019-5-17
union ptr_node fd_node;
int flag; //用于标志描述符是否被使用
int dev_index;
};
/**
* Since all invocations of `rw_sector()' in FS look similar (most of the
* params are the same), we use this macro to make code more readable.
*/
#define RD_SECT(dev,sect_nr,fsbuf) rw_sector(DEV_READ, \
dev, \
(sect_nr) * SECTOR_SIZE, \
SECTOR_SIZE, /* read one sector */ \
proc2pid(p_proc_current),/*TASK_A*/ \
fsbuf);
#define WR_SECT(dev,sect_nr,fsbuf) rw_sector(DEV_WRITE, \
dev, \
(sect_nr) * SECTOR_SIZE, \
SECTOR_SIZE, /* write one sector */ \
proc2pid(p_proc_current), \
fsbuf);
//modified by mingxuan 2020-10-27
#define RD_SECT_FAT(dev, buf, sect_nr) rw_sector_fat(DEV_READ, \
dev, \
(sect_nr) * SECTOR_SIZE, \
SECTOR_SIZE, /* read one sector */ \
proc2pid(p_proc_current),/*TASK_A*/ \
buf);
//modified by mingxuan 2020-10-27
#define WR_SECT_FAT(dev, buf, sect_nr) rw_sector_fat(DEV_WRITE, \
dev, \
(sect_nr) * SECTOR_SIZE, \
SECTOR_SIZE, /* write one sector */ \
proc2pid(p_proc_current), \
buf);
//added by xw, 18/8/27
#define RD_SECT_SCHED(dev,sect_nr,fsbuf) rw_sector_sched(DEV_READ, \
dev, \
(sect_nr) * SECTOR_SIZE, \
SECTOR_SIZE, /* read one sector */ \
proc2pid(p_proc_current),/*TASK_A*/ \
fsbuf);
#define WR_SECT_SCHED(dev,sect_nr,fsbuf) rw_sector_sched(DEV_WRITE, \
dev, \
(sect_nr) * SECTOR_SIZE, \
SECTOR_SIZE, /* write one sector */ \
proc2pid(p_proc_current), \
fsbuf);
//modified by mingxuan 2020-10-27
#define RD_SECT_SCHED_FAT(dev, buf, sect_nr) rw_sector_sched_fat(DEV_READ, \
dev, \
(sect_nr) * SECTOR_SIZE, \
SECTOR_SIZE, /* read one sector */ \
proc2pid(p_proc_current),/*TASK_A*/ \
buf);
//modified by mingxuan 2020-10-27
#define WR_SECT_SCHED_FAT(dev, buf, sect_nr) rw_sector_sched_fat(DEV_WRITE, \
dev, \
(sect_nr) * SECTOR_SIZE, \
SECTOR_SIZE, /* write one sector */ \
proc2pid(p_proc_current), \
buf);
//~xw
#endif /* FS_MISC_H */

53
include/global.h Normal file
View File

@ -0,0 +1,53 @@
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
global.h
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Forrest Yu, 2005
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
/* equal to 1 if kernel is initializing, equal to 0 if done.
* added by xw, 18/5/31
*/
extern int kernel_initial;
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 int u_proc_sum; //内核中用户进程/线程数量 add by visual 2016.5.25
extern TSS tss;
extern PROCESS* p_proc_current;
extern PROCESS* p_proc_next; //the next process that will run. added by xw, 18/4/26
extern PROCESS cpu_table[]; //added by xw, 18/6/1
extern PROCESS proc_table[];
extern char task_stack[];
extern TASK task_table[];
extern irq_handler irq_table[];
/* tty */
//added by mingxuan 2019-5-19
#include "tty.h"
#include "console.h"
extern TTY tty_table[];
extern CONSOLE console_table[];
extern int current_console;
// u32 PageTblNum; //页表数量 add by visual 2016.4.5
extern u32 cr3_ready; //当前进程的页目录 add by visual 2016.4.5
struct memfree{
u32 addr;
u32 size;
};
#include "fs_const.h"
#include "hd.h"
extern struct hd_info hd_info[1]; //added by mingxuan 2020-10-27

308
include/hd.h Normal file
View File

@ -0,0 +1,308 @@
/*************************************************************************//**
*****************************************************************************
* @file include/sys/hd.h
* @brief
* @author Forrest Y. Yu
* @date 2008
*****************************************************************************
*****************************************************************************/
#ifndef _ORANGES_HD_H_
#define _ORANGES_HD_H_
/**
* @struct part_ent
* @brief Partition Entry struct.
*
* <b>Master Boot Record (MBR):</b>
* Located at offset 0x1BE in the 1st sector of a disk. MBR contains
* four 16-byte partition entries. Should end with 55h & AAh.
*
* <b>partitions in MBR:</b>
* A PC hard disk can contain either as many as four primary partitions,
* or 1-3 primaries and a single extended partition. Each of these
* partitions are described by a 16-byte entry in the Partition Table
* which is located in the Master Boot Record.
*
* <b>extented partition:</b>
* It is essentially a link list with many tricks. See
* http://en.wikipedia.org/wiki/Extended_boot_record for details.
*/
struct part_ent {
u8 boot_ind; /**
* boot indicator
* Bit 7 is the active partition flag,
* bits 6-0 are zero (when not zero this
* byte is also the drive number of the
* drive to boot so the active partition
* is always found on drive 80H, the first
* hard disk).
*/
u8 start_head; /**
* Starting Head
*/
u8 start_sector; /**
* Starting Sector.
* Only bits 0-5 are used. Bits 6-7 are
* the upper two bits for the Starting
* Cylinder field.
*/
u8 start_cyl; /**
* Starting Cylinder.
* This field contains the lower 8 bits
* of the cylinder value. Starting cylinder
* is thus a 10-bit number, with a maximum
* value of 1023.
*/
u8 sys_id; /**
* System ID
* e.g.
* 01: FAT12
* 81: MINIX
* 83: Linux
*/
u8 end_head; /**
* Ending Head
*/
u8 end_sector; /**
* Ending Sector.
* Only bits 0-5 are used. Bits 6-7 are
* the upper two bits for the Ending
* Cylinder field.
*/
u8 end_cyl; /**
* Ending Cylinder.
* This field contains the lower 8 bits
* of the cylinder value. Ending cylinder
* is thus a 10-bit number, with a maximum
* value of 1023.
*/
u32 start_sect; /**
* starting sector counting from
* 0 / Relative Sector. / start in LBA
*/
u32 nr_sects; /**
* nr of sectors in partition
*/
} ;
// added by mingxuan 2020-10-27
struct fs_flags
{
u8 orange_flag;
//u8 reserved1;
//u8 reserved2;
u16 reserved;
u32 fat32_flag1;
u32 fat32_flag2;
};
/********************************************/
/* I/O Ports used by hard disk controllers. */
/********************************************/
/* slave disk not supported yet, all master registers below */
/* Command Block Registers */
/* MACRO PORT DESCRIPTION INPUT/OUTPUT */
/* ----- ---- ----------- ------------ */
#define REG_DATA 0x1F0 /* Data I/O */
#define REG_FEATURES 0x1F1 /* Features O */
#define REG_ERROR REG_FEATURES /* Error I */
/* The contents of this register are valid only when the error bit
(ERR) in the Status Register is set, except at drive power-up or at the
completion of the drive's internal diagnostics, when the register
contains a status code.
When the error bit (ERR) is set, Error Register bits are interpreted as such:
| 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
+-----+-----+-----+-----+-----+-----+-----+-----+
| BRK | UNC | | IDNF| | ABRT|TKONF| AMNF|
+-----+-----+-----+-----+-----+-----+-----+-----+
| | | | | | | |
| | | | | | | `--- 0. Data address mark not found after correct ID field found
| | | | | | `--------- 1. Track 0 not found during execution of Recalibrate command
| | | | | `--------------- 2. Command aborted due to drive status error or invalid command
| | | | `--------------------- 3. Not used
| | | `--------------------------- 4. Requested sector's ID field not found
| | `--------------------------------- 5. Not used
| `--------------------------------------- 6. Uncorrectable data error encountered
`--------------------------------------------- 7. Bad block mark detected in the requested sector's ID field
*/
#define REG_NSECTOR 0x1F2 /* Sector Count I/O */
#define REG_LBA_LOW 0x1F3 /* Sector Number / LBA Bits 0-7 I/O */
#define REG_LBA_MID 0x1F4 /* Cylinder Low / LBA Bits 8-15 I/O */
#define REG_LBA_HIGH 0x1F5 /* Cylinder High / LBA Bits 16-23 I/O */
#define REG_DEVICE 0x1F6 /* Drive | Head | LBA bits 24-27 I/O */
/* | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
+-----+-----+-----+-----+-----+-----+-----+-----+
| 1 | L | 1 | DRV | HS3 | HS2 | HS1 | HS0 |
+-----+-----+-----+-----+-----+-----+-----+-----+
| | \_____________________/
| | |
| | `------------ If L=0, Head Select.
| | These four bits select the head number.
| | HS0 is the least significant.
| | If L=1, HS0 through HS3 contain bit 24-27 of the LBA.
| `--------------------------- Drive. When DRV=0, drive 0 (master) is selected.
| When DRV=1, drive 1 (slave) is selected.
`--------------------------------------- LBA mode. This bit selects the mode of operation.
When L=0, addressing is by 'CHS' mode.
When L=1, addressing is by 'LBA' mode.
*/
#define REG_STATUS 0x1F7 /* Status I */
/* Any pending interrupt is cleared whenever this register is read.
| 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
+-----+-----+-----+-----+-----+-----+-----+-----+
| BSY | DRDY|DF/SE| # | DRQ | | | ERR |
+-----+-----+-----+-----+-----+-----+-----+-----+
| | | | | | | |
| | | | | | | `--- 0. Error.(an error occurred)
| | | | | | `--------- 1. Obsolete.
| | | | | `--------------- 2. Obsolete.
| | | | `--------------------- 3. Data Request. (ready to transfer data)
| | | `--------------------------- 4. Command dependent. (formerly DSC bit)
| | `--------------------------------- 5. Device Fault / Stream Error.
| `--------------------------------------- 6. Drive Ready.
`--------------------------------------------- 7. Busy. If BSY=1, no other bits in the register are valid.
*/
#define STATUS_BSY 0x80
#define STATUS_DRDY 0x40
#define STATUS_DFSE 0x20
#define STATUS_DSC 0x10
#define STATUS_DRQ 0x08
#define STATUS_CORR 0x04
#define STATUS_IDX 0x02
#define STATUS_ERR 0x01
#define REG_CMD REG_STATUS /* Command O */
/*
+--------+---------------------------------+-----------------+
| Command| Command Description | Parameters Used |
| Code | | PC SC SN CY DH |
+--------+---------------------------------+-----------------+
| ECh @ | Identify Drive | D |
| 91h | Initialize Drive Parameters | V V |
| 20h | Read Sectors With Retry | V V V V |
| E8h @ | Write Buffer | D |
+--------+---------------------------------+-----------------+
KEY FOR SYMBOLS IN THE TABLE:
===========================================-----=========================================================================
PC Register 1F1: Write Precompensation @ These commands are optional and may not be supported by some drives.
SC Register 1F2: Sector Count D Only DRIVE parameter is valid, HEAD parameter is ignored.
SN Register 1F3: Sector Number D+ Both drives execute this command regardless of the DRIVE parameter.
CY Register 1F4+1F5: Cylinder low + high V Indicates that the register contains a valid paramterer.
DH Register 1F6: Drive / Head
*/
/* Control Block Registers */
/* MACRO PORT DESCRIPTION INPUT/OUTPUT */
/* ----- ---- ----------- ------------ */
#define REG_DEV_CTRL 0x3F6 /* Device Control O */
/* | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
+-----+-----+-----+-----+-----+-----+-----+-----+
| HOB | - | - | - | - |SRST |-IEN | 0 |
+-----+-----+-----+-----+-----+-----+-----+-----+
| | |
| | `--------- Interrupt Enable.
| | - IEN=0, and the drive is selected,
| | drive interrupts to the host will be enabled.
| | - IEN=1, or the drive is not selected,
| | drive interrupts to the host will be disabled.
| `--------------- Software Reset.
| - The drive is held reset when RST=1.
| Setting RST=0 re-enables the drive.
| - The host must set RST=1 and wait for at least
| 5 microsecondsbefore setting RST=0, to ensure
| that the drive recognizes the reset.
`--------------------------------------------- HOB (High Order Byte)
- defined by 48-bit Address feature set.
*/
#define REG_ALT_STATUS REG_DEV_CTRL /* Alternate Status I */
/* This register contains the same information as the Status Register.
The only difference is that reading this register does not imply interrupt acknowledge or clear a pending interrupt.
*/
#define REG_DRV_ADDR 0x3F7 /* Drive Address I */
struct hd_cmd {
u8 features;
u8 count;
u8 lba_low;
u8 lba_mid;
u8 lba_high;
u8 device;
u8 command;
};
// added by mingxuan 2020-10-27
# define NO_FS_TYPE 0x0 //added by mingxuan 2020-10-30
# define ORANGE_TYPE 0x1
# define FAT32_TYPE 0x2
# define TTY_FS_TYPE 0x3 //added by mingxuan 2020-10-30
struct part_info {
u32 base; /* # of start sector (NOT byte offset, but SECTOR) */
u32 size; /* how many sectors in this partition */
u32 fs_type; //added by mingxuan 2020-10-27
};
/* main drive struct, one entry per drive */
struct hd_info
{
int open_cnt;
struct part_info primary[NR_PRIM_PER_DRIVE]; // NR_PRIM_PER_DRIVE = 5
struct part_info logical[NR_SUB_PER_DRIVE]; // NR_SUB_PER_DRIVE = 16 *4 =64
};
/***************/
/* DEFINITIONS */
/***************/
#define HD_TIMEOUT 10000 /* in millisec */
#define PARTITION_TABLE_OFFSET 0x1BE
#define ATA_IDENTIFY 0xEC
#define ATA_READ 0x20
#define ATA_WRITE 0x30
/* for DEVICE register. */
#define MAKE_DEVICE_REG(lba,drv,lba_highest) (((lba) << 6) | \
((drv) << 4) | \
(lba_highest & 0xF) | 0xA0)
// added by xw, 18/8/26
typedef struct rdwt_info
{
MESSAGE *msg;
void *kbuf;
PROCESS *proc;
struct rdwt_info *next;
} RWInfo;
typedef struct
{
RWInfo *front;
RWInfo *rear;
} HDQueue;
void init_hd();
void hd_open(int device);
void hd_close(int device);
void hd_service();
void hd_rdwt(MESSAGE *p);
void hd_rdwt_sched(MESSAGE *p);
void hd_ioctl(MESSAGE *p);
//~xw
#endif /* _ORANGES_HD_H_ */

147
include/keyboard.h Normal file
View File

@ -0,0 +1,147 @@
/*************************************************************************//**
*****************************************************************************
* @file keyboard.h
* @brief
* @author Forrest Y. Yu
* @date 2005
*****************************************************************************
*****************************************************************************/
#ifndef _ORANGES_KEYBOARD_H_
#define _ORANGES_KEYBOARD_H_
/************************************************************************/
/* Macros Declaration */
/************************************************************************/
#define KB_IN_BYTES 320 /* size of keyboard input buffer */ /* FIXME */
#define MOUSE_IN_BYTES 3
#define MAP_COLS 3 /* Number of columns in keymap */
#define NR_SCAN_CODES 0x80 /* Number of scan codes (rows in keymap) */
#define FLAG_BREAK 0x0080 /* Break Code */
#define FLAG_EXT 0x0100 /* Normal function keys */
#define FLAG_SHIFT_L 0x0200 /* Shift key */
#define FLAG_SHIFT_R 0x0400 /* Shift key */
#define FLAG_CTRL_L 0x0800 /* Control key */
#define FLAG_CTRL_R 0x1000 /* Control key */
#define FLAG_ALT_L 0x2000 /* Alternate key */
#define FLAG_ALT_R 0x4000 /* Alternate key */
#define FLAG_PAD 0x8000 /* keys in num pad */
#define MASK_RAW 0x01FF /* raw key value = code_passed_to_tty & MASK_RAW
* the value can be found either in the keymap
* column 0 or in the list below
*/
/* Special keys */
#define ESC (0x01 + FLAG_EXT) /* Esc */
#define TAB (0x02 + FLAG_EXT) /* Tab */
#define ENTER (0x03 + FLAG_EXT) /* Enter */
#define BACKSPACE (0x04 + FLAG_EXT) /* BackSpace */
#define GUI_L (0x05 + FLAG_EXT) /* L GUI */
#define GUI_R (0x06 + FLAG_EXT) /* R GUI */
#define APPS (0x07 + FLAG_EXT) /* APPS */
/* Shift, Ctrl, Alt */
#define SHIFT_L (0x08 + FLAG_EXT) /* L Shift */
#define SHIFT_R (0x09 + FLAG_EXT) /* R Shift */
#define CTRL_L (0x0A + FLAG_EXT) /* L Ctrl */
#define CTRL_R (0x0B + FLAG_EXT) /* R Ctrl */
#define ALT_L (0x0C + FLAG_EXT) /* L Alt */
#define ALT_R (0x0D + FLAG_EXT) /* R Alt */
/* Lock keys */
#define CAPS_LOCK (0x0E + FLAG_EXT) /* Caps Lock */
#define NUM_LOCK (0x0F + FLAG_EXT) /* Number Lock */
#define SCROLL_LOCK (0x10 + FLAG_EXT) /* Scroll Lock */
/* Function keys */
#define F1 (0x11 + FLAG_EXT) /* F1 */
#define F2 (0x12 + FLAG_EXT) /* F2 */
#define F3 (0x13 + FLAG_EXT) /* F3 */
#define F4 (0x14 + FLAG_EXT) /* F4 */
#define F5 (0x15 + FLAG_EXT) /* F5 */
#define F6 (0x16 + FLAG_EXT) /* F6 */
#define F7 (0x17 + FLAG_EXT) /* F7 */
#define F8 (0x18 + FLAG_EXT) /* F8 */
#define F9 (0x19 + FLAG_EXT) /* F9 */
#define F10 (0x1A + FLAG_EXT) /* F10 */
#define F11 (0x1B + FLAG_EXT) /* F11 */
#define F12 (0x1C + FLAG_EXT) /* F12 */
/* Control Pad */
#define PRINTSCREEN (0x1D + FLAG_EXT) /* Print Screen */
#define PAUSEBREAK (0x1E + FLAG_EXT) /* Pause/Break */
#define INSERT (0x1F + FLAG_EXT) /* Insert */
#define DELETE (0x20 + FLAG_EXT) /* Delete */
#define HOME (0x21 + FLAG_EXT) /* Home */
#define END (0x22 + FLAG_EXT) /* End */
#define PAGEUP (0x23 + FLAG_EXT) /* Page Up */
#define PAGEDOWN (0x24 + FLAG_EXT) /* Page Down */
#define UP (0x25 + FLAG_EXT) /* Up */
#define DOWN (0x26 + FLAG_EXT) /* Down */
#define LEFT (0x27 + FLAG_EXT) /* Left */
#define RIGHT (0x28 + FLAG_EXT) /* Right */
/* ACPI keys */
#define POWER (0x29 + FLAG_EXT) /* Power */
#define SLEEP (0x2A + FLAG_EXT) /* Sleep */
#define WAKE (0x2B + FLAG_EXT) /* Wake Up */
/* Num Pad */
#define PAD_SLASH (0x2C + FLAG_EXT) /* / */
#define PAD_STAR (0x2D + FLAG_EXT) /* * */
#define PAD_MINUS (0x2E + FLAG_EXT) /* - */
#define PAD_PLUS (0x2F + FLAG_EXT) /* + */
#define PAD_ENTER (0x30 + FLAG_EXT) /* Enter */
#define PAD_DOT (0x31 + FLAG_EXT) /* . */
#define PAD_0 (0x32 + FLAG_EXT) /* 0 */
#define PAD_1 (0x33 + FLAG_EXT) /* 1 */
#define PAD_2 (0x34 + FLAG_EXT) /* 2 */
#define PAD_3 (0x35 + FLAG_EXT) /* 3 */
#define PAD_4 (0x36 + FLAG_EXT) /* 4 */
#define PAD_5 (0x37 + FLAG_EXT) /* 5 */
#define PAD_6 (0x38 + FLAG_EXT) /* 6 */
#define PAD_7 (0x39 + FLAG_EXT) /* 7 */
#define PAD_8 (0x3A + FLAG_EXT) /* 8 */
#define PAD_9 (0x3B + FLAG_EXT) /* 9 */
#define PAD_UP PAD_8 /* Up */
#define PAD_DOWN PAD_2 /* Down */
#define PAD_LEFT PAD_4 /* Left */
#define PAD_RIGHT PAD_6 /* Right */
#define PAD_HOME PAD_7 /* Home */
#define PAD_END PAD_1 /* End */
#define PAD_PAGEUP PAD_9 /* Page Up */
#define PAD_PAGEDOWN PAD_3 /* Page Down */
#define PAD_INS PAD_0 /* Ins */
#define PAD_MID PAD_5 /* Middle key */
#define PAD_DEL PAD_DOT /* Del */
/************************************************************************/
/* Stucture Definition */
/************************************************************************/
/* Keyboard structure, 1 per console. */
/**
* @todo change u8 into char
*
*/
typedef struct kb_inbuf {
u8* p_head; /**< points to the next free slot */
u8* p_tail; /**< points to the byte to be handled */
int count; /**< how many bytes to be handled in the buffer */
u8 buf[KB_IN_BYTES];
} KB_INPUT;
#define MOUSE_UPDOWN_BOUND 15
typedef struct mouse_inbuf{
int count;
u8 buf[MOUSE_IN_BYTES];
}MOUSE_INPUT;
#endif /* _ORANGES_KEYBOARD_H_ */

230
include/keymap.h Normal file
View File

@ -0,0 +1,230 @@
#ifndef _ORANGES_KEYMAP_H_
#define _ORANGES_KEYMAP_H_
/* Keymap for US MF-2 keyboard. */
static u32 keymap[NR_SCAN_CODES * MAP_COLS] = {
/* scan-code !Shift Shift E0 XX */
/* ==================================================================== */
/* 0x00 - none */ 0, 0, 0,
/* 0x01 - ESC */ ESC, ESC, 0,
/* 0x02 - '1' */ '1', '!', 0,
/* 0x03 - '2' */ '2', '@', 0,
/* 0x04 - '3' */ '3', '#', 0,
/* 0x05 - '4' */ '4', '$', 0,
/* 0x06 - '5' */ '5', '%', 0,
/* 0x07 - '6' */ '6', '^', 0,
/* 0x08 - '7' */ '7', '&', 0,
/* 0x09 - '8' */ '8', '*', 0,
/* 0x0A - '9' */ '9', '(', 0,
/* 0x0B - '0' */ '0', ')', 0,
/* 0x0C - '-' */ '-', '_', 0,
/* 0x0D - '=' */ '=', '+', 0,
/* 0x0E - BS */ BACKSPACE, BACKSPACE, 0,
/* 0x0F - TAB */ TAB, TAB, 0,
/* 0x10 - 'q' */ 'q', 'Q', 0,
/* 0x11 - 'w' */ 'w', 'W', 0,
/* 0x12 - 'e' */ 'e', 'E', 0,
/* 0x13 - 'r' */ 'r', 'R', 0,
/* 0x14 - 't' */ 't', 'T', 0,
/* 0x15 - 'y' */ 'y', 'Y', 0,
/* 0x16 - 'u' */ 'u', 'U', 0,
/* 0x17 - 'i' */ 'i', 'I', 0,
/* 0x18 - 'o' */ 'o', 'O', 0,
/* 0x19 - 'p' */ 'p', 'P', 0,
/* 0x1A - '[' */ '[', '{', 0,
/* 0x1B - ']' */ ']', '}', 0,
/* 0x1C - CR/LF */ ENTER, ENTER, PAD_ENTER,
/* 0x1D - l. Ctrl */ CTRL_L, CTRL_L, CTRL_R,
/* 0x1E - 'a' */ 'a', 'A', 0,
/* 0x1F - 's' */ 's', 'S', 0,
/* 0x20 - 'd' */ 'd', 'D', 0,
/* 0x21 - 'f' */ 'f', 'F', 0,
/* 0x22 - 'g' */ 'g', 'G', 0,
/* 0x23 - 'h' */ 'h', 'H', 0,
/* 0x24 - 'j' */ 'j', 'J', 0,
/* 0x25 - 'k' */ 'k', 'K', 0,
/* 0x26 - 'l' */ 'l', 'L', 0,
/* 0x27 - ';' */ ';', ':', 0,
/* 0x28 - '\'' */ '\'', '"', 0,
/* 0x29 - '`' */ '`', '~', 0,
/* 0x2A - l. SHIFT */ SHIFT_L, SHIFT_L, 0,
/* 0x2B - '\' */ '\\', '|', 0,
/* 0x2C - 'z' */ 'z', 'Z', 0,
/* 0x2D - 'x' */ 'x', 'X', 0,
/* 0x2E - 'c' */ 'c', 'C', 0,
/* 0x2F - 'v' */ 'v', 'V', 0,
/* 0x30 - 'b' */ 'b', 'B', 0,
/* 0x31 - 'n' */ 'n', 'N', 0,
/* 0x32 - 'm' */ 'm', 'M', 0,
/* 0x33 - ',' */ ',', '<', 0,
/* 0x34 - '.' */ '.', '>', 0,
/* 0x35 - '/' */ '/', '?', PAD_SLASH,
/* 0x36 - r. SHIFT */ SHIFT_R, SHIFT_R, 0,
/* 0x37 - '*' */ '*', '*', 0,
/* 0x38 - ALT */ ALT_L, ALT_L, ALT_R,
/* 0x39 - ' ' */ ' ', ' ', 0,
/* 0x3A - CapsLock */ CAPS_LOCK, CAPS_LOCK, 0,
/* 0x3B - F1 */ F1, F1, 0,
/* 0x3C - F2 */ F2, F2, 0,
/* 0x3D - F3 */ F3, F3, 0,
/* 0x3E - F4 */ F4, F4, 0,
/* 0x3F - F5 */ F5, F5, 0,
/* 0x40 - F6 */ F6, F6, 0,
/* 0x41 - F7 */ F7, F7, 0,
/* 0x42 - F8 */ F8, F8, 0,
/* 0x43 - F9 */ F9, F9, 0,
/* 0x44 - F10 */ F10, F10, 0,
/* 0x45 - NumLock */ NUM_LOCK, NUM_LOCK, 0,
/* 0x46 - ScrLock */ SCROLL_LOCK, SCROLL_LOCK, 0,
/* 0x47 - Home */ PAD_HOME, '7', HOME,
/* 0x48 - CurUp */ PAD_UP, '8', UP,
/* 0x49 - PgUp */ PAD_PAGEUP, '9', PAGEUP,
/* 0x4A - '-' */ PAD_MINUS, '-', 0,
/* 0x4B - Left */ PAD_LEFT, '4', LEFT,
/* 0x4C - MID */ PAD_MID, '5', 0,
/* 0x4D - Right */ PAD_RIGHT, '6', RIGHT,
/* 0x4E - '+' */ PAD_PLUS, '+', 0,
/* 0x4F - End */ PAD_END, '1', END,
/* 0x50 - Down */ PAD_DOWN, '2', DOWN,
/* 0x51 - PgDown */ PAD_PAGEDOWN, '3', PAGEDOWN,
/* 0x52 - Insert */ PAD_INS, '0', INSERT,
/* 0x53 - Delete */ PAD_DOT, '.', DELETE,
/* 0x54 - Enter */ 0, 0, 0,
/* 0x55 - ??? */ 0, 0, 0,
/* 0x56 - ??? */ 0, 0, 0,
/* 0x57 - F11 */ F11, F11, 0,
/* 0x58 - F12 */ F12, F12, 0,
/* 0x59 - ??? */ 0, 0, 0,
/* 0x5A - ??? */ 0, 0, 0,
/* 0x5B - ??? */ 0, 0, GUI_L,
/* 0x5C - ??? */ 0, 0, GUI_R,
/* 0x5D - ??? */ 0, 0, APPS,
/* 0x5E - ??? */ 0, 0, 0,
/* 0x5F - ??? */ 0, 0, 0,
/* 0x60 - ??? */ 0, 0, 0,
/* 0x61 - ??? */ 0, 0, 0,
/* 0x62 - ??? */ 0, 0, 0,
/* 0x63 - ??? */ 0, 0, 0,
/* 0x64 - ??? */ 0, 0, 0,
/* 0x65 - ??? */ 0, 0, 0,
/* 0x66 - ??? */ 0, 0, 0,
/* 0x67 - ??? */ 0, 0, 0,
/* 0x68 - ??? */ 0, 0, 0,
/* 0x69 - ??? */ 0, 0, 0,
/* 0x6A - ??? */ 0, 0, 0,
/* 0x6B - ??? */ 0, 0, 0,
/* 0x6C - ??? */ 0, 0, 0,
/* 0x6D - ??? */ 0, 0, 0,
/* 0x6E - ??? */ 0, 0, 0,
/* 0x6F - ??? */ 0, 0, 0,
/* 0x70 - ??? */ 0, 0, 0,
/* 0x71 - ??? */ 0, 0, 0,
/* 0x72 - ??? */ 0, 0, 0,
/* 0x73 - ??? */ 0, 0, 0,
/* 0x74 - ??? */ 0, 0, 0,
/* 0x75 - ??? */ 0, 0, 0,
/* 0x76 - ??? */ 0, 0, 0,
/* 0x77 - ??? */ 0, 0, 0,
/* 0x78 - ??? */ 0, 0, 0,
/* 0x78 - ??? */ 0, 0, 0,
/* 0x7A - ??? */ 0, 0, 0,
/* 0x7B - ??? */ 0, 0, 0,
/* 0x7C - ??? */ 0, 0, 0,
/* 0x7D - ??? */ 0, 0, 0,
/* 0x7E - ??? */ 0, 0, 0,
/* 0x7F - ??? */ 0, 0, 0
};
/*
:
:
*/
/*====================================================================
Appendix: Scan code set 1
*====================================================================
KEY MAKE BREAK| KEY MAKE BREAK | KEY MAKE BREAK
---------------------|------------------------|-----------------------
A 1E 9E | 9 0A 8A | [ 1A 9A
B 30 B0 | ` 29 89 | INSERT E0,52 E0,D2
C 2E AE | - 0C 8C | HOME E0,47 E0,C7
D 20 A0 | = 0D 8D | PG UP E0,49 E0,C9
E 12 92 | \ 2B AB | DELETE E0,53 E0,D3
F 21 A1 | BKSP 0E 8E | END E0,4F E0,CF
G 22 A2 | SPACE 39 B9 | PG DN E0,51 E0,D1
H 23 A3 | TAB 0F 8F | U ARROW E0,48 E0,C8
I 17 97 | CAPS 3A BA | L ARROW E0,4B E0,CB
J 24 A4 | L SHFT 2A AA | D ARROW E0,50 E0,D0
K 25 A5 | L CTRL 1D 9D | R ARROW E0,4D E0,CD
L 26 A6 | L GUI E0,5B E0,DB | NUM 45 C5
M 32 B2 | L ALT 38 B8 | KP / E0,35 E0,B5
N 31 B1 | R SHFT 36 B6 | KP * 37 B7
O 18 98 | R CTRL E0,1D E0,9D | KP - 4A CA
P 19 99 | R GUI E0,5C E0,DC | KP + 4E CE
Q 10 19 | R ALT E0,38 E0,B8 | KP EN E0,1C E0,9C
R 13 93 | APPS E0,5D E0,DD | KP . 53 D3
S 1F 9F | ENTER 1C 9C | KP 0 52 D2
T 14 94 | ESC 01 81 | KP 1 4F CF
U 16 96 | F1 3B BB | KP 2 50 D0
V 2F AF | F2 3C BC | KP 3 51 D1
W 11 91 | F3 3D BD | KP 4 4B CB
X 2D AD | F4 3E BE | KP 5 4C CC
Y 15 95 | F5 3F BF | KP 6 4D CD
Z 2C AC | F6 40 C0 | KP 7 47 C7
0 0B 8B | F7 41 C1 | KP 8 48 C8
1 02 82 | F8 42 C2 | KP 9 49 C9
2 03 83 | F9 43 C3 | ] 1B 9B
3 04 84 | F10 44 C4 | ; 27 A7
4 05 85 | F11 57 D7 | ' 28 A8
5 06 86 | F12 58 D8 | , 33 B3
| |
6 07 87 | PRTSCRN E0,2A E0,B7 | . 34 B4
| E0,37 E0,AA |
| |
7 08 88 | SCROLL 46 C6 | / 35 B5
| |
8 09 89 | PAUSE E1,1D |
| 45,E1, -NONE-|
| 9D,C5 |
----------------------------------------------------------------------
-----------------
ACPI Scan Codes:
-------------------------------------------
Key Make Code Break Code
-------------------------------------------
Power E0, 5E E0, DE
Sleep E0, 5F E0, DF
Wake E0, 63 E0, E3
-------------------------------
Windows Multimedia Scan Codes:
-------------------------------------------
Key Make Code Break Code
-------------------------------------------
Next Track E0, 19 E0, 99
Previous Track E0, 10 E0, 90
Stop E0, 24 E0, A4
Play/Pause E0, 22 E0, A2
Mute E0, 20 E0, A0
Volume Up E0, 30 E0, B0
Volume Down E0, 2E E0, AE
Media Select E0, 6D E0, ED
E-Mail E0, 6C E0, EC
Calculator E0, 21 E0, A1
My Computer E0, 6B E0, EB
WWW Search E0, 65 E0, E5
WWW Home E0, 32 E0, B2
WWW Back E0, 6A E0, EA
WWW Forward E0, 69 E0, E9
WWW Stop E0, 68 E0, E8
WWW Refresh E0, 67 E0, E7
WWW Favorites E0, 66 E0, E6
*=====================================================================================*/
#endif /* _ORANGES_KEYMAP_H_ */

31
include/memman.h Normal file
View File

@ -0,0 +1,31 @@
#ifndef _ORANGES_MEMMAN_H_
#define _ORANGES_MEMMAN_H_
#define MEMMAN_FREES 4090 //32KB
#define MEMMAN_ADDR 0x01ff0000 //存memman31M960K
#define FMIBuff 0x007ff000 //loader中getFreeMemInfo返回值存放起始地址(7M1020K)
#define KWALL 0x00600000
#define WALL 0x00800000
#define UWALL 0x01000000
#define MEMSTART 0x00400000
#define MEMEND 0x02000000
#define TEST 0x11223344
struct FREEINFO{
u32 addr,size;
};
struct MEMMAN{
u32 frees,maxfrees,lostsize,losts; //frees为当前空闲内存块数
struct FREEINFO free[MEMMAN_FREES]; //空闲内存
};
void init();
u32 do_malloc(u32 size);
u32 do_kmalloc(u32 size);
u32 do_malloc_4k();
u32 do_kmalloc_4k();
u32 do_free(u32 addr,u32 size);
u32 do_free_4k(u32 addr);
#endif

176
include/proc.h Normal file
View File

@ -0,0 +1,176 @@
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
proc.h
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Forrest Yu, 2005
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
/* Used to find saved registers in the new kernel stack,
* for there is no variable name you can use in C.
* The macro defined below must coordinate with the equivalent in sconst.inc,
* whose content is used in asm.
* Note that you shouldn't use saved registers in the old
* kernel stack, i.e. STACK_FRAME, any more.
* To access them, use a pointer plus a offset defined
* below instead.
* added by xw, 17/12/11
*/
#define INIT_STACK_SIZE 1024 * 8 //new kernel stack is 8kB
#define P_STACKBASE 0
#define GSREG 0
#define FSREG 1 * 4
#define ESREG 2 * 4
#define DSREG 3 * 4
#define EDIREG 4 * 4
#define ESIREG 5 * 4
#define EBPREG 6 * 4
#define KERNELESPREG 7 * 4
#define EBXREG 8 * 4
#define EDXREG 9 * 4
#define ECXREG 10 * 4
#define EAXREG 11 * 4
#define RETADR 12 * 4
#define EIPREG 13 * 4
#define CSREG 14 * 4
#define EFLAGSREG 15 * 4
#define ESPREG 16 * 4
#define SSREG 17 * 4
#define P_STACKTOP 18 * 4
/*总PCB表数和taskPCB表数*/
//modified by xw, 18/8/27
//the memory space we put kernel is 0x30400~0x6ffff, so we should limit kernel size
// #define NR_PCBS 32 //add by visual 2016.4.5
// #define NR_K_PCBS 10 //add by visual 2016.4.5
#define NR_PCBS 12
//#define NR_TASKS 4 //TestA~TestC + hd_service //deleted by mingxuan 2019-5-19
#define NR_TASKS 2 //task_tty + hd_service //modified by mingxuan 2019-5-19
#define NR_K_PCBS 4 //no K_PCB is empty now
//~xw
#define NR_CPUS 1 //numbers of cpu. added by xw, 18/6/1
#define NR_FILES 64 //numbers of files a process can own. added by xw, 18/6/14
//enum proc_stat {IDLE,READY,WAITING,RUNNING}; //add by visual smile 2016.4.5
//enum proc_stat {IDLE,READY,SLEEPING}; //eliminate RUNNING state
enum proc_stat {IDLE,READY,SLEEPING,KILLED}; /* add KILLED state. when a process's state is KILLED, the process
* won't be scheduled anymore, but all of the resources owned by
* it is not freed yet.
* added by xw, 18/12/19
*/
#define NR_CHILD_MAX (NR_PCBS-NR_K_PCBS-1) //定义最多子进程/线程数量 //add by visual 2016.5.26
#define TYPE_PROCESS 0//进程//add by visual 2016.5.26
#define TYPE_THREAD 1//线程//add by visual 2016.5.26
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_tree_info{//进程树记录,包括父进程,子进程,子线程 //add by visual 2016.5.25
int type; //当前是进程还是线程
int real_ppid; //亲父进程,创建它的那个进程
int ppid; //当前父进程
int child_p_num; //子进程数量
int child_process[NR_CHILD_MAX];//子进程列表
int child_t_num; //子线程数量
int child_thread[NR_CHILD_MAX];//子线程列表
int text_hold; //是否拥有代码
int data_hold; //是否拥有数据
}TREE_INFO;
typedef struct s_lin_memmap {//线性地址分布结构体 edit by visual 2016.5.25
u32 text_lin_base; //代码段基址
u32 text_lin_limit; //代码段界限
u32 data_lin_base; //数据段基址
u32 data_lin_limit; //数据段界限
u32 vpage_lin_base; //保留内存基址
u32 vpage_lin_limit; //保留内存界限
u32 heap_lin_base; //堆基址
u32 heap_lin_limit; //堆界限
u32 stack_lin_base; //栈基址
u32 stack_lin_limit; //栈界限(使用时注意栈的生长方向)
u32 arg_lin_base; //参数内存基址
u32 arg_lin_limit; //参数内存界限
u32 kernel_lin_base; //内核基址
u32 kernel_lin_limit; //内核界限
u32 stack_child_limit; //分给子线程的栈的界限 //add by visual 2016.5.27
}LIN_MEMMAP;
typedef 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 */
char* esp_save_int; //to save the position of esp in the kernel stack of the process
//added by xw, 17/12/11
char* esp_save_syscall; //to save the position of esp in the kernel stack of the process
char* esp_save_context; //to save the position of esp in the kernel stack of the process
// int save_type; //the cause of process losting CPU //save_type is not needed any more, xw, 18/4/20
//1st-bit for interruption, 2nd-bit for context, 3rd-bit for syscall
void* channel; /*if non-zero, sleeping on channel, which is a pointer of the target field
for example, as for syscall sleep(int n), the target field is 'ticks',
and the channel is a pointer of 'ticks'.
*/
LIN_MEMMAP memmap; //线性内存分部信息 add by visual 2016.5.4
TREE_INFO info; //记录进程树关系 add by visual 2016.5.25
int ticks; /* remained ticks */
int priority;
u32 pid; /* process id passed in from MM */
char p_name[16]; /* name of the process */
enum proc_stat stat; //add by visual 2016.4.5
u32 cr3; //add by visual 2016.4.5
//added by zcr
struct file_desc * filp[NR_FILES];
//~zcr
}PROCESS_0;
//new PROCESS struct with PCB and process's kernel stack
//added by xw, 17/12/11
typedef union task_union {
PROCESS_0 task;
char stack[INIT_STACK_SIZE/sizeof(char)];
}PROCESS;
typedef struct s_task {
task_f initial_eip;
int stacksize;
char name[32];
}TASK;
#define STACK_SIZE_TASK 0x1000 //add by visual 2016.4.5
//#define STACK_SIZE_TOTAL (STACK_SIZE_TASK*NR_PCBS) //edit by visual 2016.4.5
//added by zcr
#define proc2pid(x) (x - proc_table)

159
include/protect.h Normal file
View File

@ -0,0 +1,159 @@
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
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
//added by zcr
/* descriptor indices in LDT */
#define INDEX_LDT_C 0
#define INDEX_LDT_RW 1
//~zcr
/* 描述符类型值说明 */
#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_ */

141
include/proto.h Normal file
View File

@ -0,0 +1,141 @@
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
proto.h
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Forrest Yu, 2005
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
/* klib.asm */
void disp_str(char* info);
void disp_int(int input);
void disp_color_str(char* info, int color);
void write_char(char ch); //added by mingxuan 2019-5-19
//added by zcr
void disable_irq(int irq);
void enable_irq(int irq);
void init_8259A();
//~zcr
/* protect.c */
void init_prot();
u32 seg2phys(u16 seg);
/* klib.c */
void delay(int time);
/* kernel.asm */
u32 read_cr2(); //add by visual 2016.5.9
void refresh_page_cache(); //add by visual 2016.5.12
//void restart_int();
//void save_context();
void restart_initial(); //added by xw, 18/4/18
void restart_restore(); //added by xw, 18/4/20
void sched(); //added by xw, 18/4/18
void halt(); //added by xw, 18/6/11
u32 get_arg(void *uesp, int order); //added by xw, 18/6/18
/* ktest.c */
void initial();
/* keyboard.c */
//added by mingxuan 2019-5-19
void init_kb();
void keyboard_read();
/* tty.c */
//added by mingxuan 2019-5-19
void in_process(TTY* p_tty,u32 key);
void task_tty();
void tty_write(TTY* tty, char* buf, int len);
int tty_read(TTY* tty, char* buf, int len);
/* printf.c */
//added by mingxuan 2019-5-19
int printf(const char *fmt, ...);
/* vsprintf.c */
//added by mingxuan 2019-5-19
int vsprintf(char *buf, const char *fmt, va_list args);
/* i8259.c */
void put_irq_handler(int irq, irq_handler handler);
void spurious_irq(int irq);
/* clock.c */
void clock_handler(int irq);
/***************************************************************
*
****************************************************************/
/* syscall.asm */
void sys_call(); /* int_handler */
int get_ticks();
int get_pid(); //add by visual 2016.4.6
void* kmalloc(int size); //edit by visual 2016.5.9
void* kmalloc_4k(); //edit by visual 2016.5.9
void* malloc(int size); //edit by visual 2016.5.9
void* malloc_4k(); //edit by visual 2016.5.9
int free(void *arg); //edit by visual 2016.5.9
int free_4k(void* AdddrLin); //edit by visual 2016.5.9
int fork(); //add by visual 2016.4.8
int pthread(void *arg); //add by visual 2016.4.11
void udisp_int(int arg); //add by visual 2016.5.16
void udisp_str(char* arg); //add by visual 2016.5.16
u32 exec(char* path); //add by visual 2016.5.16
void yield(); //added by xw, 18/4/19
void sleep(int n); //added by xw, 18/4/19
void print_E();
void print_F();
/* syscallc.c */ //edit by visual 2016.4.6
int sys_get_ticks(); /* sys_call */
int sys_get_pid(); //add by visual 2016.4.6
void* sys_kmalloc(int size); //edit by visual 2016.5.9
void* sys_kmalloc_4k(); //edit by visual 2016.5.9
void* sys_malloc(int size); //edit by visual 2016.5.9
void* sys_malloc_4k(); //edit by visual 2016.5.9
int sys_free(void *arg); //edit by visual 2016.5.9
int sys_free_4k(void* AdddrLin); //edit by visual 2016.5.9
int sys_pthread(void *arg); //add by visual 2016.4.11
void sys_udisp_int(int arg); //add by visual 2016.5.16
void sys_udisp_str(char* arg); //add by visual 2016.5.16
/* proc.c */
PROCESS* alloc_PCB();
void free_PCB(PROCESS *p);
void sys_yield();
void sys_sleep(int n);
void sys_wakeup(void *channel);
int ldt_seg_linear(PROCESS *p, int idx);
void* va2la(int pid, void* va);
/* testfunc.c */
void sys_print_E();
void sys_print_F();
/*exec.c*/
u32 sys_exec(char* path); //add by visual 2016.5.23
/*fork.c*/
int sys_fork(); //add by visual 2016.5.25
/***************************************************************
*
****************************************************************/
/*pagepte.c*/
u32 init_page_pte(u32 pid); //edit by visual 2016.4.28
void page_fault_handler(u32 vec_no, u32 err_code, u32 eip, u32 cs, u32 eflags);//add by visual 2016.4.19
u32 get_pde_index(u32 AddrLin);//add by visual 2016.4.28
u32 get_pte_index(u32 AddrLin);
u32 get_pde_phy_addr(u32 pid);
u32 get_pte_phy_addr(u32 pid,u32 AddrLin);
u32 get_page_phy_addr(u32 pid,u32 AddrLin);//线性地址
u32 pte_exist(u32 PageTblAddrPhy,u32 AddrLin);
u32 phy_exist(u32 PageTblPhyAddr,u32 AddrLin);
void write_page_pde(u32 PageDirPhyAddr,u32 AddrLin,u32 TblPhyAddr,u32 Attribute);
void write_page_pte( u32 TblPhyAddr,u32 AddrLin,u32 PhyAddr,u32 Attribute);
u32 vmalloc(u32 size);
int lin_mapping_phy(u32 AddrLin,u32 phy_addr,u32 pid,u32 pde_Attribute,u32 pte_Attribute);//edit by visual 2016.5.19
void clear_kernel_pagepte_low(); //add by visual 2016.5.12

52
include/sconst.inc Normal file
View File

@ -0,0 +1,52 @@
; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; 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
;added by xw
;begin
INIT_STACK_SIZE equ 1024 * 8
ESP_SAVE_INT equ P_LDT + 16
ESP_SAVE_SYSCALL equ ESP_SAVE_INT + 4
ESP_SAVE_CONTEXT equ ESP_SAVE_SYSCALL + 4
;SAVE_TYPE equ ESP_SAVE_CONTEXT + 4 ;Deleted by xw, 18/4/19
;end
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
SELECTOR_VIDEO equ 0x1b ; added by xw, 18/6/20

29
include/spinlock.h Normal file
View File

@ -0,0 +1,29 @@
/**********************************************************
* spinlock.h //added by mingxuan 2018-12-26
***********************************************************/
// Mutual exclusion lock.
#define uint unsigned
struct spinlock {
uint locked; // Is the lock held?
// For debugging:
char *name; // Name of lock.
int cpu; // The number of the cpu holding the lock.
uint pcs[10]; // The call stack (an array of program counters)
// that locked the lock.
};
void initlock(struct spinlock *lock, char *name);
// Acquire the lock.
// Loops (spins) until the lock is acquired.
// (Because contention is handled by spinning, must not
// go to sleep holding any locks.)
void acquire(struct spinlock *lock);
// Release the lock.
void release(struct spinlock *lock);

12
include/stdarg.h Normal file
View File

@ -0,0 +1,12 @@
#ifndef MINIOS_STDARG_H
#define MINIOS_STDARG_H
typedef __builtin_va_list va_list;
#define va_start(ap, last) __builtin_va_start(ap, last)
#define va_arg(ap, type) __builtin_va_arg(ap, type)
#define va_end(ap) __builtin_va_end(ap)
#endif /* MINIOS_STDARG_H */

74
include/stdio.h Normal file
View File

@ -0,0 +1,74 @@
/********************************************
* add by visual 2016.5.16
*************************************************/
#include "const.h" //added by mingxuan 2019-5-19
#include "type.h" //added by mingxuan 2019-5-19
#include "stdarg.h"
#ifndef _STDIO_H_ //added by mingxuan 2019-5-19
#define _STDIO_H_ //added by mingxuan 2019-5-19
/*syscall.asm*/
int get_ticks();
int get_pid();
void* kmalloc(int size);
void* kmalloc_4k();
void* malloc(int size);
void* malloc_4k();
int free(void *arg);
int free_4k(void* AdddrLin);
int fork();
int pthread(void *arg);
void udisp_int(int arg);
void udisp_str(char* arg);
//added by xw
/* file system */
#define MAX_FILENAME_LEN 12
#define MAX_PATH 128
#define O_CREAT 1
#define O_RDWR 2
#define SEEK_SET 1
#define SEEK_CUR 2
#define SEEK_END 3
int open(const char *pathname, int flags); //added by xw, 18/6/19
int close(int fd); //added by xw, 18/6/19
int read(int fd, void *buf, int count); //added by xw, 18/6/19
int write(int fd, const void *buf, int count); //added by xw, 18/6/19
int lseek(int fd, int offset, int whence); //added by xw, 18/6/19
int unlink(const char *pathname); //added by xw, 18/6/19
//~xw
/*string.asm*/
long strtol(const char *cp,char **endp,unsigned int base);
/*printf.c*/
//added by mingxuan 2019-5-19
#define EOF -1
// #define _INTSIZEOF(n) ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )
// #define va_start(ap,v) ( ap = (va_list)&v + _INTSIZEOF(v) )
// #define va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )
// #define va_end(ap) ( ap = (va_list)0 )
#define isspace(s) (s==' ')
#define TOLOWER(x) ((x) | 0x20)
#define isxdigit(c) (('0' <= (c) && (c) <= '9') || ('a' <= (c) && (c) <= 'f') || ('A' <= (c) && (c) <= 'F'))
#define isdigit(c) ('0' <= (c) && (c) <= '9')
void printfmt(void (*putch)(int, void*), void *putdat, const char *fmt, ...);
void vprintfmt(void (*putch)(int, void*), void *putdat, const char *fmt, va_list);
int vsnprintf(char *buf, int n, const char *fmt, va_list ap);
int snprintf(char *buf, int n, const char *fmt, ...);
int vprintf(const char *fmt, va_list ap);
int printf(const char *fmt, ...);
int vkprintf(const char *fmt, va_list ap);
int kprintf(const char *fmt, ...);
// int scanf(char *str, ...);
char getchar(); //added by mingxuan 2019-5-23
char* gets(char *str); //added by mingxuan 2019-5-23
#endif //added by mingxuan 2019-5-19

17
include/string.h Normal file
View File

@ -0,0 +1,17 @@
#ifndef MINIOS_STRING_H
#define MINIOS_STRING_H
#include "type.h"
int strlen(const char *s);
int strnlen(const char *s, size_t size);
char * strcpy(char *dst, const char *src);
char * strncpy(char *dst, const char *src, size_t size);
char * strcat(char *dst, const char *src);
int strcmp(const char *s1, const char *s2);
int strncmp(const char *s1, const char *s2, size_t size);
void * memset(void *v, int c, size_t n);
void * memcpy(void *dst, const void *src, size_t n);
#endif /* MINIOS_STRING_H */

59
include/tty.h Normal file
View File

@ -0,0 +1,59 @@
/*************************************************************************//**
*****************************************************************************
* @file tty.h
* @brief
* @author Forrest Y. Yu
* @date 2005
*****************************************************************************
*****************************************************************************/
/**********************************************************
* tty.h //added by mingxuan 2019-5-17
***********************************************************/
#ifndef _ORANGES_TTY_H_
#define _ORANGES_TTY_H_
#define TTY_IN_BYTES 256 /* tty input queue size */
#define TTY_OUT_BUF_LEN 2 /* tty output buffer size */
/* TTY state (3bit)
wait_enter wait_space display
1/0 1/0 1/0
*/
#define TTY_STATE_WAIT_ENTER 4 /*100*/
#define TTY_STATE_WAIT_SPACE 2 /*010*/
#define TTY_STATE_DISPLAY 1 /*001*/
struct s_tty;
struct s_console;
/* TTY */
typedef struct s_tty
{
u32 ibuf[TTY_IN_BYTES]; /* TTY input buffer */
u32* ibuf_head; /* the next free slot */
u32* ibuf_tail; /* 缓冲区显示位置指针 */
u32* ibuf_read;
int ibuf_cnt; /* how many */
int ibuf_read_cnt;
int status;
int mouse_left_button;
int mouse_mid_button;
int mouse_X;
int mouse_Y;
struct s_console * console;
}TTY;
#include "console.h"
void select_console(int nr_console);
void init_screen(TTY* tty);
void out_char(CONSOLE* con, char ch);
int is_current_console(CONSOLE* con);
#endif /* _ORANGES_TTY_H_ */

112
include/type.h Normal file
View File

@ -0,0 +1,112 @@
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
type.h
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Forrest Yu, 2005
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
#ifndef _ORANGES_TYPE_H_
#define _ORANGES_TYPE_H_
#ifndef NULL
#define NULL ((void*) 0)
#endif
typedef _Bool bool;
enum { false, true };
typedef long long i64;
typedef unsigned long long u64;
typedef int i32;
typedef unsigned int u32;
typedef short i16;
typedef unsigned short u16;
typedef char i8;
typedef unsigned char u8;
typedef i32 intptr_t;
typedef u32 uintptr_t;
// 通常描述一个对象的大小,会根据机器的型号变化类型
typedef u32 size_t;
// signed size_t 通常描述系统调用返回值,会根据机器的型号变化类型
typedef i32 ssize_t;
// 通常描述偏移量,会根据机器的型号变化类型
typedef i32 off_t;
// 通常描述物理地址
typedef u32 phyaddr_t;
typedef void (*int_handler) ();
typedef void (*task_f) ();
typedef void (*irq_handler) (int irq);
typedef char * va_list; //added by mingxuan 2019-5-19
typedef void* system_call;
//mainly used in filesystem. added by xw, 18/8/27
/**
* MESSAGE mechanism is borrowed from MINIX
*/
struct mess1 {
int m1i1;
int m1i2;
int m1i3;
int m1i4;
};
struct mess2 {
void* m2p1;
void* m2p2;
void* m2p3;
void* m2p4;
};
struct mess3 {
int m3i1;
int m3i2;
int m3i3;
int m3i4;
u64 m3l1;
u64 m3l2;
void* m3p1;
void* m3p2;
};
typedef struct {
int source;
int type;
union {
struct mess1 m1;
struct mess2 m2;
struct mess3 m3;
} u;
} MESSAGE;
/**
* @enum msgtype
* @brief MESSAGE types
*/
enum msgtype {
/*
* when hard interrupt occurs, a msg (with type==HARD_INT) will
* be sent to some tasks
*/
HARD_INT = 1,
/* SYS task */
GET_TICKS,
/// zcr added from ch9/e/include/const.h
/* FS */
OPEN, CLOSE, READ, WRITE, LSEEK, STAT, UNLINK,
/* message type for drivers */
DEV_OPEN = 1001,
DEV_CLOSE,
DEV_READ,
DEV_WRITE,
DEV_IOCTL
};
#endif /* _ORANGES_TYPE_H_ */

91
include/vfs.h Normal file
View File

@ -0,0 +1,91 @@
/**********************************************************
* vfs.h //added by mingxuan 2019-5-17
***********************************************************/
//#define NR_DEV 10
#define NR_FS 10 //modified by mingxuan 2020-10-18
#define DEV_NAME_LEN 15
//#define NR_fs 3
#define NR_FS_OP 3 //modified by mingxuan 2020-10-18
#define NR_SB_OP 2 //added by mingxuan 2020-10-30
//#define FILE_MAX_LEN 512*4 //最大长度为4个扇区
#define FILE_MAX_LEN 512*16 //最大长度为16个扇区(8KB)
/* //deleted by mingxuan 2020-10-18
//设备表
struct device{
char * dev_name; //设备名
struct file_op * op; //指向操作表的一项
int dev_num; //设备号
};
*/
// Replace struct device, added by mingxuan 2020-10-18
struct vfs{
char * fs_name; //设备名
struct file_op * op; //指向操作表的一项
//int dev_num; //设备号 //deleted by mingxuan 2020-10-29
struct super_block *sb; //added by mingxuan 2020-10-29
struct sb_op *s_op; //added by mingxuan 2020-10-29
};
int sys_open(void *uesp);
int sys_close(void *uesp);
int sys_read(void *uesp);
int sys_write(void *uesp);
int sys_lseek(void *uesp);
int sys_unlink(void *uesp);
int sys_create(void *uesp);
int sys_delete(void *uesp);
int sys_opendir(void *uesp);
int sys_createdir(void *uesp);
int sys_deletedir(void *uesp);
int do_vopen(const char *path, int flags);
int do_vclose(int fd);
int do_vread(int fd, char *buf, int count);
int do_vwrite(int fd, const char *buf, int count);
int do_vunlink(const char *path);
int do_vlseek(int fd, int offset, int whence);
int do_vcreate(char *pathname);
int do_vdelete(char *path);
int do_vopendir(char *dirname);
int do_vcreatedir(char *dirname);
int do_vdeletedir(char *dirname);
void init_vfs();
void init_file_desc_table();
void init_fileop_table();
int sys_CreateFile(void *uesp);
int sys_DeleteFile(void *uesp);
int sys_OpenFile(void *uesp);
int sys_CloseFile(void *uesp);
int sys_WriteFile(void *uesp);
int sys_ReadFile(void *uesp);
int sys_OpenDir(void *uesp);
int sys_CreateDir(void *uesp);
int sys_DeleteDir(void *uesp);
int sys_ListDir(void *uesp);
//文件系统的操作函数
struct file_op{
int (*create) (const char*);
int (*open) (const char* ,int);
int (*close) (int);
int (*read) (int,void * ,int);
int (*write) (int ,const void* ,int);
int (*lseek) (int ,int ,int);
int (*unlink) (const char*);
int (*delete) (const char*);
int (*opendir) (const char *);
int (*createdir) (const char *);
int (*deletedir) (const char *);
};
//added by mingxuan 2020-10-29
struct sb_op{
void (*read_super_block) (int);
struct super_block* (*get_super_block) (int);
};

223
include/x86.h Normal file
View File

@ -0,0 +1,223 @@
#ifndef MINIOS_X86_H
#define MINIOS_X86_H
#include <type.h>
static inline u8
inb(int port)
{
u8 data;
asm volatile("inb %w1,%0" : "=a" (data) : "d" (port));
return data;
}
static inline void
insb(int port, void *addr, int cnt)
{
asm volatile("cld\n\trepne\n\tinsb"
: "=D" (addr), "=c" (cnt)
: "d" (port), "0" (addr), "1" (cnt)
: "memory", "cc");
}
static inline u16
inw(int port)
{
u16 data;
asm volatile("inw %w1,%0" : "=a" (data) : "d" (port));
return data;
}
static inline void
insw(int port, void *addr, int cnt)
{
asm volatile("cld\n\trepne\n\tinsw"
: "=D" (addr), "=c" (cnt)
: "d" (port), "0" (addr), "1" (cnt)
: "memory", "cc");
}
static inline u32
inl(int port)
{
u32 data;
asm volatile("inl %w1,%0" : "=a" (data) : "d" (port));
return data;
}
static inline void
insl(int port, void *addr, int cnt)
{
asm volatile("cld\n\trepne\n\tinsl"
: "=D" (addr), "=c" (cnt)
: "d" (port), "0" (addr), "1" (cnt)
: "memory", "cc");
}
static inline void
outb(int port, u8 data)
{
asm volatile("outb %0,%w1" : : "a" (data), "d" (port));
}
static inline void
outsb(int port, const void *addr, int cnt)
{
asm volatile("cld\n\trepne\n\toutsb"
: "=S" (addr), "=c" (cnt)
: "d" (port), "0" (addr), "1" (cnt)
: "cc");
}
static inline void
outw(int port, u16 data)
{
asm volatile("outw %0,%w1" : : "a" (data), "d" (port));
}
static inline void
outsw(int port, const void *addr, int cnt)
{
asm volatile("cld\n\trepne\n\toutsw"
: "=S" (addr), "=c" (cnt)
: "d" (port), "0" (addr), "1" (cnt)
: "cc");
}
static inline void
outsl(int port, const void *addr, int cnt)
{
asm volatile("cld\n\trepne\n\toutsl"
: "=S" (addr), "=c" (cnt)
: "d" (port), "0" (addr), "1" (cnt)
: "cc");
}
static inline void
outl(int port, u32 data)
{
asm volatile("outl %0,%w1" : : "a" (data), "d" (port));
}
static inline void
lcr0(u32 val)
{
asm volatile("movl %0,%%cr0" : : "r" (val));
}
static inline u32
rcr0(void)
{
u32 val;
asm volatile("movl %%cr0,%0" : "=r" (val));
return val;
}
static inline u32
rcr2(void)
{
u32 val;
asm volatile("movl %%cr2,%0" : "=r" (val));
return val;
}
static inline void
lcr3(u32 val)
{
asm volatile("movl %0,%%cr3" : : "r" (val));
}
static inline u32
rcr3(void)
{
u32 val;
asm volatile("movl %%cr3,%0" : "=r" (val));
return val;
}
static inline void
lcr4(u32 val)
{
asm volatile("movl %0,%%cr4" : : "r" (val));
}
static inline u32
rcr4(void)
{
u32 cr4;
asm volatile("movl %%cr4,%0" : "=r" (cr4));
return cr4;
}
static inline void
tlbflush(void)
{
u32 cr3;
asm volatile("movl %%cr3,%0" : "=r" (cr3));
asm volatile("movl %0,%%cr3" : : "r" (cr3));
}
static inline u32
read_eflags(void)
{
u32 eflags;
asm volatile("pushfl\n\t popl %0" : "=r" (eflags));
return eflags;
}
static inline void
write_eflags(u32 eflags)
{
asm volatile("pushl %0\n\t popfl" : : "r" (eflags));
}
static inline u32
read_ebp(void)
{
u32 ebp;
asm volatile("movl %%ebp,%0" : "=r" (ebp));
return ebp;
}
static inline u32
read_esp(void)
{
u32 esp;
asm volatile("movl %%esp,%0" : "=r" (esp));
return esp;
}
static inline u64
read_tsc(void)
{
u64 tsc;
asm volatile("rdtsc" : "=A" (tsc));
return tsc;
}
static inline u32
xchg(volatile u32 *addr, u32 newval)
{
u32 result;
// The + in "+m" denotes a read-modify-write operand.
asm volatile("lock\n\t xchgl %0, %1"
: "+m" (*addr), "=a" (result)
: "1" (newval)
: "cc");
return result;
}
static inline void
disable_int()
{
asm volatile("cli");
}
static inline void
enable_int()
{
asm volatile("sti");
}
#endif /* MINIOS_X86_H */

74
kernel/Makefrag Normal file
View File

@ -0,0 +1,74 @@
OBJDIRS += kern
KERN_ENTRY_ADDR := 0xC0030400
KERN_SRCFILES :=kernel/kernel.asm \
kernel/hd.c \
kernel/fat32.c \
kernel/tty.c \
kernel/fs.c \
kernel/global.c \
kernel/clock.c \
kernel/elf.c \
kernel/spinlock.c \
kernel/keyboard.c \
kernel/assist.c \
kernel/fork.c \
kernel/file.c \
kernel/console.c \
kernel/syscallc.c \
kernel/vfs.c \
kernel/proc.c \
kernel/pagetbl.c \
kernel/pthread.c \
kernel/memman.c \
kernel/main.c \
kernel/exec.c \
kernel/ktest.c \
kernel/base.c \
kernel/start.c \
kernel/i8259.c \
kernel/testfunc.c \
kernel/protect.c \
lib/klib.c \
lib/kliba.asm \
KERN_OBJFILES := $(patsubst %.c, $(OBJDIR)/%.o, $(KERN_SRCFILES))
KERN_OBJFILES := $(patsubst %.asm, $(OBJDIR)/%.o, $(KERN_OBJFILES))
$(OBJDIR)/kernel/ktest.o: kernel/ktest.c $(OBJDIR)/.vars.CFLAGS
@echo + cc $<
@mkdir -p $(@D)
@$(CC) $(CFLAGS) -c -o $@ $< \
-D INSTALL_FILENAME='"$(INSTALL_FILENAME)"' \
-D $(INSTALL_TYPE) \
$(OBJDIR)/kernel/fs.o: kernel/fs.c $(OBJDIR)/.vars.CFLAGS
@echo + cc $<
@mkdir -p $(@D)
@$(CC) $(CFLAGS) -c -o $@ $< \
-D INSTALL_FILENAME='"$(INSTALL_FILENAME)"' \
-D INSTALL_NR_SECTORS=$(INSTALL_NR_SECTORS) \
-D INSTALL_START_SECTOR=$(INSTALL_START_SECTOR) \
-D $(INSTALL_TYPE) \
$(OBJDIR)/kernel/spinlock.o: kernel/spinlock.c $(OBJDIR)/.vars.CFLAGS
@echo + cc $<
@mkdir -p $(@D)
@$(CC) $(CFLAGS) -masm=intel -c -o $@ $<
$(OBJDIR)/kernel/%.o: kernel/%.c $(OBJDIR)/.vars.CFLAGS
@echo + cc $<
@mkdir -p $(@D)
@$(CC) $(CFLAGS) -c -o $@ $<
$(OBJDIR)/kernel/%.o: kernel/%.asm
@echo + as obj $<
@mkdir -p $(@D)
@$(AS) -I ./include -f elf -o $@ $<
$(OBJDIR)/kernel/kernel.bin: $(KERN_OBJFILES) $(LIB_A) $(OBJDIR)/.vars.LDFLAGS
@echo + ld $@
@$(LD) $(LDFLAGS) -s -Ttext $(KERN_ENTRY_ADDR) -o $@ $(KERN_OBJFILES) $(LIB_A) $(GCC_LIB)
@$(LD) $(LDFLAGS) -Ttext $(KERN_ENTRY_ADDR) -o $(OBJDIR)/kernel/kernel.dbg $(KERN_OBJFILES) $(LIB_A) $(GCC_LIB)

257
kernel/assist.c Normal file
View File

@ -0,0 +1,257 @@
/**********************************************************
* assist.c //added by mingxuan 2019-5-17
***********************************************************/
#include "fat32.h"
#include "type.h"
#include "const.h"
#include "protect.h"
#include "string.h"
#include "proc.h"
#include "tty.h"
#include "console.h"
#include "global.h"
#include "proto.h"
#include "fs_const.h"
#include "hd.h"
#include "fs.h"
#include "fs_misc.h"
extern CHAR cur_path[256];
extern u8* buf;
void MakeFullPath(PCHAR parent,PCHAR name,PCHAR fullpath)
{
int i=0,j=0,len=0;
len=strlen(parent);
for(i=0;i<len;i++)
{
fullpath[i]=parent[i];
}
if(fullpath[i-1]!='\\')
{
fullpath[i++]='\\';
}
len=strlen(name);
for(j=0;j<len;j++)
{
fullpath[i++]=name[j];
}
}
void ChangeCurrentPath(PCHAR addpath)
{
int i=0,len1=0,len2=0;
len1=strlen(cur_path);
if(strcmp(addpath,"..")==0)
{
for(i=len1-1;i>=0;i--)
{
if(cur_path[i]!='\\')
{
cur_path[i]=0;
}else{
cur_path[i]=0;
break;
}
}
len2=strlen(cur_path);
if(len2<=2)//根目录
{
cur_path[len2]='\\';
}
}else if(strcmp(addpath,"\\")==0){
for(i=len1;i>=0;i--)
{
if(cur_path[i]!=':')
{
cur_path[i]=0;
}else{
break;
}
}
cur_path[i+1]='\\';
}else{
if(cur_path[len1-1]!='\\')
{
cur_path[len1]='\\';
len1++;
}
len2=strlen(addpath);
for(i=0;i<len2;i++)
{
cur_path[i+len1]=addpath[i];
}
}
}
void GetNameFromPath(PCHAR path,PCHAR name)
{
int i=0,j=0,len=0;
len=strlen(path);
for(i=len-1;i>=0;i--)
{
if(path[i]=='\\')
{
break;
}
}
for(i=i+1;i<len;i++)
{
name[j++]=path[i];
}
}
void GetParentFromPath(PCHAR fullpath,PCHAR parent)
{
int i,len;
len=strlen(fullpath);
for(i=len-1;;i--)
{
if(fullpath[i]=='\\')
{
break;
}
}
for(i=i-1;i>=0;i--)
{
parent[i]=fullpath[i];
}
}
STATE IsFullPath(PCHAR path)
{
int i=0;
for(i=0;i<2;i++)//只看是不是以盘符和:开头的
{
if(cur_path[i]!=path[i])
{
return FALSE;
}
}
return TRUE;
}
void ToFullPath(PCHAR path,PCHAR fullpath)
{
int i=0,j=0,len=0;
if(IsFullPath(path))
{
strcpy(fullpath,path);
}else
{
len=strlen(cur_path);
for(i=0;i<len;i++)
{
fullpath[i]=cur_path[i];
}
if(cur_path[i-1]!='\\')
{
fullpath[i++]='\\';
}
len=strlen(path);
for(j=0;j<len;j++)
{
fullpath[i++]=path[j];
}
}
len=strlen(fullpath);
if(fullpath[len-1]=='\\')
{
fullpath[len-1]=0;
}
}
void TimeToBytes(WORD result[])//t是一个WORD类型的数组长度为2第0个元素为日期第1个元素为时间
{
WORD year,month,day,hour,minute,second;
/*
time_t nowtime;
struct tm *timeinfo;
time(&nowtime);
timeinfo=localtime(&nowtime);
year=timeinfo->tm_year + 1900;
month=timeinfo->tm_mon + 1;
day=timeinfo->tm_mday;
hour=timeinfo->tm_hour;
minute=timeinfo->tm_min;
second=timeinfo->tm_sec;
*/
year = 2018;
month = 12;
day = 27;
hour = 14;
minute = 30;
second = 24;
result[1]=hour*2048+minute*32+second/2;
result[0]=(year-1980)*512+month*32+day;
}
void FormatFileNameAndExt(PCHAR filename,PCHAR name,PCHAR ext)
{
UINT i=0,j=0,len=0;
len=strlen(filename);
for(i=0;i<len&&i<8;i++)
{
if(filename[i]=='.')
{
break;
}else{
if(filename[i]>='a'&&filename[i]<='z')
{
name[i]=filename[i]-32;
}else{
name[i]=filename[i];
}
}
}
for(j=i;j<8;j++)
{
name[j]=' ';
}
if(i<len)
{
j=0;
for(i=i+1;i<len;i++)
{
if(filename[i]>='a'&&filename[i]<='z')
{
ext[j++]=filename[i]-32;
}else{
ext[j++]=filename[i];
}
}
for(;j<3;j++)
{
ext[j]=' ';
}
}
}
void FormatDirNameAndExt(PCHAR dirname,PCHAR name,PCHAR ext)
{
UINT i=0,len=0;
len=strlen(dirname);
for(i=0;i<len&&i<8;i++)
{
if(dirname[i]>='a'&&dirname[i]<='z')
{
name[i]=dirname[i]-32;
}else{
name[i]=dirname[i];
}
}
for(;i<8;i++)
{
name[i]=' ';
}
for(i=0;i<3;i++)
{
ext[i]=' ';
}
}

783
kernel/base.c Normal file
View File

@ -0,0 +1,783 @@
/**********************************************************
* base.c //added by mingxuan 2019-5-17
***********************************************************/
#include "fat32.h"
#include "type.h"
#include "const.h"
#include "protect.h"
#include "string.h"
#include "proc.h"
#include "tty.h"
#include "console.h"
#include "global.h"
#include "proto.h"
#include "fs_const.h"
#include "hd.h"
#include "fs.h"
#include "fs_misc.h"
DWORD FAT_END=268435455;//文件簇号结束标记
DWORD TotalSectors=0;//总扇区数当载入磁盘时才从DBR中读取。
WORD Bytes_Per_Sector=0;//每个扇区的字节数当载入磁盘时才从DBR中读取。
BYTE Sectors_Per_Cluster=0;//每个簇的扇区数当载入磁盘时才从DBR中读取。
WORD Reserved_Sector=0;//保留扇区数当载入磁盘时才从DBR中读取。
DWORD Sectors_Per_FAT=0;//每个FAT所占的扇区数当载入磁盘时才从DBR中读取。
UINT Position_Of_RootDir=0;//根目录的位置。
UINT Position_Of_FAT1=0;//FAT1的位置。
UINT Position_Of_FAT2=0;//FAT2的位置。
extern CHAR cur_path[256];
BYTE FATBuf[1024]={0};
DWORD globalSectorIndex=-1;
void ReadSector(BYTE* buf,DWORD sectorIndex)
{
int fat32_dev = get_fs_dev(PRIMARY_MASTER, FAT32_TYPE); //added by mingxuan 2020-10-27
//RD_SECT_SCHED_FAT(buf, sectorIndex); // deleted by mingxuan 2020-10-27
RD_SECT_SCHED_FAT(fat32_dev, buf, sectorIndex); // modified by mingxuan 2020-10-27
}
void WriteSector(BYTE* buf,DWORD sectorIndex)
{
if(sectorIndex==globalSectorIndex)
{
memcpy(FATBuf,buf,512);//写FAT表的缓冲区保持数据同步
}
int fat32_dev = get_fs_dev(PRIMARY_MASTER, FAT32_TYPE); //added by mingxuan 2020-10-27
//WR_SECT_SCHED_FAT(buf, sectorIndex); // deleted by mingxuan 2020-10-27
WR_SECT_SCHED_FAT(fat32_dev, buf, sectorIndex); // modified by mingxuan 2020-10-27
}
void DeleteAllRecord(DWORD startCluster)
{
PBYTE buf=NULL;
Record record;
DWORD off=0;
DWORD curClusterIndex=startCluster,nextClusterIndex=0,start=0;
DWORD curSectorIndex=0,preSectorIndex=0,off_in_sector=0,last=0;
if(startCluster==2)
{
off=Position_Of_RootDir+(startCluster-2)*Sectors_Per_Cluster*Bytes_Per_Sector+sizeof(Record);
}else{
off=Position_Of_RootDir+(startCluster-2)*Sectors_Per_Cluster*Bytes_Per_Sector+2*sizeof(Record);
}
buf = (PBYTE)K_PHY2LIN(sys_kmalloc(Bytes_Per_Sector*sizeof(BYTE)));
last=Reserved_Sector+2*Sectors_Per_FAT+(startCluster-2)*Sectors_Per_Cluster+Sectors_Per_Cluster;
do
{
curSectorIndex=off/Bytes_Per_Sector;
off_in_sector=off%Bytes_Per_Sector;
if(curSectorIndex!=preSectorIndex)
{
if(preSectorIndex!=0)
{
WriteSector(buf,preSectorIndex);
}
ReadSector(buf,curSectorIndex);
preSectorIndex=curSectorIndex;
}
memcpy(&record,buf+off_in_sector,sizeof(Record));
if(record.filename[0]==0)
{
WriteSector(buf,curSectorIndex);
break;
}
if(record.filename[0]!=(BYTE)0xE5&&record.filename[0]!=0)
{
record.filename[0]=(BYTE)0xE5;
memcpy(buf+off_in_sector,&record,sizeof(Record));
start=(DWORD)(record.highClusterNum<<16)+(DWORD)record.lowClusterNum;
if(record.proByte==(BYTE)0x10)//是子目录
{
DeleteAllRecord(start);//删除此子目录
}else{
ClearFATs(start);
}
}
preSectorIndex=curSectorIndex;
if(curSectorIndex>=last)
{
GetNextCluster(curClusterIndex,&nextClusterIndex);
if(nextClusterIndex==FAT_END)
{
WriteSector(buf,curSectorIndex);
break;
}else{
curClusterIndex=nextClusterIndex;
off=Position_Of_RootDir+(curClusterIndex-2)*Sectors_Per_Cluster*Bytes_Per_Sector;
}
}else{
off+=sizeof(Record);
}
}while(1);
sys_free(buf);
ClearFATs(startCluster);
}
STATE FindClusterForDir(PDWORD pcluster)
{
PBYTE buf=NULL;
DWORD clusterIndex=2,nextClusterIndex=0;
DWORD curSectorIndex=0,last=0,offset=0;
buf = (PBYTE)K_PHY2LIN(sys_kmalloc(Bytes_Per_Sector*sizeof(BYTE)));
if(buf==NULL)
{
return SYSERROR;
}
curSectorIndex=Reserved_Sector;
last=curSectorIndex+Sectors_Per_FAT;
offset=8;
for(;curSectorIndex<last;curSectorIndex++)
{
ReadSector(buf,curSectorIndex);
for(;offset<Bytes_Per_Sector;offset+=sizeof(DWORD),clusterIndex++)
{
memcpy(&nextClusterIndex,buf+offset,sizeof(DWORD));
if(nextClusterIndex==0)
{
sys_free(buf);
*pcluster=clusterIndex;
ClearClusters(clusterIndex);
return OK;
}
}
offset=0;
}
sys_free(buf);
return INSUFFICIENTSPACE;
}
void GetFileOffset(PFile pfile,PDWORD sectorIndex,PDWORD off_in_sector,PUINT isLastSector)
{
DWORD curSectorIndex=0,nextSectorIndex=0,sectorNum=0,totalSectors=0,counter=0;
if(pfile->size%Bytes_Per_Sector==0)
{
totalSectors=pfile->size/Bytes_Per_Sector;
}else{
totalSectors=pfile->size/Bytes_Per_Sector+1;
}
sectorNum=pfile->off/Bytes_Per_Sector+1;
if(off_in_sector!=NULL)
{
(*off_in_sector)=pfile->off%Bytes_Per_Sector;
}
curSectorIndex=Reserved_Sector+2*Sectors_Per_FAT+(pfile->start-2)*Sectors_Per_Cluster;
do
{
counter++;
if(counter==sectorNum)
{
if(totalSectors==1)
{
*sectorIndex=curSectorIndex;
*isLastSector=1;
}else{
*sectorIndex=curSectorIndex;
}
break;
}
GetNextSector(pfile,curSectorIndex,&nextSectorIndex,isLastSector);
curSectorIndex=nextSectorIndex;
}while(1);
}
void GetNextSector(PFile pfile,DWORD curSectorIndex,PDWORD nextSectorIndex,PUINT isLastSector)
{
DWORD temp=0;
DWORD curClusterIndex=0,nextClusterIndex=0,last=0;
BYTE off_in_cluster=0;
temp=curSectorIndex-Reserved_Sector-2*Sectors_Per_FAT;
curClusterIndex=temp/Sectors_Per_Cluster+2;//此扇区所在的簇
off_in_cluster=(BYTE)(temp%Sectors_Per_Cluster);//此扇区是所在簇的的几个扇区,从零开始
GetNextCluster(curClusterIndex,&nextClusterIndex);
if(nextClusterIndex==FAT_END)//此扇区所在簇是该文件的最后一个簇
{
if(pfile->flag==R)
{
temp=pfile->size%(Sectors_Per_Cluster*Bytes_Per_Sector);
if(temp==0)//此文件实际占用了整数个簇
{
last=Sectors_Per_Cluster;
}else{
if(temp%Bytes_Per_Sector==0)
{
last=temp/Bytes_Per_Sector;
}else{
last=temp/Bytes_Per_Sector+1;//最后一簇实际占用的扇区数
}
}
}else{
last=Sectors_Per_Cluster;
}
if(off_in_cluster<last-1)
{
(*nextSectorIndex)=Reserved_Sector+2*Sectors_Per_FAT+(curClusterIndex-2)*Sectors_Per_Cluster+off_in_cluster+1;
if(off_in_cluster==last-2)//返回的扇区号是该文件的最后一个扇区
{
*isLastSector=1;
}else{
*isLastSector=0;
}
}
}else{
if(off_in_cluster<Sectors_Per_Cluster-1)
{
(*nextSectorIndex)=Reserved_Sector+2*Sectors_Per_FAT+(curClusterIndex-2)*Sectors_Per_Cluster+off_in_cluster+1;
}else{
curClusterIndex=nextClusterIndex;
(*nextSectorIndex)=Reserved_Sector+2*Sectors_Per_FAT+(curClusterIndex-2)*Sectors_Per_Cluster;
}
GetNextCluster(curClusterIndex,&nextClusterIndex);
if(nextClusterIndex==FAT_END)
{
if(pfile->flag==R)
{
temp=pfile->size%(Sectors_Per_Cluster*Bytes_Per_Sector);
if(temp!=0)//此文件实际占用了整数个簇
{
last=temp/Bytes_Per_Sector+1;//最后一簇实际占用的扇区数
if(last==1)//最后一簇实际上只占用了一个扇区
{
*isLastSector=1;//那么当前返回的扇区就是此文件的最后一个扇区
}else{
*isLastSector=0;
}
}
}
}
}
}
STATE GetNextCluster(DWORD clusterIndex,PDWORD nextCluster)
{
DWORD sectorIndex=0,offset=0,off_in_sector=0;
offset=8+(clusterIndex-2)*sizeof(DWORD);
sectorIndex=Reserved_Sector+offset/Bytes_Per_Sector;
off_in_sector=offset%Bytes_Per_Sector;
if(sectorIndex!=globalSectorIndex)
{
ReadSector(FATBuf,sectorIndex);
globalSectorIndex=sectorIndex;
}
memcpy(nextCluster,FATBuf+off_in_sector,sizeof(DWORD));
return OK;
}
STATE ReadRecord(DWORD parentCluster,PCHAR name,PRecord record,PDWORD sectorIndex,PDWORD off_in_sector)
{
CHAR temp[256]={0};
DWORD curSectorIndex=0,curClusterIndex=parentCluster,off=0,size_of_Record;
BYTE *buf;
UINT last=0;
size_of_Record=sizeof(Record);
buf = (PBYTE)K_PHY2LIN(sys_kmalloc(Bytes_Per_Sector*sizeof(BYTE)));
do
{
curSectorIndex=Reserved_Sector+2*Sectors_Per_FAT+(curClusterIndex-2)*Sectors_Per_Cluster;
last=curSectorIndex+8;
for(;curSectorIndex<last;curSectorIndex++)//扇区号循环
{
ReadSector(buf,curSectorIndex);
for(off=0;off<Bytes_Per_Sector;off+=size_of_Record)//目录项号循环
{
memcpy(record,buf+off,size_of_Record);
if(record->filename[0]==0)//没有此目录项
{
sys_free(buf);
return WRONGPATH;
}
memset(temp,0,sizeof(temp));
// if(record->sysReserved==0x18)//是长文件名文件的短目录项
// {
// do
// {
// memcpy(&lrecord,buf+off,size_of_Record);
// strcpy(temp+offinlongname,lrecord.name1);
// offinlongname+=10;
// strcpy(temp+offinlongname,lrecord.name2);
// offinlongname+=19;
// if(lrecord.proByte&0x40!=0)
// {
// break;
// }
// if(off>=Bytes_Per_Sector)
// {
// ReadSector(buf,curSectorIndex);
// off=0;
// }
// }while(1);
// }else{
// GetNameFromRecord(*record,temp);
// }
GetNameFromRecord(*record,temp);
if(strcmp(temp,name)==0)
{
if(sectorIndex!=NULL)
{
*sectorIndex=curSectorIndex;
}
if(off_in_sector!=NULL)
{
*off_in_sector=off;
}
sys_free(buf);
return OK;
}
}
}
// GetNextCluster(curClusterIndex,&nextClusterIndex);
// if(nextClusterIndex==FAT_END)
// {
// sys_free(buf);
// return WRONGPATH;
// }else{
// curClusterIndex=nextClusterIndex;
// }
}while(1);
}
void ClearFATs(DWORD startClusterIndex)
{
PBYTE buf=NULL;
DWORD curClusterIndex=startClusterIndex,nextClusterIndex=0;
DWORD curSectorIndex=0,preSectorIndex=0,temp=0,offset=0;
DWORD clear=0;
if(startClusterIndex==0)
{
return;
}
buf = (PBYTE)K_PHY2LIN(sys_kmalloc(Bytes_Per_Sector*sizeof(BYTE)));
do
{
temp=(curClusterIndex-2)*sizeof(DWORD)+8;
curSectorIndex=Reserved_Sector+temp/Bytes_Per_Sector;
offset=temp%Bytes_Per_Sector;
if(curSectorIndex!=preSectorIndex)
{
if(preSectorIndex!=0)//不是第一个扇区
{
WriteSector(buf,preSectorIndex);
}
preSectorIndex=curSectorIndex;
ReadSector(buf,curSectorIndex);
}
memcpy(&nextClusterIndex,buf+offset,sizeof(DWORD));
curClusterIndex=nextClusterIndex;
memcpy(buf+offset,&clear,sizeof(DWORD));
preSectorIndex=curSectorIndex;
}while(curClusterIndex!=FAT_END);
WriteSector(buf,curSectorIndex);
sys_free(buf);
}
STATE ClearRecord(DWORD parentCluster,PCHAR name,PDWORD startCluster)
{
Record record;
DWORD startClusterIndex=0,sectorIndex=0,off_in_sector=0;
STATE state;
state=ReadRecord(parentCluster,name,&record,&sectorIndex,&off_in_sector);
if(state!=OK)
{
return state;
}
record.filename[0]=(BYTE)0xE5;
startClusterIndex=((DWORD)record.highClusterNum<<16)+(DWORD)record.lowClusterNum;
WriteRecord(record,sectorIndex,off_in_sector);
*startCluster=startClusterIndex;
return OK;
}
STATE PathToCluster(PCHAR path, PDWORD cluster)
{
UINT i=0,j=0,len=0;
CHAR name[256]={0};
CHAR fullpath[256]={0};
Record record;
DWORD parentCluster=2;
STATE state;
ToFullPath(path,fullpath);
len=strlen(fullpath);
for(i=0;i<len;i++)
{
if(fullpath[i]=='\\')
{
break;
}
}
if(i>=len)//说明是根目录
{
*cluster=2;
return OK;
}
j=0;
for(i=i+1;i<len;i++)
{
if(fullpath[i]=='\\'||i==len-1)
{
if(i==len-1)
{
name[j]=fullpath[i];
}
state=ReadRecord(parentCluster,name,&record,NULL,NULL);
if(state==OK)
{
parentCluster=(record.highClusterNum<<16)+record.lowClusterNum;
memset(name,0,sizeof(name));
}else{
return state;
}
j=0;
}else{
name[j++]=fullpath[i];
}
}
*cluster=parentCluster;
return OK;
}
STATE FindSpaceInDir(DWORD parentClusterIndex,PCHAR name,PDWORD sectorIndex,PDWORD off_in_sector)
{
PBYTE buf=NULL;
Record record;
CHAR fullname[256]={0};
DWORD curClusterIndex=parentClusterIndex;
DWORD curSectorIndex=0,offset=0,last=0;
UINT recordsnum=1,curnum=0;
buf = (PBYTE)K_PHY2LIN(sys_kmalloc(Bytes_Per_Sector*sizeof(BYTE)));
if(strlen(name)%29==0)
{
recordsnum=strlen(name)/29;
}else{
recordsnum=strlen(name)/29+1;
}
do//簇号循环
{
curSectorIndex=Reserved_Sector+2*Sectors_Per_FAT+(curClusterIndex-2)*Sectors_Per_Cluster;
last=curSectorIndex+8;
for(;curSectorIndex<last;curSectorIndex++)//扇区号循环
{
ReadSector(buf,curSectorIndex);
for(offset=0;offset<Bytes_Per_Sector;offset+=sizeof(Record))//目录项号循环
{
memcpy(&record,buf+offset,sizeof(Record));
if(record.filename[0]==0||record.filename[0]==(BYTE)0xE5)
{
do
{
curnum++;
if(curnum==recordsnum)
{
*sectorIndex=curSectorIndex;
*off_in_sector=offset;
sys_free(buf);
return OK;//为目录项找到位置了
}
memcpy(&record,buf+offset,sizeof(Record));
offset+=sizeof(Record);
if(record.filename[0]!=0&&record.filename[0]!=(BYTE)0xE5)
{
curnum=0;
break;
}
if(offset>=Bytes_Per_Sector)
{
ReadSector(buf,curSectorIndex);
offset=0;
}
}while(1);
}
else
{
if(record.proByte!=(BYTE)0x08)//不是卷标
{
GetNameFromRecord(record,fullname);
if(strcmp(name,fullname)==0)//有重名的文件或目录
{
sys_free(buf);
return NAMEEXIST;
}
}
}
}
}
}while(1);
}
void GetNameFromRecord(Record record,PCHAR fullname)
{
UINT i=0,j=0,point=0;
for(i=0;i<8;i++)
{
if(record.filename[i]==' ')
{
break;
}
if(record.filename[i]>='A'&&record.filename[i]<='Z')
{
fullname[j++]=record.filename[i]+32;
}else{
fullname[j++]=record.filename[i];
}
}
point=j;
fullname[j++]='.';
for(i=0;i<3;i++)
{
if(record.extension[i]>='A'&&record.extension[i]<='Z')
{
fullname[j++]=record.extension[i]+32;
}else{
fullname[j++]=record.extension[i];
}
}
for(j=j-1;j>=0;j--)//去掉后面的空格
{
if(fullname[j]==' '||(fullname[j]=='.'&&j==point))
{
fullname[j]=0;
}else{
break;
}
}
}
void CreateRecord(PCHAR filename,BYTE type,DWORD startCluster,DWORD size,PRecord precord)
{
WORD time[2];
CHAR name[256]={0};
CHAR ext[256]={0};
if(type==(BYTE)0x08||type==(BYTE)0x10)
{
FormatDirNameAndExt(filename,name,ext);
precord->sysReserved=0x08;
}else{
FormatFileNameAndExt(filename,name,ext);
precord->sysReserved=0x18;
}
TimeToBytes(time);//获取当前时间
strcpy((char *)precord->filename,name);
strcpy((char *)precord->extension,ext);
precord->proByte=type;
precord->createMsecond=0;
precord->createTime=time[1];
precord->createDate=time[0];
precord->lastAccessDate=time[0];
precord->highClusterNum=(WORD)(startCluster>>16);
precord->lastModifiedTime=time[1];
precord->lastModifiedDate=time[0];
precord->lowClusterNum=(WORD)(startCluster&0x0000ffff);
precord->filelength=size;
}
STATE WriteRecord(Record record,DWORD sectorIndex,DWORD off_in_sector)
{
BYTE *buf=NULL;
buf = (PBYTE)K_PHY2LIN(sys_kmalloc(Bytes_Per_Sector*sizeof(BYTE)));
ReadSector(buf,sectorIndex);
memcpy(buf+off_in_sector,&record,sizeof(Record));
WriteSector(buf,sectorIndex);
sys_free(buf);
return OK;
}
STATE WriteFAT(DWORD totalclusters,PDWORD clusters)
{
PBYTE buf=NULL;
DWORD i=0,curSectorIndex=0,preSectorIndex=0,offset=0,off_in_sector=0;
buf = (PBYTE)K_PHY2LIN(sys_kmalloc(Bytes_Per_Sector*sizeof(BYTE)));
if(buf==NULL)
{
return SYSERROR;
}
for(i=0;i<totalclusters;i++)
{
offset=8+(clusters[i]-2)*sizeof(DWORD);
curSectorIndex=Reserved_Sector+offset/Bytes_Per_Sector;
off_in_sector=offset%Bytes_Per_Sector;
if(curSectorIndex!=preSectorIndex)//两个簇号不在同一个扇区。
{
if(preSectorIndex!=0)
{
WriteSector(buf,preSectorIndex);//先把上一个扇区的内容写入FAT1中
}
ReadSector(buf,curSectorIndex);
preSectorIndex=curSectorIndex;
}
if(i<totalclusters-1)
{
memcpy(buf+off_in_sector,clusters+i+1,sizeof(DWORD));
}else{
memcpy(buf+off_in_sector,&FAT_END,sizeof(DWORD));
}
preSectorIndex=curSectorIndex;
}
WriteSector(buf,curSectorIndex);
//暂时用不上FAT2所以不写FAT2
sys_free(buf);
return OK;
}
STATE AllotClustersForEmptyFile(PFile pfile,DWORD size)
{
DWORD n=0,bytes_per_cluster=0;
PDWORD clusters=NULL;
bytes_per_cluster=Sectors_Per_Cluster*Bytes_Per_Sector;
if(size%bytes_per_cluster==0)
{
n=size/bytes_per_cluster;//n表示实际要占用的簇的个数
}else{
n=size/bytes_per_cluster+1;
}
clusters = (PDWORD)K_PHY2LIN(sys_kmalloc(n*sizeof(DWORD)));
if(clusters==NULL)
{
return SYSERROR;
}
if(!FindClusterForFile(n,clusters))//空间不足
{
return INSUFFICIENTSPACE;
}
pfile->start=clusters[0];
WriteFAT(n,clusters);
sys_free(clusters);
return OK;
}
STATE AddCluster(DWORD startClusterIndex,DWORD num)//cluster表示该文件或目录所在目录的簇,num表示增加几个簇
{
PDWORD clusters=NULL;
DWORD curClusterIndex=startClusterIndex,nextClusterIndex=0;
// DWORD bytes_per_sector=Sectors_Per_FAT*Bytes_Per_Sector;
STATE state;
clusters = (PDWORD)K_PHY2LIN(sys_kmalloc((num+1)*sizeof(DWORD)));
if(clusters==NULL)
{
return SYSERROR;
}
state=FindClusterForFile(num,clusters+1);
if(state!=OK)
{
return state;
}
do
{
GetNextCluster(curClusterIndex,&nextClusterIndex);
if(nextClusterIndex==FAT_END)
{
clusters[0]=curClusterIndex;
break;
}else{
curClusterIndex=nextClusterIndex;
}
}while(1);
WriteFAT(num+1,clusters);
sys_free(clusters);
return OK;
}
STATE NeedMoreCluster(PFile pfile,DWORD size,PDWORD number)
{
DWORD n=0,clusterNum,bytes_per_cluster=0;
bytes_per_cluster=Sectors_Per_Cluster*Bytes_Per_Sector;
if(pfile->off == 0) {
return FALSE;
}
if(pfile->off%bytes_per_cluster==0)//clusterNum是实际占用的簇的个数
{
clusterNum=pfile->off/bytes_per_cluster;
}else{
clusterNum=pfile->off/bytes_per_cluster+1;
}
if(size>clusterNum*bytes_per_cluster-pfile->off)//空间不足需要追加更多的簇
{
if((size-(clusterNum*bytes_per_cluster-pfile->off))%bytes_per_cluster==0)
{
n=(size-(clusterNum*bytes_per_cluster-pfile->off))/bytes_per_cluster;
}else{
n=(size-(clusterNum*bytes_per_cluster-pfile->off))/bytes_per_cluster+1;
}
*number=n;
return TRUE;//表示还需要n簇
}
return FALSE;//表示目前空间够用,不需要更多的簇
}
STATE FindClusterForFile(DWORD totalClusters,PDWORD clusters)
{
PBYTE buf=NULL;
DWORD clusterIndex=1,nextClusterIndex=0;
UINT index=0,i=0,j=0;
DWORD curSectorIndex=0,off_in_sector=0;
buf = (PBYTE)K_PHY2LIN(sys_kmalloc(Bytes_Per_Sector*sizeof(BYTE)));
if(buf==NULL)
{
return SYSERROR;
}
curSectorIndex=Reserved_Sector;
off_in_sector=8;
do
{
ReadSector(buf,curSectorIndex);
for(i=off_in_sector;i<Bytes_Per_Sector;i+=sizeof(DWORD))
{
memcpy(&nextClusterIndex,buf+i,sizeof(DWORD));
clusterIndex++;
if(nextClusterIndex==0)
{
clusters[index++]=clusterIndex;
if(index>=totalClusters)//找够了
{
sys_free(buf);
for(j=0;j<totalClusters;j++)
{
ClearClusters(clusters[j]);//清空这些簇
}
return OK;
}
}
}
if(curSectorIndex*Bytes_Per_Sector>=Position_Of_FAT2)
{
sys_free(buf);
return INSUFFICIENTSPACE;
}else{
curSectorIndex++;
off_in_sector=0;
}
}while(1);
}
void ClearClusters(DWORD cluster)
{
BYTE buf[512]={0};
UINT sectorIndex=0;
UINT first=0,last=0;
first=Reserved_Sector+2*Sectors_Per_FAT+(cluster-2)*Sectors_Per_Cluster;
last=first+8;
for(sectorIndex=first;sectorIndex<last;sectorIndex++)
{
WriteSector(buf,sectorIndex);
}
}

45
kernel/clock.c Normal file
View File

@ -0,0 +1,45 @@
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
clock.c
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Forrest Yu, 2005
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
#include "type.h"
#include "const.h"
#include "protect.h"
#include "string.h"
#include "proc.h"
#include "global.h"
#include "proto.h"
/*======================================================================*
clock_handler
*======================================================================*/
void clock_handler(int irq)
{
ticks++;
/* There is two stages - in kernel intializing or in process running.
* Some operation shouldn't be valid in kernel intializing stage.
* added by xw, 18/6/1
*/
if(kernel_initial == 1){
return;
}
irq = 0;
p_proc_current->task.ticks--;
sys_wakeup(&ticks);
}
/*======================================================================*
milli_delay
*======================================================================*/
void milli_delay(int milli_sec)
{
int t = get_ticks();
while(((get_ticks() - t) * 1000 / HZ) < milli_sec) {}
}

327
kernel/console.c Normal file
View File

@ -0,0 +1,327 @@
#include "type.h"
#include "stdio.h"
#include "const.h"
#include "protect.h"
#include "string.h"
#include "fs.h"
#include "proc.h"
#include "tty.h"
#include "console.h"
#include "global.h"
#include "keyboard.h"
#include "proto.h"
#include "x86.h"
/* local routines */
static void set_cursor(unsigned int position);
static void set_video_start_addr(u32 addr);
static void flush(CONSOLE* con);
static void w_copy(unsigned int dst, const unsigned int src, int size);
static void clear_screen(int pos, int len);
void scroll_screen(CONSOLE* con, int dir);
/*****************************************************************************
* init_screen
*****************************************************************************/
/**
* Initialize the console of a certain tty.
*
* @param tty Whose console is to be initialized.
*****************************************************************************/
void init_screen(TTY* tty)
{
int nr_tty = tty - tty_table;
tty->console = console_table + nr_tty;
/*
* NOTE:
* variables related to `position' and `size' below are
* in WORDs, but not in BYTEs.
*/
int v_mem_size = V_MEM_SIZE >> 1; /* size of Video Memory */
int size_per_con = (v_mem_size / NR_CONSOLES)/80*80;
tty->console->orig = nr_tty * size_per_con;
tty->console->con_size = size_per_con / SCR_WIDTH * SCR_WIDTH;
tty->console->cursor = tty->console->crtc_start = tty->console->orig;
tty->console->is_full = 0;
tty->console->current_line = 0;
if(nr_tty==0){
tty->console->cursor = disp_pos / 2;
}
const char prompt[] = "[TTY #?]\n";
const char * p = prompt;
for (; *p; p++){
out_char(tty->console, *p == '?' ? nr_tty + '0' : *p);
}
set_cursor(tty->console->cursor);
}
/*****************************************************************************
* out_char
*****************************************************************************/
/**
* Print a char in a certain console.
*
* @param con The console to which the char is printed.
* @param ch The char to print.
*****************************************************************************/
void out_char(CONSOLE* con, char ch)
{
disable_int();
int cursor_x = (con->cursor - con->orig) % SCR_WIDTH;
int cursor_y = (con->cursor - con->orig) / SCR_WIDTH;
switch(ch) {
case '\n':
con->cursor = con->orig + SCR_WIDTH * (cursor_y + 1);
break;
case '\b':
if (con->cursor > con->orig) {
con->cursor--;
//*(pch - 2) = ' ';
//*(pch - 1) = DEFAULT_CHAR_COLOR;
disp_pos = con->cursor*2;
write_char(' ');
}
break;
default:
//*pch++ = ch;
//*pch++ = DEFAULT_CHAR_COLOR;
disp_pos = con->cursor*2;
write_char(ch);
con->cursor++;
break;
}
if (con->cursor - con->orig >= con->con_size) {
cursor_x = (con->cursor - con->orig) % SCR_WIDTH;
cursor_y = (con->cursor - con->orig) / SCR_WIDTH;
int cp_orig = con->orig + (cursor_y + 1) * SCR_WIDTH - SCR_SIZE;
w_copy(con->orig, cp_orig, SCR_SIZE - SCR_WIDTH);
con->crtc_start = con->orig;
con->cursor = con->orig + (SCR_SIZE - SCR_WIDTH) + cursor_x;
clear_screen(con->cursor, SCR_WIDTH);
if (!con->is_full)
con->is_full = 1;
}
//assert(con->cursor - con->orig < con->con_size);
while (con->cursor >= con->crtc_start + SCR_SIZE ||
con->cursor < con->crtc_start) {
scroll_screen(con, SCR_UP);
clear_screen(con->cursor, SCR_WIDTH);
}
flush(con);
enable_int();
}
/*****************************************************************************
* clear_screen
*****************************************************************************/
/**
* Write whitespaces to the screen.
*
* @param pos Write from here.
* @param len How many whitespaces will be written.
*****************************************************************************/
static void clear_screen(int pos, int len)
{
u8 * pch = (u8*)K_PHY2LIN(V_MEM_BASE + pos * 2);
while (--len >= 0) {
*pch++ = ' ';
*pch++ = DEFAULT_CHAR_COLOR;
}
}
/*****************************************************************************
* is_current_console
*****************************************************************************/
/**
* Uses `nr_current_console' to determine if a console is the current one.
*
* @param con Ptr to console.
*
* @return TRUE if con is the current console.
*****************************************************************************/
int is_current_console(CONSOLE* con)
{
return (con == &console_table[current_console]);
}
/*****************************************************************************
* set_cursor
*****************************************************************************/
/**
* Display the cursor by setting CRTC (6845 compatible) registers.
*
* @param position Position of the cursor based on the beginning of the video
* memory. Note that it counts in WORDs, not in BYTEs.
*****************************************************************************/
static void set_cursor(unsigned int position)
{
disable_int();
outb(CRTC_ADDR_REG, CURSOR_H);
outb(CRTC_DATA_REG, (position >> 8) & 0xFF);
outb(CRTC_ADDR_REG, CURSOR_L);
outb(CRTC_DATA_REG, position & 0xFF);
enable_int();
}
/*****************************************************************************
* set_video_start_addr
*****************************************************************************/
/**
* Routine for hardware screen scrolling.
*
* @param addr Offset in the video memory.
*****************************************************************************/
static void set_video_start_addr(u32 addr)
{
disable_int();
outb(CRTC_ADDR_REG, START_ADDR_H);
outb(CRTC_DATA_REG, (addr >> 8) & 0xFF);
outb(CRTC_ADDR_REG, START_ADDR_L);
outb(CRTC_DATA_REG, addr & 0xFF);
enable_int();
}
/*****************************************************************************
* select_console
*****************************************************************************/
/**
* Select a console as the current.
*
* @param nr_console Console nr, range in [0, NR_CONSOLES-1].
*****************************************************************************/
void select_console(int nr_console)
{
if ((nr_console < 0) || (nr_console >= NR_CONSOLES)) return;
flush(&console_table[current_console = nr_console]);
}
/*****************************************************************************
* scroll_screen
*****************************************************************************/
/**
* Scroll the screen.
*
* Note that scrolling UP means the content of the screen will go upwards, so
* that the user can see lines below the bottom. Similarly scrolling DOWN means
* the content of the screen will go downwards so that the user can see lines
* above the top.
*
* When there is no line below the bottom of the screen, scrolling UP takes no
* effects; when there is no line above the top of the screen, scrolling DOWN
* takes no effects.
*
* @param con The console whose screen is to be scrolled.
* @param dir SCR_UP : scroll the screen upwards;
* SCR_DN : scroll the screen downwards
*****************************************************************************/
void scroll_screen(CONSOLE* con, int dir)
{
/*
* variables below are all in-console-offsets (based on con->orig)
*/
int oldest; /* addr of the oldest available line in the console */
int newest; /* .... .. ... latest ......... .... .. ... ....... */
int scr_top;/* position of the top of current screen */
newest = (con->cursor - con->orig) / SCR_WIDTH * SCR_WIDTH;
oldest = con->is_full ? (newest + SCR_WIDTH) % con->con_size : 0;
scr_top = con->crtc_start - con->orig;
if (dir == SCR_DN) {
if (!con->is_full && scr_top > 0) {
con->crtc_start -= SCR_WIDTH;
}
else if (con->is_full && scr_top != oldest) {
if (con->cursor - con->orig >= con->con_size - SCR_SIZE) {
if (con->crtc_start != con->orig)
con->crtc_start -= SCR_WIDTH;
}
else if (con->crtc_start == con->orig) {
scr_top = con->con_size - SCR_SIZE;
con->crtc_start = con->orig + scr_top;
}
else {
con->crtc_start -= SCR_WIDTH;
}
}
}
else if (dir == SCR_UP) {
if (!con->is_full && newest >= scr_top + SCR_SIZE) {
con->crtc_start += SCR_WIDTH;
}
else if (con->is_full && scr_top + SCR_SIZE - SCR_WIDTH != newest) {
if (scr_top + SCR_SIZE == con->con_size)
con->crtc_start = con->orig;
else
con->crtc_start += SCR_WIDTH;
}
}
else {
//assert(dir == SCR_DN || dir == SCR_UP);
}
flush(con);
}
/*****************************************************************************
* flush
*****************************************************************************/
/**
* Set the cursor and starting address of a console by writing the
* CRT Controller Registers.
*
* @param con The console to be set.
*****************************************************************************/
static void flush(CONSOLE* con)
{
if (is_current_console(con)) {
set_cursor(con->cursor);
set_video_start_addr(con->crtc_start);
}
}
/*****************************************************************************
* w_copy
*****************************************************************************/
/**
* Copy data in WORDS.
*
* Note that the addresses of dst and src are not pointers, but integers, 'coz
* in most cases we pass integers into it as parameters.
*
* @param dst Addr of destination.
* @param src Addr of source.
* @param size How many words will be copied.
*****************************************************************************/
static void w_copy(unsigned int dst, const unsigned int src, int size)
{
memcpy((void*)(V_MEM_BASE + (dst << 1)),
(void*)(V_MEM_BASE + (src << 1)),
size << 1);
}

28
kernel/elf.c Normal file
View File

@ -0,0 +1,28 @@
#include "type.h"
#include "const.h"
#include "protect.h"
#include "string.h"
#include "proc.h"
#include "global.h"
#include "proto.h"
#include "elf.h"
#include "fs.h" //added by mingxuan 2019-5-23
#include "vfs.h"
void read_Ehdr(u32 fd,Elf32_Ehdr *File_Ehdr,u32 offset)
{
do_vlseek(fd,offset,SEEK_SET); //modified by mingxuan 2019-5-24
do_vread(fd,(void*)File_Ehdr,sizeof(Elf32_Ehdr)); //modified by mingxuan 2019-5-24
}
void read_Phdr(u32 fd,Elf32_Phdr *File_Phdr,u32 offset)
{
do_vlseek(fd,offset,SEEK_SET); //modified by mingxuan 2019-5-24
do_vread(fd,(void*)File_Phdr,sizeof(Elf32_Phdr)); //modified by mingxuan 2019-5-24
}
void read_Shdr(u32 fd,Elf32_Shdr *File_Shdr,u32 offset)
{
do_vlseek(fd,offset,SEEK_SET); //modified by mingxuan 2019-5-24
do_vread(fd,(void*)File_Shdr,sizeof(Elf32_Shdr)); //modified by mingxuan 2019-5-23
}

248
kernel/exec.c Normal file
View File

@ -0,0 +1,248 @@
/**********************************************
* exec.c add by visual 2016.5.23
*************************************************/
#include "type.h"
#include "const.h"
#include "protect.h"
#include "string.h"
#include "proc.h"
#include "global.h"
#include "proto.h"
#include "elf.h"
#include "fs.h" //added by mingxuan 2019-5-19
#include "vfs.h"
static u32 exec_elfcpy(u32 fd,Elf32_Phdr Echo_Phdr,u32 attribute);
static u32 exec_load(u32 fd,const Elf32_Ehdr* Echo_Ehdr,const Elf32_Phdr Echo_Phdr[]);
static int exec_pcb_init(char* path);
/*======================================================================*
* sys_exec add by visual 2016.5.23
*exec系统调用功能实现部分
*======================================================================*/
u32 sys_exec(char *path)
{
Elf32_Ehdr *Echo_Ehdr = NULL;
Elf32_Phdr *Echo_Phdr = NULL;
u32 addr_lin;
u32 err_temp;
char* p_reg; //point to a register in the new kernel stack, added by xw, 17/12/11
if( 0==path )
{
disp_color_str("exec: path ERROR!",0x74);
return -1;
}
/*******************打开文件************************/
// u32 fd = open(path,"r"); //deleted by mingxuan 2019-5-19
u32 fd = do_vopen(path, O_RDWR); //deleted by mingxuan 2019-5-19
if(fd==-1)
{
//printf("sys_exec open error!\n"); //deleted by mingxuan 2019-5-23
return -1;
}
// u32 fd = fake_open(path,"r"); //modified by xw, 18/5/30
/*************获取elf信息**************/
Echo_Ehdr = sys_kmalloc(sizeof(Elf32_Ehdr));
read_Ehdr(fd, Echo_Ehdr, 0);
Echo_Phdr = sys_kmalloc(sizeof(Elf32_Phdr) * Echo_Ehdr->e_phnum);
for (int i = 0 ; i < Echo_Ehdr->e_phnum ; i++)
read_Phdr(fd, Echo_Phdr + i, Echo_Ehdr->e_phoff + i * sizeof(Elf32_Phdr));
/*************释放进程内存****************/
//目前还没有实现 思路是数据、代码根据text_info和data_info属性决定释放深度其余内存段可以完全释放
/*************根据elf的program复制文件信息**************/
if(-1==exec_load(fd,Echo_Ehdr,Echo_Phdr)) return -1;//使用了const指针传递
/*****************重新初始化该进程的进程表信息包括LDT、线性地址布局、进程树属性********************/
exec_pcb_init(path);
/***********************代码、数据、堆、栈***************************/
//代码、数据已经处理将eip重置即可
p_proc_current->task.regs.eip = Echo_Ehdr->e_entry;//进程入口线性地址
p_reg = (char*)(p_proc_current + 1); //added by xw, 17/12/11
*((u32*)(p_reg + EIPREG - P_STACKTOP)) = p_proc_current->task.regs.eip; //added by xw, 17/12/11
//栈
p_proc_current->task.regs.esp=(u32)p_proc_current->task.memmap.stack_lin_base; //栈地址最高处
*((u32*)(p_reg + ESPREG - P_STACKTOP)) = p_proc_current->task.regs.esp; //added by xw, 17/12/11
for( addr_lin=p_proc_current->task.memmap.stack_lin_base ; addr_lin > p_proc_current->task.memmap.stack_lin_limit ; addr_lin-=num_4K )
{
err_temp = lin_mapping_phy( addr_lin,//线性地址 //add by visual 2016.5.9
MAX_UNSIGNED_INT,//物理地址 //edit by visual 2016.5.19
p_proc_current->task.pid,//进程pid //edit by visual 2016.5.19
PG_P | PG_USU | PG_RWW,//页目录的属性位
PG_P | PG_USU | PG_RWW);//页表的属性位
if( err_temp!=0 )
{
disp_color_str("kernel_main Error:lin_mapping_phy",0x74);
return -1;
}
}
//堆 用户还没有申请所以没有分配只在PCB表里标示了线性起始位置
real_close(fd); //added by mingxuan 2019-5-23
if (Echo_Ehdr != NULL)
sys_free(Echo_Ehdr);
if (Echo_Phdr != NULL)
sys_free(Echo_Phdr);
//disp_color_str("\n[exec success:",0x72);//灰底绿字
//disp_color_str(path,0x72);//灰底绿字
//disp_color_str("]",0x72);//灰底绿字
return 0;
}
/*======================================================================*
* exec_elfcpy add by visual 2016.5.23
*elf中program到内存中
*======================================================================*/
static u32 exec_elfcpy(u32 fd,Elf32_Phdr Echo_Phdr,u32 attribute) // 这部分代码将来要移动到exec.c文件中包括下面exec()中的一部分
{
u32 lin_addr = Echo_Phdr.p_vaddr;
u32 lin_limit = Echo_Phdr.p_vaddr + Echo_Phdr.p_memsz;
u32 file_offset = Echo_Phdr.p_offset;
u32 file_limit = Echo_Phdr.p_offset + Echo_Phdr.p_filesz;
char ch;
//u32 pde_addr_phy = get_pde_phy_addr(p_proc_current->task.pid); //页目录物理地址 //delete by visual 2016.5.19
//u32 addr_phy = do_malloc(Echo_Phdr.p_memsz);//申请物理内存 //delete by visual 2016.5.19
for( ; lin_addr<lin_limit ; lin_addr++,file_offset++ )
{
lin_mapping_phy(lin_addr,MAX_UNSIGNED_INT,p_proc_current->task.pid,PG_P | PG_USU | PG_RWW/*说明*/,attribute);//说明PDE属性尽量为读写因为它要映射1024个物理页可能既有数据又有代码 //edit by visual 2016.5.19
if( file_offset<file_limit )
{//文件中还有数据,正常拷贝
//modified by xw, 18/5/30
// seek(file_offset);
// read(fd,&ch,1);
//fake_seek(file_offset); //deleted by mingxuan 2019-5-22
//real_lseek(fd, file_offset, SEEK_SET); //modified by mingxuan 2019-5-22
do_vlseek(fd, file_offset, SEEK_SET); //modified by mingxuan 2019-5-24
//fake_read(fd,&ch,1); //deleted by mingxuan 2019-5-22
//real_read(fd, &ch, 1); //modified by mingxuan 2019-5-22
do_vread(fd, &ch, 1); //modified by mingxuan 2019-5-24
//~xw
*((u8*)lin_addr) = ch;//memcpy((void*)lin_addr,&ch,1);
}
else
{
//已初始化数据段拷贝完毕剩下的是未初始化的数据段在内存中填0
*((u8*)lin_addr) = 0;//memset((void*)lin_addr,0,1);
}
}
return 0;
}
/*======================================================================*
* exec_load add by visual 2016.5.23
*elf的program复制文件信息
*======================================================================*/
static u32 exec_load(u32 fd,const Elf32_Ehdr* Echo_Ehdr,const Elf32_Phdr Echo_Phdr[])
{
u32 ph_num;
if( 0==Echo_Ehdr->e_phnum )
{
disp_color_str("exec_load: elf ERROR!",0x74);
return -1;
}
//我们还不能确定elf中一共能有几个program但就目前我们查看过的elf文件中只出现过两中program一种.textR-E和一种.dataRW-
for( ph_num=0; ph_num<Echo_Ehdr->e_phnum ; ph_num++ )
{
if( 0==Echo_Phdr[ph_num].p_memsz )
{//最后一个program
break;
}
if( Echo_Phdr[ph_num].p_flags == 0x5 || Echo_Phdr[ph_num].p_flags == 0x4) //101只读
{//.text
exec_elfcpy(fd,Echo_Phdr[ph_num],PG_P | PG_USU | PG_RWR);//进程代码段
p_proc_current->task.memmap.text_lin_base = Echo_Phdr[ph_num].p_vaddr;
p_proc_current->task.memmap.text_lin_limit = Echo_Phdr[ph_num].p_vaddr + Echo_Phdr[ph_num].p_memsz;
}
else if(Echo_Phdr[ph_num].p_flags == 0x6)//110读写
{//.data
exec_elfcpy(fd,Echo_Phdr[ph_num],PG_P | PG_USU | PG_RWW);//进程数据段
p_proc_current->task.memmap.data_lin_base = Echo_Phdr[ph_num].p_vaddr;
p_proc_current->task.memmap.data_lin_limit = Echo_Phdr[ph_num].p_vaddr + Echo_Phdr[ph_num].p_memsz;
}
else
{
disp_color_str("exec_load: unKnown elf'program!",0x74);
return -1;
}
}
return 0;
}
/*======================================================================*
* exec_init add by visual 2016.5.23
* 线
*======================================================================*/
static int exec_pcb_init(char* path)
{
char* p_regs; //point to registers in the new kernel stack, added by xw, 17/12/11
//名称 状态 特权级 寄存器
strcpy(p_proc_current->task.p_name, path); //名称
p_proc_current->task.stat = READY; //状态
p_proc_current->task.ldts[0].attr1 = DA_C | PRIVILEGE_USER << 5;//特权级修改为用户级
p_proc_current->task.ldts[1].attr1 = DA_DRW | PRIVILEGE_USER << 5;//特权级修改为用户级
p_proc_current->task.regs.cs = ((8 * 0) & SA_RPL_MASK & SA_TI_MASK)| SA_TIL | RPL_USER;
p_proc_current->task.regs.ds = ((8 * 1) & SA_RPL_MASK & SA_TI_MASK)| SA_TIL | RPL_USER;
p_proc_current->task.regs.es = ((8 * 1) & SA_RPL_MASK & SA_TI_MASK)| SA_TIL | RPL_USER;
p_proc_current->task.regs.fs = ((8 * 1) & SA_RPL_MASK & SA_TI_MASK)| SA_TIL | RPL_USER;
p_proc_current->task.regs.ss = ((8 * 1) & SA_RPL_MASK & SA_TI_MASK)| SA_TIL | RPL_USER;
p_proc_current->task.regs.gs = (SELECTOR_KERNEL_GS & SA_RPL_MASK)| RPL_USER;
p_proc_current->task.regs.eflags = 0x202; /* IF=1,bit2 永远是1 */
/***************copy registers data****************************/
//copy registers data to the bottom of the new kernel stack
//added by xw, 17/12/11
p_regs = (char*)(p_proc_current + 1);
p_regs -= P_STACKTOP;
memcpy(p_regs, (char*)p_proc_current, 18 * 4);
//进程表线性地址布局部分text、data已经在前面初始化了
p_proc_current->task.memmap.vpage_lin_base = VpageLinBase; //保留内存基址
p_proc_current->task.memmap.vpage_lin_limit = VpageLinBase; //保留内存界限
p_proc_current->task.memmap.heap_lin_base = HeapLinBase; //堆基址
p_proc_current->task.memmap.heap_lin_limit = HeapLinBase; //堆界限
p_proc_current->task.memmap.stack_child_limit = StackLinLimitMAX; //add by visual 2016.5.27
p_proc_current->task.memmap.stack_lin_base = StackLinBase; //栈基址
p_proc_current->task.memmap.stack_lin_limit = StackLinBase - 0x4000; //栈界限(使用时注意栈的生长方向)
p_proc_current->task.memmap.arg_lin_base = ArgLinBase; //参数内存基址
p_proc_current->task.memmap.arg_lin_limit = ArgLinBase; //参数内存界限
p_proc_current->task.memmap.kernel_lin_base = KernelLinBase; //内核基址
p_proc_current->task.memmap.kernel_lin_limit = KernelLinBase + KernelSize; //内核大小初始化为8M
//进程树属性,只要改两项,其余不用改
//p_proc_current->task.info.type = TYPE_PROCESS; //当前是进程还是线程
//p_proc_current->task.info.real_ppid = -1; //亲父进程,创建它的那个进程
//p_proc_current->task.info.ppid = -1; //当前父进程
//p_proc_current->task.info.child_p_num = 0; //子进程数量
//p_proc_current->task.info.child_process[NR_CHILD_MAX];//子进程列表
//p_proc_current->task.info.child_t_num = 0; //子线程数量
//p_proc_current->task.info.child_thread[NR_CHILD_MAX];//子线程列表
p_proc_current->task.info.text_hold = 1; //是否拥有代码
p_proc_current->task.info.data_hold = 1; //是否拥有数据
return 0;
}

910
kernel/fat32.c Normal file
View File

@ -0,0 +1,910 @@
/**********************************************************
* fat32.c //added by mingxuan 2019-5-17
***********************************************************/
#include "fat32.h"
#include "type.h"
#include "const.h"
#include "protect.h"
#include "string.h"
#include "proc.h"
#include "tty.h"
#include "console.h"
#include "global.h"
#include "proto.h"
#include "fs_const.h"
#include "hd.h"
#include "fs.h"
#include "fs_misc.h"
#include "string.h"
#include "stdio.h"
extern DWORD FAT_END;
extern DWORD TotalSectors;
extern WORD Bytes_Per_Sector;
extern BYTE Sectors_Per_Cluster;
extern WORD Reserved_Sector;
extern DWORD Sectors_Per_FAT;
extern UINT Position_Of_RootDir;
extern UINT Position_Of_FAT1;
extern UINT Position_Of_FAT2;
extern struct file_desc f_desc_table[NR_FILE_DESC];
CHAR VDiskPath[256]={0};
CHAR cur_path[256]={0};
u8* buf;
STATE state;
File f_desc_table_fat[NR_FILE_DESC];
static void load_disk();
static void mkfs_fat();
STATE DeleteDir(const char *dirname)
{
CHAR fullpath[256]={0};
CHAR parent[256]={0};
CHAR name[256]={0};
DWORD parentCluster=0,startCluster=0;
UINT tag=0;
STATE state;
ToFullPath((PCHAR)dirname,fullpath);
GetParentFromPath(fullpath,parent);
GetNameFromPath(fullpath,name);
state=IsFile(fullpath,&tag);
if(state!=OK)
{
return state;
}
if(tag==F)
{
return WRONGPATH;
}
state=PathToCluster(parent,&parentCluster);
if(state!=OK)
{
return state;
}
state=ClearRecord(parentCluster,name,&startCluster);
if(state!=OK)
{
return state;
}
DeleteAllRecord(startCluster);
return OK;
}
STATE CreateDir(const char *dirname)
{
Record record;
CHAR fullname[256]={0};
CHAR name[256]={0};
CHAR parent[256]={0};
DWORD parentCluster=0,startCluster=0,sectorIndex=0,off_in_sector=0;
STATE state;
ToFullPath((PCHAR)dirname,fullname);
GetNameFromPath(fullname,name);
GetParentFromPath(fullname,parent);
state=PathToCluster(parent,&parentCluster);
if(state!=OK)
{
return state;//找不到路径
}
state=FindSpaceInDir(parentCluster,name,&sectorIndex,&off_in_sector);
if(state!=OK)
{
return state;//虚拟磁盘空间不足
}
state=FindClusterForDir(&startCluster);
if(state!=OK)
{
return state;//虚拟磁盘空间不足
}
CreateRecord(name,0x10,startCluster,0,&record);
WriteRecord(record,sectorIndex,off_in_sector);
WriteFAT(1,&startCluster);//写FAT
CreateRecord(".",0x10,startCluster,0,&record);//准备目录项.的数据
sectorIndex=Reserved_Sector+2*Sectors_Per_FAT+(startCluster-2)*Sectors_Per_Cluster;
WriteRecord(record,sectorIndex,0);//写.目录项
CreateRecord("..",0x10,parentCluster,0,&record);//准备目录项..的数据
WriteRecord(record,sectorIndex,sizeof(Record));//写..目录项
//fflush(fp);
return OK;
}
STATE OpenDir(const char* dirname)
{
DWORD parentCluster=0;
CHAR fullpath[256]={0},parent[256]={0},name[256]={0};
Record record;
STATE state;
if(strcmp(dirname,".")==0)
{
return OK;
}else if(strcmp(dirname,"..")==0||strcmp(dirname,"\\")==0){
ChangeCurrentPath((PCHAR)dirname);
return OK;
}else{
if(IsFullPath((PCHAR)dirname))
{
strcpy(fullpath,(PCHAR)dirname);
GetParentFromPath(fullpath,parent);
if(strlen(parent)==0)//说明dirname是根目录
{
memset(cur_path,0,sizeof(cur_path));
strcpy(cur_path,fullpath);
cur_path[strlen(cur_path)]='\\';
return OK;
}
GetNameFromPath(fullpath,name);
}else{
MakeFullPath(cur_path,(PCHAR)dirname,fullpath);
strcpy(parent,cur_path);
strcpy(name,(PCHAR)dirname);
}
state=PathToCluster(parent,&parentCluster);
if(state!=OK)
{
return state;
}
state=ReadRecord(parentCluster,name,&record,NULL,NULL);
if(state!=OK)
{
return state;
}
if(record.proByte==(BYTE)0x10)
{
strcpy(cur_path,fullpath);
return OK;
}else{
return WRONGPATH;
}
}
return OK;
}
STATE ReadFile(int fd,void *buf, int length)
{
int size = 0;
PBYTE sector=NULL;
DWORD curSectorIndex=0,nextSectorIndex=0,off_in_sector=0,free_in_sector=0,readsize=0;
UINT isLastSector=0,tag=0;
PFile pfile = p_proc_current->task.filp[fd] ->fd_node.fd_file;
if(pfile->flag!=R && pfile->flag!=RW && pfile->flag!=(RW|C)) //modified by mingxuan 2019-5-18
{
return ACCESSDENIED;
}
disp_str("read:");
if(pfile->off>=pfile->size)
{
return 0;
}
sector = (PBYTE)K_PHY2LIN(sys_kmalloc(Bytes_Per_Sector*sizeof(BYTE)));
if(sector==NULL)
{
return SYSERROR;
}
GetFileOffset(pfile,&curSectorIndex,&off_in_sector,&isLastSector);
do
{
if(isLastSector)//当前的扇区是该文件的最后一个扇区
{
if(pfile->size%Bytes_Per_Sector==0)
{
free_in_sector=Bytes_Per_Sector-off_in_sector;
}else{
free_in_sector=pfile->size%Bytes_Per_Sector-off_in_sector;//最后一个扇区的剩余量
}
tag=1;//置跳出标志
}else{
free_in_sector=Bytes_Per_Sector-off_in_sector;//本扇区的剩余量
}
if(free_in_sector<length-(size))//缓冲区装不满
{
readsize=free_in_sector;
}else{//缓冲区能装满
readsize=length-(size);
tag=1;//置跳出标志
}
ReadSector(sector,curSectorIndex);
memcpy(buf+(size),sector+off_in_sector,readsize);
(size)+=readsize;
pfile->off+=readsize;
if(tag==1)//最后一个扇区或缓冲区装满了
{
break;
}else{//缓冲区还没装满并且还没到最后一个扇区
GetNextSector(pfile,curSectorIndex,&nextSectorIndex,&isLastSector);
curSectorIndex=nextSectorIndex;
off_in_sector=0;
}
}while(1);
sys_free(sector);
//pfile->off = 0;
return size;
}
STATE WriteFile(int fd, const void *buf, int length)
{
PBYTE sector=NULL;
DWORD clusterNum=0;
DWORD curSectorIndex=0,nextSectorIndex=0,off_in_sector=0,free_in_sector=0,off_in_buf=0;
UINT isLastSector=0;
STATE state;
PFile pfile = p_proc_current->task.filp[fd] ->fd_node.fd_file;
//PFile pfile = &f_desc_table_fat[0];
//if(pfile->flag!=W) //deleted by mingxuan 2019-5-18
if(pfile->flag!=W && pfile->flag!=RW && pfile->flag!=(RW|C) ) //modified by mingxuan 2019-5-18
{
return ACCESSDENIED;
}
sector = (PBYTE)K_PHY2LIN(sys_kmalloc(Bytes_Per_Sector*sizeof(BYTE)));
if(sector==NULL)
{
return SYSERROR;
}
if(pfile->start==0)//此文件是个空文件原来没有分配簇
{
state=AllotClustersForEmptyFile(pfile,length);//空间不足无法分配
if(state!=OK)
{
sys_free(sector);
return state;//虚拟磁盘空间不足
}
}else{
if(NeedMoreCluster(pfile,length,&clusterNum))
{
state=AddCluster(pfile->start,clusterNum);//空间不足
if(state!=OK)
{
sys_free(sector);
return state;//虚拟磁盘空间不足
}
}
}
GetFileOffset(pfile,&curSectorIndex,&off_in_sector,&isLastSector);
free_in_sector=Bytes_Per_Sector-off_in_sector;
while(free_in_sector<length-off_in_buf)//当前扇区的空闲空间放不下本次要写入的内容
{
ReadSector(sector,curSectorIndex);
memcpy(sector+off_in_sector,(void *)buf+off_in_buf,free_in_sector);
WriteSector(sector,curSectorIndex);
off_in_buf+=free_in_sector;
pfile->off+=free_in_sector;
GetNextSector(pfile,curSectorIndex,&nextSectorIndex,&isLastSector);
curSectorIndex=nextSectorIndex;
free_in_sector=Bytes_Per_Sector;
off_in_sector=0;
}
ReadSector(sector,curSectorIndex);
memcpy(sector+off_in_sector,(void *)buf+off_in_buf,length-off_in_buf);
WriteSector(sector,curSectorIndex);
pfile->off+=length-off_in_buf;
sys_free(sector);
//fflush(fp);
return OK;
}
STATE CloseFile(int fd)
{
PFile pfile;
pfile = p_proc_current->task.filp[fd] ->fd_node.fd_file;
DWORD curSectorIndex=0,curClusterIndex=0,nextClusterIndex=0,parentCluster=0;
UINT isLastSector=0;
Record record;
DWORD sectorIndex=0,off_in_sector=0;
//p_proc_current->task.filp_fat[fd] = 0;
f_desc_table_fat[fd].flag = 0;
p_proc_current->task.filp[fd]->flag = 0;
p_proc_current->task.filp[fd] = 0;
if(pfile->flag==R)
{
return OK;
}else{
if(pfile->off<pfile->size)
{
GetFileOffset(pfile,&curSectorIndex,NULL,&isLastSector);
if(isLastSector==0)
{
curSectorIndex=(curClusterIndex-Reserved_Sector-2*Sectors_Per_FAT)/Sectors_Per_Cluster+2;
GetNextCluster(curClusterIndex,&nextClusterIndex);
if(nextClusterIndex!=FAT_END)//说明当前簇不是此文件的最后一簇
{
WriteFAT(1,&curClusterIndex);//把当前簇设置为此文件的最后一簇
ClearFATs(nextClusterIndex);//清除此文件的多余簇
}
}
}
PathToCluster(pfile->parent,&parentCluster);
ReadRecord(parentCluster,pfile->name,&record,&sectorIndex,&off_in_sector);
record.highClusterNum=(WORD)(pfile->start>>16);
record.lowClusterNum=(WORD)(pfile->start&0x0000FFFF);
record.filelength=pfile->off;
WriteRecord(record,sectorIndex,off_in_sector);
}
return OK;
}
STATE OpenFile(const char *filename,int mode)
{
CHAR fullpath[256]={0};
CHAR parent[256]={0};
CHAR name[256]={0};
Record record;
DWORD parentCluster;
STATE state;
DWORD sectorIndex=0,off_in_sector=0; //added by mingxuan 2019-5-19
ToFullPath((PCHAR)filename,fullpath);
GetParentFromPath(fullpath,parent);
GetNameFromPath(fullpath,name);
state=PathToCluster(parent,&parentCluster);
disp_str("\nstate=");
disp_int(state);
if(state!=OK)
{
return -1;
}
//added by mingxuan 2019-5-19
state=FindSpaceInDir(parentCluster,name,&sectorIndex,&off_in_sector); //检测文件名是否存在
if(mode & O_CREAT) //如果用户使用了O_CREAT
{
if(state == NAMEEXIST) //文件存在使用O_CREAT是多余的继续执行OpenFile即可
{
disp_str("file exists, O_CREAT is no use!");
}
else //文件不存在需要使用O_CREAT先创建文件再执行OpenFile
{
CreateRecord(name,0x20,0,0,&record);
WriteRecord(record,sectorIndex,off_in_sector);//写目录项
}
}
else //用户没有使用O_CREAT
{
if(state != NAMEEXIST) //文件不存在需要使用O_CREAT用户没有使用则报错并返回-1表示路径有误
{
disp_str("no file, use O_CREAT!");
return -1;
}
else{} //文件存在使用O_CREAT是多余的继续执行OpenFile即可
}
//~mingxuan 2019-5-19
state=ReadRecord(parentCluster,name,&record,NULL,NULL);
disp_str("state=");
disp_int(state);
if(state!=OK)
{
disp_str("ReadRecord Fail!");
return -1;
}
int i;
int fd = -1;
for (i = 3; i < NR_FILES; i++) {
if (p_proc_current->task.filp[i] == 0) {
fd = i;
break;
}
}
if ((fd < 0) || (fd >= NR_FILES)) {
// panic("filp[] is full (PID:%d)", proc2pid(p_proc_current));
disp_str("filp[] is full (PID:");
disp_int(proc2pid(p_proc_current));
disp_str(")\n");
return -1;
}
//找一个未用的文件描述符
for (i = 0; i < NR_FILE_DESC; i++)
if ((f_desc_table[i].flag == 0))
break;
if (i >= NR_FILE_DESC) {
disp_str("f_desc_table[] is full (PID:");
disp_int(proc2pid(p_proc_current));
disp_str(")\n");
return -1;
}
p_proc_current->task.filp[fd] = &f_desc_table[i];
f_desc_table[i].flag = 1;
//找一个未用的FILE
for (i = 0; i < NR_FILE_DESC; i++)
if (f_desc_table_fat[i].flag == 0)
break;
if (i >= NR_FILE_DESC) {
disp_str("f_desc_table[] is full (PID:");
disp_int(proc2pid(p_proc_current));
disp_str(")\n");
}
//以下是给File结构体赋值
memset(f_desc_table_fat[i].parent,0,sizeof(f_desc_table_fat[i].parent));//初始化parent字段
memset(f_desc_table_fat[i].name,0,sizeof(f_desc_table_fat[i].name));//初始化name字段
strcpy(f_desc_table_fat[i].parent,parent);
strcpy(f_desc_table_fat[i].name,name);
f_desc_table_fat[i].start=(record.highClusterNum<<16)+record.lowClusterNum;
f_desc_table_fat[i].off=0;
f_desc_table_fat[i].size=record.filelength;
f_desc_table_fat[i].flag=mode;
// disp_str("flag:");
// deint(f_desc_table_fat[i].flag);
// disp_str("index:");
// deint(i);
p_proc_current->task.filp[fd] ->fd_node.fd_file = &f_desc_table_fat[i];
return fd;
}
STATE CreateFile(const char *filename)
{
Record record;
CHAR fullpath[256]={0};
CHAR parent[256]={0};
CHAR name[256]={0};
DWORD parentCluster=0,sectorIndex=0,off_in_sector=0;
STATE state;
ToFullPath((PCHAR)filename,fullpath);
GetParentFromPath(fullpath,parent);
GetNameFromPath((PCHAR)filename,name);
state=PathToCluster(parent,&parentCluster);
if(state!=OK)
{
return state;//找不到路径
}
state=FindSpaceInDir(parentCluster,name,&sectorIndex,&off_in_sector);
if(state != OK) {
return state;
}
CreateRecord(name,0x20,0,0,&record);
WriteRecord(record,sectorIndex,off_in_sector);//写目录项
return OK;
}
STATE DeleteFile(const char *filename)
{
CHAR fullpath[256]={0};
CHAR parent[256]={0};
CHAR name[256]={0};
DWORD parentCluster=0;
DWORD startCluster=0;
UINT tag=0;
STATE state;
ToFullPath((PCHAR)filename,fullpath);
GetParentFromPath(fullpath,parent);
GetNameFromPath(fullpath,name);
state=IsFile(fullpath,&tag);
if(state!=OK)
{
return state;
}
if(tag==D)
{
return WRONGPATH;
}
state=PathToCluster(parent,&parentCluster);
if(state!=OK)
{
return state;
}
state=ClearRecord(parentCluster,name,&startCluster);
if(state!=OK)
{
return state;
}
if(startCluster!=0)
{
ClearFATs(startCluster);
}
return OK;
}
STATE IsFile(PCHAR path,PUINT tag)
{
CHAR fullpath[256]={0};
CHAR parent[256]={0};
CHAR name[256]={0};
DWORD parentCluster=0;
Record record;
STATE state;
ToFullPath(path,fullpath);
GetParentFromPath(fullpath,parent);
GetNameFromPath(fullpath,name);
state=PathToCluster(parent,&parentCluster);
if(state!=OK)
{
return state;//找不到路径
}
state=ReadRecord(parentCluster,name,&record,NULL,NULL);
if(state!=OK)
{
return state;//找不到路径
}
if(record.proByte==0x10)
{
*tag=D;
}else{
*tag=F;
}
return OK;
}
void init_fs_fat()
{
disp_str("Initializing fat32 file system... \n");
buf = (u8*)K_PHY2LIN(sys_kmalloc(FSBUF_SIZE));
int fat32_dev = get_fs_dev(PRIMARY_MASTER, FAT32_TYPE); //added by mingxuan 2020-10-27
//load_disk(FAT_DEV); // deleted by mingxuan 2020-10-27
load_disk(fat32_dev); // modified by mingxuan 2020-10-27
if (TotalSectors == 0) {
mkfs_fat();
//load_disk(FAT_DEV); //deleted by mingxuan 2020-10-27
load_disk(fat32_dev); //modified by mingxuan 2020-10-27
}
int i;
for (i = 0; i < NR_FILE_DESC; ++i) {
f_desc_table_fat[i].flag = 0;
}
}
static void load_disk(int dev) {
MESSAGE driver_msg;
PCHAR cur="V:\\";
driver_msg.type = DEV_READ;
driver_msg.DEVICE = MINOR(dev);
driver_msg.POSITION = SECTOR_SIZE * 1;
driver_msg.BUF = buf;
driver_msg.CNT = SECTOR_SIZE;
driver_msg.PROC_NR = proc2pid(p_proc_current);///TASK_A
hd_rdwt(&driver_msg);
memcpy(&Bytes_Per_Sector,buf+11,2);
memcpy(&Sectors_Per_Cluster,buf+13,1);
memcpy(&Reserved_Sector,buf+14,2);
memcpy(&TotalSectors,buf+32,4);
memcpy(&Sectors_Per_FAT,buf+36,4);
Position_Of_RootDir=(Reserved_Sector+Sectors_Per_FAT*2)*Bytes_Per_Sector;
Position_Of_FAT1=Reserved_Sector*Bytes_Per_Sector;
Position_Of_FAT2=(Reserved_Sector+Sectors_Per_FAT)*Bytes_Per_Sector;
strcpy(cur_path,cur);
}
static void mkfs_fat() {
MESSAGE driver_msg;
int fat32_dev = get_fs_dev(PRIMARY_MASTER, FAT32_TYPE); //added by mingxuan 2020-10-27
/* get the geometry of ROOTDEV */
struct part_info geo;
driver_msg.type = DEV_IOCTL;
//driver_msg.DEVICE = MINOR(FAT_DEV); //deleted by mingxuan 2020-10-27
driver_msg.DEVICE = MINOR(fat32_dev); //modified by mingxuan 2020-10-27
driver_msg.REQUEST = DIOCTL_GET_GEO;
driver_msg.BUF = &geo;
driver_msg.PROC_NR = proc2pid(p_proc_current);
hd_ioctl(&driver_msg);
disp_str("dev size: ");
disp_int(geo.size);
disp_str(" sectors\n");
TotalSectors = geo.size;
DWORD jump=0x009058eb;//跳转指令占3个字节
DWORD oem[2]={0x4f44534d,0x302e3553};//厂商标志OS版本号:占8个字节
//以下是BPB的内容
WORD bytes_per_sector=512;//每扇区字节数占2个字节
WORD sectors_per_cluster=8;//每簇扇区数占1个字节
WORD reserved_sector=32;//保留扇区数占2个字节
WORD number_of_FAT=2;//FAT数占1个字节
BYTE mediaDescriptor=0xF8;
DWORD sectors_per_FAT=(TotalSectors*512-8192)/525312+1;//每FAT所占扇区数用此公式可以算出来占4个字节
DWORD root_cluster_number=2;//根目录簇号占4个字节
//以下是扩展BPB内容
CHAR volumeLabel[11]={'N','O',' ','N','A','M','E',' ',' ',' ',' '};//卷标占11个字节
CHAR systemID[8]={'F','A','T','3','2',' ',' ',' '};//系统IDFAT32系统中一般取为“FAT32”占8个字节
//以下是有效结束标志
DWORD end=0xaa55;
DWORD media_descriptor[2]={0x0ffffff8,0xffffffff};//FAT介质描述符
DWORD cluster_tag=0x0fffffff;//文件簇的结束单元标记
Record vLabel;//卷标的记录项。
// DWORD clearSize=sectors_per_cluster*bytes_per_sector-sizeof(Record);
char volumelabel[3] = "MZY";
memcpy(buf,&jump,3);//写入跳转指令:占3个字节(其实没有用)
memcpy(buf+3,oem,8);//厂商标志OS版本号:占8个字节
//以下是写 BPB
memcpy(buf+11,&bytes_per_sector,2);//每扇区字节数占2个字节
memcpy(buf+13,&sectors_per_cluster,1);//写入每簇扇区数占1个字节
memcpy(buf+14,&reserved_sector,2);//写入保留扇区数占2个字节
memcpy(buf+16,&number_of_FAT,1);//写入FAT数占1个字节
memcpy(buf+21,&mediaDescriptor,1);//写入媒体描述符
memcpy(buf+32,&TotalSectors,4);//写入总扇区数
memcpy(buf+36,&sectors_per_FAT,4);//写入每FAT所占扇区数占4个字节
memcpy(buf+44,&root_cluster_number,4);//写入根目录簇号占4个字节
//以下是写 扩展BPB
memcpy(buf+71,volumeLabel,11);//写卷标占11个字节
memcpy(buf+82,systemID,8);//系统IDFAT32系统中一般取为“FAT32”占8个字节
//由于引导代码对于本虚拟系统没有用,故省略
memcpy(buf+510,&end,2);
//WR_SECT_FAT(buf, 1); //deleted by mingxuan 2020-10-27
WR_SECT_FAT(fat32_dev, buf, 1); //modified by mingxuan 2020-10-27
//初始化FAT
memset(buf,0,SECTOR_SIZE);//写介质描述单元
memcpy(buf,media_descriptor,8);
memcpy(buf+8,&cluster_tag,4);//写根目录的簇号
//WR_SECT_FAT(buf, reserved_sector); // deleted by mingxuan 2020-10-27
WR_SECT_FAT(fat32_dev, buf, reserved_sector); // modified by mingxuan 2020-10-27
//初始化根目录
CreateRecord(volumelabel,0x08,0,0,&vLabel);//准备卷标的目录项的数据
memset(buf,0,SECTOR_SIZE);//将准备好的记录项数据写入虚拟硬盘
memcpy(buf,&vLabel,sizeof(Record));
//WR_SECT_FAT(buf, reserved_sector+2*sectors_per_FAT); // deleted by mingxuan 2020-10-27
WR_SECT_FAT(fat32_dev, buf, reserved_sector+2*sectors_per_FAT); // modified by mingxuan 2020-10-27
}
int rw_sector_fat(int io_type, int dev, u64 pos, int bytes, int proc_nr, void* buf)
{
MESSAGE driver_msg;
driver_msg.type = io_type;
driver_msg.DEVICE = MINOR(dev);
driver_msg.POSITION = pos;
driver_msg.CNT = bytes; /// hu is: 512
driver_msg.PROC_NR = proc_nr;
driver_msg.BUF = buf;
hd_rdwt(&driver_msg);
return 0;
}
int rw_sector_sched_fat(int io_type, int dev, int pos, int bytes, int proc_nr, void* buf)
{
MESSAGE driver_msg;
driver_msg.type = io_type;
driver_msg.DEVICE = MINOR(dev);
driver_msg.POSITION = pos;
driver_msg.CNT = bytes; /// hu is: 512
driver_msg.PROC_NR = proc_nr;
driver_msg.BUF = buf;
hd_rdwt_sched(&driver_msg);
return 0;
}
int sys_CreateFile(void *uesp)
{
state=CreateFile((PCHAR)(void *)get_arg(uesp, 1));
if(state==OK)
{
kprintf(" create file success");
}
else {
DisErrorInfo(state);
}
return state;
}
int sys_DeleteFile(void *uesp)
{
state=DeleteFile((PCHAR)(void *)get_arg(uesp, 1));
if(state==OK)
{
kprintf(" delete file success");
}
else {
DisErrorInfo(state);
}
return state;
}
int sys_OpenFile(void *uesp)
{
/* // state=OpenFile(get_arg(uesp, 1),
// get_arg(uesp, 2));
// if(state==OK)
// {
// kprintf("open file success");
// }
// else {
// DisErrorInfo(state);
// }
// return state;
state=OpenFile(get_arg(uesp, 1),
get_arg(uesp, 2));
kprintf(" open file success");
return state; */
return 0;
}
int sys_CloseFile(void *uesp)
{
state=CloseFile(get_arg(uesp, 1));
if(state==OK)
{
kprintf(" close file success");
}
else {
DisErrorInfo(state);
}
return state;
}
int sys_WriteFile(void *uesp)
{
state=WriteFile(get_arg(uesp, 1),
(BYTE *)(void *)get_arg(uesp, 2),
get_arg(uesp, 3));
if(state==OK)
{
kprintf(" write file success");
}
else {
DisErrorInfo(state);
}
return state;
}
int sys_ReadFile(void *uesp)
{
// state=ReadFile(get_arg(uesp, 1),
// get_arg(uesp, 2),
// get_arg(uesp, 3),
// get_arg(uesp, 4));
// if(state==OK)
// {
// //debug("read file success");
// debug(" read file success");
// }
// else {
// DisErrorInfo(state);
// }
// return state;
return 0;
}
int sys_OpenDir(void *uesp)
{
// state=OpenDir(get_arg(uesp, 1));
// if(state==OK)
// {
// //debug("open dir success");
// debug(" open dir success");
// }
// else {
// DisErrorInfo(state);
// }
// return state;
return 0;
}
int sys_CreateDir(void *uesp)
{
// state=CreateDir(get_arg(uesp, 1));
// if(state==OK)
// {
// //debug("create dir success");
// debug(" create dir success");
// }
// else {
// DisErrorInfo(state);
// }
// return state;
return 0;
}
int sys_DeleteDir(void *uesp)
{
// state=DeleteDir(get_arg(uesp, 1));
// if(state==OK)
// {
// debug("delete dir success");
// debug(" delete dir success");
// }
// else {
// DisErrorInfo(state);
// }
// return state;
return 0;
}
int sys_ListDir(void *uesp) {
// DArray *array=NULL;
// char *s = get_arg(uesp, 1);
// CHAR temp[256]={0};
// UINT tag=0;
// array = InitDArray(10, 10);
// memset(temp, 0, sizeof(temp));
// if (strlen(s) != 0)
// {
// strcpy(temp,s);
// if(IsFile(temp,&tag))
// {
// if(tag==1)
// {
// printf("不是目录的路径\n\n");
// }
// }
// }
// else {
// GetCurrentPath(temp);
// }
// state=ListAll(temp, array);
// if(state==OK)
// {
// DirCheckup(array);
// }else {
// DisErrorInfo(state);
// disp_str("\n");
// }
// DestroyDArray(array);
return 0;
}
void DisErrorInfo(STATE state)
{
if(state==SYSERROR)
{
disp_str(" system error\n");
}
else if(state==VDISKERROR)
{
disp_str(" disk error\n");
}
else if(state==INSUFFICIENTSPACE)
{
disp_str(" no much space\n");
}
else if(state==WRONGPATH)
{
disp_str(" path error\n");
}
else if(state==NAMEEXIST)
{
disp_str(" name exists\n");
}
else if(state==ACCESSDENIED)
{
disp_str(" deny access\n");
}
else
{
disp_str(" unknown error\n");
}
}

51
kernel/file.c Normal file
View File

@ -0,0 +1,51 @@
/********************************************
* file.c //add by visual 2016.5.17
*
***********************************************/
#include "type.h"
#include "const.h"
#include "protect.h"
#include "string.h"
#include "proc.h"
#include "global.h"
#include "proto.h"
// #define BaseOfEchoFilePhyAddr (K_PHY2LIN(0x7e00)) //目前就这一个文件
// static u32 position=0;
// /*****************************************************
// * open //add by visual 2016.5.17
// *目前没有什么用的open
// ******************************************************/
// // u32 open(char* path,char* mode)
// u32 fake_open(char* path,char* mode) //modified by xw, 18/5/30
// {
// position = 0;
// return 0;
// }
// /******************************************************
// * read //add by visual 2016.5.17
// ********************************************************/
// // u32 read(u32 fd,void* buffer,u32 size)
// u32 fake_read(u32 fd,void* buffer,u32 size) //modified by xw, 18/5/30
// {
// u32 addr_lin = BaseOfEchoFilePhyAddr + position;
// position += size;
// memcpy(buffer,(void*)addr_lin,size);
// return 0;
// }
// /******************************************************
// * seek //add by visual 2016.5.17
// *******************************************************/
// // u32 seek(u32 pos)
// u32 fake_seek(u32 pos) //modified by xw, 18/5/30
// {
// position = pos;
// return 0;
// }

238
kernel/fork.c Normal file
View File

@ -0,0 +1,238 @@
/*****************************************************
* fork.c //add by visual 2016.5.25
*fork()sys_fork()
********************************************************/
#include "type.h"
#include "const.h"
#include "protect.h"
#include "string.h"
#include "proc.h"
#include "global.h"
#include "proto.h"
static int fork_mem_cpy(u32 ppid,u32 pid);
static int fork_pcb_cpy(PROCESS* p_child);
static int fork_update_info(PROCESS* p_child);
/**********************************************************
* sys_fork //add by visual 2016.5.25
*sys_fork的具体实现部分
*************************************************************/
int sys_fork()
{
PROCESS* p_child;
char* p_reg; //point to a register in the new kernel stack, added by xw, 17/12/11
/*****************申请空白PCB表**********************/
p_child = alloc_PCB();
if( 0==p_child )
{
disp_color_str("PCB NULL,fork faild!",0x74);
return -1;
}
else
{
/****************初始化子进程高端地址页表(内核部分)***********************///这个页表可以复制父进程的!
init_page_pte(p_child->task.pid); //这里面已经填写了该进程的cr3寄存器变量
/************复制父进程的PCB部分内容保留了自己的标识信息**************/
fork_pcb_cpy(p_child);
/**************复制线性内存,包括堆、栈、代码数据等等***********************/
fork_mem_cpy(p_proc_current->task.pid,p_child->task.pid);
/**************更新进程树标识info信息************************/
fork_update_info(p_child);
/************修改子进程的名字***************/
strcpy(p_child->task.p_name,"fork"); // 所有的子进程都叫fork
/*************子进程返回值在其eax寄存器***************/
p_child->task.regs.eax = 0;//return child with 0
p_reg = (char*)(p_child + 1); //added by xw, 17/12/11
*((u32*)(p_reg + EAXREG - P_STACKTOP)) = p_child->task.regs.eax; //added by xw, 17/12/11
/****************用户进程数+1****************************/
u_proc_sum += 1;
disp_color_str("[fork success:",0x72);
disp_color_str(p_proc_current->task.p_name,0x72);
disp_color_str("]",0x72);
//anything child need is prepared now, set its state to ready. added by xw, 17/12/11
p_child->task.stat = READY;
}
return p_child->task.pid;
}
/**********************************************************
* fork_mem_cpy //add by visual 2016.5.24
*
*************************************************************/
static int fork_mem_cpy(u32 ppid,u32 pid)
{
u32 addr_lin;
//复制代码,代码是共享的,直接将物理地址挂载在子进程的页表上
for(addr_lin = p_proc_current->task.memmap.text_lin_base ; addr_lin < p_proc_current->task.memmap.text_lin_limit ; addr_lin+=num_4K )
{
lin_mapping_phy(addr_lin,//线性地址
get_page_phy_addr(ppid,addr_lin),//物理地址为MAX_UNSIGNED_INT时由该函数自动分配物理内存
pid,//要挂载的进程的pid子进程的pid
PG_P | PG_USU | PG_RWW,//页目录属性,一般都为可读写
PG_P | PG_USU | PG_RWR);//页表属性,代码是只读的
}
//复制数据,数据不共享,子进程需要申请物理地址,并复制过来
for(addr_lin = p_proc_current->task.memmap.data_lin_base ; addr_lin < p_proc_current->task.memmap.data_lin_limit ; addr_lin+=num_4K )
{
lin_mapping_phy(SharePageBase,0,ppid,PG_P | PG_USU | PG_RWW,0);//使用前必须清除这个物理页映射
lin_mapping_phy(SharePageBase,MAX_UNSIGNED_INT,ppid,PG_P | PG_USU | PG_RWW,PG_P | PG_USU | PG_RWW);//利用父进程的共享页申请物理页
memcpy((void*)SharePageBase,(void*)(addr_lin&0xFFFFF000),num_4K);//将数据复制到物理页上,注意这个地方是强制一页一页复制的
lin_mapping_phy(addr_lin,//线性地址
get_page_phy_addr(ppid,SharePageBase),//物理地址,获取共享页的物理地址,填进子进程页表
pid,//要挂载的进程的pid子进程的pid
PG_P | PG_USU | PG_RWW,//页目录属性,一般都为可读写
PG_P | PG_USU | PG_RWW);//页表属性,数据是可读写的
}
//复制保留内存,保留内存不共享,子进程需要申请物理地址,并复制过来
for(addr_lin = p_proc_current->task.memmap.vpage_lin_base ; addr_lin < p_proc_current->task.memmap.vpage_lin_limit ; addr_lin+=num_4K )
{
lin_mapping_phy(SharePageBase,0,ppid,PG_P | PG_USU | PG_RWW,0);//使用前必须清除这个物理页映射
lin_mapping_phy(SharePageBase,MAX_UNSIGNED_INT,ppid,PG_P | PG_USU | PG_RWW,PG_P | PG_USU | PG_RWW);//利用父进程的共享页申请物理页
memcpy((void*)SharePageBase,(void*)(addr_lin&0xFFFFF000),num_4K);//将数据复制到物理页上,注意这个地方是强制一页一页复制的
lin_mapping_phy(addr_lin,//线性地址
get_page_phy_addr(ppid,SharePageBase),//物理地址,获取共享页的物理地址,填进子进程页表
pid,//要挂载的进程的pid子进程的pid
PG_P | PG_USU | PG_RWW,//页目录属性,一般都为可读写
PG_P | PG_USU | PG_RWW);//页表属性,保留内存是可读写的
}
//复制堆,堆不共享,子进程需要申请物理地址,并复制过来
for(addr_lin = p_proc_current->task.memmap.heap_lin_base ; addr_lin < p_proc_current->task.memmap.heap_lin_limit ; addr_lin+=num_4K )
{
lin_mapping_phy(SharePageBase,0,ppid,PG_P | PG_USU | PG_RWW,0);//使用前必须清除这个物理页映射
lin_mapping_phy(SharePageBase,MAX_UNSIGNED_INT,ppid,PG_P | PG_USU | PG_RWW,PG_P | PG_USU | PG_RWW);//利用父进程的共享页申请物理页
memcpy((void*)SharePageBase,(void*)(addr_lin&0xFFFFF000),num_4K);//将数据复制到物理页上,注意这个地方是强制一页一页复制的
lin_mapping_phy(addr_lin,//线性地址
get_page_phy_addr(ppid,SharePageBase),//物理地址,获取共享页的物理地址,填进子进程页表
pid,//要挂载的进程的pid子进程的pid
PG_P | PG_USU | PG_RWW,//页目录属性,一般都为可读写
PG_P | PG_USU | PG_RWW);//页表属性,堆是可读写的
}
//复制栈,栈不共享,子进程需要申请物理地址,并复制过来(注意栈的复制方向)
for(addr_lin = p_proc_current->task.memmap.stack_lin_base ; addr_lin > p_proc_current->task.memmap.stack_lin_limit ; addr_lin-=num_4K )
{
lin_mapping_phy(SharePageBase,0,ppid,PG_P | PG_USU | PG_RWW,0);//使用前必须清除这个物理页映射
lin_mapping_phy(SharePageBase,MAX_UNSIGNED_INT,ppid,PG_P | PG_USU | PG_RWW,PG_P | PG_USU | PG_RWW);//利用父进程的共享页申请物理页
memcpy((void*)SharePageBase,(void*)(addr_lin&0xFFFFF000),num_4K);//将数据复制到物理页上,注意这个地方是强制一页一页复制的
lin_mapping_phy(addr_lin,//线性地址
get_page_phy_addr(ppid,SharePageBase),//物理地址,获取共享页的物理地址,填进子进程页表
pid,//要挂载的进程的pid子进程的pid
PG_P | PG_USU | PG_RWW,//页目录属性,一般都为可读写
PG_P | PG_USU | PG_RWW);//页表属性,栈是可读写的
}
//复制参数区,参数区不共享,子进程需要申请物理地址,并复制过来
for(addr_lin = p_proc_current->task.memmap.arg_lin_base ; addr_lin < p_proc_current->task.memmap.arg_lin_limit ; addr_lin+=num_4K )
{
lin_mapping_phy(SharePageBase,0,ppid,PG_P | PG_USU | PG_RWW,0);//使用前必须清除这个物理页映射
lin_mapping_phy(SharePageBase,MAX_UNSIGNED_INT,ppid,PG_P | PG_USU | PG_RWW,PG_P | PG_USU | PG_RWW);//利用父进程的共享页申请物理页
memcpy((void*)SharePageBase,(void*)(addr_lin&0xFFFFF000),num_4K);//将数据复制到物理页上,注意这个地方是强制一页一页复制的
lin_mapping_phy(addr_lin,//线性地址
get_page_phy_addr(ppid,SharePageBase),//物理地址,获取共享页的物理地址,填进子进程页表
pid,//要挂载的进程的pid子进程的pid
PG_P | PG_USU | PG_RWW,//页目录属性,一般都为可读写
PG_P | PG_USU | PG_RWW);//页表属性,参数区是可读写的
}
return 0;
}
/**********************************************************
* fork_pcb_cpy //add by visual 2016.5.26
*PCB表
*************************************************************/
static int fork_pcb_cpy(PROCESS* p_child)
{
int pid;
u32 eflags,selector_ldt,cr3_child;
char* p_reg; //point to a register in the new kernel stack, added by xw, 17/12/11
// char* esp_save_int, esp_save_context; //It's not what you want! damn it.
char *esp_save_int, *esp_save_context; //use to save corresponding field in child's PCB.
//暂存标识信息
pid = p_child->task.pid;
//eflags = p_child->task.regs.eflags;
p_reg = (char*)(p_child + 1); //added by xw, 17/12/11
eflags = *((u32*)(p_reg + EFLAGSREG - P_STACKTOP)); //added by xw, 17/12/11
selector_ldt = p_child->task.ldt_sel;
cr3_child = p_child->task.cr3;
//复制PCB内容
//modified by xw, 17/12/11
//modified begin
//*p_child = *p_proc_current;
//esp_save_int and esp_save_context must be saved, because the child and the parent
//use different kernel stack! And these two are importent to the child's initial running.
//Added by xw, 18/4/21
esp_save_int = p_child->task.esp_save_int;
esp_save_context = p_child->task.esp_save_context;
p_child->task = p_proc_current->task;
//note that syscalls can be interrupted now! the state of child can only be setted
//READY when anything else is well prepared. if an interruption happens right here,
//an error will still occur.
p_child->task.stat = IDLE;
p_child->task.esp_save_int = esp_save_int; //esp_save_int of child must be restored!!
p_child->task.esp_save_context = esp_save_context; //same above
// p_child->task.esp_save_context = (char*)(p_child + 1) - P_STACKTOP - 4 * 6;
memcpy(((char*)(p_child + 1) - P_STACKTOP), ((char*)(p_proc_current + 1) - P_STACKTOP), 18 * 4);
//modified end
//恢复标识信息
p_child->task.pid = pid;
//p_child->task.regs.eflags = eflags;
p_reg = (char*)(p_child + 1); //added by xw, 17/12/11
*((u32*)(p_reg + EFLAGSREG - P_STACKTOP)) = eflags; //added by xw, 17/12/11
p_child->task.ldt_sel = selector_ldt;
p_child->task.cr3 = cr3_child;
return 0;
}
/**********************************************************
* fork_update_info //add by visual 2016.5.26
*info
*************************************************************/
static int fork_update_info(PROCESS* p_child)
{
/************更新父进程的info***************/
//p_proc_current->task.info.type; //当前是进程还是线程
//p_proc_current->task.info.real_ppid; //亲父进程,创建它的那个进程
//p_proc_current->task.info.ppid; //当前父进程
p_proc_current->task.info.child_p_num += 1; //子进程数量
p_proc_current->task.info.child_process[p_proc_current->task.info.child_p_num-1] = p_child->task.pid;//子进程列表
//p_proc_current->task.info.child_t_num; //子线程数量
//p_proc_current->task.info.child_thread[NR_CHILD_MAX];//子线程列表
//p_proc_current->task.text_hold; //是否拥有代码
//p_proc_current->task.data_hold; //是否拥有数据
/************更新子进程的info***************/
p_child->task.info.type = p_proc_current->task.info.type; //当前进程属性跟父进程一样
p_child->task.info.real_ppid = p_proc_current->task.pid; //亲父进程,创建它的那个进程
p_child->task.info.ppid = p_proc_current->task.pid; //当前父进程
p_child->task.info.child_p_num = 0; //子进程数量
//p_child->task.info.child_process[NR_CHILD_MAX] = pid;//子进程列表
p_child->task.info.child_t_num = 0; //子线程数量
//p_child->task.info.child_thread[NR_CHILD_MAX];//子线程列表
p_child->task.info.text_hold = 0; //是否拥有代码,子进程不拥有代码
p_child->task.info.data_hold = 1; //是否拥有数据,子进程拥有数据
return 0;
}

1560
kernel/fs.c Normal file

File diff suppressed because it is too large Load Diff

85
kernel/global.c Normal file
View File

@ -0,0 +1,85 @@
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
global.c
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Forrest Yu, 2005
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
/*
* To make things more direct. In the headers below,
* the variable will be defined here.
* added by xw, 18/6/17
*/
// #define GLOBAL_VARIABLES_HERE
#include "const.h"
#include "type.h"
#include "protect.h"
#include "proc.h"
#include "global.h"
#include "proto.h"
#include "fs_const.h"
#include "hd.h"
#include "fs.h"
#include "fat32.h" //added by mingxuan 2019-5-17
#include "vfs.h" //added by mingxuan 2019-5-17
int kernel_initial;
int ticks;
int disp_pos;
u8 gdt_ptr[6];
DESCRIPTOR gdt[GDT_SIZE];
u8 idt_ptr[6];
GATE idt[IDT_SIZE];
u32 k_reenter;
int u_proc_sum;
TSS tss;
PROCESS *p_proc_current;
PROCESS *p_proc_next;
u32 cr3_ready;
/* save the execution environment of each cpu, which doesn't belong to any process.
* added by xw, 18/6/1
*/
PROCESS cpu_table[NR_CPUS];
PROCESS proc_table[NR_PCBS]; // edit by visual 2016.4.5
TASK task_table[NR_TASKS] = {
{hd_service, STACK_SIZE_TASK, "hd_service"},
{task_tty, STACK_SIZE_TASK, "task_tty"}}; // added by xw, 18/8/27
irq_handler irq_table[NR_IRQ];
system_call sys_call_table[NR_SYS_CALL] = {
sys_get_ticks, // 1st
sys_get_pid, // add by visual 2016.4.6
sys_kmalloc, // add by visual 2016.4.6
sys_kmalloc_4k, // add by visual 2016.4.7
sys_malloc, // add by visual 2016.4.7 //5th
sys_malloc_4k, // add by visual 2016.4.7
sys_free, // add by visual 2016.4.7
sys_free_4k, // add by visual 2016.4.7
sys_fork, // add by visual 2016.4.8
sys_pthread, // add by visual 2016.4.11 //10th
sys_udisp_int, // add by visual 2016.5.16
sys_udisp_str, // add by visual 2016.5.16
sys_exec, // add by visual 2016.5.16
sys_yield, // added by xw
sys_sleep, // added by xw //15th
sys_print_E, // added by xw
sys_print_F, // added by xw
sys_open, // added by xw, 18/6/18
sys_close, // added by xw, 18/6/18
sys_read, // added by xw, 18/6/18 //20th
sys_write, // added by xw, 18/6/18
sys_lseek, // added by xw, 18/6/18
sys_unlink, // added by xw, 18/6/19 //23th
sys_create, // added by mingxuan 2019-5-17
sys_delete, // added by mingxuan 2019-5-17
sys_opendir, // added by mingxuan 2019-5-17
sys_createdir, // added by mingxuan 2019-5-17
sys_deletedir // added by mingxuan 2019-5-17
};
TTY tty_table[NR_CONSOLES]; // added by mingxuan 2019-5-19
CONSOLE console_table[NR_CONSOLES]; // added by mingxuan 2019-5-19

672
kernel/hd.c Normal file
View File

@ -0,0 +1,672 @@
/// zcr copy whole file from Orange's and the file was modified.
/*************************************************************************//**
*****************************************************************************
* @file hd.c
* @brief Hard disk (winchester) driver.
* The `device nr' in this file means minor device nr.
* @author Forrest Y. Yu
* @date 2005~2008
*****************************************************************************
*****************************************************************************/
#include "type.h"
#include "const.h"
#include "protect.h"
#include "string.h"
#include "proc.h"
#include "global.h"
#include "proto.h"
#include "fs_const.h"
#include "hd.h"
#include "fs.h"
#include "fs_misc.h"
#include "x86.h"
#include "stdio.h"
#include "assert.h"
struct part_ent PARTITION_ENTRY;
//added by xw, 18/8/28
static HDQueue hdque;
static volatile int hd_int_waiting_flag;
static u8 hd_status;
static u8 hdbuf[SECTOR_SIZE * 2];
//static struct hd_info hd_info[1];
struct hd_info hd_info[1]; //modified by mingxuan 2020-10-27
static void init_hd_queue(HDQueue *hdq);
static void in_hd_queue(HDQueue *hdq, RWInfo *p);
static int out_hd_queue(HDQueue *hdq, RWInfo **p);
static void hd_rdwt_real(RWInfo *p);
static void get_part_table(int drive, int sect_nr, struct part_ent *entry);
static void partition(int device, int style);
static void print_hdinfo(struct hd_info *hdi);
static void hd_identify(int drive);
static void print_identify_info(u16 *hdinfo);
static void hd_cmd_out(struct hd_cmd *cmd);
static void inform_int();
static void interrupt_wait();
static void hd_handler(int irq);
static int waitfor(int mask, int val, int timeout);
//~xw
#define DRV_OF_DEV(dev) (dev <= MAX_PRIM ? \
dev / NR_PRIM_PER_DRIVE : \
(dev - MINOR_hd1a) / NR_SUB_PER_DRIVE)
/*****************************************************************************
* init_hd
*****************************************************************************/
/**
* <Ring 1> Check hard drive, set IRQ handler, enable IRQ and initialize data
* structures.
*****************************************************************************/
void init_hd()
{
int i;
put_irq_handler(AT_WINI_IRQ, hd_handler);
enable_irq(CASCADE_IRQ);
enable_irq(AT_WINI_IRQ);
for (i = 0; i < (sizeof(hd_info) / sizeof(hd_info[0])); i++)
memset(&hd_info[i], 0, sizeof(hd_info[0]));
hd_info[0].open_cnt = 0;
init_hd_queue(&hdque);
}
/*****************************************************************************
* hd_open
*****************************************************************************/
/**
* <Ring 1> This routine handles DEV_OPEN message. It identify the drive
* of the given device and read the partition table of the drive if it
* has not been read.
*
* @param device The device to be opened.
*****************************************************************************/
// void hd_open(int device) //no need for int device, mingxuan
void hd_open(int drive) //modified by mingxuan 2020-10-27
{
kprintf("Read hd information... ");
/* Get the number of drives from the BIOS data area */
// u8 * pNrDrives = (u8*)(0x475);
hd_identify(drive);
if (hd_info[drive].open_cnt++ == 0) {
partition(drive * (NR_PART_PER_DRIVE + 1), P_PRIMARY);
print_hdinfo(&hd_info[drive]);
}
}
/*****************************************************************************
* hd_close
*****************************************************************************/
/**
* <Ring 1> This routine handles DEV_CLOSE message.
*
* @param device The device to be opened.
*****************************************************************************/
void hd_close(int device)
{
int drive = DRV_OF_DEV(device);
hd_info[drive].open_cnt--;
}
/*****************************************************************************
* hd_rdwt
*****************************************************************************/
/**
* <Ring 1> This routine handles DEV_READ and DEV_WRITE message.
*
* @param p Message ptr.
*****************************************************************************/
void hd_rdwt(MESSAGE * p)
{
int drive = DRV_OF_DEV(p->DEVICE);
u64 pos = p->POSITION;
//We only allow to R/W from a SECTOR boundary:
u32 sect_nr = (u32)(pos >> SECTOR_SIZE_SHIFT); // pos / SECTOR_SIZE
int logidx = (p->DEVICE - MINOR_hd1a) % NR_SUB_PER_DRIVE;
sect_nr += p->DEVICE < MAX_PRIM ?
hd_info[drive].primary[p->DEVICE].base :
hd_info[drive].logical[logidx].base;
struct hd_cmd cmd;
cmd.features = 0;
cmd.count = (p->CNT + SECTOR_SIZE - 1) / SECTOR_SIZE;
cmd.lba_low = sect_nr & 0xFF;
cmd.lba_mid = (sect_nr >> 8) & 0xFF;
cmd.lba_high = (sect_nr >> 16) & 0xFF;
cmd.device = MAKE_DEVICE_REG(1, drive, (sect_nr >> 24) & 0xF);
cmd.command = (p->type == DEV_READ) ? ATA_READ : ATA_WRITE;
hd_cmd_out(&cmd);
int bytes_left = p->CNT;
void * la = (void*)va2la(p->PROC_NR, p->BUF);
while (bytes_left) {
int bytes = min(SECTOR_SIZE, bytes_left);
if (p->type == DEV_READ) {
interrupt_wait();
insw(REG_DATA, hdbuf, SECTOR_SIZE);
memcpy(la, hdbuf, bytes);
}
else {
if (!waitfor(STATUS_DRQ, STATUS_DRQ, HD_TIMEOUT))
("hd writing error.");
memcpy(hdbuf, la, bytes);
outsw(REG_DATA, hdbuf, SECTOR_SIZE);
interrupt_wait();
}
bytes_left -= SECTOR_SIZE;
la += SECTOR_SIZE;
}
}
//added by xw, 18/8/26
void hd_service()
{
RWInfo *rwinfo;
while(1)
{
//the hd queue is not empty when out_hd_queue return 1.
while(out_hd_queue(&hdque, &rwinfo))
{
hd_rdwt_real(rwinfo);
rwinfo->proc->task.stat = READY;
}
yield();
}
}
static void hd_rdwt_real(RWInfo *p)
{
int drive = DRV_OF_DEV(p->msg->DEVICE);
u64 pos = p->msg->POSITION;
//We only allow to R/W from a SECTOR boundary:
u32 sect_nr = (u32)(pos >> SECTOR_SIZE_SHIFT); // pos / SECTOR_SIZE
int logidx = (p->msg->DEVICE - MINOR_hd1a) % NR_SUB_PER_DRIVE;
sect_nr += p->msg->DEVICE < MAX_PRIM ?
hd_info[drive].primary[p->msg->DEVICE].base :
hd_info[drive].logical[logidx].base;
struct hd_cmd cmd;
cmd.features = 0;
cmd.count = (p->msg->CNT + SECTOR_SIZE - 1) / SECTOR_SIZE;
cmd.lba_low = sect_nr & 0xFF;
cmd.lba_mid = (sect_nr >> 8) & 0xFF;
cmd.lba_high = (sect_nr >> 16) & 0xFF;
cmd.device = MAKE_DEVICE_REG(1, drive, (sect_nr >> 24) & 0xF);
cmd.command = (p->msg->type == DEV_READ) ? ATA_READ : ATA_WRITE;
hd_cmd_out(&cmd);
int bytes_left = p->msg->CNT;
void *la = p->kbuf; //attention here!
while (bytes_left) {
int bytes = min(SECTOR_SIZE, bytes_left);
if (p->msg->type == DEV_READ) {
interrupt_wait();
insw(REG_DATA, hdbuf, SECTOR_SIZE);
memcpy(la, hdbuf, bytes);
}
else {
if (!waitfor(STATUS_DRQ, STATUS_DRQ, HD_TIMEOUT))
panic("hd writing error.");
memcpy(hdbuf, la, bytes);
outsw(REG_DATA, hdbuf, SECTOR_SIZE);
interrupt_wait();
}
bytes_left -= SECTOR_SIZE;
la += SECTOR_SIZE;
}
}
void hd_rdwt_sched(MESSAGE *p)
{
RWInfo rwinfo;
struct memfree hdque_buf;
int size = p->CNT;
void *buffer;
buffer = (void*)K_PHY2LIN(sys_kmalloc(size));
rwinfo.msg = p;
rwinfo.kbuf = buffer;
rwinfo.proc = p_proc_current;
if (p->type == DEV_READ) {
in_hd_queue(&hdque, &rwinfo);
p_proc_current->task.channel = &hdque;
p_proc_current->task.stat = SLEEPING;
sched();
memcpy(p->BUF, buffer, p->CNT);
} else {
memcpy(buffer, p->BUF, p->CNT);
in_hd_queue(&hdque, &rwinfo);
p_proc_current->task.channel = &hdque;
p_proc_current->task.stat = SLEEPING;
sched();
}
hdque_buf.addr = K_LIN2PHY((u32)buffer);
hdque_buf.size = size;
sys_free(&hdque_buf);
}
void init_hd_queue(HDQueue *hdq)
{
hdq->front = hdq->rear = NULL;
}
static void in_hd_queue(HDQueue *hdq, RWInfo *p)
{
p->next = NULL;
if(hdq->rear == NULL) { //put in the first node
hdq->front = hdq->rear = p;
} else {
hdq->rear->next = p;
hdq->rear = p;
}
}
static int out_hd_queue(HDQueue *hdq, RWInfo **p)
{
if (hdq->rear == NULL)
return 0; //empty
*p = hdq->front;
if (hdq->front == hdq->rear) { //put out the last node
hdq->front = hdq->rear = NULL;
} else {
hdq->front = hdq->front->next;
}
return 1; //not empty
}
//~xw
/*****************************************************************************
* hd_ioctl
*****************************************************************************/
/**
* <Ring 1> This routine handles the DEV_IOCTL message.
*
* @param p Ptr to the MESSAGE.
*****************************************************************************/
void hd_ioctl(MESSAGE * p)
{
int device = p->DEVICE;
int drive = DRV_OF_DEV(device);
struct hd_info * hdi = &hd_info[drive];
if (p->REQUEST == DIOCTL_GET_GEO) {
void * dst = va2la(p->PROC_NR, p->BUF);
void * src = va2la(proc2pid(p_proc_current),
device < MAX_PRIM ?
&hdi->primary[device] :
&hdi->logical[(device - MINOR_hd1a) %
NR_SUB_PER_DRIVE]);
memcpy(dst, src, sizeof(struct part_info));
}
else {
// assert(0);
}
}
/*****************************************************************************
* get_part_table
*****************************************************************************/
/**
* <Ring 1> Get a partition table of a drive.
*
* @param drive Drive nr (0 for the 1st disk, 1 for the 2nd, ...)n
* @param sect_nr The sector at which the partition table is located.
* @param entry Ptr to part_ent struct.
*****************************************************************************/
static void get_part_table(int drive, int sect_nr, struct part_ent * entry)
{
struct hd_cmd cmd;
cmd.features = 0;
cmd.count = 1;
cmd.lba_low = sect_nr & 0xFF;
cmd.lba_mid = (sect_nr >> 8) & 0xFF;
cmd.lba_high = (sect_nr >> 16) & 0xFF;
cmd.device = MAKE_DEVICE_REG(1, /* LBA mode*/
drive,
(sect_nr >> 24) & 0xF);
cmd.command = ATA_READ;
hd_cmd_out(&cmd);
interrupt_wait();
insw(REG_DATA, hdbuf, SECTOR_SIZE);
memcpy(entry,
hdbuf + PARTITION_TABLE_OFFSET,
sizeof(struct part_ent) * NR_PART_PER_DRIVE);
}
// added by mingxuan 2020-10-27
static void get_fs_flags(int drive, int sect_nr, struct fs_flags * fs_flags_buf)
{
struct hd_cmd cmd;
cmd.features = 0;
cmd.count = 1;
cmd.lba_low = sect_nr & 0xFF;
cmd.lba_mid = (sect_nr >> 8) & 0xFF;
cmd.lba_high = (sect_nr >> 16) & 0xFF;
cmd.device = MAKE_DEVICE_REG(1, /* LBA mode*/
drive,
(sect_nr >> 24) & 0xF);
cmd.command = ATA_READ;
hd_cmd_out(&cmd);
interrupt_wait();
insw(REG_DATA, hdbuf, SECTOR_SIZE);
memcpy(fs_flags_buf,
hdbuf,
sizeof(struct fs_flags));
}
/*****************************************************************************
* partition
*****************************************************************************/
/**
* <Ring 1> This routine is called when a device is opened. It reads the
* partition table(s) and fills the hd_info struct.
*
* @param device Device nr.
* @param style P_PRIMARY or P_EXTENDED.
*****************************************************************************/
static void partition(int device, int style)
{
int i;
int drive = DRV_OF_DEV(device);
struct hd_info * hdi = &hd_info[drive];
struct part_ent part_tbl[NR_SUB_PER_DRIVE];
if (style == P_PRIMARY) {
get_part_table(drive, drive, part_tbl);
int nr_prim_parts = 0;
for (i = 0; i < NR_PART_PER_DRIVE; i++) { /* 0~3 */
if (part_tbl[i].sys_id == NO_PART)
continue;
nr_prim_parts++;
int dev_nr = i + 1; /* 1~4 */
hdi->primary[dev_nr].base = part_tbl[i].start_sect;
hdi->primary[dev_nr].size = part_tbl[i].nr_sects;
// added by mingxuan 2020-10-27
struct fs_flags fs_flags_buf;
get_fs_flags(drive, hdi->primary[dev_nr].base+1, &fs_flags_buf); //hdi->primary[dev_nr].base + 1 beacause of orange and fat32 is in 2nd sector, mingxuan
if(fs_flags_buf.orange_flag == 0x11) // Orange's Magic
hdi->primary[dev_nr].fs_type = ORANGE_TYPE;
else if(fs_flags_buf.fat32_flag1 == 0x534f4453 && fs_flags_buf.fat32_flag2 == 0x302e35) // FAT32 flags
hdi->primary[dev_nr].fs_type = FAT32_TYPE;
// added end, mingxuan 2020-10-27
if (part_tbl[i].sys_id == EXT_PART) /* extended */
partition(device + dev_nr, P_EXTENDED);
}
}
else if (style == P_EXTENDED) {
int j = device % NR_PRIM_PER_DRIVE; /* 1~4 */
int ext_start_sect = hdi->primary[j].base;
int s = ext_start_sect;
int nr_1st_sub = (j - 1) * NR_SUB_PER_PART; /* 0/16/32/48 */
for (i = 0; i < NR_SUB_PER_PART; i++) {
int dev_nr = nr_1st_sub + i;/* 0~15/16~31/32~47/48~63 */
get_part_table(drive, s, part_tbl);
hdi->logical[dev_nr].base = s + part_tbl[0].start_sect;
hdi->logical[dev_nr].size = part_tbl[0].nr_sects;
// added by mingxuan 2020-10-29
struct fs_flags fs_flags_buf;
get_fs_flags(drive, hdi->logical[dev_nr].base+1, &fs_flags_buf); //hdi->primary[dev_nr].base + 1 beacause of orange and fat32 is in 2nd sector, mingxuan
if(fs_flags_buf.orange_flag == 0x11) // Orange's Magic
hdi->logical[dev_nr].fs_type = ORANGE_TYPE;
else if(fs_flags_buf.fat32_flag1 == 0x534f4453 && fs_flags_buf.fat32_flag2 == 0x302e35) // FAT32 flags
hdi->logical[dev_nr].fs_type = FAT32_TYPE;
// added end, mingxuan 2020-10-29
s = ext_start_sect + part_tbl[1].start_sect;
/* no more logical partitions
in this extended partition */
if (part_tbl[1].sys_id == NO_PART)
break;
}
}
else {
// assert(0);
}
}
/*****************************************************************************
* print_hdinfo
*****************************************************************************/
/**
* <Ring 1> Print disk info.
*
* @param hdi Ptr to struct hd_info.
*****************************************************************************/
static void print_hdinfo(struct hd_info * hdi)
{
int i;
for (i = 0; i < NR_PART_PER_DRIVE + 1; i++) {
if(i == 0) {
kprintf(" ");
}
else {
kprintf(" ");
}
kprintf("PART_%d: base %d, size: %d (in sector)\n",
i, hdi->primary[i].base, hdi->primary[i].size);
}
for (i = 0; i < NR_SUB_PER_DRIVE; i++) {
if (hdi->logical[i].size == 0)
continue;
kprintf(" %d: base %d, size %d (in sector)\n",
i, hdi->logical[i].base, hdi->logical[i].size);
}
}
/*****************************************************************************
* hd_identify
*****************************************************************************/
/**
* <Ring 1> Get the disk information.
*
* @param drive Drive Nr.
*****************************************************************************/
static void hd_identify(int drive)
{
struct hd_cmd cmd;
cmd.device = MAKE_DEVICE_REG(0, drive, 0);
cmd.command = ATA_IDENTIFY;
hd_cmd_out(&cmd);
interrupt_wait();
insw(REG_DATA, hdbuf, SECTOR_SIZE);
print_identify_info((u16*)hdbuf);
u16* hdinfo = (u16*)hdbuf;
hd_info[drive].primary[0].base = 0;
/* Total Nr of User Addressable Sectors */
hd_info[drive].primary[0].size = ((int)hdinfo[61] << 16) + hdinfo[60];
}
/*****************************************************************************
* print_identify_info
*****************************************************************************/
/**
* <Ring 1> Print the hdinfo retrieved via ATA_IDENTIFY command.
*
* @param hdinfo The buffer read from the disk i/o port.
*****************************************************************************/
static void print_identify_info(u16* hdinfo)
{
int i, k;
char s[64];
struct iden_info_ascii {
int idx;
int len;
char * desc;
} iinfo[] = {{10, 20, "HD SN"}, /* Serial number in ASCII */
{27, 40, "HD Model"} /* Model number in ASCII */ };
for (k = 0; k < sizeof(iinfo)/sizeof(iinfo[0]); k++) {
char * p = (char*)&hdinfo[iinfo[k].idx];
for (i = 0; i < iinfo[k].len/2; i++) {
s[i*2+1] = *p++;
s[i*2] = *p++;
}
s[i*2] = 0;
kprintf("%s: %s\n", iinfo[k].desc, s);
}
int capabilities = hdinfo[49];
kprintf("LBA supported:%s ", capabilities & 0x0200 ? "YES" : "NO");
int cmd_set_supported = hdinfo[83];
kprintf("LBA48 supported:%s ", cmd_set_supported & 0x0400 ? "YES" : "NO");
int sectors = ((int)hdinfo[61] << 16) + hdinfo[60];
kprintf("HD size:%dMB\n", sectors * 512 / 1000000);
}
/*****************************************************************************
* hd_cmd_out
*****************************************************************************/
/**
* <Ring 1> Output a command to HD controller.
*
* @param cmd The command struct ptr.
*****************************************************************************/
static void hd_cmd_out(struct hd_cmd* cmd)
{
/**
* For all commands, the host must first check if BSY=1,
* and should proceed no further unless and until BSY=0
*/
if (!waitfor(STATUS_BSY, 0, HD_TIMEOUT))
panic("hd error.");
/* Activate the Interrupt Enable (nIEN) bit */
outb(REG_DEV_CTRL, 0);
/* Load required parameters in the Command Block Registers */
outb(REG_FEATURES, cmd->features);
outb(REG_NSECTOR, cmd->count);
outb(REG_LBA_LOW, cmd->lba_low);
outb(REG_LBA_MID, cmd->lba_mid);
outb(REG_LBA_HIGH, cmd->lba_high);
outb(REG_DEVICE, cmd->device);
/* Write the command code to the Command Register */
outb(REG_CMD, cmd->command);
}
/*****************************************************************************
* interrupt_wait
*****************************************************************************/
/**
* <Ring 1> Wait until a disk interrupt occurs.
*
*****************************************************************************/
static void interrupt_wait()
{
while(hd_int_waiting_flag) {
}
hd_int_waiting_flag = 1;
}
/*****************************************************************************
* waitfor
*****************************************************************************/
/**
* <Ring 1> Wait for a certain status.
*
* @param mask Status mask.
* @param val Required status.
* @param timeout Timeout in milliseconds.
*
* @return One if sucess, zero if timeout.
*****************************************************************************/
static int waitfor(int mask, int val, int timeout)
{
int t = sys_get_ticks();
while(((sys_get_ticks() - t) * 1000 / HZ) < timeout){
if ((inb(REG_STATUS) & mask) == val)
return 1;
}
return 0;
}
/*****************************************************************************
* hd_handler
*****************************************************************************/
/**
* <Ring 0> Interrupt handler.
*
* @param irq IRQ nr of the disk interrupt.
*****************************************************************************/
static void hd_handler(int irq)
{
/*
* Interrupts are cleared when the host
* - reads the Status Register,
* - issues a reset, or
* - writes to the Command Register.
*/
hd_status = inb(REG_STATUS);
inform_int();
/* There is two stages - in kernel intializing or in process running.
* Some operation shouldn't be valid in kernel intializing stage.
* added by xw, 18/6/1
*/
if(kernel_initial == 1){
return;
}
//some operation only for process
return;
}
/*****************************************************************************
* inform_int
*****************************************************************************/
static void inform_int()
{
hd_int_waiting_flag = 0;
return;
}

75
kernel/i8259.c Normal file
View File

@ -0,0 +1,75 @@
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
i8259.c
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Forrest Yu, 2005
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
#include "type.h"
#include "const.h"
#include "protect.h"
#include "proc.h"
#include "global.h"
#include "proto.h"
#include "x86.h"
#include "stdio.h"
/*======================================================================*
init_8259A
*======================================================================*/
void init_8259A()
{
outb(INT_M_CTL, 0x11); // Master 8259, ICW1.
outb(INT_S_CTL, 0x11); // Slave 8259, ICW1.
outb(INT_M_CTLMASK, INT_VECTOR_IRQ0); // Master 8259, ICW2. 设置 '主8259' 的中断入口地址为 0x20.
outb(INT_S_CTLMASK, INT_VECTOR_IRQ8); // Slave 8259, ICW2. 设置 '从8259' 的中断入口地址为 0x28
outb(INT_M_CTLMASK, 0x4); // Master 8259, ICW3. IR2 对应 '从8259'.
outb(INT_S_CTLMASK, 0x2); // Slave 8259, ICW3. 对应 '主8259' 的 IR2.
outb(INT_M_CTLMASK, 0x1); // Master 8259, ICW4.
outb(INT_S_CTLMASK, 0x1); // Slave 8259, ICW4.
outb(INT_M_CTLMASK, 0xFF); // Master 8259, OCW1.
outb(INT_S_CTLMASK, 0xFF); // Slave 8259, OCW1.
int i;
for (i = 0; i < NR_IRQ; i++) {
irq_table[i] = spurious_irq;
}
}
void disable_irq(int irq)
{
u8 mask = 1 << (irq % 8);
if (irq < 8)
outb(INT_M_CTLMASK, inb(INT_M_CTLMASK) | mask);
else
outb(INT_S_CTLMASK, inb(INT_S_CTLMASK) | mask);
}
void enable_irq(int irq)
{
u8 mask = 1 << (irq % 8);
if (irq < 8)
outb(INT_M_CTLMASK, inb(INT_M_CTLMASK) & ~mask);
else
outb(INT_S_CTLMASK, inb(INT_S_CTLMASK) & ~mask);
}
/*======================================================================*
spurious_irq
*======================================================================*/
void spurious_irq(int irq)
{
kprintf("spurious_irq: %d\n", irq);
}
/*======================================================================*
put_irq_handler
*======================================================================*/
void put_irq_handler(int irq, irq_handler handler)
{
disable_irq(irq);
irq_table[irq] = handler;
}

608
kernel/kernel.asm Normal file
View File

@ -0,0 +1,608 @@
; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; 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 page_fault_handler
extern divide_error_handler ;added by xw, 18/12/22
extern disp_int
extern schedule
extern switch_pde
; 导入全局变量
extern gdt_ptr
extern idt_ptr
extern p_proc_current
extern tss
extern disp_pos
extern k_reenter
extern sys_call_table
extern cr3_ready ;add by visual 2016.4.5
extern p_proc_current
extern p_proc_next ;added by xw, 18/4/26
extern kernel_initial ;added by xw, 18/6/10
bits 32
[SECTION .bss]
StackSpace resb 2 * 1024
StackTop: ; used only as irq-stack in minios. added by xw
; added by xw, 18/6/15
KernelStackSpace resb 2 * 1024
KernelStackTop: ; used as stack of kernel itself
; ~xw
[section .text] ; 代码在此
global _start ; 导出 _start
;global restart
global restart_initial ;Added by xw, 18/4/21
global restart_restore ;Added by xw, 18/4/21
global sched ;Added by xw, 18/4/21
global sys_call
global read_cr2 ;//add by visual 2016.5.9
global refresh_page_cache ; // add by visual 2016.5.12
global halt ;added by xw, 18/6/11
global get_arg ;added by xw, 18/6/18
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 (04G) ┃ 8h = cs
; ┣━━━━━━━━━━━━━━━━━━┫
; ┃ DESC_FLAT_RW (04G) ┃ 10h = ds, es, fs, ss
; ┣━━━━━━━━━━━━━━━━━━┫
; ┃ DESC_VIDEO ┃ 1Bh = gs
; ┗━━━━━━━━━━━━━━━━━━┛
;
; 注意! 在使用 C 代码的时候一定要保证 ds, es, ss 这几个段寄存器的值是一样的
; 因为编译器有可能编译出使用它们的代码, 而编译器默认它们是一样的. 比如串拷贝操作会用到 ds 和 es.
;
;
; 把 esp 从 LOADER 挪到 KERNEL
; modified by xw, 18/6/15
;mov esp, StackTop ; 堆栈在 bss 段中
mov esp, KernelStackTop ; 堆栈在 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.
xor eax, eax
mov ax, SELECTOR_TSS
ltr ax
jmp kernel_main
; 中断和异常 -- 硬件中断
; ---------------------------------
%macro hwint_master 1
;call save
call save_int ;save registers and some other things. modified by xw, 17/12/11
inc dword [k_reenter] ;If k_reenter isn't equal to 0, there is no switching to the irq-stack,
;which is performed in save_int. Added by xw, 18/4/21
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
dec dword [k_reenter]
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
;added by xw, 18/5/29
call save_int ;save registers and some other things.
inc dword [k_reenter] ;If k_reenter isn't equal to 0, there is no switching to the irq-stack,
;which is performed in save_int. Added by xw, 18/4/21
in al, INT_S_CTLMASK ; `.
or al, (1 << (%1 - 8)) ; | 屏蔽当前中断
out INT_S_CTLMASK, al ; /
mov al, EOI ; `.
out INT_M_CTL, al ; / 置EOI位(master)
nop ; `.一定注意slave和master都要置EOI
out INT_S_CTL, al ; / 置EOI位(slave)
sti ; CPU在响应中断的过程中会自动关中断这句之后就允许响应新的中断
push %1 ; `.
call [irq_table + 4 * %1] ; | 中断处理程序
pop ecx ; /
cli
dec dword [k_reenter]
in al, INT_S_CTLMASK ; `.
and al, ~(1 << (%1 - 8)) ; | 恢复接受当前中断
out INT_S_CTLMASK, al ; /
ret
;~xw
%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
; ====================================================================================
; exception
; ====================================================================================
;restructured exception-handling procedure
;added by xw, 18/12/18
%macro exception_no_errcode 2
push 0xFFFFFFFF ;no err code
call save_exception ;save registers and some other things.
mov esi, esp ;esp points to pushed address of restart_exception at present
add esi, 4 * 17 ;we use esi to help to fetch arguments of exception handler from the stack.
;17 is calculated by: 4+8+retaddr+errcode+eip+cs+eflag=17
mov eax, [esi] ;saved eflags
push eax
mov eax, [esi - 4] ;saved cs
push eax
mov eax, [esi - 4 * 2] ;saved eip
push eax
mov eax, [esi - 4 * 3] ;saved err code
push eax
push %1 ;vector_no
sti
call %2
cli
add esp, 4 * 5 ;clear arguments of exception handler in stack
ret ;returned to 'restart_exception' procedure
%endmacro
%macro exception_errcode 2
call save_exception ;save registers and some other things.
mov esi, esp ;esp points to pushed address of restart_exception at present
add esi, 4 * 17 ;we use esi to help to fetch arguments of exception handler from the stack.
;17 is calculated by: 4+8+retaddr+errcode+eip+cs+eflag=17
mov eax, [esi] ;saved eflags
push eax
mov eax, [esi - 4] ;saved cs
push eax
mov eax, [esi - 4 * 2] ;saved eip
push eax
mov eax, [esi - 4 * 3] ;saved err code
push eax
push %1 ;vector_no
sti
call %2
cli
add esp, 4 * 5 ;clear arguments of exception handler in stack
ret ;returned to 'restart_exception' procedure
%endmacro
divide_error: ; vector_no = 0
; exception_no_errcode 0, exception_handler
exception_no_errcode 0, divide_error_handler ;added by xw, 18/12/22
single_step_exception: ; vector_no = 1
exception_no_errcode 1, exception_handler
nmi: ; vector_no = 2
exception_no_errcode 2, exception_handler
breakpoint_exception: ; vector_no = 3
exception_no_errcode 3, exception_handler
overflow: ; vector_no = 4
exception_no_errcode 4, exception_handler
bounds_check: ; vector_no = 5
exception_no_errcode 5, exception_handler
inval_opcode: ; vector_no = 6
exception_no_errcode 6, exception_handler
copr_not_available: ; vector_no = 7
exception_no_errcode 7, exception_handler
double_fault: ; vector_no = 8
exception_errcode 8, exception_handler
copr_seg_overrun: ; vector_no = 9
exception_no_errcode 9, exception_handler
inval_tss: ; vector_no = 10
exception_errcode 10, exception_handler
segment_not_present: ; vector_no = 11
exception_errcode 11, exception_handler
stack_exception: ; vector_no = 12
exception_errcode 12, exception_handler
general_protection: ; vector_no = 13
exception_errcode 13, exception_handler
page_fault: ; vector_no = 14
exception_errcode 14, page_fault_handler
copr_error: ; vector_no = 16
exception_no_errcode 16, exception_handler
;environment saving when an exception occurs
;added by xw, 18/12/18
save_exception:
pushad ; `.
push ds ; |
push es ; | 保存原寄存器值
push fs ; |
push gs ; /
mov dx, ss
mov ds, dx
mov es, dx
mov fs, dx ;value of fs and gs in user process is different to that in kernel
mov dx, SELECTOR_VIDEO - 2 ;added by xw, 18/6/20
mov gs, dx
mov esi, esp
push restart_exception
jmp [esi + RETADR - P_STACKBASE] ;the err code is in higher address than retaddr in stack, so there is
;no need to modify the position jumped to, that is,
;"jmp [esi + RETADR - 4 - P_STACKBASE]" is actually wrong.
;added by xw, 18/12/18
restart_exception:
call sched
pop gs
pop fs
pop es
pop ds
popad
add esp, 4 * 2 ;clear retaddr and error code in stack
iretd
; ====================================================================================
; save
; ====================================================================================
save_int:
pushad ; `.
push ds ; |
push es ; | 保存原寄存器值
push fs ; |
push gs ; /
cmp dword [k_reenter], 0 ;Added by xw, 18/4/19
jnz instack
mov ebx, [p_proc_current] ;xw
mov dword [ebx + ESP_SAVE_INT], esp ;xw save esp position in the kernel-stack of the process
; or dword [ebx + SAVE_TYPE], 1 ;set 1st-bit of save_type, added by xw, 17/12/04
mov dx, ss
mov ds, dx
mov es, dx
mov fs, dx ;value of fs and gs in user process is different to that in kernel
mov dx, SELECTOR_VIDEO - 2 ;added by xw, 18/6/20
mov gs, dx
mov esi, esp
mov esp, StackTop ;switches to the irq-stack from current process's kernel stack
push restart_int ;added by xw, 18/4/19
jmp [esi + RETADR - P_STACKBASE]
instack: ;already in the irq-stack
push restart_restore ;modified by xw, 18/4/19
; jmp [esp + RETADR - P_STACKBASE]
jmp [esp + 4 + RETADR - P_STACKBASE] ;modified by xw, 18/6/4
save_syscall: ;can't modify EAX, for it contains syscall number
;can't modify EBX, for it contains the syscall argument
pushad ; `.
push ds ; |
push es ; | 保存原寄存器值
push fs ; |
push gs ; /
mov edx, [p_proc_current] ;xw
mov dword [edx + ESP_SAVE_SYSCALL], esp ;xw save esp position in the kernel-stack of the process
mov dx, ss
mov ds, dx
mov es, dx
mov fs, dx ;value of fs and gs in user process is different to that in kernel
mov dx, SELECTOR_VIDEO - 2 ;added by xw, 18/6/20
mov gs, dx
mov esi, esp
push restart_syscall ;modified by xw, 17/12/04
jmp [esi + RETADR - P_STACKBASE]
;modified end
; ====================================================================================
; sched(process switch)
; ====================================================================================
sched:
;could be called by C function, you must save ebp, ebx, edi, esi,
;for C function assumes that they stay unchanged. added by xw, 18/4/19
;save_context
pushfd
pushad ;modified by xw, 18/6/4
cli
mov ebx, [p_proc_current]
mov dword [ebx + ESP_SAVE_CONTEXT], esp ;save esp position in the kernel-stack of the process
;schedule
call schedule ;schedule is a C function, save eax, ecx, edx if you want them to stay unchanged.
;prepare to run new process
mov ebx, [p_proc_next] ;added by xw, 18/4/26
mov dword [p_proc_current], ebx
call renew_env ;renew process executing environment
mov ebx, [p_proc_current]
mov esp, [ebx + ESP_SAVE_CONTEXT] ;switch to a new kernel stack
popad
popfd
ret
; ====================================================================================
; renew_env
; ====================================================================================
;renew process executing environment. Added by xw, 18/4/19
renew_env:
call switch_pde ;to change the global variable cr3_ready
mov eax,[cr3_ready] ;to switch the page directory table
mov cr3,eax
mov eax, [p_proc_current]
lldt [eax + P_LDT_SEL] ;load LDT
lea ebx, [eax + INIT_STACK_SIZE]
mov dword [tss + TSS3_S_SP0], ebx ;renew esp0
ret
; ====================================================================================
; sys_call
; ====================================================================================
sys_call:
;get syscall number from eax
;syscall that's called gets its argument from pushed ebx
;so we can't modify eax and ebx in save_syscall
call save_syscall ;save registers and some other things. modified by xw, 17/12/11
sti
push ebx ;push the argument the syscall need
call [sys_call_table + eax * 4] ;将参数压入堆栈后再调用函数 add by visual 2016.4.6
add esp, 4 ;clear the argument in the stack, modified by xw, 17/12/11
cli
mov edx, [p_proc_current]
mov esi, [edx + ESP_SAVE_SYSCALL]
mov [esi + EAXREG - P_STACKBASE], eax ;the return value of C function is in EAX
ret
; ====================================================================================
; restart
; ====================================================================================
restart_int:
mov eax, [p_proc_current]
mov esp, [eax + ESP_SAVE_INT] ;switch back to the kernel stack from the irq-stack
cmp dword [kernel_initial], 0 ;added by xw, 18/6/10
jnz restart_restore
call sched ;save current process's context, invoke schedule(), and then
;switch to the chosen process's kernel stack and restore it's context
;added by xw, 18/4/19
; call renew_env
jmp restart_restore
restart_syscall:
mov eax, [p_proc_current]
mov esp, [eax + ESP_SAVE_SYSCALL] ;xw restore esp position
call sched ;added by xw, 18/4/26
jmp restart_restore
;xw restart_reenter:
restart_restore:
; dec dword [k_reenter]
pop gs
pop fs
pop es
pop ds
popad
add esp, 4
iretd
;to launch the first process in the os. added by xw, 18/4/19
restart_initial:
; mov eax, [p_proc_current]
; lldt [eax + P_LDT_SEL]
; lea ebx, [eax + INIT_STACK_SIZE]
; mov dword [tss + TSS3_S_SP0], ebx
call renew_env ;renew process executing environment
mov eax, [p_proc_current]
mov esp, [eax + ESP_SAVE_INT] ;restore esp position
jmp restart_restore
; ====================================================================================
; read_cr2 //add by visual 2016.5.9
; ====================================================================================
read_cr2:
mov eax,cr2
ret
; ====================================================================================
; refresh_page_cache //add by visual 2016.5.12
; ====================================================================================
refresh_page_cache:
mov eax,cr3
mov cr3,eax
ret
; ====================================================================================
; halt //added by xw, 18/6/11
; ====================================================================================
halt:
hlt
; ====================================================================================
; u32 get_arg(void *uesp, int order) //added by xw, 18/6/18
; ====================================================================================
; used to get the specified argument of the syscall from user space stack
; @uesp: user space stack pointer
; @order: which argument you want to get
; @uesp+0: the number of args, @uesp+8: the first arg, @uesp+12: the second arg...
get_arg:
push ebp
mov ebp, esp
push esi
push edi
mov esi, dword [ebp + 8] ;void *uesp
mov edi, dword [ebp + 12] ;int order
mov eax, dword [esi + edi * 4 + 4]
pop edi
pop esi
pop ebp
ret

443
kernel/keyboard.c Normal file
View File

@ -0,0 +1,443 @@
#include "type.h"
#include "const.h"
#include "protect.h"
#include "string.h"
#include "proc.h"
#include "tty.h"
#include "console.h"
#include "global.h"
#include "proto.h"
#include "keyboard.h"
#include "keymap.h"
#include "x86.h"
static KB_INPUT kb_in;
static MOUSE_INPUT mouse_in;
static int mouse_init;
static int code_with_E0;
static int shift_l; /* l shift state */
static int shift_r; /* r shift state */
static int alt_l; /* l alt state */
static int alt_r; /* r left state */
static int ctrl_l; /* l ctrl state */
static int ctrl_r; /* l ctrl state */
static int caps_lock; /* Caps Lock */
static int num_lock; /* Num Lock */
static int scroll_lock; /* Scroll Lock */
static int column;
static u8 get_byte_from_kb_buf();
static void set_leds();
static void set_mouse_leds();
static void kb_wait();
// static void kb_ack();
void kb_handler(int irq){
u8 scan_code = inb(0x60);
if(kb_in.count < KB_IN_BYTES){
*(kb_in.p_head) = scan_code;
kb_in.p_head++;
if(kb_in.p_head==kb_in.buf+KB_IN_BYTES){
kb_in.p_head = kb_in.buf;
}
kb_in.count++;
}
};
#define TTY_FIRST (tty_table)
#define TTY_END (tty_table+NR_CONSOLES)
void mouse_handler(int irq){
u8 scan_code = inb(0x60);
if(!mouse_init){
mouse_init = 1;
return;
}
mouse_in.buf[mouse_in.count]=scan_code;
mouse_in.count++;
if(mouse_in.count==3){
TTY* p_tty;
for (p_tty = TTY_FIRST; p_tty < TTY_END; p_tty++) {
if(p_tty->console==&console_table[current_console]){
p_tty->mouse_left_button = mouse_in.buf[0]&0x01;
u8 mid_button = mouse_in.buf[0]&0b100;
if(mid_button==0b100){
p_tty->mouse_mid_button = 1;
}else{
p_tty->mouse_mid_button = 0;
}
if(p_tty->mouse_left_button){
u8 dir_Y = mouse_in.buf[0]&0x20;
u8 dir_X = mouse_in.buf[0]&0x10;
if(dir_Y==0x20){//down
p_tty->mouse_Y -= 1;
}else{//up
p_tty->mouse_Y += 1;
}
if(dir_X==0x10){//left
p_tty->mouse_X -= 1;
}else{//right
p_tty->mouse_X += 1;
}
}
}
}
mouse_in.count=0;
}
}
void init_mouse(){
mouse_in.count = 0;
put_irq_handler(MOUSE_IRQ,mouse_handler);
enable_irq(MOUSE_IRQ);
}
void init_kb(){
kb_in.count = 0;
kb_in.p_head = kb_in.p_tail = kb_in.buf;
shift_l = shift_r = 0;
alt_l = alt_r = 0;
ctrl_l = ctrl_r = 0;
caps_lock = 0;
num_lock = 1;
scroll_lock = 0;
column = 0;
set_leds();
put_irq_handler(KEYBOARD_IRQ, kb_handler);
enable_irq(KEYBOARD_IRQ);
init_mouse();
set_mouse_leds();
}
void keyboard_read(TTY* p_tty)
{
u8 scan_code;
/**
* 1 : make
* 0 : break
*/
int make;
/**
* We use a integer to record a key press.
* For instance, if the key HOME is pressed, key will be evaluated to
* `HOME' defined in keyboard.h.
*/
u32 key = 0;
/**
* This var points to a row in keymap[]. I don't use two-dimension
* array because I don't like it.
*/
u32* keyrow;
while (kb_in.count > 0) {
code_with_E0 = 0;
scan_code = get_byte_from_kb_buf();
/* parse the scan code below */
if (scan_code == 0xE1) {
int i;
u8 pausebreak_scan_code[] = {0xE1, 0x1D, 0x45, 0xE1, 0x9D, 0xC5};
int is_pausebreak = 1;
for (i = 1; i < 6; i++) {
if (get_byte_from_kb_buf() != pausebreak_scan_code[i]) {
is_pausebreak = 0;
break;
}
}
if (is_pausebreak) {
key = PAUSEBREAK;
}
}
else if (scan_code == 0xE0) {
code_with_E0 = 1;
scan_code = get_byte_from_kb_buf();
/* PrintScreen is pressed */
if (scan_code == 0x2A) {
code_with_E0 = 0;
if ((scan_code = get_byte_from_kb_buf()) == 0xE0) {
code_with_E0 = 1;
if ((scan_code = get_byte_from_kb_buf()) == 0x37) {
key = PRINTSCREEN;
make = 1;
}
}
}
/* PrintScreen is released */
else if (scan_code == 0xB7) {
code_with_E0 = 0;
if ((scan_code = get_byte_from_kb_buf()) == 0xE0) {
code_with_E0 = 1;
if ((scan_code = get_byte_from_kb_buf()) == 0xAA) {
key = PRINTSCREEN;
make = 0;
}
}
}
}
if ((key != PAUSEBREAK) && (key != PRINTSCREEN)) {
int caps;
/* make or break */
make = (scan_code & FLAG_BREAK ? 0 : 1);
keyrow = &keymap[(scan_code & 0x7F) * MAP_COLS];
column = 0;
caps = shift_l || shift_r;
if (caps_lock &&
keyrow[0] >= 'a' && keyrow[0] <= 'z')
caps = !caps;
if (caps)
column = 1;
if (code_with_E0)
column = 2;
key = keyrow[column];
switch(key) {
case SHIFT_L:
shift_l = make;
break;
case SHIFT_R:
shift_r = make;
break;
case CTRL_L:
ctrl_l = make;
break;
case CTRL_R:
ctrl_r = make;
break;
case ALT_L:
alt_l = make;
break;
case ALT_R:
alt_l = make;
break;
case CAPS_LOCK:
if (make) {
caps_lock = !caps_lock;
set_leds();
}
break;
case NUM_LOCK:
if (make) {
num_lock = !num_lock;
set_leds();
}
break;
case SCROLL_LOCK:
if (make) {
scroll_lock = !scroll_lock;
set_leds();
}
break;
default:
break;
}
}
if(make){ /* Break Code is ignored */
int pad = 0;
/* deal with the numpad first */
if ((key >= PAD_SLASH) && (key <= PAD_9)) {
pad = 1;
switch(key) { /* '/', '*', '-', '+',
* and 'Enter' in num pad
*/
case PAD_SLASH:
key = '/';
break;
case PAD_STAR:
key = '*';
break;
case PAD_MINUS:
key = '-';
break;
case PAD_PLUS:
key = '+';
break;
case PAD_ENTER:
key = ENTER;
break;
default:
/* the value of these keys
* depends on the Numlock
*/
if (num_lock) { /* '0' ~ '9' and '.' in num pad */
if (key >= PAD_0 && key <= PAD_9)
key = key - PAD_0 + '0';
else if (key == PAD_DOT)
key = '.';
}
else{
switch(key) {
case PAD_HOME:
key = HOME;
break;
case PAD_END:
key = END;
break;
case PAD_PAGEUP:
key = PAGEUP;
break;
case PAD_PAGEDOWN:
key = PAGEDOWN;
break;
case PAD_INS:
key = INSERT;
break;
case PAD_UP:
key = UP;
break;
case PAD_DOWN:
key = DOWN;
break;
case PAD_LEFT:
key = LEFT;
break;
case PAD_RIGHT:
key = RIGHT;
break;
case PAD_DOT:
key = DELETE;
break;
default:
break;
}
}
break;
}
}
key |= shift_l ? FLAG_SHIFT_L : 0;
key |= shift_r ? FLAG_SHIFT_R : 0;
key |= ctrl_l ? FLAG_CTRL_L : 0;
key |= ctrl_r ? FLAG_CTRL_R : 0;
key |= alt_l ? FLAG_ALT_L : 0;
key |= alt_r ? FLAG_ALT_R : 0;
key |= pad ? FLAG_PAD : 0;
in_process(p_tty,key);
}
}
}
/*****************************************************************************
* get_byte_from_kb_buf
*****************************************************************************/
/**
* Read a byte from the keyboard buffer.
*
* @return The byte read.
*****************************************************************************/
static u8 get_byte_from_kb_buf()
{
u8 scan_code;
while (kb_in.count <= 0) {} /* wait for a byte to arrive */
disable_int(); /* for synchronization */
scan_code = *(kb_in.p_tail);
kb_in.p_tail++;
if (kb_in.p_tail == kb_in.buf + KB_IN_BYTES) {
kb_in.p_tail = kb_in.buf;
}
kb_in.count--;
enable_int(); /* for synchronization */
return scan_code;
}
/*****************************************************************************
* kb_wait
*****************************************************************************/
/**
* Wait until the input buffer of 8042 is empty.
*
*****************************************************************************/
static void kb_wait() /* 等待 8042 的输入缓冲区空 */
{
u8 kb_stat;
do {
kb_stat = inb(KB_CMD);
} while (kb_stat & 0x02);
}
/*****************************************************************************
* kb_ack
*****************************************************************************/
/**
* Read from the keyboard controller until a KB_ACK is received.
*
*****************************************************************************/
// static void kb_ack()
// {
// u8 kb_read;
// do {
// kb_read = inb(KB_DATA);
// } while (kb_read != KB_ACK);
// }
/*****************************************************************************
* set_leds
*****************************************************************************/
/**
* Set the leds according to: caps_lock, num_lock & scroll_lock.
*
*****************************************************************************/
static void set_leds()
{
kb_wait();
outb(KB_CMD, KEYCMD_WRITE_MODE);
kb_wait();
outb(KB_DATA, KBC_MODE);
}
static void set_mouse_leds(){
kb_wait();
outb(KB_CMD,KBCMD_EN_MOUSE_INTFACE);
kb_wait();
outb(KB_CMD, KEYCMD_SENDTO_MOUSE);
kb_wait();
outb(KB_DATA, MOUSECMD_ENABLE);
kb_wait();
outb(KB_CMD, KEYCMD_WRITE_MODE);
kb_wait();
outb(KB_DATA, KBC_MODE);
}

133
kernel/ktest.c Normal file
View File

@ -0,0 +1,133 @@
/*
* To test if new kernel features work normally, and if old features still
* work normally with new features added.
* added by xw, 18/4/27
*/
#include "type.h"
#include "const.h"
#include "protect.h"
#include "string.h"
#include "proc.h"
#include "global.h"
#include "proto.h"
#include "fs.h"
#include "vfs.h"
#include "string.h"
/**
* @struct posix_tar_header
* Borrowed from GNU `tar'
*/
//added by mingxuan 2019-5-18
struct posix_tar_header
{ /* byte offset */
char name[100]; /* 0 */
char mode[8]; /* 100 */
char uid[8]; /* 108 */
char gid[8]; /* 116 */
char size[12]; /* 124 */
char mtime[12]; /* 136 */
char chksum[8]; /* 148 */
char typeflag; /* 156 */
char linkname[100]; /* 157 */
char magic[6]; /* 257 */
char version[2]; /* 263 */
char uname[32]; /* 265 */
char gname[32]; /* 297 */
char devmajor[8]; /* 329 */
char devminor[8]; /* 337 */
char prefix[155]; /* 345 */
/* 500 */
};
/*****************************************************************************
* untar
* added by mingxuan 2019-5-18
*****************************************************************************/
/**
* Extract the tar file and store them.
*
* @param filename The tar file.
*****************************************************************************/
static void untar(const char * filename)
{
printf("[extract %s \n", filename);
int fd = do_vopen(filename, O_RDWR);//modified by mingxuan 2019-5-20
char buf[512 * 16];
int chunk = sizeof(buf);
int i = 0;
while (1) {
do_vread(fd, buf, 512); //modified by mingxuan 2019-5-21
if (buf[0] == 0) {
if (i == 0)
printf(" need not unpack the file.\n");
break;
}
i++;
struct posix_tar_header * phdr = (struct posix_tar_header *)buf;
/* calculate the file size */
char * p = phdr->size;
int f_len = 0;
while (*p)
f_len = (f_len * 8) + (*p++ - '0'); /* octal */
int bytes_left = f_len;
char full_name[30] = "orange/";
strcat(full_name,phdr->name);
int fdout = do_vopen(full_name, O_CREAT | O_RDWR ); //modified by mingxuan 2019-5-20
if (fdout == -1) {
printf(" failed to extract file: %s\n", phdr->name);
printf(" aborted]\n");
do_vclose(fd); //modified by mingxuan 2019-5-20
return;
}
printf(" %s \n", phdr->name); //deleted by mingxuan 2019-5-22
while (bytes_left) {
int iobytes = min(chunk, bytes_left);
do_vread(fd, buf, ((iobytes - 1) / 512 + 1) * 512); //modified by mingxuan 2019-5-21
do_vwrite(fdout, buf, iobytes); //modified by mingxuan 2019-5-21
bytes_left -= iobytes;
}
do_vclose(fdout); //modified by mingxuan 2019-5-20
}
if (i) {
do_vlseek(fd, 0, SEEK_SET); //modified by mingxuan 2019-5-20
buf[0] = 0;
do_vwrite(fd, buf, 1); //modified by mingxuan 2019-5-20
}
do_vclose(fd); //modified by mingxuan 2019-5-21
printf(" done, %d files extracted]\n", i);
}
void initial()
{
int stdin = do_vopen("dev_tty0",O_RDWR);
int stdout= do_vopen("dev_tty0",O_RDWR);
int stderr= do_vopen("dev_tty0",O_RDWR);
//untar(INSTALL_FILENAME);
//modified by mingxuan 2019-5-21
char full_name[30]="orange/";;
printf("untar:%s\n",full_name);
strcat(full_name,INSTALL_FILENAME);
untar(full_name);
do_vclose(stdin);
do_vclose(stdout);
do_vclose(stderr);
exec("orange/shell_0.bin");
while(1);
}

472
kernel/main.c Normal file
View File

@ -0,0 +1,472 @@
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
main.c
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Forrest Yu, 2005
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
#include "type.h"
#include "const.h"
#include "protect.h"
#include "string.h"
#include "proc.h"
#include "global.h"
#include "proto.h"
#include "fs_const.h"
#include "hd.h"
#include "fs.h"
#include "memman.h"
#include "vfs.h"
#include "fat32.h"
#include "x86.h"
#include "assert.h"
#include "stdio.h"
static int initialize_processes(); //added by xw, 18/5/26
static int initialize_cpus(); //added by xw, 18/6/2
/*======================================================================*
kernel_main
*======================================================================*/
int kernel_main()
{
int error;
disp_pos = 0;
for (int i = 0; i < 25; i++) {
for (int j = 0; j < 80; j++) {
kprintf(" ");
}
}
disp_pos = 0;
kprintf("-----Kernel Initialization Begins-----\n");
kernel_initial = 1; //kernel is in initial state. added by xw, 18/5/31
init();//内存管理模块的初始化 add by liang
//initialize PCBs, added by xw, 18/5/26
error = initialize_processes();
if(error != 0)
return error;
//initialize CPUs, added by xw, 18/6/2
error = initialize_cpus();
if(error != 0)
return error;
k_reenter = 0; //record nest level of only interruption! it's different from Orange's.
//usage modified by xw
ticks = 0; //initialize system-wide ticks
p_proc_current = cpu_table;
/************************************************************************
*device initialization
added by xw, 18/6/4
*************************************************************************/
/* initialize 8253 PIT */
outb(TIMER_MODE, RATE_GENERATOR);
outb(TIMER0, (u8) (TIMER_FREQ/HZ) );
outb(TIMER0, (u8) ((TIMER_FREQ/HZ) >> 8));
/* initialize clock-irq */
put_irq_handler(CLOCK_IRQ, clock_handler); /* 设定时钟中断处理程序 */
enable_irq(CLOCK_IRQ); /* 让8259A可以接收时钟中断 */
init_kb(); //added by mingxuan 2019-5-19
/* initialize hd-irq and hd rdwt queue */
init_hd();
/* enable interrupt, we should read information of some devices by interrupt.
* Note that you must have initialized all devices ready before you enable
* interrupt. added by xw
*/
enable_int();
/***********************************************************************
open hard disk and initialize file system
coded by zcr on 2017.6.10. added by xw, 18/5/31
************************************************************************/
init_fileop_table(); //added by mingxuan 2019-5-17
//hd_open(MINOR(ROOT_DEV));
hd_open(PRIMARY_MASTER); //modified by mingxuan 2020-10-27
init_vfs(); //added by mingxuan 2020-10-30
init_fs();
init_fs_fat(); //added by mingxuan 2019-5-17
//init_vfs(); //added by mingxuan 2019-5-17 //deleted by mingxuan 2020-10-30
/*************************************************************************
*
**************************************************************************/
/* we don't want interrupt happens before processes run.
* added by xw, 18/5/31
*/
disable_int();
kprintf("-----Processes Begin-----\n");
/* linear address 0~8M will no longer be mapped to physical address 0~8M.
* note that disp_xx can't work after this function is invoked until processes runs.
* add by visual 2016.5.13; moved by xw, 18/5/30
*/
clear_kernel_pagepte_low();
p_proc_current = proc_table;
kernel_initial = 0; //kernel initialization is done. added by xw, 18/5/31
restart_initial(); //modified by xw, 18/4/19
while(1){}
}
/*************************************************************************
return 0 if there is no error, or return -1.
added by xw, 18/6/2
***************************************************************************/
static int initialize_cpus()
{
//just use the fields of struct PCB in cpu_table, we needn't initialize
//something at present.
return 0;
}
/*************************************************************************
return 0 if there is no error, or return -1.
moved from kernel_main() by xw, 18/5/26
***************************************************************************/
static int initialize_processes()
{
TASK* p_task = task_table;
PROCESS* p_proc = proc_table;
u16 selector_ldt = SELECTOR_LDT_FIRST;
char* p_regs; //point to registers in the new kernel stack, added by xw, 17/12/11
task_f eip_context; //a funtion pointer, added by xw, 18/4/18
/*************************************************************************
* edit by visual 2016.5.4
***************************************************************************/
int pid;
u32 AddrLin,err_temp;//edit by visual 2016.5.9
/* set common fields in PCB. added by xw, 18/5/25 */
p_proc = proc_table;
for( pid=0 ; pid<NR_PCBS ; pid++ )
{
//some operations
p_proc++;
}
p_proc = proc_table;
for( pid=0 ; pid<NR_TASKS ; pid++ )
{//1>对前NR_TASKS个PCB初始化,且状态为READY(生成的进程)
/*************基本信息*********************************/
strcpy(p_proc->task.p_name, p_task->name); //名称
p_proc->task.pid = pid; //pid
p_proc->task.stat = READY; //状态
/**************LDT*********************************/
p_proc->task.ldt_sel = selector_ldt;
memcpy(&p_proc->task.ldts[0], &gdt[SELECTOR_KERNEL_CS >> 3],sizeof(DESCRIPTOR));
p_proc->task.ldts[0].attr1 = DA_C | PRIVILEGE_TASK << 5;
memcpy(&p_proc->task.ldts[1], &gdt[SELECTOR_KERNEL_DS >> 3],sizeof(DESCRIPTOR));
p_proc->task.ldts[1].attr1 = DA_DRW | PRIVILEGE_TASK << 5;
/**************寄存器初值**********************************/
p_proc->task.regs.cs = ((8 * 0) & SA_RPL_MASK & SA_TI_MASK)| SA_TIL | RPL_TASK;
p_proc->task.regs.ds = ((8 * 1) & SA_RPL_MASK & SA_TI_MASK)| SA_TIL | RPL_TASK;
p_proc->task.regs.es = ((8 * 1) & SA_RPL_MASK & SA_TI_MASK)| SA_TIL | RPL_TASK;
p_proc->task.regs.fs = ((8 * 1) & SA_RPL_MASK & SA_TI_MASK)| SA_TIL | RPL_TASK;
p_proc->task.regs.ss = ((8 * 1) & SA_RPL_MASK & SA_TI_MASK)| SA_TIL | RPL_TASK;
p_proc->task.regs.gs = (SELECTOR_KERNEL_GS & SA_RPL_MASK)| RPL_TASK;
p_proc->task.regs.eflags = 0x1202; /* IF=1, IOPL=1 */
//p_proc->task.cr3 在页表初始化中处理
/**************线性地址布局初始化**********************************/// add by visual 2016.5.4
/**************task的代码数据大小及位置暂时是不会用到的所以没有初始化************************************/
p_proc->task.memmap.heap_lin_base = HeapLinBase;
p_proc->task.memmap.heap_lin_limit = HeapLinBase; //堆的界限将会一直动态变化
p_proc->task.memmap.stack_child_limit = StackLinLimitMAX; //add by visual 2016.5.27
p_proc->task.memmap.stack_lin_base = StackLinBase;
p_proc->task.memmap.stack_lin_limit = StackLinBase - 0x4000; //栈的界限将会一直动态变化目前赋值为16k这个值会根据esp的位置进行调整目前初始化为16K大小
p_proc->task.memmap.kernel_lin_base = KernelLinBase;
p_proc->task.memmap.kernel_lin_limit = KernelLinBase + KernelSize; //内核大小初始化为8M //add by visual 2016.5.10
/***************初始化PID进程页表*****************************/
if( 0 != init_page_pte(pid) )
{
disp_color_str("kernel_main Error:init_page_pte",0x74);
return -1;
}
// pde_addr_phy_temp = get_pde_phy_addr(pid);//获取该进程页目录物理地址 //delete by visual 2016.5.19
/****************代码数据*****************************/
p_proc->task.regs.eip= (u32)p_task->initial_eip;//进程入口线性地址 edit by visual 2016.5.4
/****************栈(此时堆、栈已经区分,以后实验会重新规划堆的位置)*****************************/
p_proc->task.regs.esp=(u32)StackLinBase; //栈地址最高处
for( AddrLin=StackLinBase ; AddrLin>p_proc->task.memmap.stack_lin_limit ; AddrLin-=num_4K )
{//栈
//addr_phy_temp = (u32)do_kmalloc_4k();//为栈申请一个物理页,Task的栈是在内核里面 //delete by visual 2016.5.19
//if( addr_phy_temp<0 || (addr_phy_temp&0x3FF)!=0 )
//{
// disp_color_str("kernel_main Error:addr_phy_temp",0x74);
// return -1;
//}
err_temp = lin_mapping_phy( AddrLin,//线性地址 //add by visual 2016.5.9
MAX_UNSIGNED_INT,//物理地址 //edit by visual 2016.5.19
pid,//进程pid //edit by visual 2016.5.19
PG_P | PG_USU | PG_RWW,//页目录的属性位
PG_P | PG_USU | PG_RWW);//页表的属性位
if( err_temp!=0 )
{
disp_color_str("kernel_main Error:lin_mapping_phy",0x74);
return -1;
}
}
/***************copy registers data to kernel stack****************************/
//copy registers data to the bottom of the new kernel stack
//added by xw, 17/12/11
p_regs = (char*)(p_proc + 1);
p_regs -= P_STACKTOP;
memcpy(p_regs, (char*)p_proc, 18 * 4);
/***************some field about process switch****************************/
p_proc->task.esp_save_int = p_regs; //initialize esp_save_int, added by xw, 17/12/11
//p_proc->task.save_type = 1;
p_proc->task.esp_save_context = p_regs - 10 * 4; //when the process is chosen to run for the first time,
//sched() will fetch value from esp_save_context
eip_context = restart_restore;
*(u32*)(p_regs - 4) = (u32)eip_context; //initialize EIP in the context, so the process can
//start run. added by xw, 18/4/18
*(u32*)(p_regs - 8) = 0x1202; //initialize EFLAGS in the context, IF=1, IOPL=1. xw, 18/4/20
/***************变量调整****************************/
p_proc++;
p_task++;
selector_ldt += 1 << 3;
}
for( ; pid<NR_K_PCBS ; pid++ )
{//2>对中NR_TASKS~NR_K_PCBS的PCB表初始化,状态为IDLE,没有初始化esp(并没有生成,所以没有代码入口,只是留位置)
/*************基本信息*********************************/
strcpy(p_proc->task.p_name, "Task"); //名称
p_proc->task.pid = pid; //pid
p_proc->task.stat = IDLE; //状态
/**************LDT*********************************/
p_proc->task.ldt_sel = selector_ldt;
memcpy(&p_proc->task.ldts[0], &gdt[SELECTOR_KERNEL_CS >> 3],sizeof(DESCRIPTOR));
p_proc->task.ldts[0].attr1 = DA_C | PRIVILEGE_TASK << 5;
memcpy(&p_proc->task.ldts[1], &gdt[SELECTOR_KERNEL_DS >> 3],sizeof(DESCRIPTOR));
p_proc->task.ldts[1].attr1 = DA_DRW | PRIVILEGE_TASK << 5;
/**************寄存器初值**********************************/
p_proc->task.regs.cs = ((8 * 0) & SA_RPL_MASK & SA_TI_MASK)| SA_TIL | RPL_TASK;
p_proc->task.regs.ds = ((8 * 1) & SA_RPL_MASK & SA_TI_MASK)| SA_TIL | RPL_TASK;
p_proc->task.regs.es = ((8 * 1) & SA_RPL_MASK & SA_TI_MASK)| SA_TIL | RPL_TASK;
p_proc->task.regs.fs = ((8 * 1) & SA_RPL_MASK & SA_TI_MASK)| SA_TIL | RPL_TASK;
p_proc->task.regs.ss = ((8 * 1) & SA_RPL_MASK & SA_TI_MASK)| SA_TIL | RPL_TASK;
p_proc->task.regs.gs = (SELECTOR_KERNEL_GS & SA_RPL_MASK)| RPL_TASK;
p_proc->task.regs.eflags = 0x1202; /* IF=1, IOPL=1 */
/****************页表、代码数据、堆栈*****************************/
//无
/***************copy registers data to kernel stack****************************/
//copy registers data to the bottom of the new kernel stack
//added by xw, 17/12/11
p_regs = (char*)(p_proc + 1);
p_regs -= P_STACKTOP;
memcpy(p_regs, (char*)p_proc, 18 * 4);
/***************some field about process switch****************************/
p_proc->task.esp_save_int = p_regs; //initialize esp_save_int, added by xw, 17/12/11
//p_proc->task.save_type = 1;
p_proc->task.esp_save_context = p_regs - 10 * 4; //when the process is chosen to run for the first time,
//sched() will fetch value from esp_save_context
eip_context = restart_restore;
*(u32*)(p_regs - 4) = (u32)eip_context; //initialize EIP in the context, so the process can
//start run. added by xw, 18/4/18
*(u32*)(p_regs - 8) = 0x1202; //initialize EFLAGS in the context, IF=1, IOPL=1. xw, 18/4/20
/***************变量调整****************************/
p_proc++;
selector_ldt += 1 << 3;
}
for( ; pid<NR_K_PCBS+1 ; pid++ )
{//initial 进程的初始化 //add by visual 2016.5.17
/*************基本信息*********************************/
strcpy(p_proc->task.p_name,"initial"); //名称
p_proc->task.pid = pid; //pid
p_proc->task.stat = READY; //状态
/**************LDT*********************************/
p_proc->task.ldt_sel = selector_ldt;
memcpy(&p_proc->task.ldts[0], &gdt[SELECTOR_KERNEL_CS >> 3],sizeof(DESCRIPTOR));
p_proc->task.ldts[0].attr1 = DA_C | PRIVILEGE_TASK << 5;
memcpy(&p_proc->task.ldts[1], &gdt[SELECTOR_KERNEL_DS >> 3],sizeof(DESCRIPTOR));
p_proc->task.ldts[1].attr1 = DA_DRW | PRIVILEGE_TASK << 5;
/**************寄存器初值**********************************/
p_proc->task.regs.cs = ((8 * 0) & SA_RPL_MASK & SA_TI_MASK)| SA_TIL | RPL_TASK;
p_proc->task.regs.ds = ((8 * 1) & SA_RPL_MASK & SA_TI_MASK)| SA_TIL | RPL_TASK;
p_proc->task.regs.es = ((8 * 1) & SA_RPL_MASK & SA_TI_MASK)| SA_TIL | RPL_TASK;
p_proc->task.regs.fs = ((8 * 1) & SA_RPL_MASK & SA_TI_MASK)| SA_TIL | RPL_TASK;
p_proc->task.regs.ss = ((8 * 1) & SA_RPL_MASK & SA_TI_MASK)| SA_TIL | RPL_TASK;
p_proc->task.regs.gs = (SELECTOR_KERNEL_GS & SA_RPL_MASK)| RPL_TASK;
p_proc->task.regs.eflags = 0x1202; /* IF=1, IOPL=1 */
//p_proc->task.cr3 在页表初始化中处理
/**************线性地址布局初始化**********************************/ //edit by visual 2016.5.25
p_proc->task.memmap.text_lin_base = 0; //initial这些段的数据并不清楚在变身init的时候才在中赋新值
p_proc->task.memmap.text_lin_limit = 0; //initial这些段的数据并不清楚在变身init的时候才在exec中赋新值
p_proc->task.memmap.data_lin_base = 0; //initial这些段的数据并不清楚在变身init的时候才在exec中赋新值
p_proc->task.memmap.data_lin_limit= 0; //initial这些段的数据并不清楚在变身init的时候才在exec中赋新值
p_proc->task.memmap.vpage_lin_base = VpageLinBase; //保留内存基址
p_proc->task.memmap.vpage_lin_limit = VpageLinBase; //保留内存界限
p_proc->task.memmap.heap_lin_base = HeapLinBase; //堆基址
p_proc->task.memmap.heap_lin_limit = HeapLinBase; //堆界限
p_proc->task.memmap.stack_lin_base = StackLinBase; //栈基址
p_proc->task.memmap.stack_lin_limit = StackLinBase - 0x4000; //栈界限(使用时注意栈的生长方向)
p_proc->task.memmap.arg_lin_base = ArgLinBase; //参数内存基址
p_proc->task.memmap.arg_lin_limit = ArgLinBase; //参数内存界限
p_proc->task.memmap.kernel_lin_base = KernelLinBase; //内核基址
p_proc->task.memmap.kernel_lin_limit = KernelLinBase + KernelSize; //内核大小初始化为8M
/*************************进程树信息初始化***************************************/
p_proc->task.info.type = TYPE_PROCESS; //当前是进程还是线程
p_proc->task.info.real_ppid = -1; //亲父进程,创建它的那个进程
p_proc->task.info.ppid = -1; //当前父进程
p_proc->task.info.child_p_num = 0; //子进程数量
//p_proc->task.info.child_process[NR_CHILD_MAX];//子进程列表
p_proc->task.info.child_t_num = 0; //子线程数量
//p_proc->task.info.child_thread[NR_CHILD_MAX];//子线程列表
p_proc->task.info.text_hold = 1; //是否拥有代码
p_proc->task.info.data_hold = 1; //是否拥有数据
/***************初始化PID进程页表*****************************/
if( 0 != init_page_pte(pid) )
{
disp_color_str("kernel_main Error:init_page_pte",0x74);
return -1;
}
//pde_addr_phy_temp = get_pde_phy_addr(pid);//获取该进程页目录物理地址 //edit by visual 2016.5.19
/****************代码数据*****************************/
p_proc->task.regs.eip= (u32)initial;//进程入口线性地址 edit by visual 2016.5.17
/****************栈(此时堆、栈已经区分,以后实验会重新规划堆的位置)*****************************/
p_proc->task.regs.esp=(u32)StackLinBase; //栈地址最高处
for( AddrLin=StackLinBase ; AddrLin>p_proc->task.memmap.stack_lin_limit ; AddrLin-=num_4K )
{//栈
//addr_phy_temp = (u32)do_kmalloc_4k();//为栈申请一个物理页,Task的栈是在内核里面 //delete by visual 2016.5.19
//if( addr_phy_temp<0 || (addr_phy_temp&0x3FF)!=0 )
//{
// disp_color_str("kernel_main Error:addr_phy_temp",0x74);
// return -1;
//}
err_temp = lin_mapping_phy( AddrLin,//线性地址
MAX_UNSIGNED_INT,//物理地址 //edit by visual 2016.5.19
pid,//进程pid //edit by visual 2016.5.19
PG_P | PG_USU | PG_RWW,//页目录的属性位
PG_P | PG_USU | PG_RWW);//页表的属性位
if( err_temp!=0 )
{
disp_color_str("kernel_main Error:lin_mapping_phy",0x74);
return -1;
}
}
/***************copy registers data to kernel stack****************************/
//copy registers data to the bottom of the new kernel stack
//added by xw, 17/12/11
p_regs = (char*)(p_proc + 1);
p_regs -= P_STACKTOP;
memcpy(p_regs, (char*)p_proc, 18 * 4);
/***************some field about process switch****************************/
p_proc->task.esp_save_int = p_regs; //initialize esp_save_int, added by xw, 17/12/11
//p_proc->task.save_type = 1;
p_proc->task.esp_save_context = p_regs - 10 * 4; //when the process is chosen to run for the first time,
//sched() will fetch value from esp_save_context
eip_context = restart_restore;
*(u32*)(p_regs - 4) = (u32)eip_context; //initialize EIP in the context, so the process can
//start run. added by xw, 18/4/18
*(u32*)(p_regs - 8) = 0x1202; //initialize EFLAGS in the context, IF=1, IOPL=1. xw, 18/4/20
/***************变量调整****************************/
p_proc++;
selector_ldt += 1 << 3;
}
for( ; pid<NR_PCBS ; pid++ )
{//3>对后NR_K_PCBS~NR_PCBS的PCB表部分初始化,(名称,pid,stat,LDT选择子),状态为IDLE.
/*************基本信息*********************************/
strcpy(p_proc->task.p_name, "USER"); //名称
p_proc->task.pid = pid; //pid
p_proc->task.stat = IDLE; //状态
/**************LDT*********************************/
p_proc->task.ldt_sel = selector_ldt;
memcpy(&p_proc->task.ldts[0], &gdt[SELECTOR_KERNEL_CS >> 3],sizeof(DESCRIPTOR));
p_proc->task.ldts[0].attr1 = DA_C | PRIVILEGE_USER << 5;
memcpy(&p_proc->task.ldts[1], &gdt[SELECTOR_KERNEL_DS >> 3],sizeof(DESCRIPTOR));
p_proc->task.ldts[1].attr1 = DA_DRW | PRIVILEGE_USER << 5;
/**************寄存器初值**********************************/
p_proc->task.regs.cs = ((8 * 0) & SA_RPL_MASK & SA_TI_MASK)| SA_TIL | RPL_USER;
p_proc->task.regs.ds = ((8 * 1) & SA_RPL_MASK & SA_TI_MASK)| SA_TIL | RPL_USER;
p_proc->task.regs.es = ((8 * 1) & SA_RPL_MASK & SA_TI_MASK)| SA_TIL | RPL_USER;
p_proc->task.regs.fs = ((8 * 1) & SA_RPL_MASK & SA_TI_MASK)| SA_TIL | RPL_USER;
p_proc->task.regs.ss = ((8 * 1) & SA_RPL_MASK & SA_TI_MASK)| SA_TIL | RPL_USER;
p_proc->task.regs.gs = (SELECTOR_KERNEL_GS & SA_RPL_MASK)| RPL_USER;
p_proc->task.regs.eflags = 0x0202; /* IF=1, 倒数第二位恒为1 */
/****************页表、代码数据、堆栈*****************************/
//无
/***************copy registers data to kernel stack****************************/
//copy registers data to the bottom of the new kernel stack
//added by xw, 17/12/11
p_regs = (char*)(p_proc + 1);
p_regs -= P_STACKTOP;
memcpy(p_regs, (char*)p_proc, 18 * 4);
/***************some field about process switch****************************/
p_proc->task.esp_save_int = p_regs; //initialize esp_save_int, added by xw, 17/12/11
//p_proc->task.save_type = 1;
p_proc->task.esp_save_context = p_regs - 10 * 4; //when the process is chosen to run for the first time,
//sched() will fetch value from esp_save_context
eip_context = restart_restore;
*(u32*)(p_regs - 4) = (u32)eip_context; //initialize EIP in the context, so the process can
//start run. added by xw, 18/4/18
*(u32*)(p_regs - 8) = 0x1202; //initialize EFLAGS in the context, IF=1, IOPL=1. xw, 18/4/20
/***************变量调整****************************/
p_proc++;
selector_ldt += 1 << 3;
}
proc_table[0].task.ticks = proc_table[0].task.priority = 1;
proc_table[1].task.ticks = proc_table[1].task.priority = 1;
proc_table[2].task.ticks = proc_table[2].task.priority = 1;
proc_table[3].task.ticks = proc_table[3].task.priority = 1; //added by xw, 18/8/27
proc_table[NR_K_PCBS].task.ticks = proc_table[NR_K_PCBS].task.priority = 1;
/* When the first process begin running, a clock-interruption will happen immediately.
* If the first process's initial ticks is 1, it won't be the first process to execute its
* user code. Thus, it's will look weird, for proc_table[0] don't output first.
* added by xw, 18/4/19
*/
proc_table[0].task.ticks = 2;
return 0;
}

405
kernel/memman.c Normal file
View File

@ -0,0 +1,405 @@
#include "type.h"
#include "const.h"
#include "protect.h"
#include "string.h"
#include "proc.h"
#include "global.h"
#include "proto.h"
#include "memman.h"
#include "stdio.h"
u32 MemInfo[256] = {0}; //存放FMIBuff后1k内容
struct MEMMAN s_memman;
struct MEMMAN *memman = &s_memman;//(struct MEMMAN *) MEMMAN_ADDR;
void memman_init(struct MEMMAN *man);
u32 memman_alloc(struct MEMMAN *man,u32 size);
u32 memman_kalloc(struct MEMMAN *man,u32 size);
u32 memman_alloc_4k(struct MEMMAN *man);
u32 memman_kalloc_4k(struct MEMMAN *man);
u32 memman_free(struct MEMMAN *man, u32 addr, u32 size);
void disp_free();
u32 memman_total(struct MEMMAN *man);
void init() //初始化
{
u32 memstart = MEMSTART; //4M 开始初始化
u32 i,j;
memcpy(MemInfo,(u32 *)FMIBuff,1024); //复制内存
memman_init(memman); //初始化memman中frees,maxfrees,lostsize,losts
for(i = 1; i <= MemInfo[0]; i++)
{
if(MemInfo[i] < memstart)continue; //4M 之后开始free
memman_free(memman,memstart,MemInfo[i] - memstart); //free每一段可用内存
memstart = MemInfo[i] + 0x1000; //memtest_sub(start,end)中每4KB检测一次
}
for(i = 0; i < memman->frees; i++)
{//6M处分开46M为kmalloc_4k使用68M为kmalloc使用
if((memman->free[i].addr <= KWALL)&&(memman->free[i].addr + memman->free[i].size > KWALL)){
if(memman->free[i].addr == KWALL)break;
else{
for(j = memman->frees; j>i+1; j--)
{ //i之后向后一位
memman->free[j] = memman->free[j-1];
}
memman->frees++;
if(memman->maxfrees < memman->frees){ //更新man->maxfrees
memman->maxfrees = memman->frees;
}
memman->free[i+1].addr = KWALL;
memman->free[i+1].size = memman->free[i].addr + memman->free[i].size - KWALL;
memman->free[i].size = KWALL - 0x1000 - memman->free[i].addr;
break;
}
}
}
for(i = 0; i < memman->frees; i++)
{//8M处分开48M为kmalloc使用832M为malloc使用
if((memman->free[i].addr <= WALL)&&(memman->free[i].addr + memman->free[i].size > WALL)){
if(memman->free[i].addr == WALL)break;
else{
for(j = memman->frees; j>i+1; j--)
{ //i之后向后一位
memman->free[j] = memman->free[j-1];
}
memman->frees++;
if(memman->maxfrees < memman->frees){ //更新man->maxfrees
memman->maxfrees = memman->frees;
}
memman->free[i+1].addr = WALL;
memman->free[i+1].size = memman->free[i].addr + memman->free[i].size - WALL;
memman->free[i].size = WALL - 0x1000 - memman->free[i].addr;
break;
}
}
}
for(i = 0; i < memman->frees; i++)
{//16M处分开816M为malloc使用1632M为malloc_4k使用
if((memman->free[i].addr <= UWALL)&&(memman->free[i].addr + memman->free[i].size > UWALL)){
if(memman->free[i].addr == UWALL)break;
else{
for(j = memman->frees; j>i+1; j--)
{ //i之后向后一位
memman->free[j] = memman->free[j-1];
}
memman->frees++;
if(memman->maxfrees < memman->frees){ //更新man->maxfrees
memman->maxfrees = memman->frees;
}
memman->free[i+1].addr = UWALL;
memman->free[i+1].size = memman->free[i].addr + memman->free[i].size - UWALL;
memman->free[i].size = UWALL - 0x1000 - memman->free[i].addr;
break;
}
}
}
//modified by xw, 18/6/18
//显示初始总容量
kprintf("Memory Available:%d\n", memman_total(memman));
//~xw
return;
} //于kernel_main()中调用,进行初始化
void memman_init(struct MEMMAN *man)
{ //memman基本信息初始化
man->frees = 0;
man->maxfrees = 0;
man->lostsize = 0;
man->losts = 0;
return;
}
u32 memman_alloc(struct MEMMAN *man,u32 size)
{ //分配
u32 i,a;
for(i=0; i<man->frees; i++)
{
if((man->free[i].addr >= WALL)&&(man->free[i].addr + size < UWALL)){ //8M到16M
if(man->free[i].size >= size){
a = man->free[i].addr;
man->free[i].addr += size;
man->free[i].size -= size;
if(man->free[i].size == 0){
man->frees--;
for(; i<man->frees; i++)
{
man->free[i] = man->free[i+1];
}
}
return a;
}
}
}
return -1;
}
u32 memman_kalloc(struct MEMMAN *man,u32 size)
{ //分配
u32 i,a;
for(i=0; i<man->frees; i++)
{
if((man->free[i].addr >= KWALL)&&(man->free[i].addr + size < WALL)){ //4M到8M
if(man->free[i].size >= size){
a = man->free[i].addr;
man->free[i].addr += size;
man->free[i].size -= size;
if(man->free[i].size == 0){
man->frees--;
for(; i<man->frees; i++)
{
man->free[i] = man->free[i+1];
}
}
return a;
}
}
}
return -1;
}
u32 memman_alloc_4k(struct MEMMAN *man)
{ //分配
u32 i,a;
u32 size = 0x1000;
for(i=0; i<man->frees; i++)
{
if((man->free[i].addr >= UWALL)&&(man->free[i].addr + size < MEMEND)){ //16M到32M
if(man->free[i].size >= size){
a = man->free[i].addr;
man->free[i].addr += size;
man->free[i].size -= size;
if(man->free[i].size == 0){
man->frees--;
for(; i<man->frees; i++)
{
man->free[i] = man->free[i+1];
}
}
return a;
}
}
}
return -1;
}
u32 memman_kalloc_4k(struct MEMMAN *man)
{ //分配
u32 i,a;
u32 size = 0x1000;
for(i=0; i<man->frees; i++)
{
if((man->free[i].addr >= MEMSTART)&&(man->free[i].addr + size < KWALL)){ //4M到6M
if(man->free[i].size >= size){
a = man->free[i].addr;
man->free[i].addr += size;
man->free[i].size -= size;
if(man->free[i].size == 0){
man->frees--;
for(; i<man->frees; i++)
{
man->free[i] = man->free[i+1];
}
}
return a;
}
}
}
return -1;
}
u32 memman_free(struct MEMMAN *man, u32 addr, u32 size)
{ //释放
int i,j;
if(size == 0)return 0; //初始化时,防止有连续坏块
for(i=0; i<man->frees; i++)
{
if(man->free[i].addr > addr){
break;
}
} //man->free[i-1].addr < addr <man->free[i].addr
if(i > 0){ //前面有可分配内存
if(man->free[i-1].addr + man->free[i-1].size == addr){ //与前面相邻
man->free[i-1].size += size;
if(i < man->frees){ //后面有可分配内存
if(addr + size == man->free[i].addr){ //同时与后面相邻
man->free[i-1].size += man->free[i].size;
man->frees--;
for(; i<man->frees; i++)
{
man->free[i] = man->free[i+1]; //结构体赋值i之后向前一位
}
}
}
return 0;
} //与前面不相邻
} //前面无可分配内存
if(i < man->frees){ //后面有可分配内存
if(addr + size == man->free[i].addr){ //与后面相邻
man->free[i].addr = addr;
man->free[i].size += size;
return 0;
}
}
if(man->frees < MEMMAN_FREES){ //数组未满
for(j = man->frees; j>i; j--)
{ //i之后向后一位
man->free[j] = man->free[j-1];
}
man->frees++;
if(man->maxfrees < man->frees){ //更新man->maxfrees
man->maxfrees = man->frees;
}
man->free[i].addr = addr; //插入
man->free[i].size = size;
return 0;
}
man->losts++; //free失败
man->lostsize += size;
return -1;
}
u32 memman_free_4k(struct MEMMAN *man, u32 addr)
{
return memman_free(man, addr, 0x1000);
}
u32 do_malloc(u32 size)
{
return memman_alloc(memman,size);
}
u32 do_kmalloc(u32 size)
{
return memman_kalloc(memman,size);
}
u32 do_malloc_4k()
{
return memman_alloc_4k(memman);
}
u32 do_kmalloc_4k()
{
return memman_kalloc_4k(memman);
}
u32 do_free(u32 addr,u32 size)
{
return memman_free(memman,addr,size);
}
u32 do_free_4k(u32 addr)
{
return memman_free_4k(memman,addr);
}
void disp_free()
{ //打印空闲内存块信息
for(int i = 0; i < memman->frees; i++)
kprintf("0x%x#0x%x###", memman->free[i].addr, memman->free[i].size);
}
u32 memman_total(struct MEMMAN *man)
{ //free总容量
u32 i,t=0;
for(i=0; i<man->frees; i++){
t += man->free[i].size;
}
return t;
}
void memman_test()
{ //测试
u32 *p1 = 0;
u32 *p2 = 0;
u32 *p3 = 0;
u32 *p4 = 0;
u32 *p = 0;
p1 = (u32 *)do_malloc(4);
if(-1 != (u32)p1){ //打印p1当前空闲内存信息p1所指内存的内容
disp_str("START");
disp_int((u32)p1);
//disp_free();
*p1 = TEST;
disp_int(*p1);
disp_str("END");
}
p2 = (u32 *)do_kmalloc(4);
if(-1 != (u32)p2){
disp_str("START");
disp_int((u32)p2);
//disp_free();
*p2 = TEST;
disp_int(*p2);
disp_str("END");
}
do_free((u32)p1,4);
do_free((u32)p2,4);
p3 = (u32 *)do_malloc_4k();
if(-1 != (u32)p3){
disp_str("START");
disp_int((u32)p3);
//disp_free();
*p3 = TEST;
disp_int(*p3);
p = p3 + 2044;
*p = 0x22334455;
disp_int(*p);
p += 2048;
*p = 0x33445566;
disp_int(*p);
disp_str("END");
}
p4 = (u32 *)do_kmalloc_4k(4);
if(-1 != (u32)p4){
disp_str("START");
disp_int((u32)p4);
//disp_free();
*p4 = TEST;
disp_int(*p4);
p = p4 + 2044;
*p = 0x22334455;
disp_int(*p);
p += 2048;
*p = 0x33445566;
disp_int(*p);
disp_str("END");
}
do_free_4k((u32)p3);
do_free_4k((u32)p4);
disp_str("START");
disp_free();
disp_str("END");
return;
}

375
kernel/pagetbl.c Normal file
View File

@ -0,0 +1,375 @@
/*************************************************************
* add by visual 2016.4.19
**************************************************************/
#include "type.h"
#include "const.h"
#include "protect.h"
#include "string.h"
#include "proc.h"
#include "global.h"
#include "proto.h"
#include "memman.h"
// to determine if a page fault is reparable. added by xw, 18/6/11
u32 cr2_save;
u32 cr2_count = 0;
/*======================================================================*
switch_pde added by xw, 17/12/11
*switch the page directory table after schedule() is called
*======================================================================*/
void switch_pde()
{
cr3_ready = p_proc_current->task.cr3;
}
/*======================================================================*
init_page_pte add by visual 2016.4.19
*
*======================================================================*/
u32 init_page_pte(u32 pid)
{ //页表初始化函数
u32 AddrLin, pde_addr_phy_temp, err_temp;
pde_addr_phy_temp = do_kmalloc_4k(); //为页目录申请一页
memset((void *)K_PHY2LIN(pde_addr_phy_temp), 0, num_4K); // add by visual 2016.5.26
if (pde_addr_phy_temp < 0 || (pde_addr_phy_temp & 0x3FF) != 0) // add by visual 2016.5.9
{
disp_color_str("init_page_pte Error:pde_addr_phy_temp", 0x74);
return -1;
}
proc_table[pid].task.cr3 = pde_addr_phy_temp; //初始化了进程表中cr3寄存器变量属性位暂时不管
/*********************页表初始化部分*********************************/
u32 phy_addr = 0;
for (AddrLin = KernelLinBase, phy_addr = 0; AddrLin < KernelLinBase + KernelSize; AddrLin += num_4K, phy_addr += num_4K)
{ //只初始化内核部分3G后的线性地址映射到物理地址开始处
err_temp = lin_mapping_phy(AddrLin, //线性地址 //add by visual 2016.5.9
phy_addr, //物理地址
pid, //进程pid //edit by visual 2016.5.19
PG_P | PG_USU | PG_RWW, //页目录的属性位(用户权限) //edit by visual 2016.5.26
PG_P | PG_USS | PG_RWW); //页表的属性位(系统权限) //edit by visual 2016.5.17
if (err_temp != 0)
{
disp_color_str("init_page_pte Error:lin_mapping_phy", 0x74);
return -1;
}
}
return 0;
}
/*======================================================================*
page_fault_handle edit by visual 2016.5.9
*======================================================================*/
void page_fault_handler(u32 vec_no, //异常编号此时应该是14代表缺页异常
u32 err_code, //错误码
u32 eip, //导致缺页的指令的线性地址
u32 cs, //发生错误时的代码段寄存器内容
u32 eflags) //时发生错误的标志寄存器内容
{ //缺页中断处理函数
u32 pde_addr_phy_temp;
u32 pte_addr_phy_temp;
u32 cr2;
cr2 = read_cr2();
// if page fault happens in kernel, it's an error.
if (kernel_initial == 1)
{
disp_str("\n");
disp_color_str("Page Fault\n", 0x74);
disp_color_str("eip=", 0x74); //灰底红字
disp_int(eip);
disp_color_str("eflags=", 0x74);
disp_int(eflags);
disp_color_str("cs=", 0x74);
disp_int(cs);
disp_color_str("err_code=", 0x74);
disp_int(err_code);
disp_color_str("Cr2=", 0x74); //灰底红字
disp_int(cr2);
halt();
}
//获取该进程页目录物理地址
pde_addr_phy_temp = get_pde_phy_addr(p_proc_current->task.pid);
//获取该线性地址对应的页表的物理地址
pte_addr_phy_temp = get_pte_phy_addr(p_proc_current->task.pid, cr2);
if (cr2 == cr2_save)
{
cr2_count++;
if (cr2_count == 5)
{
disp_str("\n");
disp_color_str("Page Fault\n", 0x74);
disp_color_str("eip=", 0x74); //灰底红字
disp_int(eip);
disp_color_str("eflags=", 0x74);
disp_int(eflags);
disp_color_str("cs=", 0x74);
disp_int(cs);
disp_color_str("err_code=", 0x74);
disp_int(err_code);
disp_color_str("Cr2=", 0x74); //灰底红字
disp_int(cr2);
disp_color_str("Cr3=", 0x74);
disp_int(p_proc_current->task.cr3);
//获取页目录中填写的内容
disp_color_str("Pde=", 0x74);
disp_int(*((u32 *)K_PHY2LIN(pde_addr_phy_temp) + get_pde_index(cr2)));
//获取页表中填写的内容
disp_color_str("Pte=", 0x74);
disp_int(*((u32 *)K_PHY2LIN(pte_addr_phy_temp) + get_pte_index(cr2)));
halt();
}
}
else
{
cr2_save = cr2;
cr2_count = 0;
}
if (0 == pte_exist(pde_addr_phy_temp, cr2))
{ //页表不存在
// disp_color_str("[Pde Fault!]",0x74); //灰底红字
(*((u32 *)K_PHY2LIN(pde_addr_phy_temp) + get_pde_index(cr2))) |= PG_P;
// disp_color_str("[Solved]",0x74);
}
else
{ //只是缺少物理页
// disp_color_str("[Pte Fault!]",0x74); //灰底红字
(*((u32 *)K_PHY2LIN(pte_addr_phy_temp) + get_pte_index(cr2))) |= PG_P;
// disp_color_str("[Solved]",0x74);
}
refresh_page_cache();
}
/***************************地址转换过程***************************
*
*CR3包含着页目录的起始地址32线10A31~A22作为页目录的页目录项的索引
*4CR3中的页目录的起始地址相加
*
*3212032
*32线A21~A12位作为页表中的页面的索引432
*
*A11~A0作为相对于页面地址的偏移量3232
*************************************************************************/
/*======================================================================*
get_pde_index add by visual 2016.4.28
*======================================================================*/
inline u32 get_pde_index(u32 AddrLin)
{ //由 线性地址 得到 页目录项编号
return (AddrLin >> 22); //高10位A31~A22
}
/*======================================================================*
get_pte_index add by visual 2016.4.28
*======================================================================*/
inline u32 get_pte_index(u32 AddrLin)
{ //由 线性地址 得到 页表项编号
return (((AddrLin)&0x003FFFFF) >> 12); //中间10位A21~A12,0x3FFFFF = 0000 0000 0011 1111 1111 1111 1111 1111
}
/*======================================================================*
get_pde_phy_addr add by visual 2016.4.28
*======================================================================*/
inline u32 get_pde_phy_addr(u32 pid)
{ //获取页目录物理地址
if (proc_table[pid].task.cr3 == 0)
{ //还没有初始化页目录
return -1;
}
else
{
return ((proc_table[pid].task.cr3) & 0xFFFFF000);
}
}
/*======================================================================*
get_pte_phy_addr add by visual 2016.4.28
*======================================================================*/
inline u32 get_pte_phy_addr(u32 pid, //页目录物理地址 //edit by visual 2016.5.19
u32 AddrLin) //线性地址
{ //获取该线性地址所属页表的物理地址
u32 PageDirPhyAddr = get_pde_phy_addr(pid); // add by visual 2016.5.19
return (*((u32 *)K_PHY2LIN(PageDirPhyAddr) + get_pde_index(AddrLin))) & 0xFFFFF000; //先找到该进程页目录首地址,然后计算出该线性地址对应的页目录项,再访问,最后注意4k对齐
}
/*======================================================================*
get_page_phy_addr add by visual 2016.5.9
*======================================================================*/
inline u32 get_page_phy_addr(u32 pid, //页表物理地址 //edit by visual 2016.5.19
u32 AddrLin) //线性地址
{ //获取该线性地址对应的物理页物理地址
u32 PageTblPhyAddr = get_pte_phy_addr(pid, AddrLin); // add by visual 2016.5.19
return (*((u32 *)K_PHY2LIN(PageTblPhyAddr) + get_pte_index(AddrLin))) & 0xFFFFF000;
}
/*======================================================================*
pte_exist add by visual 2016.4.28
*======================================================================*/
u32 pte_exist(u32 PageDirPhyAddr, //页目录物理地址
u32 AddrLin) //线性地址
{ //判断 有没有 页表
if ((0x00000001 & (*((u32 *)K_PHY2LIN(PageDirPhyAddr) + get_pde_index(AddrLin)))) == 0) //先找到该进程页目录,然后计算出该线性地址对应的页目录项,访问并判断其是否存在
{ //标志位为0不存在
return 0;
}
else
{
return 1;
}
}
/*======================================================================*
phy_exist add by visual 2016.4.28
*======================================================================*/
u32 phy_exist(u32 PageTblPhyAddr, //页表物理地址
u32 AddrLin) //线性地址
{ //判断 该线性地址 有没有 对应的 物理页
if ((0x00000001 & (*((u32 *)K_PHY2LIN(PageTblPhyAddr) + get_pte_index(AddrLin)))) == 0)
{ //标志位为0不存在
return 0;
}
else
{
return 1;
}
}
/*======================================================================*
write_page_pde add by visual 2016.4.28
*======================================================================*/
void write_page_pde(u32 PageDirPhyAddr, //页目录物理地址
u32 AddrLin, //线性地址
u32 TblPhyAddr, //要填写的页表的物理地址函数会进行4k对齐
u32 Attribute) //属性
{ //填写页目录
(*((u32 *)K_PHY2LIN(PageDirPhyAddr) + get_pde_index(AddrLin))) = (TblPhyAddr & 0xFFFFF000) | Attribute;
//进程页目录起始地址+每一项的大小*所属的项
}
/*======================================================================*
write_page_pte add by visual 2016.4.28
*======================================================================*/
void write_page_pte(u32 TblPhyAddr, //页表物理地址
u32 AddrLin, //线性地址
u32 PhyAddr, //要填写的物理页物理地址(任意的物理地址函数会进行4k对齐)
u32 Attribute) //属性
{ //填写页目录,会添加属性
(*((u32 *)K_PHY2LIN(TblPhyAddr) + get_pte_index(AddrLin))) = (PhyAddr & 0xFFFFF000) | Attribute;
//页表起始地址+一项的大小*所属的项
}
/*======================================================================*
* vmalloc add by visual 2016.5.4
*size大小的内存线
*======================================================================*/
u32 vmalloc(u32 size)
{
u32 temp;
if (p_proc_current->task.info.type == TYPE_PROCESS)
{ //进程直接就是标识
temp = p_proc_current->task.memmap.heap_lin_limit;
p_proc_current->task.memmap.heap_lin_limit += size;
}
else
{ //线程需要取父进程的标识
temp = *((u32 *)p_proc_current->task.memmap.heap_lin_limit);
(*((u32 *)p_proc_current->task.memmap.heap_lin_limit)) += size;
}
return temp;
}
/*======================================================================*
* lin_mapping_phy add by visual 2016.5.9
*线,
*======================================================================*/
int lin_mapping_phy(u32 AddrLin, //线性地址
u32 phy_addr, //物理地址,若为MAX_UNSIGNED_INT(0xFFFFFFFF)则表示需要由该函数判断是否分配物理地址否则将phy_addr直接和AddrLin建立映射
u32 pid, //进程pid //edit by visual 2016.5.19
u32 pde_Attribute, //页目录中的属性位
u32 pte_Attribute) //页表中的属性位
{
u32 pte_addr_phy;
u32 pde_addr_phy = get_pde_phy_addr(pid); // add by visual 2016.5.19
if (0 == pte_exist(pde_addr_phy, AddrLin))
{ //页表不存在,创建一个,并填进页目录中
pte_addr_phy = (u32)do_kmalloc_4k(); //为页表申请一页
memset((void *)K_PHY2LIN(pte_addr_phy), 0, num_4K); // add by visual 2016.5.26
if (pte_addr_phy < 0 || (pte_addr_phy & 0x3FF) != 0) // add by visual 2016.5.9
{
disp_color_str("lin_mapping_phy Error:pte_addr_phy", 0x74);
return -1;
}
write_page_pde(pde_addr_phy, //页目录物理地址
AddrLin, //线性地址
pte_addr_phy, //页表物理地址
pde_Attribute); //属性
}
else
{ //页表存在,获取该页表物理地址
pte_addr_phy = get_pte_phy_addr(pid, //进程pid //edit by visual 2016.5.19
AddrLin); //线性地址
}
if (MAX_UNSIGNED_INT == phy_addr) // add by visual 2016.5.19
{ //由函数申请内存
if (0 == phy_exist(pte_addr_phy, AddrLin))
{ //无物理页申请物理页并修改phy_addr
if (AddrLin >= K_PHY2LIN(0))
phy_addr = do_kmalloc_4k(); //从内核物理地址申请一页
else
{
// disp_str("%");
phy_addr = do_malloc_4k(); //从用户物理地址空间申请一页
}
}
else
{
//有物理页,什么也不做,直接返回,必须返回
return 0;
}
}
else
{ //指定填写phy_addr
//不用修改phy_addr
}
if (phy_addr < 0 || (phy_addr & 0x3FF) != 0)
{
disp_color_str("lin_mapping_phy:phy_addr ERROR", 0x74);
return -1;
}
write_page_pte(pte_addr_phy, //页表物理地址
AddrLin, //线性地址
phy_addr, //物理页物理地址
pte_Attribute); //属性
refresh_page_cache();
return 0;
}
/*======================================================================*
* clear_kernel_pagepte_low add by visual 2016.5.12
*
*======================================================================*/
void clear_kernel_pagepte_low()
{
u32 page_num = *(u32 *)PageTblNumAddr;
memset((void *)(K_PHY2LIN(KernelPageTblAddr)), 0, 4 * page_num); //从内核页目录中清除内核页目录项前8项
memset((void *)(K_PHY2LIN(KernelPageTblAddr + 0x1000)), 0, 4096 * page_num); //从内核页表中清除线性地址的低端映射关系
refresh_page_cache();
}

137
kernel/proc.c Normal file
View File

@ -0,0 +1,137 @@
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
proc.c
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Forrest Yu, 2005
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
#include "type.h"
#include "const.h"
#include "protect.h"
#include "string.h"
#include "proc.h"
#include "global.h"
#include "proto.h"
/*======================================================================*
schedule
*======================================================================*/
void schedule()
{
PROCESS* p;
int greatest_ticks = 0;
//Added by xw, 18/4/21
if (p_proc_current->task.stat == READY && p_proc_current->task.ticks > 0) {
p_proc_next = p_proc_current; //added by xw, 18/4/26
return;
}
while (!greatest_ticks)
{
for (p = proc_table; p < proc_table+NR_PCBS; p++) //edit by visual 2016.4.5
{
if (p->task.stat == READY && p->task.ticks > greatest_ticks) //edit by visual 2016.4.5
{
greatest_ticks = p->task.ticks;
// p_proc_current = p;
p_proc_next = p; //modified by xw, 18/4/26
}
}
if (!greatest_ticks)
{
for (p = proc_table; p < proc_table+NR_PCBS; p++) //edit by visual 2016.4.5
{
p->task.ticks = p->task.priority;
}
}
}
}
/*======================================================================*
alloc_PCB add by visual 2016.4.8
*======================================================================*/
PROCESS* alloc_PCB()
{//分配PCB表
PROCESS* p;
int i;
p=proc_table+NR_K_PCBS;//跳过前NR_K_PCBS个
for(i=NR_K_PCBS;i<NR_PCBS;i++)
{
if(p->task.stat==IDLE)break;
p++;
}
if(i>=NR_PCBS) return 0; //NULL
else return p;
}
/*======================================================================*
free_PCB add by visual 2016.4.8
*======================================================================*/
void free_PCB(PROCESS *p)
{//释放PCB表
p->task.stat=IDLE;
}
/*======================================================================*
yield and sleep
*======================================================================*/
//used for processes to give up the CPU
void sys_yield()
{
p_proc_current->task.ticks = 0; /* modified by xw, 18/4/27 */
sched(); //Modified by xw, 18/4/19
}
//used for processes to sleep for n ticks
void sys_sleep(int n)
{
int ticks0;
ticks0 = ticks;
p_proc_current->task.channel = &ticks;
while(ticks - ticks0 < n){
p_proc_current->task.stat = SLEEPING;
// save_context();
sched(); //Modified by xw, 18/4/19
}
}
/*invoked by clock-interrupt handler to wakeup
*processes sleeping on ticks.
*/
void sys_wakeup(void *channel)
{
PROCESS *p;
for(p = proc_table; p < proc_table + NR_PCBS; p++){
if(p->task.stat == SLEEPING && p->task.channel == channel){
p->task.stat = READY;
}
}
}
//added by zcr
int ldt_seg_linear(PROCESS *p, int idx)
{
struct s_descriptor * d = &p->task.ldts[idx];
return d->base_high << 24 | d->base_mid << 16 | d->base_low;
}
void* va2la(int pid, void* va)
{
if(kernel_initial == 1){
return va;
}
PROCESS* p = &proc_table[pid];
u32 seg_base = ldt_seg_linear(p, INDEX_LDT_RW);
u32 la = seg_base + (u32)va;
return (void*)la;
}
//~zcr

334
kernel/protect.c Normal file
View File

@ -0,0 +1,334 @@
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
protect.c
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Forrest Yu, 2005
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
#include "type.h"
#include "const.h"
#include "protect.h"
#include "proc.h"
#include "global.h"
#include "proto.h"
#include "string.h"
/* 本文件内函数声明 */
static void init_idt_desc(unsigned char vector, u8 desc_type, int_handler handler, unsigned char privilege);
static 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
*======================================================================*/
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);
/*修改显存描述符*/ //add by visual 2016.5.12
init_descriptor(&gdt[INDEX_VIDEO],
K_PHY2LIN(0x0B8000),
0x0ffff,
DA_DRW | DA_DPL3);
/* 填充 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_PCBS;i++){ //edit by visual 2016.4.5
init_descriptor(&gdt[selector_ldt>>3],
vir2phys(seg2phys(SELECTOR_KERNEL_DS),proc_table[i].task.ldts),
LDT_SIZE * sizeof(DESCRIPTOR) - 1,
DA_LDT);
p_proc++;
selector_ldt += 1 << 3;
}
}
/*======================================================================*
init_idt_desc
*----------------------------------------------------------------------*
386
*======================================================================*/
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
*----------------------------------------------------------------------*
*======================================================================*/
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
*----------------------------------------------------------------------*
*======================================================================*/
static 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
*----------------------------------------------------------------------*
*======================================================================*/
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);
}
//added by xw, 18/12/19
disp_str("\n");
//added by xw, 18/12/19
p_proc_current->task.stat = KILLED;
}
/*======================================================================*
divide error handler
*======================================================================*/
//used for testing if a exception handler can be interrupted rightly, so it's
//not a real divide_error handler now. added by xw, 18/12/22
void divide_error_handler()
{
int vec_no, err_code, eip, cs, eflags;
int i, j;
asm volatile ( "mov 8(%%ebp), %0\n\t" //get vec_no from stack
"mov 12(%%ebp), %1\n\t" //get err_code from stack
"mov 16(%%ebp), %2\n\t" //get eip from stack
"mov 20(%%ebp), %3\n\t" //get cs from stack
"mov 24(%%ebp), %4\n\t" //get eflags from stack
: "=r"(vec_no), "=r"(err_code), "=r"(eip),
"=r"(cs), "=r"(eflags)
);
exception_handler(vec_no, err_code, eip, cs, eflags);
while (1)
{
disp_str("Loop in divide error handler...\n");
i = 100;
while(--i){
j = 1000;
while(--j){}
}
}
}

213
kernel/pthread.c Normal file
View File

@ -0,0 +1,213 @@
/******************************************************************
* pthread.c //add by visual 2016.5.26
*pthread()
*******************************************************************/
#include "type.h"
#include "const.h"
#include "protect.h"
#include "string.h"
#include "proc.h"
#include "global.h"
#include "proto.h"
static int pthread_pcb_cpy(PROCESS *p_child,PROCESS *p_parent);
static int pthread_update_info(PROCESS *p_child,PROCESS *p_parent);
static int pthread_stack_init(PROCESS *p_child,PROCESS *p_parent);
static int pthread_heap_init(PROCESS *p_child,PROCESS *p_parent);
/**********************************************************
* sys_pthread //add by visual 2016.5.25
*sys_pthread的具体实现部分
*************************************************************/
int sys_pthread(void *entry)
{
PROCESS* p_child;
char* p_reg; //point to a register in the new kernel stack, added by xw, 17/12/11
/*if(p_proc_current->task.info.type == TYPE_THREAD )
{//线程不能创建线程
disp_color_str("[pthread failed:",0x74);
disp_color_str(p_proc_current->task.p_name,0x74);
disp_color_str("]",0x74);
return -1;
}*/
/*****************申请空白PCB表**********************/
p_child = alloc_PCB();
if( 0==p_child )
{
disp_color_str("PCB NULL,pthread faild!",0x74);
return -1;
}
else
{
PROCESS *p_parent;
if( p_proc_current->task.info.type == TYPE_THREAD )
{//线程
p_parent = &(proc_table[p_proc_current->task.info.ppid]);//父进程
}
else
{//进程
p_parent = p_proc_current;//父进程就是父线程
}
/************复制父进程的PCB部分内容保留了自己的标识信息,但cr3使用的是父进程的**************/
pthread_pcb_cpy(p_child,p_parent);
/************在父进程的栈中分配子线程的栈从进程栈的低地址分配8M,注意方向)**********************/
pthread_stack_init(p_child,p_parent);
/**************初始化子线程的堆(此时的这两个变量已经变成了指针)***********************/
pthread_heap_init(p_child,p_parent);
/********************设置线程的执行入口**********************************************/
p_child->task.regs.eip = (u32)entry;
p_reg = (char*)(p_child + 1); //added by xw, 17/12/11
*((u32*)(p_reg + EIPREG - P_STACKTOP)) = p_child->task.regs.eip; //added by xw, 17/12/11
/**************更新进程树标识info信息************************/
pthread_update_info(p_child,p_parent);
/************修改子进程的名字***************/
strcpy(p_child->task.p_name,"pthread"); // 所有的子进程都叫pthread
/*************子进程返回值在其eax寄存器***************/
p_child->task.regs.eax = 0;//return child with 0
p_reg = (char*)(p_child + 1); //added by xw, 17/12/11
*((u32*)(p_reg + EAXREG - P_STACKTOP)) = p_child->task.regs.eax; //added by xw, 17/12/11
/****************用户进程数+1****************************/
u_proc_sum += 1;
disp_color_str("[pthread success:",0x72);
disp_color_str(p_proc_current->task.p_name,0x72);
disp_color_str("]",0x72);
//anything child need is prepared now, set its state to ready. added by xw, 17/12/11
p_child->task.stat = READY;
}
return p_child->task.pid;
}
/**********************************************************
* pthread_pcb_cpy //add by visual 2016.5.26
*PCB表
*************************************************************/
static int pthread_pcb_cpy(PROCESS *p_child,PROCESS *p_parent)
{
int pid;
u32 eflags,selector_ldt;
char* p_reg; //point to a register in the new kernel stack, added by xw, 17/12/11
char *esp_save_int, *esp_save_context; //use to save corresponding field in child's PCB, xw, 18/4/21
//暂存标识信息
pid = p_child->task.pid;
//eflags = p_child->task.regs.eflags; //deleted by xw, 17/12/11
p_reg = (char*)(p_child + 1); //added by xw, 17/12/11
eflags = *((u32*)(p_reg + EFLAGSREG - P_STACKTOP)); //added by xw, 17/12/11
selector_ldt = p_child->task.ldt_sel;
//复制PCB内容
//modified by xw, 17/12/11
//modified begin
//*p_child = *p_parent;
//esp_save_int and esp_save_context must be saved, because the child and the parent
//use different kernel stack! And these two are importent to the child's initial running.
//Added by xw, 18/4/21
esp_save_int = p_child->task.esp_save_int;
esp_save_context = p_child->task.esp_save_context;
p_child->task = p_parent->task;
//note that syscalls can be interrupted now! the state of child can only be setted
//READY when anything else is well prepared. if an interruption happens right here,
//an error will still occur.
p_child->task.stat = IDLE;
p_child->task.esp_save_int = esp_save_int; //esp_save_int of child must be restored!!
p_child->task.esp_save_context = esp_save_context; //same above
memcpy(((char*)(p_child + 1) - P_STACKTOP), ((char*)(p_parent + 1) - P_STACKTOP), 18 * 4);
//modified end
//恢复标识信息
p_child->task.pid = pid;
//p_child->task.regs.eflags = eflags;
p_reg = (char*)(p_child + 1); //added by xw, 17/12/11
*((u32*)(p_reg + EFLAGSREG - P_STACKTOP)) = eflags; //added by xw, 17/12/11
p_child->task.ldt_sel = selector_ldt;
return 0;
}
/**********************************************************
* pthread_update_info //add by visual 2016.5.26
*线info
*************************************************************/
static int pthread_update_info(PROCESS* p_child,PROCESS *p_parent)
{
/************更新父进程的info***************///注意 父进程 父进程 父进程
if( p_parent!=p_proc_current )
{//只有在线程创建线程的时候才会执行 p_parent事实上是父进程
p_parent->task.info.child_t_num += 1; //子线程数量
p_parent->task.info.child_thread[p_parent->task.info.child_t_num-1] = p_child->task.pid;//子线程列表
}
/************更新父线程的info**************/
//p_proc_current->task.info.type; //当前是进程还是线程
//p_proc_current->task.info.real_ppid; //亲父进程,创建它的那个进程
//p_proc_current->task.info.ppid; //当前父进程
//p_proc_current->task.info.child_p_num += 1; //子进程数量
//p_proc_current->task.info.child_process[p_proc_current->task.info.child_p_num-1] = p_child->task.pid;//子进程列表
p_proc_current->task.info.child_t_num += 1; //子线程数量
p_proc_current->task.info.child_thread[p_proc_current->task.info.child_t_num-1] = p_child->task.pid;//子线程列表
//p_proc_current->task.text_hold; //是否拥有代码
//p_proc_current->task.data_hold; //是否拥有数据
/************更新子线程的info***************/
p_child->task.info.type = TYPE_THREAD ;//这是一个线程
p_child->task.info.real_ppid = p_proc_current->task.pid; //亲父进程创建它的那个线程注意这个是创建它的那个线程p_proc_current
p_child->task.info.ppid = p_parent->task.pid; //当前父进程
p_child->task.info.child_p_num = 0; //子进程数量
//p_child->task.info.child_process[NR_CHILD_MAX] = pid;//子进程列表
p_child->task.info.child_t_num = 0; //子线程数量
//p_child->task.info.child_thread[NR_CHILD_MAX];//子线程列表
p_child->task.info.text_hold = 0; //是否拥有代码,子进程不拥有代码
p_child->task.info.data_hold = 0; //是否拥有数据,子进程拥有数据
return 0;
}
/**********************************************************
* pthread_stack_init //add by visual 2016.5.26
*线esp
*************************************************************/
static int pthread_stack_init(PROCESS* p_child,PROCESS *p_parent)
{
int addr_lin;
char* p_reg; //point to a register in the new kernel stack, added by xw, 17/12/11
p_child->task.memmap.stack_lin_limit = p_parent->task.memmap.stack_child_limit;//子线程的栈界
p_parent->task.memmap.stack_child_limit += 0x4000; //分配16K
p_child->task.memmap.stack_lin_base = p_parent->task.memmap.stack_child_limit - num_4B; //子线程的基址
for( addr_lin=p_child->task.memmap.stack_lin_base ; addr_lin>p_child->task.memmap.stack_lin_limit ; addr_lin-=num_4K)//申请物理地址
lin_mapping_phy(addr_lin,MAX_UNSIGNED_INT,p_child->task.pid,PG_P | PG_USU | PG_RWW,PG_P | PG_USU | PG_RWW);
p_child->task.regs.esp = p_child->task.memmap.stack_lin_base; //调整esp
p_reg = (char*)(p_child + 1); //added by xw, 17/12/11
*((u32*)(p_reg + ESPREG - P_STACKTOP)) = p_child->task.regs.esp; //added by xw, 17/12/11
return 0;
}
/**********************************************************
* pthread_stack_init //add by visual 2016.5.26
*线使
*************************************************************/
static int pthread_heap_init(PROCESS* p_child,PROCESS *p_parent)
{
p_child->task.memmap.heap_lin_base = (u32)&(p_parent->task.memmap.heap_lin_base);
p_child->task.memmap.heap_lin_limit = (u32)&(p_parent->task.memmap.heap_lin_limit);
return 0;
}

56
kernel/spinlock.c Normal file
View File

@ -0,0 +1,56 @@
/**********************************************************
* spinlock.c //added by mingxuan 2018-12-26
***********************************************************/
// Mutual exclusion spin locks.
//#include "types.h"
//#include "defs.h"
//#include "x86.h"
//#include "mmu.h"
//#include "param.h"
//#include "proc.h"
#include "spinlock.h"
//extern int use_console_lock;
static inline uint
cmpxchg(uint oldval, uint newval, volatile uint* lock_addr)
{
uint result;
asm volatile("lock; cmpxchg %0, %2" :
"+m" (*lock_addr), "=a" (result) :
"r"(newval), "1"(oldval) :
"cc");
return result;
}
void
initlock(struct spinlock *lock, char *name)
{
lock->name = name;
lock->locked = 0;
lock->cpu = 0xffffffff;
}
// Acquire the lock.
// Loops (spins) until the lock is acquired.
// (Because contention is handled by spinning, must not
// go to sleep holding any locks.)
void
acquire(struct spinlock *lock)
{
while(cmpxchg(0, 1, &lock->locked) == 1)
;
}
// Release the lock.
void
release(struct spinlock *lock)
{
lock->locked = 0;
}

82
kernel/start.c Normal file
View File

@ -0,0 +1,82 @@
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
start.c
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Forrest Yu, 2005
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
#include "stdio.h"
#include "protect.h"
#include "proc.h"
#include "global.h"
#include "proto.h"
#include "assert.h"
#include "string.h"
/*
* 使CPU核休眠
*/
void
_panic(const char *file, int line, const char *fmt,...)
{
va_list ap;
// 确保CPU核不受外界中断的影响
asm volatile("cli");
asm volatile("cld");
va_start(ap, fmt);
kprintf("kernel panic at %s:%d: ", file, line);
vkprintf(fmt, ap);
kprintf("\n");
va_end(ap);
// 休眠CPU核直接罢工
while(1)
asm volatile("hlt");
}
/*
* panicCPU核
*/
void
_warn(const char *file, int line, const char *fmt,...)
{
va_list ap;
va_start(ap, fmt);
kprintf("kernel warning at %s:%d: ", file, line);
vkprintf(fmt, ap);
kprintf("\n");
va_end(ap);
}
/*======================================================================*
cstart
*======================================================================*/
void cstart()
{
kprintf("\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();
kprintf("-----\"cstart\" finished-----\n");
}

361
kernel/syscall.asm Normal file
View File

@ -0,0 +1,361 @@
; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; syscall.asm
; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; Forrest Yu, 2005
; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
%include "sconst.inc"
_NR_get_ticks equ 0 ; 要跟 global.c 中 sys_call_table 的定义相对应!
_NR_get_pid equ 1 ; //add by visual 2016.4.6
_NR_kmalloc equ 2 ; //add by visual 2016.4.6
_NR_kmalloc_4k equ 3 ; //add by visual 2016.4.7
_NR_malloc equ 4 ; //add by visual 2016.4.7
_NR_malloc_4k equ 5 ; //add by visual 2016.4.7
_NR_free equ 6 ; //add by visual 2016.4.7
_NR_free_4k equ 7 ; //add by visual 2016.4.7
_NR_fork equ 8 ; //add by visual 2016.4.8
_NR_pthread equ 9 ; //add by visual 2016.4.11
_NR_udisp_int equ 10 ; //add by visual 2016.5.16
_NR_udisp_str equ 11 ; //add by visual 2016.5.16
_NR_exec equ 12 ; //add by visual 2016.5.16
_NR_yield equ 13 ; //added by xw, 17/12
_NR_sleep equ 14 ; //added by xw, 17/12
_NR_print_E equ 15 ; //added by xw, 18/4/27
_NR_print_F equ 16 ; //added by xw, 18/4/27
_NR_open equ 17 ; //added by xw, 18/6/18
_NR_close equ 18 ; //added by xw, 18/6/18
_NR_read equ 19 ; //added by xw, 18/6/18
_NR_write equ 20 ; //added by xw, 18/6/18
_NR_lseek equ 21 ; //added by xw, 18/6/18
_NR_unlink equ 22 ; //added by xw, 18/6/18
_NR_create equ 23 ; //added by mingxuan 2019-5-17
_NR_delete equ 24 ; //added by mingxuan 2019-5-17
_NR_opendir equ 25 ; //added by mingxuan 2019-5-17
_NR_createdir equ 26 ; //added by mingxuan 2019-5-17
_NR_deletedir equ 27 ; //added by mingxuan 2019-5-17
INT_VECTOR_SYS_CALL equ 0x90
; 导出符号
global get_ticks
global get_pid ; //add by visual 2016.4.6
global kmalloc ; //add by visual 2016.4.6
global kmalloc_4k ; //add by visual 2016.4.7
global malloc ; //add by visual 2016.4.7
global malloc_4k ; //add by visual 2016.4.7
global free ; //add by visual 2016.4.7
global free_4k ; //add by visual 2016.4.7
global fork ; //add by visual 2016.4.8
global pthread ; //add by visual 2016.4.11
global udisp_int ; //add by visual 2016.5.16
global udisp_str ; //add by visual 2016.5.16
global exec ; //add by visual 2016.5.16
global yield ; //added by xw
global sleep ; //added by xw
global print_E ; //added by xw
global print_F ; //added by xw
global open ; //added by xw, 18/6/18
global close ; //added by xw, 18/6/18
global read ; //added by xw, 18/6/18
global write ; //added by xw, 18/6/18
global lseek ; //added by xw, 18/6/18
global unlink ; //added by xw, 18/6/19
global create ; //added by mingxuan 2019-5-17
global delete ; //added by mingxuan 2019-5-17
global opendir ; //added by mingxuan 2019-5-17
global createdir ; //added by mingxuan 2019-5-17
global deletedir ; //added by mingxuan 2019-5-17
bits 32
[section .text]
; ====================================================================
; get_ticks
; ====================================================================
get_ticks:
mov eax, _NR_get_ticks
int INT_VECTOR_SYS_CALL
ret
; ====================================================================
; get_pid //add by visual 2016.4.6
; ====================================================================
get_pid:
mov eax, _NR_get_pid
int INT_VECTOR_SYS_CALL
ret
; ; ====================================================================
; ; kmalloc //add by visual 2016.4.6
; ; ====================================================================
; kmalloc:
; push ebx
; mov ebx,[esp+4] ; 将C函数调用时传来的参数放到ebx里!!
; mov eax, _NR_kmalloc
; int INT_VECTOR_SYS_CALL
; pop ebx
; ret
; ; ====================================================================
; ; kmalloc_4k //add by visual 2016.4.7
; ; ====================================================================
; kmalloc_4k:
; push ebx
; mov ebx,[esp+4] ; 将C函数调用时传来的参数放到ebx里!!111
; mov eax, _NR_kmalloc_4k
; int INT_VECTOR_SYS_CALL
; pop ebx
; ret
; ; ====================================================================
; ; malloc //add by visual 2016.4.7
; ; ====================================================================
; malloc:
; push ebx
; mov ebx,[esp+4] ; 将C函数调用时传来的参数放到ebx里!!111
; mov eax, _NR_malloc
; int INT_VECTOR_SYS_CALL
; pop ebx
; ret
; ; ====================================================================
; ; malloc_4k //add by visual 2016.4.7
; ; ====================================================================
; malloc_4k:
; push ebx
; mov ebx,[esp+4] ; 将C函数调用时传来的参数放到ebx里!!111
; mov eax, _NR_malloc_4k
; int INT_VECTOR_SYS_CALL
; pop ebx
; ret
; ; ====================================================================
; ; free //add by visual 2016.4.7
; ; ====================================================================
; free:
; push ebx
; mov ebx,[esp+4] ; 将C函数调用时传来的参数放到ebx里!!111
; mov eax, _NR_free
; int INT_VECTOR_SYS_CALL
; pop ebx
; ret
; ; ====================================================================
; ; free_4k //add by visual 2016.4.7
; ; ====================================================================
; free_4k:
; push ebx
; mov ebx,[esp+4] ; 将C函数调用时传来的参数放到ebx里!!111
; mov eax, _NR_free_4k
; int INT_VECTOR_SYS_CALL
; pop ebx
; ret
; ====================================================================
; fork //add by visual 2016.4.8
; ====================================================================
fork:
mov eax, _NR_fork
int INT_VECTOR_SYS_CALL
ret
; ====================================================================
; pthread //add by visual 2016.4.11
; ====================================================================
pthread:
push ebx
mov ebx,[esp+8]
mov eax, _NR_pthread
int INT_VECTOR_SYS_CALL
pop ebx
ret
; ====================================================================
; udisp_int //add by visual 2016.5.16
; ====================================================================
udisp_int:
push ebx
mov ebx,[esp+8]
mov eax, _NR_udisp_int
int INT_VECTOR_SYS_CALL
pop ebx
ret
; ====================================================================
; udisp_str //add by visual 2016.5.16
; ====================================================================
udisp_str:
push ebx
mov ebx,[esp+8]
mov eax, _NR_udisp_str
int INT_VECTOR_SYS_CALL
pop ebx
ret
; ====================================================================
; exec //add by visual 2016.5.16
; ====================================================================
exec:
push ebx
mov ebx,[esp+8]
mov eax, _NR_exec
int INT_VECTOR_SYS_CALL
pop ebx
ret
; ====================================================================
; yield //added by xw
; ====================================================================
yield:
mov eax, _NR_yield
int INT_VECTOR_SYS_CALL
ret
; ====================================================================
; sleep //added by xw
; ====================================================================
sleep:
push ebx
mov ebx,[esp+8]
mov eax, _NR_sleep
int INT_VECTOR_SYS_CALL
pop ebx
ret
; ; ====================================================================
; ; print_E //added by xw
; ; ====================================================================
; print_E:
; push ebx
; mov ebx,[esp+4]
; mov eax, _NR_print_E
; int INT_VECTOR_SYS_CALL
; pop ebx
; ret
; ; ====================================================================
; ; print_F //added by xw
; ; ====================================================================
; print_F:
; push ebx
; mov ebx,[esp+4]
; mov eax, _NR_print_F
; int INT_VECTOR_SYS_CALL
; pop ebx
; ret
; ====================================================================
; open //added by xw, 18/6/18
; ====================================================================
; open has more than one parameter, to pass them, we save the esp to ebx,
; and ebx will be passed into kernel as usual. In kernel, we use the saved
; esp in user space to get the number of parameters and the values of them.
open:
push ebx
mov ebx, esp
mov eax, _NR_open
int INT_VECTOR_SYS_CALL
pop ebx
ret
; ====================================================================
; close //added by xw, 18/6/18
; ====================================================================
; close has only one parameter, but we can still use this method.
close:
push ebx
mov ebx, esp
mov eax, _NR_close
int INT_VECTOR_SYS_CALL
pop ebx
ret
; ====================================================================
; read //added by xw, 18/6/18
; ====================================================================
read:
push ebx
mov ebx, esp
mov eax, _NR_read
int INT_VECTOR_SYS_CALL
pop ebx
ret
; ====================================================================
; write //added by xw, 18/6/18
; ====================================================================
write:
push ebx
mov ebx, esp
mov eax, _NR_write
int INT_VECTOR_SYS_CALL
pop ebx
ret
; ====================================================================
; lseek //added by xw, 18/6/18
; ====================================================================
lseek:
push ebx
mov ebx, esp
mov eax, _NR_lseek
int INT_VECTOR_SYS_CALL
pop ebx
ret
; ====================================================================
; unlink //added by xw, 18/6/18
; ====================================================================
unlink:
push ebx
mov ebx, esp
mov eax, _NR_unlink
int INT_VECTOR_SYS_CALL
pop ebx
ret
;和FAT32有关的系统调用
create:
push ebx
mov ebx, esp
mov eax, _NR_create
int INT_VECTOR_SYS_CALL
pop ebx
ret
delete:
push ebx
mov ebx, esp
mov eax, _NR_delete
int INT_VECTOR_SYS_CALL
pop ebx
ret
opendir:
push ebx
mov ebx, esp
mov eax, _NR_opendir
int INT_VECTOR_SYS_CALL
pop ebx
ret
createdir:
push ebx
mov ebx, esp
mov eax, _NR_createdir
int INT_VECTOR_SYS_CALL
pop ebx
ret
deletedir:
push ebx
mov ebx, esp
mov eax, _NR_deletedir
int INT_VECTOR_SYS_CALL
pop ebx
ret

136
kernel/syscallc.c Normal file
View File

@ -0,0 +1,136 @@
/*********************************************************
*
*
*
*
**********************************************************/
#include "type.h"
#include "const.h"
#include "protect.h"
#include "string.h"
#include "proc.h"
#include "global.h"
#include "proto.h"
#include "memman.h"
struct memfree *memarg = 0;
/*======================================================================*
sys_get_ticks add by visual 2016.4.6
*======================================================================*/
int sys_get_ticks()
{
return ticks;
}
/*======================================================================*
sys_get_pid add by visual 2016.4.6
*======================================================================*/
int sys_get_pid()
{
return p_proc_current->task.pid;
}
/*======================================================================*
sys_kmalloc add by visual 2016.4.6
*======================================================================*/
void* sys_kmalloc(int size)
{ //edit by visual 2015.5.9
return (void*)(do_kmalloc(size));
}
/*======================================================================*
sys_kmalloc_4k add by visual 2016.4.7
*======================================================================*/
void* sys_kmalloc_4k()
{
return (void*)(do_kmalloc_4k());
}
/*======================================================================*
sys_malloc edit by visual 2016.5.4
*======================================================================*/
void* sys_malloc(int size)
{
int vir_addr,AddrLin;
vir_addr = vmalloc(size);
for( AddrLin=vir_addr; AddrLin<vir_addr+size ; AddrLin += num_4B )//一个字节一个字节处理
{
lin_mapping_phy(AddrLin,//线性地址 //add by visual 2016.5.9
MAX_UNSIGNED_INT,//物理地址 //edit by visual 2016.5.19
p_proc_current->task.pid,//进程pid //edit by visual 2016.5.19
PG_P | PG_USU | PG_RWW,//页目录的属性位
PG_P | PG_USU | PG_RWW);//页表的属性位
}
return (void*)vir_addr;
}
/*======================================================================*
sys_malloc_4k edit by visual 2016.5.4
*======================================================================*/
void* sys_malloc_4k()
{
int vir_addr,AddrLin;
vir_addr = vmalloc(num_4K);
for( AddrLin=vir_addr; AddrLin<vir_addr+num_4K ; AddrLin += num_4K )//一页一页处理(事实上只有一页,而且一定没有填写页表,页目录是否填写不确定)
{
lin_mapping_phy( AddrLin,//线性地址 //add by visual 2016.5.9
MAX_UNSIGNED_INT,//物理地址
p_proc_current->task.pid,//进程pid //edit by visual 2016.5.19
PG_P | PG_USU | PG_RWW,//页目录的属性位
PG_P | PG_USU | PG_RWW);//页表的属性位
}
return (void*)vir_addr;
}
/*======================================================================*
sys_free add by visual 2016.4.7
*======================================================================*/
int sys_free(void *arg)
{
memarg = (struct memfree *)arg;
return do_free(memarg->addr,memarg->size);
}
/*======================================================================*
sys_free_4k edit by visual 2016.5.9
*======================================================================*/
int sys_free_4k(void* AddrLin)
{//线性地址可以不释放,但是页表映射关系必须清除!
int phy_addr; //add by visual 2016.5.9
phy_addr = get_page_phy_addr(p_proc_current->task.pid,(int)AddrLin);//获取物理页的物理地址 //edit by visual 2016.5.19
lin_mapping_phy( (int)AddrLin,//线性地址
phy_addr,//物理地址
p_proc_current->task.pid,//进程pid //edit by visual 2016.5.19
PG_P | PG_USU | PG_RWW,//页目录的属性位
0 | PG_USU | PG_RWW);//页表的属性位
return do_free_4k(phy_addr);
}
/*======================================================================*
sys_udisp_int add by visual 2016.5.16
*======================================================================*/
void sys_udisp_int(int arg)
{
disp_int(arg);
return ;
}
/*======================================================================*
sys_udisp_str add by visual 2016.5.16
*======================================================================*/
void sys_udisp_str(char *arg)
{
disp_str(arg);
return ;
}

53
kernel/testfunc.c Normal file
View File

@ -0,0 +1,53 @@
/**
* testfunc.c
* This file contains functions that are used to test features we add.
* Added by xw, 18/6/17
*/
#include "type.h"
#include "const.h"
#include "protect.h"
#include "string.h"
#include "proc.h"
#include "global.h"
#include "proto.h"
/*
* This syscall needs long time to finish, so we can use it
* to check if our os is kernel-preemptive.
* added by xw, 18/4/27
*/
void sys_print_E()
{
int i, j;
disp_str("E( ");
i = 100;
while(--i){
j = 1000;
while(--j){}
}
disp_str(") ");
}
/*
* This syscall needs long time to finish, so we can use it
* to check if our os is kernel-preemptive.
* added by xw, 18/4/27
*/
void sys_print_F()
{
int i, j;
disp_str("F( ");
i = 100;
while(--i){
j = 1000;
while(--j){}
}
disp_str(") ");
}

295
kernel/tty.c Normal file
View File

@ -0,0 +1,295 @@
#include "type.h"
#include "const.h"
#include "protect.h"
#include "string.h"
#include "proc.h"
#include "tty.h"
#include "console.h"
#include "global.h"
#include "proto.h"
#include "keyboard.h"
#include "x86.h"
int current_console; //当前显示在屏幕上的console
void tty_write(TTY *tty, char *buf, int len);
int tty_read(TTY *tty, char *buf, int len);
static void init_tty(TTY *tty);
static void tty_mouse(TTY *tty);
static void tty_dev_read(TTY *tty);
static void tty_dev_write(TTY *tty);
static void put_key(TTY *tty, u32 key);
void in_process(TTY *p_tty, u32 key)
{
int real_line = p_tty->console->orig / SCR_WIDTH;
if (!(key & FLAG_EXT))
{
put_key(p_tty, key);
}
else
{
int raw_code = key & MASK_RAW;
switch (raw_code)
{
case ENTER:
put_key(p_tty, '\n');
p_tty->status = p_tty->status & 3; //&3'b011
break;
case BACKSPACE:
put_key(p_tty, '\b');
break;
case UP:
if (p_tty->console->current_line < 43)
{
disable_int();
p_tty->console->current_line++;
outb(CRTC_ADDR_REG, START_ADDR_H);
outb(CRTC_DATA_REG, ((80 * (p_tty->console->current_line + real_line)) >> 8) & 0xFF);
outb(CRTC_ADDR_REG, START_ADDR_L);
outb(CRTC_DATA_REG, (80 * (p_tty->console->current_line + real_line)) & 0xFF);
enable_int();
}
break;
case DOWN:
if (p_tty->console->current_line > 0)
{
disable_int();
p_tty->console->current_line--;
outb(CRTC_ADDR_REG, START_ADDR_H);
outb(CRTC_DATA_REG, ((80 * (p_tty->console->current_line + real_line)) >> 8) & 0xFF);
outb(CRTC_ADDR_REG, START_ADDR_L);
outb(CRTC_DATA_REG, (80 * (p_tty->console->current_line + real_line)) & 0xFF);
enable_int();
}
break;
case F1:
case F2:
case F3:
case F4:
case F5:
case F6:
case F7:
case F8:
case F9:
case F10:
case F11:
case F12:
select_console(raw_code - F1);
break;
}
}
}
#define TTY_FIRST (tty_table)
#define TTY_END (tty_table + NR_CONSOLES)
void task_tty()
{
TTY *p_tty;
for (p_tty = TTY_FIRST; p_tty < TTY_END; p_tty++)
{
init_tty(p_tty);
}
p_tty = tty_table;
select_console(0);
//设置第一个tty光标位置第一个tty需要特殊处理
disable_int();
outb(CRTC_ADDR_REG, CURSOR_H);
outb(CRTC_DATA_REG, ((disp_pos / 2) >> 8) & 0xFF);
outb(CRTC_ADDR_REG, CURSOR_L);
outb(CRTC_DATA_REG, (disp_pos / 2) & 0xFF);
enable_int();
//轮询
while (1)
{
for (p_tty = TTY_FIRST; p_tty < TTY_END; p_tty++)
{
do
{
tty_mouse(p_tty); /* tty判断鼠标操作 */
tty_dev_read(p_tty); /* 从键盘输入缓冲区读到这个tty自己的缓冲区 */
tty_dev_write(p_tty); /* 把tty缓存区的数据写到这个tty占有的显存 */
} while (p_tty->ibuf_cnt);
}
}
}
static void init_tty(TTY *p_tty)
{
p_tty->ibuf_read_cnt = p_tty->ibuf_cnt = 0;
p_tty->status = TTY_STATE_DISPLAY;
p_tty->ibuf_read = p_tty->ibuf_head = p_tty->ibuf_tail = p_tty->ibuf;
int det = p_tty - tty_table;
p_tty->console = console_table + det;
p_tty->mouse_left_button = 0;
p_tty->mouse_mid_button = 0;
p_tty->mouse_X = 0;
p_tty->mouse_Y = 0;
init_screen(p_tty);
}
static void tty_mouse(TTY *tty)
{
if (is_current_console(tty->console))
{
int real_line = tty->console->orig / SCR_WIDTH;
if (tty->mouse_left_button)
{
if (tty->mouse_Y > MOUSE_UPDOWN_BOUND)
{ //按住鼠标左键向上滚动
if (tty->console->current_line < 43)
{
disable_int();
tty->console->current_line++;
outb(CRTC_ADDR_REG, START_ADDR_H);
outb(CRTC_DATA_REG, ((80 * (tty->console->current_line + real_line)) >> 8) & 0xFF);
outb(CRTC_ADDR_REG, START_ADDR_L);
outb(CRTC_DATA_REG, (80 * (tty->console->current_line + real_line)) & 0xFF);
enable_int();
tty->mouse_Y = 0;
}
}
else if (tty->mouse_Y < -MOUSE_UPDOWN_BOUND)
{ //按住鼠标左键向下滚动
if (tty->console->current_line > 0)
{
disable_int();
tty->console->current_line--;
outb(CRTC_ADDR_REG, START_ADDR_H);
outb(CRTC_DATA_REG, ((80 * (tty->console->current_line + real_line)) >> 8) & 0xFF);
outb(CRTC_ADDR_REG, START_ADDR_L);
outb(CRTC_DATA_REG, (80 * (tty->console->current_line + real_line)) & 0xFF);
enable_int();
tty->mouse_Y = 0;
}
}
}
if (tty->mouse_mid_button)
{ //点击中键复原
disable_int();
tty->console->current_line = 0;
outb(CRTC_ADDR_REG, START_ADDR_H);
outb(CRTC_DATA_REG, ((80 * (tty->console->current_line + real_line)) >> 8) & 0xFF);
outb(CRTC_ADDR_REG, START_ADDR_L);
outb(CRTC_DATA_REG, (80 * (tty->console->current_line + real_line)) & 0xFF);
enable_int();
tty->mouse_Y = 0;
}
}
}
static void tty_dev_read(TTY *tty)
{
if (is_current_console(tty->console))
{
keyboard_read(tty);
}
}
static void tty_dev_write(TTY *tty)
{
if (tty->ibuf_cnt)
{
char ch = *(tty->ibuf_tail);
tty->ibuf_tail++;
if (tty->ibuf_tail == tty->ibuf + TTY_IN_BYTES)
{
tty->ibuf_tail = tty->ibuf;
}
tty->ibuf_cnt--;
if (ch == '\b')
{
if (tty->ibuf_read_cnt == 1)
{
tty->ibuf_read_cnt--;
tty->ibuf_head--;
tty->ibuf_tail--;
return;
}
else
{
tty->ibuf_read_cnt -= 2;
if (tty->ibuf_head == tty->ibuf)
{
tty->ibuf_head = tty->ibuf_tail = &tty->ibuf[256 - 2];
}
else
{
tty->ibuf_head--;
tty->ibuf_tail--;
tty->ibuf_head--;
tty->ibuf_tail--;
}
}
}
out_char(tty->console, ch);
}
}
static void put_key(TTY *tty, u32 key)
{
if (tty->ibuf_cnt < TTY_IN_BYTES)
{
*(tty->ibuf_head) = key;
tty->ibuf_head++;
if (tty->ibuf_head == tty->ibuf + TTY_IN_BYTES)
tty->ibuf_head = tty->ibuf;
tty->ibuf_cnt++;
tty->ibuf_read_cnt++;
}
}
/*****************************************************************************
* tty_write
****************************************************************************
* fd=STD_OUT时write()
*****************************************************************************/
void tty_write(TTY *tty, char *buf, int len)
{
while (--len >= 0)
out_char(tty->console, *buf++);
}
/*****************************************************************************
* tty_read
****************************************************************************
* fd=STD_IN时read()
*****************************************************************************/
int tty_read(TTY *tty, char *buf, int len)
{
int i = 0;
if (!tty->ibuf_read_cnt)
{
tty->status |= TTY_STATE_WAIT_ENTER;
}
while ((tty->status & TTY_STATE_WAIT_ENTER))
;
while (tty->ibuf_read_cnt && i < len)
{
buf[i] = *tty->ibuf_read;
tty->ibuf_read++;
if (tty->ibuf_read == tty->ibuf + TTY_IN_BYTES)
{
tty->ibuf_read = tty->ibuf;
}
tty->ibuf_read_cnt--;
i++;
}
return i;
}

477
kernel/vfs.c Normal file
View File

@ -0,0 +1,477 @@
/**********************************************************
* vfs.c //added by mingxuan 2019-5-17
***********************************************************/
#include "type.h"
#include "const.h"
#include "protect.h"
#include "string.h"
#include "proc.h"
#include "global.h"
#include "proto.h"
#include "fs_const.h"
#include "hd.h"
#include "fs.h"
#include "fs_misc.h"
#include "vfs.h"
#include "fat32.h"
#include "stdio.h"
//static struct device device_table[NR_DEV]; //deleted by mingxuan 2020-10-18
static struct vfs vfs_table[NR_FS]; //modified by mingxuan 2020-10-18
struct file_desc f_desc_table[NR_FILE_DESC];
struct super_block super_block[NR_SUPER_BLOCK]; //added by mingxuan 2020-10-30
//static struct file_op f_op_table[NR_fs]; //文件系统操作表
static struct file_op f_op_table[NR_FS_OP]; //modified by mingxuan 2020-10-18
static struct sb_op sb_op_table[NR_SB_OP]; //added by mingxuan 2020-10-30
//static void init_dev_table();//deleted by mingxuan 2020-10-30
static void init_vfs_table(); //modified by mingxuan 2020-10-30
void init_file_desc_table(); //added by mingxuan 2020-10-30
void init_fileop_table();
void init_super_block_table(); //added by mingxuan 2020-10-30
void init_sb_op_table();
static int get_index(char path[]);
void init_vfs()
{
init_file_desc_table();
init_fileop_table();
init_super_block_table();
init_sb_op_table(); //added by mingxuan 2020-10-30
//init_dev_table(); //deleted by mingxuan 2020-10-30
init_vfs_table(); //modified by mingxuan 2020-10-30
}
//added by mingxuan 2020-10-30
void init_file_desc_table()
{
int i;
for (i = 0; i < NR_FILE_DESC; i++)
memset(&f_desc_table[i], 0, sizeof(struct file_desc));
}
void init_fileop_table()
{
// table[0] for tty
f_op_table[0].open = real_open;
f_op_table[0].close = real_close;
f_op_table[0].write = real_write;
f_op_table[0].lseek = real_lseek;
f_op_table[0].unlink = real_unlink;
f_op_table[0].read = real_read;
// table[1] for orange
f_op_table[1].open = real_open;
f_op_table[1].close = real_close;
f_op_table[1].write = real_write;
f_op_table[1].lseek = real_lseek;
f_op_table[1].unlink = real_unlink;
f_op_table[1].read = real_read;
// table[2] for fat32
f_op_table[2].create = CreateFile;
f_op_table[2].delete = DeleteFile;
f_op_table[2].open = OpenFile;
f_op_table[2].close = CloseFile;
f_op_table[2].write = WriteFile;
f_op_table[2].read = ReadFile;
f_op_table[2].opendir = OpenDir;
f_op_table[2].createdir = CreateDir;
f_op_table[2].deletedir = DeleteDir;
}
//added by mingxuan 2020-10-30
void init_super_block_table(){
struct super_block * sb = super_block; //deleted by mingxuan 2020-10-30
//super_block[0] is tty0, super_block[1] is tty1, uper_block[2] is tty2
for(; sb < &super_block[3]; sb++) {
sb->sb_dev = DEV_CHAR_TTY;
sb->fs_type = TTY_FS_TYPE;
}
//super_block[3] is orange's superblock
sb->sb_dev = DEV_HD;
sb->fs_type = ORANGE_TYPE;
sb++;
//super_block[4] is fat32's superblock
sb->sb_dev = DEV_HD;
sb->fs_type = FAT32_TYPE;
sb++;
//another super_block are free
for (; sb < &super_block[NR_SUPER_BLOCK]; sb++) {
sb->sb_dev = NO_DEV;
sb->fs_type = NO_FS_TYPE;
}
}
//added by mingxuan 2020-10-30
void init_sb_op_table(){
//orange
sb_op_table[0].read_super_block = read_super_block;
sb_op_table[0].get_super_block = get_super_block;
//fat32 and tty
sb_op_table[1].read_super_block = NULL;
sb_op_table[1].get_super_block = NULL;
}
//static void init_dev_table(){
static void init_vfs_table(){ // modified by mingxuan 2020-10-30
// 我们假设每个tty就是一个文件系统
// tty0
// device_table[0].dev_name="dev_tty0";
// device_table[0].op = &f_op_table[0];
vfs_table[0].fs_name = "dev_tty0"; //modifed by mingxuan 2020-10-18
vfs_table[0].op = &f_op_table[0];
vfs_table[0].sb = &super_block[0]; //每个tty都有一个superblock //added by mingxuan 2020-10-30
vfs_table[0].s_op = &sb_op_table[1]; //added by mingxuan 2020-10-30
// tty1
//device_table[1].dev_name="dev_tty1";
//device_table[1].op =&f_op_table[0];
vfs_table[1].fs_name = "dev_tty1"; //modifed by mingxuan 2020-10-18
vfs_table[1].op = &f_op_table[0];
vfs_table[1].sb = &super_block[1]; //每个tty都有一个superblock //added by mingxuan 2020-10-30
vfs_table[1].s_op = &sb_op_table[1]; //added by mingxuan 2020-10-30
// tty2
//device_table[2].dev_name="dev_tty2";
//device_table[2].op=&f_op_table[0];
vfs_table[2].fs_name = "dev_tty2"; //modifed by mingxuan 2020-10-18
vfs_table[2].op = &f_op_table[0];
vfs_table[2].sb = &super_block[2]; //每个tty都有一个superblock //added by mingxuan 2020-10-30
vfs_table[2].s_op = &sb_op_table[1]; //added by mingxuan 2020-10-30
// fat32
//device_table[3].dev_name="fat0";
//device_table[3].op=&f_op_table[2];
vfs_table[3].fs_name = "fat0"; //modifed by mingxuan 2020-10-18
vfs_table[3].op = &f_op_table[2];
vfs_table[3].sb = &super_block[4]; //added by mingxuan 2020-10-30
vfs_table[3].s_op = &sb_op_table[1]; //added by mingxuan 2020-10-30
// orange
//device_table[4].dev_name="orange";
//device_table[4].op=&f_op_table[1];
vfs_table[4].fs_name = "orange"; //modifed by mingxuan 2020-10-18
vfs_table[4].op = &f_op_table[1];
vfs_table[4].sb = &super_block[3]; //added by mingxuan 2020-10-30
vfs_table[4].s_op = &sb_op_table[0]; //added by mingxuan 2020-10-30
}
static int get_index(char path[]){
int pathlen = strlen(path);
//char dev_name[DEV_NAME_LEN];
char fs_name[DEV_NAME_LEN]; //modified by mingxuan 2020-10-18
int len = (pathlen < DEV_NAME_LEN) ? pathlen : DEV_NAME_LEN;
int i,a=0;
for(i=0;i<len;i++){
if( path[i] == '/'){
a=i;
a++;
break;
}
else {
//dev_name[i] = path[i];
fs_name[i] = path[i]; //modified by mingxuan 2020-10-18
}
}
//dev_name[i] = '\0';
fs_name[i] = '\0'; //modified by mingxuan 2020-10-18
for(i=0;i<pathlen-a;i++)
path[i] = path[i+a];
path[pathlen-a] = '\0';
//for(i=0;i<NR_DEV;i++)
for(i=0;i<NR_FS;i++) //modified by mingxuan 2020-10-29
{
// if(!strcmp(dev_name, device_table[i].dev_name))
if(!strcmp(fs_name, vfs_table[i].fs_name)) //modified by mingxuan 2020-10-18
return i;
}
return -1;
}
/*======================================================================*
sys_*
*======================================================================*/
int sys_open(void *uesp)
{
return do_vopen((const char *)get_arg(uesp, 1), get_arg(uesp, 2));
}
int sys_close(void *uesp)
{
return do_vclose(get_arg(uesp, 1));
}
int sys_read(void *uesp)
{
return do_vread(get_arg(uesp, 1), (char *)get_arg(uesp, 2), get_arg(uesp, 3));
}
int sys_write(void *uesp)
{
return do_vwrite(get_arg(uesp, 1), (const char *)get_arg(uesp, 2), get_arg(uesp, 3));
}
int sys_lseek(void *uesp)
{
return do_vlseek(get_arg(uesp, 1), get_arg(uesp, 2), get_arg(uesp, 3));
}
int sys_unlink(void *uesp) {
return do_vunlink((const char *)get_arg(uesp, 1));
}
int sys_create(void *uesp) {
return do_vcreate((char *)get_arg(uesp, 1));
}
int sys_delete(void *uesp) {
return do_vdelete((char *)get_arg(uesp, 1));
}
int sys_opendir(void *uesp) {
return do_vopendir((char *)get_arg(uesp, 1));
}
int sys_createdir(void *uesp) {
return do_vcreatedir((char *)get_arg(uesp, 1));
}
int sys_deletedir(void *uesp) {
return do_vdeletedir((char *)get_arg(uesp, 1));
}
/*======================================================================*
do_v*
*======================================================================*/
int do_vopen(const char *path, int flags) {
int pathlen = strlen(path);
char pathname[MAX_PATH];
strcpy(pathname,(char *)path);
pathname[pathlen] = 0;
int index;
int fd = -1;
index = get_index(pathname);
if(index == -1){
kprintf("pathname error! path: %s\n", path);
return -1;
}
fd = vfs_table[index].op->open(pathname, flags); //modified by mingxuan 2020-10-18
if(fd != -1)
{
p_proc_current -> task.filp[fd] -> dev_index = index;
} else {
kprintf(" error!\n");
}
return fd;
}
int do_vclose(int fd) {
int index = p_proc_current->task.filp[fd]->dev_index;
return vfs_table[index].op->close(fd); //modified by mingxuan 2020-10-18
}
int do_vread(int fd, char *buf, int count) {
int index = p_proc_current->task.filp[fd]->dev_index;
return vfs_table[index].op->read(fd, buf, count); //modified by mingxuan 2020-10-18
}
int do_vwrite(int fd, const char *buf, int count) {
//modified by mingxuan 2019-5-23
char s[512];
int index = p_proc_current->task.filp[fd]->dev_index;
const char *fsbuf = buf;
int f_len = count;
int bytes;
while(f_len)
{
int iobytes = min(512, f_len);
int i=0;
for(i=0; i<iobytes; i++)
{
s[i] = *fsbuf;
fsbuf++;
}
//bytes = device_table[index].op->write(fd,s,iobytes);
bytes = vfs_table[index].op->write(fd,s,iobytes); //modified by mingxuan 2020-10-18
if(bytes != iobytes)
{
return bytes;
}
f_len -= bytes;
}
return count;
}
int do_vunlink(const char *path) {
int pathlen = strlen(path);
char pathname[MAX_PATH];
strcpy(pathname,(char *)path);
pathname[pathlen] = 0;
int index;
index = get_index(pathname);
if(index==-1){
kprintf("pathname error!\n");
return -1;
}
//return device_table[index].op->unlink(pathname);
return vfs_table[index].op->unlink(pathname); //modified by mingxuan 2020-10-18
}
int do_vlseek(int fd, int offset, int whence) {
int index = p_proc_current->task.filp[fd]->dev_index;
//return device_table[index].op->lseek(fd, offset, whence);
return vfs_table[index].op->lseek(fd, offset, whence); //modified by mingxuan 2020-10-18
}
//int do_vcreate(char *pathname) {
int do_vcreate(char *filepath) { //modified by mingxuan 2019-5-17
//added by mingxuan 2019-5-17
int state;
const char *path = filepath;
int pathlen = strlen(path);
char pathname[MAX_PATH];
strcpy(pathname,(char *)path);
pathname[pathlen] = 0;
int index;
index = get_index(pathname);
if(index == -1){
kprintf("pathname error! path: %s\n", path);
return -1;
}
state = vfs_table[index].op->create(pathname); //modified by mingxuan 2020-10-18
if (state == 1) {
kprintf(" create file success!");
} else {
DisErrorInfo(state);
}
return state;
}
int do_vdelete(char *path) {
int pathlen = strlen(path);
char pathname[MAX_PATH];
strcpy(pathname,path);
pathname[pathlen] = 0;
int index;
index = get_index(pathname);
if(index==-1){
kprintf("pathname error!\n");
return -1;
}
//return device_table[index].op->delete(pathname);
return vfs_table[index].op->delete(pathname); //modified by mingxuan 2020-10-18
}
int do_vopendir(char *path) {
int state;
int pathlen = strlen(path);
char pathname[MAX_PATH];
strcpy(pathname,path);
pathname[pathlen] = 0;
int index;
index = (int)(pathname[1]-'0');
for(int j=0;j<= pathlen-3;j++)
{
pathname[j] = pathname[j+3];
}
state = f_op_table[index].opendir(pathname);
if (state == 1) {
kprintf(" open dir success!");
} else {
DisErrorInfo(state);
}
return state;
}
int do_vcreatedir(char *path) {
int state;
int pathlen = strlen(path);
char pathname[MAX_PATH];
strcpy(pathname,path);
pathname[pathlen] = 0;
int index;
index = (int)(pathname[1]-'0');
for(int j=0;j<= pathlen-3;j++)
{
pathname[j] = pathname[j+3];
}
state = f_op_table[index].createdir(pathname);
if (state == 1) {
kprintf(" create dir success!");
} else {
DisErrorInfo(state);
}
return state;
}
int do_vdeletedir(char *path) {
int state;
int pathlen = strlen(path);
char pathname[MAX_PATH];
strcpy(pathname,path);
pathname[pathlen] = 0;
int index;
index = (int)(pathname[1]-'0');
for(int j=0;j<= pathlen-3;j++)
{
pathname[j] = pathname[j+3];
}
state = f_op_table[index].deletedir(pathname);
if (state == 1) {
kprintf(" delete dir success!");
} else {
DisErrorInfo(state);
}
return state;
}

26
lib/Makefrag Normal file
View File

@ -0,0 +1,26 @@
OBJDIRS += lib
LIB_OBJS := lib/string.o \
kernel/syscall.o \
lib/printf.o \
lib/kprintf.o \
lib/scanf.o \
lib/printfmt.o \
LIB_OBJS := $(patsubst %, $(OBJDIR)/%, $(LIB_OBJS))
LIB_A = $(OBJDIR)/lib/ulib.a
$(OBJDIR)/lib/%.o: lib/%.c $(OBJDIR)/.vars.CFLAGS
@echo + cc $<
@mkdir -p $(@D)
@$(CC) $(CFLAGS) -c -o $@ $<
$(OBJDIR)/lib/%.o: lib/%.asm
@echo + as obj $<
@mkdir -p $(@D)
@$(AS) -I ./include -f elf -o $@ $<
$(LIB_A): $(LIB_OBJS)
@echo + ar $@
@$(AR) $(ARFLAGS) -o $@ $(LIB_OBJS)

75
lib/klib.c Normal file
View File

@ -0,0 +1,75 @@
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
klib.c
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Forrest Yu, 2005
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
#include "type.h"
#include "const.h"
#include "protect.h"
#include "string.h"
#include "proc.h"
#include "global.h"
#include "proto.h"
/*======================================================================*
itoa
*======================================================================*/
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
*======================================================================*/
void disp_int(int input)
{
char output[16];
itoa(output, input);
disp_str(output);
}
/*======================================================================*
delay
*======================================================================*/
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++){}
}
}
}

124
lib/kliba.asm Normal file
View File

@ -0,0 +1,124 @@
; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; klib.asm
; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; Forrest Yu, 2005
; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
%include "sconst.inc"
; 导入全局变量
extern disp_pos
[SECTION .text]
; 导出函数
global disp_str
global disp_color_str
global write_char ; added by mingxuan 2019-5-19
; ========================================================================
; void disp_str(char * info);
; ========================================================================
disp_str:
push ebp
mov ebp, esp
pushad
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:
;added by xw, 17/12/11
;added begin
cmp edi, 1F40h
jnz .4
mov edi, 0FA0h
.4:
;added end
mov [gs:edi], ax
add edi, 2
jmp .1
.2:
mov [disp_pos], edi
popad
pop ebp
ret
; ========================================================================
; void disp_color_str(char * info, int color);
; ========================================================================
disp_color_str:
push ebp
mov ebp, esp
pushad
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
popad
pop ebp
ret
; ========================================================================
; void write_char(char ch);
; ========================================================================
write_char:
push ebp
mov ebp,esp
mov esi,[ebp+8]
mov edi,[disp_pos]
push eax
mov eax,esi
mov ah, 0Fh
mov [gs:edi], ax
pop eax
pop ebp
ret

34
lib/kprintf.c Normal file
View File

@ -0,0 +1,34 @@
#include "stdio.h"
#include "protect.h"
#include "proc.h"
#include "global.h"
#include "proto.h"
static void
kprintfputch(int ch, void *b)
{
char buf[2]={(char)ch,'\0'};
disp_str(buf);
}
int
vkprintf(const char *fmt, va_list ap)
{
vprintfmt((void*)kprintfputch, NULL, fmt, ap);
return 0;
}
int
kprintf(const char *fmt, ...)
{
va_list ap;
int rc;
va_start(ap, fmt);
rc = vkprintf(fmt, ap);
va_end(ap);
return rc;
}

33
lib/printf.c Normal file
View File

@ -0,0 +1,33 @@
#include "stdio.h"
static void
printfputch(int ch, int *cnt)
{
char buf = (char)ch;
write(STD_OUT, &buf, 1);
(*cnt)++;
}
int
vprintf(const char *fmt, va_list ap)
{
int cnt = 0;
vprintfmt((void *)printfputch, &cnt, fmt, ap);
return cnt;
}
int
printf(const char *fmt, ...)
{
va_list ap;
int rc;
va_start(ap, fmt);
rc = vprintf(fmt, ap);
va_end(ap);
return rc;
}

261
lib/printfmt.c Normal file
View File

@ -0,0 +1,261 @@
#include <type.h>
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
/*
* Print a number (base <= 16) in reverse order,
* using specified putch function and associated pointer putdat.
*/
static void
printnum(void (*putch)(int, void*), void *putdat,
unsigned long num, unsigned base, int width, int padc)
{
// first recursively print all preceding (more significant) digits
if (num >= base) {
printnum(putch, putdat, num / base, base, width - 1, padc);
} else {
// print any needed pad characters before first digit
while (--width > 0)
putch(padc, putdat);
}
// then print this (the least significant) digit
putch("0123456789abcdef"[num % base], putdat);
}
// Get an unsigned int of various possible sizes from a varargs list,
// depending on the lflag parameter.
static unsigned long long
getuint(va_list *ap, int lflag)
{
if (lflag >= 2)
return va_arg(*ap, unsigned long long);
else if (lflag)
return va_arg(*ap, unsigned long);
else
return va_arg(*ap, unsigned int);
}
// Same as getuint but signed - can't use getuint
// because of sign extension
static long long
getint(va_list *ap, int lflag)
{
if (lflag >= 2)
return va_arg(*ap, long long);
else if (lflag)
return va_arg(*ap, long);
else
return va_arg(*ap, int);
}
// Main function to format and print a string.
void printfmt(void (*putch)(int, void*), void *putdat, const char *fmt, ...);
void
vprintfmt(void (*putch)(int, void*), void *putdat, const char *fmt, va_list ap)
{
register const char *p;
register int ch, err;
unsigned long long num;
int base, lflag, width, precision, altflag;
char padc;
while (1) {
while ((ch = *(unsigned char *) fmt++) != '%') {
if (ch == '\0')
return;
putch(ch, putdat);
}
// Process a %-escape sequence
padc = ' ';
width = -1;
precision = -1;
lflag = 0;
altflag = 0;
reswitch:
switch (ch = *(unsigned char *) fmt++) {
// flag to pad on the right
case '-':
padc = '-';
goto reswitch;
// flag to pad with 0's instead of spaces
case '0':
padc = '0';
goto reswitch;
// width field
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
for (precision = 0; ; ++fmt) {
precision = precision * 10 + ch - '0';
ch = *fmt;
if (ch < '0' || ch > '9')
break;
}
goto process_precision;
case '*':
precision = va_arg(ap, int);
goto process_precision;
case '.':
if (width < 0)
width = 0;
goto reswitch;
case '#':
altflag = 1;
goto reswitch;
process_precision:
if (width < 0)
width = precision, precision = -1;
goto reswitch;
// long flag (doubled for long long)
case 'l':
lflag++;
goto reswitch;
// character
case 'c':
putch(va_arg(ap, int), putdat);
break;
// string
case 's':
if ((p = va_arg(ap, char *)) == NULL)
p = "(null)";
if (width > 0 && padc != '-')
for (width -= strnlen(p, precision); width > 0; width--)
putch(padc, putdat);
for (; (ch = *p++) != '\0' && (precision < 0 || --precision >= 0); width--)
if (altflag && (ch < ' ' || ch > '~'))
putch('?', putdat);
else
putch(ch, putdat);
for (; width > 0; width--)
putch(' ', putdat);
break;
// (signed) decimal
case 'd':
num = getint(&ap, lflag);
if ((long long) num < 0) {
putch('-', putdat);
num = -(long long) num;
}
base = 10;
goto number;
// unsigned decimal
case 'u':
num = getuint(&ap, lflag);
base = 10;
goto number;
// (unsigned) octal
case 'o':
// Replace this with your code.
putch('X', putdat);
putch('X', putdat);
putch('X', putdat);
break;
// pointer
case 'p':
putch('0', putdat);
putch('x', putdat);
num = (unsigned long long)
(uintptr_t) va_arg(ap, void *);
base = 16;
goto number;
// (unsigned) hexadecimal
case 'x':
num = getuint(&ap, lflag);
base = 16;
number:
printnum(putch, putdat, num, base, width, padc);
break;
// escaped '%' character
case '%':
putch(ch, putdat);
break;
// unrecognized escape sequence - just print it literally
default:
putch('%', putdat);
for (fmt--; fmt[-1] != '%'; fmt--)
/* do nothing */;
break;
}
}
}
void
printfmt(void (*putch)(int, void*), void *putdat, const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
vprintfmt(putch, putdat, fmt, ap);
va_end(ap);
}
struct sprintbuf {
char *buf;
char *ebuf;
int cnt;
};
static void
sprintputch(int ch, struct sprintbuf *b)
{
b->cnt++;
if (b->buf < b->ebuf)
*b->buf++ = ch;
}
int
vsnprintf(char *buf, int n, const char *fmt, va_list ap)
{
struct sprintbuf b = {buf, buf+n-1, 0};
if (buf == NULL || n < 1)
return -1;
// print the string to the buffer
vprintfmt((void*)sprintputch, &b, fmt, ap);
// null terminate the buffer
*b.buf = '\0';
return b.cnt;
}
int
snprintf(char *buf, int n, const char *fmt, ...)
{
va_list ap;
int rc;
va_start(ap, fmt);
rc = vsnprintf(buf, n, fmt, ap);
va_end(ap);
return rc;
}

72
lib/scanf.c Normal file
View File

@ -0,0 +1,72 @@
#include "stdio.h"
char getchar()
{
char ch;
return read(STD_IN,&ch,1)==1 ? ch : EOF;
}
char* gets(char *str)
{
char c;
char *cs;
cs= str;
while( (c=getchar()) != EOF ){
if( (*cs=c)=='\n' ){
*cs = '\0';
break;
}
cs++;
}
return str;
}
// int scanf(char *str, ...)
// {
// va_list vl;
// int i = 0, j = 0, ret = 0;
// char buff[100] = {0};
// char *out_loc;
// gets(buff);
// va_start(vl, str);
// i = 0;
// while (str && str[i])
// {
// if (str[i] == '%')
// {
// i++;
// switch (str[i])
// {
// case 'c':
// {
// *(char *)va_arg(vl, char *) = buff[j];
// j++;
// ret++;
// break;
// }
// case 'd':
// {
// *(int *)va_arg(vl, int *) = strtol(&buff[j], &out_loc, 10);
// j += out_loc - &buff[j];
// ret++;
// break;
// }
// case 'x':
// {
// *(int *)va_arg(vl, int *) = strtol(&buff[j], &out_loc, 16);
// j += out_loc - &buff[j];
// ret++;
// break;
// }
// }
// }
// else
// {
// buff[j] = str[i];
// j++;
// }
// i++;
// }
// va_end(vl);
// return ret;
// }

110
lib/string.c Normal file
View File

@ -0,0 +1,110 @@
#include "string.h"
int
strlen(const char *s)
{
int n;
for (n = 0; *s != '\0'; s++)
n++;
return n;
}
int
strnlen(const char *s, size_t size)
{
int n;
for (n = 0; size > 0 && *s != '\0'; s++, size--)
n++;
return n;
}
char *
strcpy(char *dst, const char *src)
{
char *ret;
ret = dst;
while ((*dst++ = *src++) != '\0')
/* do nothing */;
return ret;
}
char *
strcat(char *dst, const char *src)
{
int len = strlen(dst);
strcpy(dst + len, src);
return dst;
}
char *
strncpy(char *dst, const char *src, size_t size) {
size_t i;
char *ret;
ret = dst;
for (i = 0; i < size; i++) {
*dst++ = *src;
// If strlen(src) < size, null-pad 'dst' out to 'size' chars
if (*src != '\0')
src++;
}
return ret;
}
int
strcmp(const char *p, const char *q)
{
while (*p && *p == *q)
p++, q++;
return (int) ((unsigned char) *p - (unsigned char) *q);
}
int
strncmp(const char *p, const char *q, size_t n)
{
while (n > 0 && *p && *p == *q)
n--, p++, q++;
if (n == 0)
return 0;
else
return (int) ((unsigned char) *p - (unsigned char) *q);
}
void *
memset(void *v, int c, size_t n)
{
char *p;
int m;
p = v;
m = n;
while (--m >= 0)
*p++ = c;
return v;
}
void *
memcpy(void *dst, const void *src, size_t n)
{
const char *s;
char *d;
s = src;
d = dst;
if (s < d && s + n > d) {
s += n;
d += n;
while (n-- > 0)
*--d = *--s;
} else {
while (n-- > 0)
*d++ = *s++;
}
return dst;
}

86
mergedep.pl Normal file
View File

@ -0,0 +1,86 @@
#!/usr/bin/perl
# Copyright 2003 Bryan Ford
# Distributed under the GNU General Public License.
#
# Usage: mergedep <main-depfile> [<new-depfiles> ...]
#
# This script merges the contents of all <new-depfiles> specified
# on the command line into the single file <main-depfile>,
# which may or may not previously exist.
# Dependencies in the <new-depfiles> will override
# any existing dependencies for the same targets in <main-depfile>.
# The <new-depfiles> are deleted after <main-depfile> is updated.
#
# The <new-depfiles> are typically generated by GCC with the -MD option,
# and the <main-depfile> is typically included from a Makefile,
# as shown here for GNU 'make':
#
# .deps: $(wildcard *.d)
# perl mergedep $@ $^
# -include .deps
#
# This script properly handles multiple dependencies per <new-depfile>,
# including dependencies having no target,
# so it is compatible with GCC3's -MP option.
#
sub readdeps {
my $filename = shift;
open(DEPFILE, $filename) or return 0;
while (<DEPFILE>) {
if (/([^:]*):([^\\:]*)([\\]?)$/) {
my $target = $1;
my $deplines = $2;
my $slash = $3;
while ($slash ne '') {
$_ = <DEPFILE>;
defined($_) or die
"Unterminated dependency in $filename";
/(^[ \t][^\\]*)([\\]?)$/ or die
"Bad continuation line in $filename";
$deplines = "$deplines\\\n$1";
$slash = $2;
}
#print "DEPENDENCY [[$target]]: [[$deplines]]\n";
$dephash{$target} = $deplines;
} elsif (/^[#]?[ \t]*$/) {
# ignore blank lines and comments
} else {
die "Bad dependency line in $filename: $_";
}
}
close DEPFILE;
return 1;
}
if ($#ARGV < 0) {
print "Usage: mergedep <main-depfile> [<new-depfiles> ..]\n";
exit(1);
}
%dephash = ();
# Read the main dependency file
$maindeps = $ARGV[0];
readdeps($maindeps);
# Read and merge in the new dependency files
foreach $i (1 .. $#ARGV) {
readdeps($ARGV[$i]) or die "Can't open $ARGV[$i]";
}
# Update the main dependency file
open(DEPFILE, ">$maindeps.tmp") or die "Can't open output file $maindeps.tmp";
foreach $target (keys %dephash) {
print DEPFILE "$target:$dephash{$target}";
}
close DEPFILE;
rename("$maindeps.tmp", "$maindeps") or die "Can't overwrite $maindeps";
# Finally, delete the new dependency files
foreach $i (1 .. $#ARGV) {
unlink($ARGV[$i]) or print "Error removing $ARGV[$i]\n";
}

33
user/Makefrag Normal file
View File

@ -0,0 +1,33 @@
OBJDIRS += user
USERLIB_SRCS := user/initstart.asm
USERLIB_OBJS := $(patsubst %.c, $(OBJDIR)/%.o, $(USERLIB_SRCS))
USERLIB_OBJS := $(patsubst %.asm, $(OBJDIR)/%.o, $(USERLIB_OBJS))
# 这里给我整不会了文件名只能长度为16位否则会寄原因还挺难找
USER_SRCS := user/ptTest.c \
user/shell_0.c \
USER_BINS := $(patsubst %.c, $(OBJDIR)/%.bin, $(USER_SRCS))
USER_BASENAMES := $(patsubst $(OBJDIR)/user/%, %, $(USER_BINS))
USER_TAR:= app.tar
$(OBJDIR)/user/%.o: user/%.c $(OBJDIR)/.vars.CFLAGS
@echo + cc $<
@mkdir -p $(@D)
@$(CC) $(CFLAGS) -c -o $@ $<
$(OBJDIR)/user/%.o: user/%.asm
@echo + as obj $<
@mkdir -p $(@D)
@$(AS) -I ./include -f elf -o $@ $<
$(OBJDIR)/user/%.bin: $(OBJDIR)/user/%.o $(USERLIB_OBJS) $(LIB_A) $(OBJDIR)/.vars.LDFLAGS
@echo + ld $@
@$(LD) $(LDFLAGS) -o $@ $< $(USERLIB_OBJS) $(LIB_A) $(GCC_LIB)
$(OBJDIR)/user/$(USER_TAR): $(USER_BINS)
@echo + tar $@
@tar -vcf $@ -C $(OBJDIR)/user $(USER_BASENAMES)

19
user/initstart.asm Normal file
View File

@ -0,0 +1,19 @@
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; initstart.asm //add by visual 2016.5.16
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
extern main
bits 32
[section .text]
global _start
_start:
push eax
push ecx
call main
hlt

41
user/ptTest.c Normal file
View File

@ -0,0 +1,41 @@
#include "stdio.h"
int global=0;
char *str2,*str3;
void pthread_test1()
{
int i;
//pthread(pthread_test2);
while(1)
{
printf("pth1");
printf("%d",++global);
printf(" ");
i=10000000;
while(--i){}
}
}
/*======================================================================*
Syscall Pthread Test
added by xw, 18/4/27
*======================================================================*/
int main(int arg,char *argv[])
{
int i=0;
pthread(pthread_test1);
while(1)
{
printf("init");
printf("%d",++global);
printf(" ");
i=10000000;
while(--i){}
}
return 0;
}

31
user/shell_0.c Normal file
View File

@ -0,0 +1,31 @@
#include "type.h"
#include "const.h"
#include "protect.h"
#include "string.h"
#include "proc.h"
#include "global.h"
#include "proto.h"
#include "stdio.h"
int main(int arg, char *argv[])
{
int stdin = open("dev_tty0", O_RDWR);
int stdout = open("dev_tty0", O_RDWR);
int stderr = open("dev_tty0", O_RDWR);
char buf[1024];
int pid;
int times = 0;
while (1)
{
printf("\nminiOS:/ $ ");
if (gets(buf) && strlen(buf) != 0)
{
if (exec(buf) != 0)
{
printf("exec failed: file not found!\n");
continue;
}
}
}
}

BIN
实验七-v0.2.pdf Normal file

Binary file not shown.