diff --git a/.clang-format b/.clang-format
index 1856c0b..58a164c 100644
--- a/.clang-format
+++ b/.clang-format
@@ -3,9 +3,9 @@ Language: Cpp
# BasedOnStyle: LLVM
AlignAfterOpenBracket: AlwaysBreak
AlignArrayOfStructures: Right
-AlignConsecutiveAssignments: true
+AlignConsecutiveAssignments: AcrossComments
AlignConsecutiveBitFields: true
-AlignConsecutiveDeclarations: true
+AlignConsecutiveDeclarations: AcrossComments
AlignConsecutiveMacros: true
AlignEscapedNewlines: Left
AlignOperands: AlignAfterOperator
@@ -92,11 +92,12 @@ PenaltyBreakComment: 300
PenaltyBreakFirstLessLess: 120
PenaltyBreakString: 1000
PenaltyBreakTemplateDeclaration: 10
-PenaltyExcessCharacter: 1000000
+PenaltyExcessCharacter: 1000
PenaltyReturnTypeOnItsOwnLine: 1000
PenaltyIndentedWhitespace: 0
PointerAlignment: Right
PPIndentWidth: -1
+QualifierAlignment: Left
ReferenceAlignment: Pointer
ReflowComments: true
SortIncludes: true
diff --git a/.gitignore b/.gitignore
index 9730bfb..b0cdc76 100644
--- a/.gitignore
+++ b/.gitignore
@@ -52,14 +52,25 @@ Module.symvers
Mkfile.old
dkms.conf
compile_commands.json
+build/
+
+# Cache
+__pycache__/
+*.pyc
+.cache/
+
+# Rubbish
+.DS_Store
# Others
-disk/
+/disk/
tools/bin/
tools/imagetool/target/
-core
fixdep
*.img
*.log
*.dat
*.idx
+dump.pcap
+target/
+.stfolder/
diff --git a/.vscode/launch.json b/.vscode/launch.json
index ac4d65d..fb7854e 100644
--- a/.vscode/launch.json
+++ b/.vscode/launch.json
@@ -9,7 +9,7 @@
"type": "cppdbg",
"request": "launch",
"miDebuggerServerAddress": "127.0.0.1:1234",
- "program": "${workspaceFolder}/src/kernel.elf",
+ "program": "${workspaceFolder}/src/build/kernel.elf",
"args": [],
"stopAtEntry": false,
"cwd": "${workspaceFolder}",
diff --git a/.vscode/settings.json b/.vscode/settings.json
index 8010ab6..0e62506 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -44,27 +44,6 @@
"utility": "c",
"cstdlib": "c"
},
- "C_Cpp.codeAnalysis.clangTidy.checks.disabled": [
- "clang-diagnostic-int-to-void-pointer-cast",
- "clang-diagnostic-int-to-pointer-cast",
- "clang-diagnostic-void-pointer-to-int-cast",
- "clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling",
- "clang-diagnostic-pointer-to-int-cast",
- "clang-diagnostic-visibility",
- "clang-analyzer-security.insecureAPI.strcpy",
- "clang-diagnostic-incompatible-library-redeclaration",
- "clang-diagnostic-implicit-function-declaration",
- "clang-analyzer-deadcode.DeadStores",
- "clang-diagnostic-error"
- ],
- "C_Cpp.errorSquiggles": "Disabled",
- "makefile.launchConfigurations": [
- {
- "cwd": "/home/ryan/Desktop/horizon/src",
- "binaryPath": "/home/ryan/Desktop/horizon/src/kernel.elf",
- "binaryArgs": []
- }
- ],
"C_Cpp.clang_format_style": "file",
"C_Cpp.clang_format_fallbackStyle": "LLVM",
"clangd.fallbackFlags": [
diff --git a/Makefile b/Makefile
index 1384fd3..da7612e 100644
--- a/Makefile
+++ b/Makefile
@@ -1,3 +1,5 @@
+UNAME_S := $(shell uname -s)
+
DD = dd
CP = cp
GRUB_MKIMG = grub-mkimage
@@ -13,6 +15,14 @@ ifeq ($(ARCH), x86)
TARGET_PLATFORM = i386-pc
endif
+ifeq ($(UNAME_S),Linux)
+ QEMU_CFG = qemu-linux.cfg
+else ifeq ($(UNAME_S),Darwin)
+ QEMU_CFG = qemu-macos.cfg
+else ifeq ($(OS),Windows_NT)
+ QEMU_CFG = qemu-windows.cfg
+endif
+
FD_IMG = ./horizon.img
HD_IMG = ./hd0.img
HD_SIZE = 64M
@@ -30,6 +40,8 @@ FS_DIR = $(KERNEL_DIR)/fs
LIB_DIR = $(KERNEL_SRC)/lib
DISK_DIR = disk
+KERNEL_OUTPUT_DIR = $(KERNEL_SRC)/build
+
LOADER_OFF = 2
LOADER_CNTS = 8
@@ -38,9 +50,12 @@ KERNEL_CNTS = 600
BOOT_BIN = $(BOOT_DIR)/boot.bin
LOADER_BIN = $(BOOT_DIR)/loader.bin
-KERNEL_ELF = $(KERNEL_SRC)/kernel.elf
+KERNEL_ELF = $(KERNEL_OUTPUT_DIR)/kernel.elf
IMAGETOOL = $(TOOL_SRC)/bin/imagetool
+CONFIGURATOR = $(TOOL_SRC)/bin/configurator
+
+INSTALL_GRUB_SCRIPT = $(TOOL_SRC)/grub/install_grub.py
.PHONY: cld
@@ -51,7 +66,7 @@ run: kernel libs qemu
run_dbg: kernel libs qemu_dbg
hd: tool
- $(PYTHON) ./install_grub.py \
+ $(PYTHON) $(INSTALL_GRUB_SCRIPT) \
--image $(HD_IMG) \
--fs fat32 \
--platform $(TARGET_PLATFORM)
@@ -59,9 +74,10 @@ hd: tool
app:
$(MAKE) -s -C $(APP_SRC)
-kernel:
+kernel: tool
$(MAKE) -s -C $(BOOT_DIR)
- $(MAKE) -s -C $(KERNEL_SRC)
+ $(CONFIGURATOR) --work-dir . --out-dir $(KERNEL_OUTPUT_DIR)
+ $(MAKE) -s -C $(KERNEL_OUTPUT_DIR)
$(IMAGETOOL) $(HD_IMG) copy $(KERNEL_ELF) /p0/kernel.elf
tool:
@@ -89,28 +105,33 @@ writehd: $(HD_IMG)
# qemu 7.1后取消了-soundhw,改用-audio
qemu_dbg:
$(QEMU) \
+ -no-reboot \
-s -S \
- -monitor stdio \
+ -serial stdio \
-m 1024 \
- -hda $(HD_IMG) \
+ -drive file=$(HD_IMG),if=ide,format=raw \
-usb \
+ -device piix3-usb-uhci \
-device usb-kbd \
-device usb-mouse \
- -audio pa,model=sb16 \
-device rtl8139,netdev=nc1 \
-netdev user,id=nc1,hostfwd=tcp::5555-:80 \
- -object filter-dump,id=f1,netdev=nc1,file=dump.dat \
+ -object filter-dump,id=f1,netdev=nc1,file=dump.pcap \
+ -readconfig $(QEMU_CFG) \
-boot c
qemu:
$(QEMU) \
- -monitor stdio \
+ -no-reboot \
+ -serial stdio \
-m 1024 \
- -hda $(HD_IMG) \
+ -drive file=$(HD_IMG),if=ide,format=raw \
-usb \
+ -device piix3-usb-uhci \
+ -device usb-kbd \
-device usb-mouse \
- -audio pa,model=sb16 \
-device rtl8139,netdev=nc1 \
-netdev user,id=nc1,hostfwd=tcp::5555-:80 \
- -object filter-dump,id=f1,netdev=nc1,file=dump.dat \
+ -object filter-dump,id=f1,netdev=nc1,file=dump.pcap \
+ -readconfig $(QEMU_CFG) \
-boot c
\ No newline at end of file
diff --git a/README.md b/README.md
index 8ab1a17..3876d78 100644
--- a/README.md
+++ b/README.md
@@ -13,6 +13,8 @@
是个半成品。。。
+真正的主分支:[master](https://github.com/Ryan1202/Horizon-Operating-System/tree/master)
+
## 环境
建议使用```VSCode```开发
@@ -29,6 +31,28 @@
- python(3.12.3)
- rust:[Install Rust - Rust Programming Language(rust-lang.org)](https://www.rust-lang.org/tools/install)
+### Grub
+
+在虚拟机中运行使用grub引导,所以需要先安装grub
+
+#### Windows
+
+使用Windows需要先下载 [Grub for Windows (2.12)](https://ftp.gnu.org/gnu/grub/grub-2.12-for-windows.zip) 并解压,在执行安装脚本时会提示输入grub路径
+
+#### macOS
+
+使用macOS需要使用homebrew安装i686-elf-grub
+
+```
+brew install i686-elf-grub
+```
+
+#### Linux
+
+大多数Linux发行版默认使用grub引导,`install_grub.py`脚本可以自动从`/usr/lib/grub`找到模块目录
+
+如果不是或者使用的并非x86 pc,需要自行安装grub
+
### VSCode
需要安装的插件:
@@ -42,7 +66,7 @@
>
> qemu 7.1开始不再支持-soundhw,
>
-> qemu 7.1之前的版本要把Makefile中的
+> qemu 7.1之前的版本要把
> ```
> -audio pa,model=sb16
> ```
diff --git a/config.toml b/config.toml
new file mode 100644
index 0000000..e0d50a8
--- /dev/null
+++ b/config.toml
@@ -0,0 +1,31 @@
+arch = "x86"
+
+[tools]
+cc = "x86_64-elf-gcc"
+as = "nasm"
+ld = "x86_64-elf-ld"
+cflags = [
+ "-march=i486",
+ "-std=gnu11",
+ "-nostdinc",
+ "-nostdlib",
+ "-O0",
+ "-m32",
+ "-g",
+ "-ffreestanding",
+ "-fno-pie",
+ "-fno-stack-protector",
+ "-fno-strict-aliasing",
+ "-fno-builtin",
+ "-Wall",
+ "-Wunused",
+]
+asflags = ["-g", "-f", "elf32"]
+ldflags = ["-m", "elf_i386", "-nostdlib"]
+rust_target = "src/arch/x86/i686-none.json"
+rustflags = ["-C", "relocation-model=static", "--emit", "obj"]
+
+[debug]
+level = "all"
+cflags = ["-O0", "-g"]
+asflags = ["-g"]
diff --git a/doc/driver framework.md b/doc/driver framework.md
new file mode 100644
index 0000000..308a640
--- /dev/null
+++ b/doc/driver framework.md
@@ -0,0 +1,469 @@
+# 关系图
+
+## 总览
+
+所有驱动框架下驱动及设备相关结构之间的关系如下(以APIC为例):
+
+```mermaid
+graph TD
+ A[Kernel]-->B[DriverManager]
+ A-->C[DeviceManager]
+
+ B-->D[Driver0]
+ C-->E[InterruptDeviceManager]
+ C-->F[TimerDeviceManager]
+
+ D-->BD0[BusDriver0]
+ D-->DD1[DeviceDriver1]
+
+ BD0-.->B0[Bus0]
+
+ B0-.->PD1
+
+ DD1-.->PD1["PhysicalDevice1(e.g. APIC)"]
+ PD1-.->D1["LogicalDevice1(e.g. APIC)"]
+ PD1-.->D2["LogiicalDevice2(e.g.APIC Timer)"]
+
+ E-.->InterruptDevice-->D1
+ F-.->TimerDevice-->D2
+
+```
+
+通过`Object`系统可访问的`PhysicalDevice`和`LogicalDevice`的关系如下:
+
+```mermaid
+graph LR
+ A["\Bus"]-->|\|PCI-.->|\|B[0]-.->|\|C[0]
+
+ Device0-->Bus0-->B
+ PhysicalDevice1-->C
+
+ PhysicalDevice1-.->LogicalDevice1
+
+ D["\Device"]-->|\|Storage0
+ LogicalDevice1-->Storage0
+
+
+```
+
+总线-设备的包含关系如下:
+
+```mermaid
+graph TD
+ A[ISA Controller]
+ B[PCI Controller]
+ A-->C[ISA Bus0]
+ B-->D[PCI Bus0]
+
+ C-->I[SB16]
+
+ D-->E[USB HCI]
+ E-->F[USB Bus0]
+
+ F-->G[Mouse]
+ F-->H[Keyboard]
+```
+
+## 链表
+
+
+
+```mermaid
+graph LR
+ A[BusDriver]-->|bus_lh|B[Bus]
+ B-->|bus_list|A
+```
+
+
+
+```mermaid
+graph LR
+ A[PhysicalDevice]-->|logical_device_lh|B[LogicalDevice];
+ B-.->|logical_device_list|A
+ subgraph SA[PhysicalDevice]
+ A1[PhysicalDevice]-.->|bus_list|AA1[Bus]
+ AA1-->|device_lh|A1
+ A1-->|irq_lh|AA4[DeviceIrq]
+ AA4-.->|device_list|A1
+ end
+ subgraph SB[LogicalDevice]
+ B0[LogicalDevice]
+ B0-.->|dm_device_list|BB2[XxDeviceManager]
+ BB2-->|device_list|B0
+ B0-.->|device_driver_device_list|BB3[DeviceDriver]
+ BB3-->|device_list|B0
+ end
+```
+
+# 结构体
+
+## Driver
+
+`Driver`结构描述一个驱动集合,类似于Windows中用户直接下载的驱动
+
+```c
+typedef struct Driver {
+ string_t short_name;
+ list_t device_driver_lh;
+ list_t remapped_memory_lh;
+
+ DriverState state;
+} Driver;
+```
+
+- `short_name`: 暂时无用
+- `device_driver_lh`: 链表,存储`Driver`下注册的所有`DeviceDriver`
+- `remapped_memory_lh`: 链表,存储`Driver`下所有驱动程序重映射的内存,方便检查是否重复映射同一片内存和在销毁时释放
+
+## BusDriver
+
+## BusType
+
+```c
+typedef enum BusType {
+ BUS_TYPE_PLATFORM,
+ BUS_TYPE_PCI,
+ BUS_TYPE_ISA,
+ BUS_TYPE_USB,
+ BUS_TYPE_MAX,
+} BusType;
+```
+
+目前支持4种Bus类型,
+
+- `BUS_TYPE_PLATFORM`: 所有通过固定配置发现的设备都挂到`platform_bus`下,如`pic`/`pit`这类设备
+- `BUS_TYPE_PCI`: PCI总线,没什么好说的。在x86中,PCI控制器通过特定IO端口直接访问,所以挂在`platform_bus`下
+- `BUS_TYPE_ISA`: ISA总线,目前已有驱动的只有一个`Sound Blaster 16`设备属于ISA总线
+- `BUS_TYPE_USB`: USB总线,需要注意的是USB主机控制器接口(Host Controller Interface, HCI)不属于USB总线,因为控制器自身是一个独立的设备挂在其他总线下,如`XHCI`(USB3.x)/`EHCI`(USB2.0)/`UHCI`(USB1.x)/`OHCI`(USB1.x)这些HCI在PC中都是通过PCI总线发现的,所以属于PCI总线
+
+### BusDriver
+
+```c
+typedef struct BusDriver {
+ list_t bus_lh;
+ string_t name;
+ BusType bus_type;
+ DriverState state;
+
+ Object *object;
+
+ uint16_t new_bus_num;
+ uint16_t bus_count;
+} BusDriver;
+```
+
+- `bus_lh`: 链表,保存这一类型总线下的所有具体的`Bus`
+- `name`: 仅用于寻址,如果为`"PCI"`则可直接通过`\Bus\PCI\x\y`寻址到总线下的`PhysicalDevice`
+- `bus_type`: 总线类型
+- `state`: 驱动状态,主要用于总线下设备驱动注册时先检查总线驱动是否初始化完成
+- `object`: 可被寻址的结构,`name`为`"PCI"`时则对应路径`\Bus\PCI`
+- `new_bus_num`: 用于分配新创建的`Bus`的编号,对应路径`\Bus\PCI\x\y`中的`x`
+- `bus_count`: 统计`Bus`的数量
+
+### Bus
+
+```c
+typedef struct Bus {
+ list_t device_lh;
+ list_t bus_list;
+ list_t bus_check_list;
+ list_t new_bus_list;
+ BusDriver *bus_driver;
+
+ struct Bus *primary_bus;
+
+ Object *object;
+
+ uint32_t bus_num;
+ uint32_t subordinate_bus_num;
+
+ int new_device_num;
+ int device_count;
+
+ BusOps *ops;
+} Bus;
+```
+
+- `device_lh`: 链表,保存总线下所有设备
+- `bus_list`: 连接到`BusDriver`中的`bus_lh`
+- `bus_check_list`: 连接到`driver.c`中的`bus_check_lh`,用于启动后持续检测总线设备连接情况,目前仅USB使用
+- `new_bus_list`: 由`register_bus_driver`添加到`driver.c`的`new_bus_lh`中,用于启动时遍历所有总线并初始化
+- `bus_driver`: 对应的`BusDriver`
+- `primary_bus`: 父总线,如果没有则为`NULL`
+- `object`: `bus`对应的`Object`,对应路径`\Bus\PCI\x\y`中的`x` `Object`
+- `bus_num`: `bus`的编号,在`create_bus`时分配,对应路径`\Bus\PCI\x\y`中的`x`的数值
+- `subordinate_bus_num`: 子`Bus`的起始编号
+- `new_device_num`: 用于分配总线下新设备的编号,对应路径`\Bus\PCI\x\y`中的`y`
+- `device_count`: 统计总线下设备的总数
+- `ops`: 每个`Bus`的操作接口
+
+### BusOps
+
+```c
+typedef struct BusOps {
+ DriverResult (*scan_bus)(struct BusDriver *bus_driver, struct Bus *bus);
+ DriverResult (*probe_device)(struct BusDriver *bus_driver, struct Bus *bus);
+} BusOps;
+```
+
+- `scan_bus`: 扫描总线下存在的设备
+- `probe_device`: 探测总线下所有的设备,并为其匹配驱动
+
+## DeviceDriver
+
+### DeviceDriver
+
+```c
+typedef struct DeviceDriver {
+ list_t device_driver_list;
+ list_t device_lh;
+} DeviceDriver;
+```
+
+- `device_driver_list`: 连接到`Driver`的`device_driver_lh`
+- `device_lh`: 链表,保存该`DeviceDriver`驱动的所有设备
+
+## Device
+
+### DeviceKind
+
+```c
+typedef enum DeviceKind {
+ DEVICE_KIND_PHYSICAL,
+ DEVICE_KIND_LOGICAL,
+} DeviceKind;
+```
+
+用于区分`PhysicalDevice`和`LogicalDevice`类型
+
+### DeviceState
+
+```c
+typedef enum {
+ DEVICE_STATE_UNINIT, // 设备未初始化
+ DEVICE_STATE_READY, // 设备准备就绪
+ DEVICE_STATE_ACTIVE, // 设备正在运行
+ DEVICE_STATE_ERROR, // 设备错误
+} DeviceState;
+```
+
+### DeviceOps
+
+```c
+typedef struct DeviceOps {
+ DriverResult (*init)(void *device); // 初始化设备
+ DriverResult (*start)(void *device); // 启动设备
+ DriverResult (*stop)(void *device); // 停止设备
+ DriverResult (*destroy)(void *device); // 销毁设备
+} DeviceOps;
+```
+
+`PhysicalDevice`和`LogicalDevice`通用,所以使用`void *`类型
+
+### PhysicalDevice
+
+```c
+typedef struct PhysicalDevice {
+ DeviceKind kind;
+ DeviceState state;
+ list_t new_device_list;
+
+ list_t bus_list;
+ list_t logical_device_lh;
+ list_t irq_lh;
+
+ int num;
+
+ struct Bus *bus;
+
+ struct Object *object;
+
+ DeviceOps *ops;
+
+ void *private_data;
+ void *bus_ext;
+} PhysicalDevice;
+```
+
+`PhysicalDevice`一般对应真实存在的设备(或芯片),一般在总线探测设备时直接创建,设备驱动需要使用`register_physical_device`才不会在初始化设备时忽略这个设备。如果不是由总线发现时则需要驱动自行调用`create_physical_device`创建
+
+- `kind`: 标识设备种类(`PhysicalDevice`/`LogicalDevice`),与`LogicalDevice`头部保持一致,所以可以先假设类型再判断
+- `state`: 标识设备状态,其余同上
+- `new_device_list`: 连接到`new_device_lh`,其余同上
+- `bus_list`: 连接到`Bus`的`device_lh`
+- `logical_device_lh`: 链表,保存`PhysicalDevice`对应的所有`LogicalDevice`
+- `irq_lh`: 暂未使用,计划用于删除`PhysicalDevice`时注销该设备所有已注册的`DeviceIrq`
+- `num`: 该设备在总线下的设备编号,对应路径`\Bus\PCI\x\y`中的`y`的数值
+- `bus`: 该设备所在的`Bus`
+- `object`: 对应路径`\Bus\PCI\x\y`指向的`Object`
+- `ops`: 设备通用的操作接口,由具体的设备驱动通过`register_physical_device`设置
+- `private_data`: 驱动自行保存的信息
+- `bus_ext`: 由总线保存的总线相关信息
+
+### DeviceType
+
+```c
+typedef enum {
+ DEVICE_TYPE_UNKNOWN = 0, // 未知设备类型
+ DEVICE_TYPE_INTERRUPT_CONTROLLER, // 中断控制器
+ DEVICE_TYPE_TIMER, // 定时器设备
+ DEVICE_TYPE_FRAMEBUFFER, // 通过显示缓冲区直接控制的屏幕
+ DEVICE_TYPE_STORAGE, // 存储设备(如硬盘)
+ DEVICE_TYPE_INPUT, // 输入设备(如键盘鼠标)
+ DEVICE_TYPE_SOUND, // 声音设备(声卡)
+ DEVICE_TYPE_BUS_CONTROLLER, // 总线控制器(如usb控制器XHCI/EHCI/OHCI/UHCI)
+ DEVICE_TYPE_INTERNET, // 网络设备(网卡)
+ DEVICE_TYPE_TIME, // 时间设备(如:Unix时间戳/UTC时间)
+ DEVICE_TYPE_SERIAL, // 串口设备
+ DEVICE_TYPE_MAX,
+} DeviceType;
+```
+
+只在`LogicalDevice`中使用,用于标识`LogicalDevice`对应的设备的功能
+
+需要注意的是USB设备不单独作为类型在`DeviceType中`,USB设备根据其具体的功能选择`DeviceType`
+
+### LogicalDevice
+
+```c
+typedef struct LogicalDevice {
+ DeviceKind kind;
+ DeviceState state;
+ list_t new_device_list;
+
+ list_t logical_device_list;
+ list_t dm_device_list;
+ list_t device_driver_device_list;
+
+ DeviceType type;
+ DeviceOps *ops;
+
+ struct PhysicalDevice *physical_device;
+ struct Object *object;
+ void *dm_ext; // 设备管理器所需的扩展信息
+
+ void *private_data;
+} LogicalDevice;
+```
+
+`LogicalDevice`根据具体的功能来划分,一个`PhysicalDevice`可以创建多个`LogicalDevice`,一般通过对应`DeviceManager`的接口隐式创建,如果是未知设备类型需要手动调用`create_logical_device`创建
+
+- `kind`: 同上
+- `state`: 同上
+- `new_device_list`: 同上
+- `logical_device_list`: 连接到`PhysicalDevice`的`logical_device_lh`
+- `dm_device_list`: 连接到`DeviceManager`的`device_lh`
+- `device_driver_device_list`: 连接到`DeviceDriver`的`device_lh`
+- `type`: 标识设备类型
+- `ops`: 同`PhysicalDevice`,一般由对应的`DeviceManager`设置,如果是未知类型则需要自行设置
+
+# 指南
+
+## 基本结构
+
+*注意:为了尽可能展示各种接口等用法,这里把很多东西拼在了一起,请根据需要选择需要用到的部分*
+
+```c
+DriverResult example_pci_probe(PciDevice *pci_device, PhysicalDevice *physical_device);
+DriverResult example_device_start(void *_device);
+DriverResult example_device_init(void *_device);
+
+// 定义全局变量
+// 操作接口
+PciDriverOps example_pci_driver_ops = {
+ .probe = example_pci_probe,
+};
+BusOps example_bus_ops = {
+ .scan_bus = NULL,
+ .probe_device = NULL,
+}
+DeviceOps example_physical_device_ops = {
+ .init = NULL,
+ .start = example_device_start,
+ .stop = NULL,
+ .destroy = NULL,
+};
+DeviceOps example_logical_device_ops = {
+ .init = example_device_init,
+ .start = NULL,
+ .stop = NULL,
+ .destroy = NULL,
+};
+
+Driver example_driver; // 驱动
+BusDriver example_bus_driver = { // 总线驱动
+ .name = STRING_INIT("Example"), // 总线名称
+};
+// 定义PCI设备驱动信息
+PciDriver example_pci_driver = {
+ .driver = &example_driver,
+ .device_driver = &example_device_driver,
+ .find_type = FIND_BY_VENDORID_DEVICEID,
+ .vendor_device = {EXAMPLE_VENDOR_ID, EXAMPLE_DEVICE_ID},
+ .ops = &example_pci_driver_ops,
+};
+DeviceDriver example_device_driver; // 设备驱动
+// 如果确认只有一个的话,Bus、PhysicalDevice、LogicalDevice等结构可以定义为全局指针变量
+Bus *bus;
+// PhysicalDevice *physical_device;
+// LogicalDevice *logical_device;
+DeviceIrq *irq;
+
+void example_irq_handler(void *_device) {
+ PhysicalDevice *device = _device;
+
+ if (!have_interrupt()) return; // 检查中断是否来自该设备
+}
+
+DriverResult example_device_start(void *_device) {
+ PhysicalDevice *physical_device = _device;
+
+ register_device_irq(&irq, physical_device, physical_device /* arg */, EXAMPLE_IRQ, example_irq_handler, IRQ_MODE_SHARED); // 注册共享IRQ中断
+
+ enable_device_irq(&irq); // 启用IRQ
+
+ return DRIVER_OK;
+}
+
+DriverResult example_device_init(void *_device) {
+ DriverResult result;
+ result = create_bus(&bus, &example_bus_driver, &example_bus_ops);
+
+ return result;
+}
+
+DriverResult example_pci_probe(PciDevice *pci_device, PhysicalDevice *physical_device) {
+ DriverResult result;
+ XxxDevice *xxx_device;
+ result = create_xxx_device(&xxx_device, &example_logical_device_ops, physical_device);
+ if (result != DRIVER_OK) return result;
+
+ register_physical_device(physical_device, &example_physical_device_ops);
+ physical_device = physical_device;
+
+ return DRIVER_OK;
+}
+
+// register_driver和register_bus_driver尽量在initcall阶段完成注册
+static __init void example_entry(void) {
+ register_driver(&example_driver);
+ register_bus_driver(&example_driver, &example_bus_driver);
+ // 如果有pci设备等总线设备的话也要在initcall阶段注册
+ pci_register_driver(&example_driver, &example_pci_driver);
+}
+
+driver_initcall(example_entry) // 链接的时候写入到.initcall段
+```
+
+
+
+
+
+## 其他
+
+`XxDevice`:基础的分配等工作由`xx_dm`完成,设备参数信息填写则是由驱动在init阶段自行完成
+
+`DeviceIrq`: 由驱动自行决定传入参数
+
+`LogicalDevice`: `private_data`由驱动自行申请内存并填入,`create_logical_device`和`delete_logical_device`不负责管理`private_data`
+
diff --git a/include/ctype.h b/include/ctype.h
index 7acf55d..da3f51f 100644
--- a/include/ctype.h
+++ b/include/ctype.h
@@ -1,34 +1,34 @@
#ifndef _CTYPE_H
#define _CTYPE_H
-#define _U 0x01 /* upper */
-#define _L 0x02 /* lower */
-#define _D 0x04 /* digit */
-#define _C 0x08 /* cntrl */
-#define _P 0x10 /* punct */
-#define _S 0x20 /* white space (space/lf/tab) */
-#define _X 0x40 /* hex digit */
-#define _SP 0x80 /* hard space (0x20) */
+#define _U 0x01 /* upper */
+#define _L 0x02 /* lower */
+#define _D 0x04 /* digit */
+#define _C 0x08 /* cntrl */
+#define _P 0x10 /* punct */
+#define _S 0x20 /* white space (space/lf/tab) */
+#define _X 0x40 /* hex digit */
+#define _SP 0x80 /* hard space (0x20) */
extern unsigned char _ctype[];
-extern char _ctmp;
+extern char _ctmp;
-#define isalnum(c) ((_ctype+1)[c]&(_U|_L|_D))
-#define isalpha(c) ((_ctype+1)[c]&(_U|_L))
-#define iscntrl(c) ((_ctype+1)[c]&(_C))
-#define isdigit(c) ((_ctype+1)[c]&(_D))
-#define isgraph(c) ((_ctype+1)[c]&(_P|_U|_L|_D))
-#define islower(c) ((_ctype+1)[c]&(_L))
-#define isprint(c) ((_ctype+1)[c]&(_P|_U|_L|_D|_SP))
-#define ispunct(c) ((_ctype+1)[c]&(_P))
-#define isspace(c) ((_ctype+1)[c]&(_S))
-#define isupper(c) ((_ctype+1)[c]&(_U))
-#define isxdigit(c) ((_ctype+1)[c]&(_D|_X))
+#define isalnum(c) ((_ctype + 1)[(int)(c)] & (_U | _L | _D))
+#define isalpha(c) ((_ctype + 1)[(int)(c)] & (_U | _L))
+#define iscntrl(c) ((_ctype + 1)[(int)(c)] & (_C))
+#define isdigit(c) ((_ctype + 1)[(int)(c)] & (_D))
+#define isgraph(c) ((_ctype + 1)[(int)(c)] & (_P | _U | _L | _D))
+#define islower(c) ((_ctype + 1)[(int)(c)] & (_L))
+#define isprint(c) ((_ctype + 1)[(int)(c)] & (_P | _U | _L | _D | _SP))
+#define ispunct(c) ((_ctype + 1)[(int)(c)] & (_P))
+#define isspace(c) ((_ctype + 1)[(int)(c)] & (_S))
+#define isupper(c) ((_ctype + 1)[(int)(c)] & (_U))
+#define isxdigit(c) ((_ctype + 1)[(int)(c)] & (_D | _X))
-#define isascii(c) (((unsigned) c)<=0x7f)
-#define toascii(c) (((unsigned) c)&0x7f)
+#define isascii(c) (((unsigned)c) <= 0x7f)
+#define toascii(c) (((unsigned)c) & 0x7f)
-#define tolower(c) (_ctmp=c,isupper(_ctmp)?_ctmp-('A'-'a'):_ctmp)
-#define toupper(c) (_ctmp=c,islower(_ctmp)?_ctmp-('a'-'A'):_ctmp)
+#define tolower(c) (_ctmp = c, isupper(_ctmp) ? _ctmp - ('A' - 'a') : _ctmp)
+#define toupper(c) (_ctmp = c, islower(_ctmp) ? _ctmp - ('a' - 'A') : _ctmp)
#endif
diff --git a/include/stddef.h b/include/stddef.h
index 6171f2a..d3b5cb5 100644
--- a/include/stddef.h
+++ b/include/stddef.h
@@ -13,8 +13,6 @@
*/
/* 32位操作系统 */
-typedef unsigned int size_t;
-typedef int ssize_t;
typedef unsigned int ino_t;
@@ -26,14 +24,13 @@ typedef unsigned int dma_addr_t;
/* 64位操作系统 */
/*
typedef unsigned long flags_t;
-typedef unsigned long size_t;
typedef unsigned long register_t;
typedef unsigned long address_t;
*/
typedef unsigned char *buf8_t; // 字节类型的缓冲区
typedef unsigned short *buf16_t; // 字类型的缓冲区
-typedef unsigned int *buf32_t; // 双字类型的缓冲区
+typedef unsigned int *buf32_t; // 双字类型的缓冲区
/*
*这里是define类型的
diff --git a/include/stdint.h b/include/stdint.h
index b04578a..a4151b9 100644
--- a/include/stdint.h
+++ b/include/stdint.h
@@ -1,25 +1,35 @@
#ifndef _STDINT_H
#define _STDINT_H
-typedef unsigned int uint32_t;
-typedef int int32_t;
-typedef unsigned short uint16_t;
-typedef short int16_t;
-typedef unsigned char uint8_t;
-typedef char int8_t;
+// 依赖编译器的内置类型__UINT64_TYPE__,__INT64_TYPE__和__SIZE_TYPE__
-typedef unsigned int u32;
-typedef int i32;
-typedef unsigned short u16;
-typedef short i16;
-typedef unsigned char u8;
-typedef char i8;
+typedef __UINT64_TYPE__ uint64_t;
+typedef __INT64_TYPE__ int64_t;
+typedef unsigned int uint32_t;
+typedef int int32_t;
+typedef unsigned short uint16_t;
+typedef short int16_t;
+typedef unsigned char uint8_t;
+typedef char int8_t;
-typedef unsigned int uint32;
-typedef int int32;
-typedef unsigned short uint16;
-typedef short int16;
-typedef unsigned char uint8;
-typedef char int8;
+typedef __UINT64_TYPE__ u64;
+typedef __INT64_TYPE__ i64;
+typedef unsigned int u32;
+typedef int i32;
+typedef unsigned short u16;
+typedef short i16;
+typedef unsigned char u8;
+typedef char i8;
+
+typedef __UINT64_TYPE__ uint64;
+typedef __INT64_TYPE__ int64;
+typedef unsigned int uint32;
+typedef int int32;
+typedef unsigned short uint16;
+typedef short int16;
+typedef unsigned char uint8;
+typedef char int8;
+
+typedef __SIZE_TYPE__ size_t;
#endif
diff --git a/install_grub.py b/install_grub.py
deleted file mode 100644
index 1657d18..0000000
--- a/install_grub.py
+++ /dev/null
@@ -1,112 +0,0 @@
-import os
-import subprocess
-import shutil
-import struct
-import argparse
-
-# 定义变量
-imagetool_path = '\"tools/bin/imagetool\"'
-hd_img_path = 'hd0.img'
-hd_size = '64M'
-embed_area_size = '1M'
-boot_img_path = 'boot.img'
-core_image_path = 'core.img'
-disk_dir_path = 'disk'
-grub_cfg_path = 'grub.cfg'
-prefix_path = "/boot/grub/"
-grub_mkimage_path = "grub-mkimage"
-grub_dir_path = "/usr/lib/grub/"
-default_mods =\
-"minicmd normal gzio gcry_crc verifiers terminal \
-priority_queue gettext extcmd datetime crypto bufio boot \
-biosdisk part_gpt part_msdos fat ext2 fshelp net multiboot2 \
-all_video gfxterm"
-
-def run_command(command, hide=False):
- if not hide:
- print("excute command: ", command)
- subprocess.run(command, shell=True, text=True, check=True)
-
-def write_boot_sector(image_path, boot_img_path):
- print("copy boot.img to disk image")
- with open(image_path, 'r+b') as img, open(boot_img_path, 'rb') as boot_img:
- img.write(boot_img.read(440))
-
-def write_core_img(image_path, core_img_path):
- print("copy core.img to disk image")
- with open(image_path, 'r+b') as img, open(core_img_path, 'rb') as core_img:
- img.seek(512)
- core_img_size = os.path.getsize(core_img_path)
- img.write(core_img.read(core_img_size))
-
-def create_grub_directory(disk_image_path, disk_dir, grub_cfg_path):
- os.makedirs(f'{disk_dir}/boot/grub', exist_ok=True)
- run_command(f"{imagetool_path} {disk_image_path} mkdir /p0/boot/", hide=True)
- run_command(f"{imagetool_path} {disk_image_path} mkdir /p0/boot/grub/", hide=True)
- run_command(f"{imagetool_path} {disk_image_path} copy {grub_cfg_path} /p0/boot/grub/grub.cfg")
-
-def install_grub(disk_image_path, platform, fs, mods):
- # 检查 hd0.img 是否存在
- flag = True
- if os.path.isfile(disk_image_path):
- print(f"{disk_image_path}已存在,要重新生成吗?(y/N):", end="")
- choice = input()
- if choice.lower() == 'y':
- flag = True
- else:
- flag = False
- if flag:
- os.remove(disk_image_path)
-
- if flag:
- # 创建空白磁盘
- run_command(f"{imagetool_path} {disk_image_path} new --size {hd_size}")
-
- # 创建分区表
- run_command(f"{imagetool_path} {disk_image_path} partition primary {fs} {embed_area_size} 100%")
-
- # 格式化分区
- run_command(f"{imagetool_path} {disk_image_path} format /p0/ {fs}")
-
- # 检查 boot.img 是否存在
- if not os.path.isfile(boot_img_path):
- # 复制 boot.img
- grub_dir_path += platform + "/"
- if not os.path.isfile(grub_dir_path + 'boot.img'):
- print(f"{grub_dir_path}boot.img不存在,请检查")
- return
- shutil.copy(os.path.join(grub_dir_path, 'boot.img'), boot_img_path)
-
- # 创建 core.img
- prefix_device = "(hd0,"
- if fs[0:3] == "fat":
- prefix_device += "msdos1"
- prefix_device += ')'
- run_command(f"{grub_mkimage_path} -O {platform} -o {core_image_path} --prefix \"{prefix_device + prefix_path}\" {mods}")
-
- # 写入引导扇区
- write_boot_sector(disk_image_path, boot_img_path)
-
- # 写入 core.img
- write_core_img(disk_image_path, core_image_path)
-
- # 创建 GRUB 目录并复制配置文件
- create_grub_directory(disk_image_path, disk_dir_path, grub_cfg_path)
-
-if __name__ == "__main__":
- parser = argparse.ArgumentParser(description="安装GRUB到磁盘镜像")
- parser.add_argument("--image", help="磁盘映像路径", default=hd_img_path)
- parser.add_argument("--platform", help="目标平台")
- parser.add_argument("--fs", help="文件系统")
- parser.add_argument("--mods", help="要额外附加的模块", default=default_mods)
- args = parser.parse_args()
-
- if os.name == 'nt':
- print("检测到为Windows,请输入grub路径:")
- path = input()
- if path[-1] != '/':
- path += '/'
- grub_dir_path = path
- grub_mkimage_path = path + grub_mkimage_path
-
- install_grub(args.image, args.platform, args.fs, args.mods)
diff --git a/qemu-linux.cfg b/qemu-linux.cfg
new file mode 100644
index 0000000..1eea83c
--- /dev/null
+++ b/qemu-linux.cfg
@@ -0,0 +1,7 @@
+[audiodev "snd0"]
+driver = "pa"
+id = "snd0"
+
+[device "sb16"]
+driver = "sb16"
+audiodev = "snd0"
\ No newline at end of file
diff --git a/qemu-macos.cfg b/qemu-macos.cfg
new file mode 100644
index 0000000..9781a47
--- /dev/null
+++ b/qemu-macos.cfg
@@ -0,0 +1,7 @@
+[audiodev "snd0"]
+driver = "coreaudio"
+id = "snd0"
+
+[device "sb16"]
+driver = "sb16"
+audiodev = "snd0"
\ No newline at end of file
diff --git a/qemu-windows.cfg b/qemu-windows.cfg
new file mode 100644
index 0000000..22f544a
--- /dev/null
+++ b/qemu-windows.cfg
@@ -0,0 +1,7 @@
+[audiodev "snd0"]
+driver = "dsound"
+id = "snd0"
+
+[device "sb16"]
+driver = "sb16"
+audiodev = "snd0"
\ No newline at end of file
diff --git a/scripts/define.mk b/scripts/define.mk
index 5e0a6cc..d1c4cb3 100644
--- a/scripts/define.mk
+++ b/scripts/define.mk
@@ -59,19 +59,19 @@ endif
export ECHO_RM ECHO_CC ECHO_CXX ECHO_AS ECHO_LD ECHO_AR ECHO_OUTPUT ECHO_HOSTCC
-CROSS_COMPILE ?=
+CROSS_COMPILE ?=
# Make variables (CC, etc...)
-AS := $(CROSS_COMPILE)clang -x assembler-with-cpp
-CC := $(CROSS_COMPILE)clang
-CPP := $(CROSS_COMPILE)clang -E
-CXX := $(CROSS_COMPILE)clang++
-LD := $(CROSS_COMPILE)lld
+AS := $(CROSS_COMPILE)clang --target=x86_64-elf -x assembler-with-cpp
+CC := $(CROSS_COMPILE)clang --target=x86_64-elf
+CPP := $(CROSS_COMPILE)clang --target=x86_64-elf -E
+CXX := $(CROSS_COMPILE)clang++ --target=x86_64-elf
+LD := $(CROSS_COMPILE)ld
AR := $(CROSS_COMPILE)ar
OC := $(CROSS_COMPILE)objcopy
OD := $(CROSS_COMPILE)objdump
NM := $(CROSS_COMPILE)nm
-HOSTCC := gcc
+HOSTCC := clang
export AS AR CC LD CPP CXX OC OD NM HOSTCC
\ No newline at end of file
diff --git a/scripts/localenv.mk b/scripts/localenv.mk
index 6aa327a..6aa6071 100644
--- a/scripts/localenv.mk
+++ b/scripts/localenv.mk
@@ -1,6 +1,6 @@
# env var
-ENV_CFLAGS := -march=i486 -fno-builtin -Wall -Wunused -m32 -std=gnu99 -fno-stack-protector -nostdinc -nostdlib -O0
+ENV_CFLAGS := -march=i486 -fno-builtin -Wall -Wunused -m32 -std=gnu11 -fno-stack-protector -nostdinc -nostdlib -O0
# kernel name & version
ENV_CFLAGS += -DKERNEL_NAME=\"horizon\" -DKERNEL_VERSION=\"0.0.1\"
@@ -11,7 +11,7 @@ ENV_APP_LD_SCRIPT := -T ../apps/app.lds
# MacOS special
ifeq ($(shell uname),Darwin)
- ENV_LD := i386-elf-ld -m elf_i386
+ ENV_LD := x86_64-elf-ld -m elf_i386
else
ENV_LD := ld -m elf_i386
endif
diff --git a/src/Cargo.template.toml b/src/Cargo.template.toml
new file mode 100644
index 0000000..4d8852d
--- /dev/null
+++ b/src/Cargo.template.toml
@@ -0,0 +1,13 @@
+[package]
+name = "kernel"
+version = "0.0.0"
+edition = "2021"
+
+[lib]
+crate-type = ["staticlib"]
+
+[profile.dev]
+panic = "abort"
+
+[profile.release]
+panic = "abort"
diff --git a/src/Makefile b/src/Makefile
index 6199ea7..81d095d 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -8,7 +8,7 @@ endif
X_ASFLAGS := $(ENV_AFLAGS) -I $(ARCH_DIR)/include/ -g
X_CFLAGS := $(ENV_CFLAGS) -fno-strict-aliasing -g
ifeq ($(ARCH), x86)
-X_CFLAGS += -DARCH_X86
+X_CFLAGS += -DARCH_X86=32
endif
X_INCDIRS := ../include/ ./include/ $(ARCH_DIR)/include/
@@ -21,7 +21,7 @@ LD := $(ENV_LD)
export AS LD
export ARCH_DIR
-SRC := $(ARCH_DIR)/ fs/ kernel/ lib/ network/
+SRC := $(ARCH_DIR)/ fs/ driver/ drivers/ kernel/ lib/ objects/
NAME := kernel.elf
diff --git a/src/arch/x86/Makefile b/src/arch/x86/Makefile
index 612ba6f..f73291b 100644
--- a/src/arch/x86/Makefile
+++ b/src/arch/x86/Makefile
@@ -1,3 +1,4 @@
SRC += multiboot2/
SRC += kernel/
-SRC += drivers/
\ No newline at end of file
+SRC += drivers/
+SRC += bios_emu/
\ No newline at end of file
diff --git a/src/arch/x86/bios_emu/Makefile b/src/arch/x86/bios_emu/Makefile
new file mode 100644
index 0000000..2a3507e
--- /dev/null
+++ b/src/arch/x86/bios_emu/Makefile
@@ -0,0 +1,7 @@
+SRC += bios_emu.c
+SRC += int.c
+SRC += decode.c
+SRC += mod_rm.c
+SRC += operations.c
+SRC += ops/
+SRC += segment.c
\ No newline at end of file
diff --git a/src/arch/x86/bios_emu/bios_emu.c b/src/arch/x86/bios_emu/bios_emu.c
new file mode 100644
index 0000000..cc2f6bc
--- /dev/null
+++ b/src/arch/x86/bios_emu/bios_emu.c
@@ -0,0 +1,61 @@
+#include "includes/stack.h"
+#include
+#include
+#include
+#include
+
+BiosEmuEnvironment bios_emu_env;
+
+#define INIT_LUT(env, arr, reg0, reg1, reg2, reg3, reg4, reg5, reg6, reg7) \
+ arr[0] = &env->regs.reg0; \
+ arr[1] = &env->regs.reg1; \
+ arr[2] = &env->regs.reg2; \
+ arr[3] = &env->regs.reg3; \
+ arr[4] = &env->regs.reg4; \
+ arr[5] = &env->regs.reg5; \
+ arr[6] = &env->regs.reg6; \
+ arr[7] = &env->regs.reg7;
+
+#define INIT_LUT_R8(env) \
+ INIT_LUT(env, env->reg_lut_r8, al, cl, dl, bl, ah, ch, dh, bh);
+
+#define INIT_LUT_R16(env) \
+ INIT_LUT(env, env->reg_lut_r16, ax, cx, dx, bx, sp, bp, si, di);
+
+#define INIT_LUT_R32(env) \
+ INIT_LUT(env, env->reg_lut_r32, eax, ecx, edx, ebx, esp, ebp, esi, edi);
+
+void bios_emu_init(void) {
+ BiosEmuEnvironment *env = &bios_emu_env;
+ env->regs.cs = 0x0000;
+ env->regs.ds = 0x0000;
+ env->regs.es = 0x0000;
+ env->regs.fs = 0x0000;
+ env->regs.gs = 0x0000;
+ env->regs.eip = 0x0000;
+ env->regs.eflags = io_load_eflags();
+
+ env->regs.eax = 0;
+ env->regs.ebx = 0;
+ env->regs.ecx = 0;
+ env->regs.edx = 0;
+ env->regs.esi = 0;
+ env->regs.edi = 0;
+ env->regs.ebp = 0;
+ env->regs.esp = 0x7c00;
+
+ env->default_ss = &env->regs.ds;
+ env->ivt = (void *)0x0000;
+ env->cur_ip = 0;
+ env->stack_bottom = STACK_POINTER16(env) - 0x2000;
+
+ env->flags.stack_size = 0;
+ env->flags.operand_size = 0;
+ env->flags.default_operand_size = 0;
+ env->flags.address_size = 0;
+ env->flags.default_address_size = 0;
+
+ INIT_LUT_R8(env);
+ INIT_LUT_R16(env);
+ INIT_LUT_R32(env);
+}
\ No newline at end of file
diff --git a/src/arch/x86/bios_emu/config.toml b/src/arch/x86/bios_emu/config.toml
new file mode 100644
index 0000000..cb40055
--- /dev/null
+++ b/src/arch/x86/bios_emu/config.toml
@@ -0,0 +1,2 @@
+dir = ["ops/"]
+c = ["bios_emu.c", "decode.c", "mod_rm.c", "operations.c", "segment.c"]
diff --git a/src/arch/x86/bios_emu/decode.c b/src/arch/x86/bios_emu/decode.c
new file mode 100644
index 0000000..038ca43
--- /dev/null
+++ b/src/arch/x86/bios_emu/decode.c
@@ -0,0 +1,839 @@
+#include "includes/decode.h"
+#include "includes/alu.h"
+#include "includes/conditions.h"
+#include "includes/instructions_1.h"
+#include "includes/instructions_2.h"
+#include "includes/mod_rm.h"
+#include "includes/operations.h"
+#include "includes/prefix.h"
+#include "includes/segment.h"
+#include "includes/stack.h"
+#include "kernel/func.h"
+#include
+#include
+#include
+#include
+
+BiosEmuExceptions nop_16(BiosEmuEnvironment *env, uint16_t *addr1) {
+ return NoException;
+}
+
+BiosEmuExceptions decode_r(
+ BiosEmuEnvironment *env, Op1_16 func16, Op1_32 func32) {
+ uint8_t reg = *(uint8_t *)env->cur_ip++;
+ env->regs.eip++;
+ if (env->flags.operand_size == 0) {
+ uint16_t *r16 = env->reg_lut_r16[reg];
+ return func16(env, r16);
+ } else {
+ uint32_t *r32 = env->reg_lut_r32[reg];
+ return func32(env, r32);
+ }
+}
+
+BiosEmuExceptions decode_rm8_r8(BiosEmuEnvironment *env, Op2_8_8 func) {
+ uint8_t modrm = *(uint8_t *)env->cur_ip++;
+ env->regs.eip++;
+ uint8_t reg = (modrm >> 3) & 0b111;
+
+ uint8_t *rm = RM_ADDR(env, modrm);
+ uint8_t *r8 = env->reg_lut_r8[reg];
+
+ return func(env, rm, r8);
+}
+
+BiosEmuExceptions decode_rm_r(
+ BiosEmuEnvironment *env, Op2_16_16 func16, Op2_32_32 func32) {
+ uint8_t modrm = *(uint8_t *)env->cur_ip++;
+ env->regs.eip++;
+ uint8_t reg = (modrm >> 3) & 0b111;
+
+ void *rm = RM_ADDR(env, modrm);
+ if (env->flags.operand_size == 0) {
+ uint16_t *r16 = env->reg_lut_r16[reg];
+ return func16(env, rm, r16);
+ } else {
+ uint32_t *r32 = env->reg_lut_r32[reg];
+ return func32(env, rm, r32);
+ }
+}
+
+BiosEmuExceptions decode_rm_imm8(
+ BiosEmuEnvironment *env, Op2_16_16 func16, Op2_32_32 func32) {
+ uint8_t modrm = *(uint8_t *)env->cur_ip++;
+ env->regs.eip++;
+
+ void *rm = RM_ADDR(env, modrm);
+ uint32_t value = *(uint8_t *)env->cur_ip++;
+ env->regs.eip++;
+ if (env->flags.operand_size == 0) {
+ return func16(env, rm, (uint16_t *)&value);
+ } else {
+ return func32(env, rm, &value);
+ }
+}
+
+BiosEmuExceptions decode_r8_rm8(BiosEmuEnvironment *env, Op2_8_8 func) {
+ uint8_t modrm = *(uint8_t *)env->cur_ip++;
+ env->regs.eip++;
+ uint8_t reg = (modrm >> 3) & 0b111;
+
+ uint8_t *rm = RM_ADDR(env, modrm);
+ uint8_t *r8 = env->reg_lut_r8[reg];
+
+ return func(env, r8, rm);
+}
+
+BiosEmuExceptions decode_r_rm(
+ BiosEmuEnvironment *env, Op2_16_16 func16, Op2_32_32 func32) {
+ uint8_t modrm = *(uint8_t *)env->cur_ip++;
+ env->regs.eip++;
+ uint8_t reg = (modrm >> 3) & 0b111;
+
+ if (env->flags.operand_size == 0) {
+ void *r = env->reg_lut_r16[reg];
+ return func16(env, r, RM_ADDR(env, modrm));
+ } else {
+ void *r = env->reg_lut_r32[reg];
+ return func32(env, r, RM_ADDR(env, modrm));
+ }
+}
+
+BiosEmuExceptions decode_rm_r_imm8(
+ BiosEmuEnvironment *env, Op3_16_16_8 func16, Op3_32_32_8 func32) {
+ uint8_t modrm = *(uint8_t *)env->cur_ip++;
+ env->regs.eip++;
+ uint8_t reg = (modrm >> 3) & 0b111;
+
+ void *rm = RM_ADDR(env, modrm);
+ if (env->flags.operand_size == 0) {
+ uint16_t *r16 = env->reg_lut_r16[reg];
+ return func16(env, rm, *r16, *(uint8_t *)env->cur_ip++);
+ } else {
+ uint32_t *r32 = env->reg_lut_r32[reg];
+ return func32(env, rm, *r32, *(uint8_t *)env->cur_ip++);
+ }
+}
+
+BiosEmuExceptions decode_rm_r_cl(
+ BiosEmuEnvironment *env, Op3_16_16_8 func16, Op3_32_32_8 func32) {
+ uint8_t modrm = *(uint8_t *)env->cur_ip++;
+ env->regs.eip++;
+ uint8_t reg = (modrm >> 3) & 0b111;
+
+ void *rm = RM_ADDR(env, modrm);
+ if (env->flags.operand_size == 0) {
+ uint16_t *r16 = env->reg_lut_r16[reg];
+ return func16(env, rm, *r16, env->regs.cl);
+ } else {
+ uint32_t *r32 = env->reg_lut_r32[reg];
+ return func32(env, rm, *r32, env->regs.cl);
+ }
+}
+
+void decode_string_instructions_8(
+ BiosEmuEnvironment *env, void *dst, int delta_dst, void *src, int delta_src,
+ OpStr opstr_8) {
+ int repeat_times;
+
+ if (env->regs.flags & BIT(DirectionFlagBit)) {
+ delta_dst = -delta_dst;
+ delta_src = -delta_src;
+ }
+
+ if (env->flags.operand_size == 0) {
+ repeat_times = (env->flags.repeat) ? env->regs.cx : 1;
+ } else {
+ repeat_times = (env->flags.repeat) ? env->regs.ecx : 1;
+ }
+ opstr_8(env, dst, delta_dst, src, delta_src, repeat_times);
+ return;
+}
+
+void decode_string_instructions_16(
+ BiosEmuEnvironment *env, void *dst, int delta_dst, void *src, int delta_src,
+ OpStr opstr_16, OpStr opstr_32) {
+ int repeat_times;
+
+ if (env->regs.flags & BIT(DirectionFlagBit)) {
+ delta_dst = -delta_dst;
+ delta_src = -delta_src;
+ }
+
+ if (env->flags.operand_size == 0) {
+ repeat_times = (env->flags.repeat) ? env->regs.cx : 1;
+ delta_dst <<= 1;
+ opstr_16(env, dst, delta_dst, src, delta_src, repeat_times);
+ } else {
+ repeat_times = (env->flags.repeat) ? env->regs.ecx : 1;
+ delta_dst <<= 2;
+ opstr_32(env, dst, delta_dst, src, delta_src, repeat_times);
+ }
+ return;
+}
+
+BiosEmuExceptions decode_two_bytes_opcode(BiosEmuEnvironment *env) {
+ TwoBytesOpcodes *opcode = env->cur_ip;
+ env->cur_ip++;
+ env->regs.eip++;
+ switch ((uint8_t)*opcode) {
+ case OP_BSF_TZCNT:
+ decode_rm_r(env, bsf_16_16, bsf_32_32);
+ break;
+ case OP_BSR_LZCNT:
+ decode_rm_r(env, bsr_16_16, bsr_32_32);
+ break;
+ case OP_BSWAP:
+ env->flags.operand_size = 1; // BSWAP只有32位操作数
+ decode_r(env, nop_16, bswap_32);
+ break;
+ case OP_BT:
+ decode_rm_r(env, bt_16_16, bt_32_32);
+ break;
+ case OP_BTC:
+ decode_rm_r(env, btc_16_16, btc_32_32);
+ break;
+ case OP_BTR:
+ decode_rm_r(env, btr_16_16, btr_32_32);
+ break;
+ case OP_BTS:
+ decode_rm_r(env, bts_16_16, bts_32_32);
+ break;
+ case OP_CMPXCHG8:
+ decode_rm8_r8(env, cmpxchg_8_8);
+ break;
+ case OP_CMPXCHG:
+ decode_rm_r(env, cmpxchg_16_16, cmpxchg_32_32);
+ break;
+ case 0xba:
+ decode_0xba(env);
+ break;
+ case OP_IMUL_r_rm:
+ decode_imul_r_rm(env);
+ break;
+ case OP_Jcc ...(OP_Jcc + 15):
+ decode_jcc(env, condition_table[*opcode & 0x0f](env));
+ break;
+ case OP_LSS:
+ decode_rm_r(env, lss_16_16, lss_32_32);
+ break;
+ case OP_LFS:
+ decode_rm_r(env, lfs_16_16, lfs_32_32);
+ break;
+ case OP_LGS:
+ decode_rm_r(env, lgs_16_16, lgs_32_32);
+ break;
+ case OP_MOVZX_r_rm8:
+ decode_movzx_r_rm8(env);
+ break;
+ case OP_MOVZX_r_rm16:
+ decode_movzx_r_rm16(env);
+ break;
+ case OP_MOVSX_r_rm8:
+ decode_movsx_r_rm8(env);
+ break;
+ case OP_MOVSX_r_rm16:
+ decode_movsx_r_rm16(env);
+ break;
+ case OP_PUSH_FS:
+ PUSH_SREG(env, fs);
+ break;
+ case OP_PUSH_GS:
+ PUSH_SREG(env, gs);
+ break;
+ case OP_POP_FS:
+ POP_SREG(env, fs);
+ break;
+ case OP_POP_GS:
+ POP_SREG(env, gs);
+ break;
+ case OP_SETcc ...(OP_SETcc + 15):
+ decode_setcc(env, condition_table[*opcode & 0x0f](env));
+ break;
+ case OP_SHLD_imm8:
+ decode_rm_r_imm8(env, shld_16_16_8, shld_32_32_8);
+ break;
+ case OP_SHLD_cl:
+ decode_rm_r_cl(env, shld_16_16_8, shld_32_32_8);
+ break;
+ case OP_SHRD_imm8:
+ decode_rm_r_imm8(env, shrd_16_16_8, shrd_32_32_8);
+ break;
+ case OP_SHRD_cl:
+ decode_rm_r_cl(env, shrd_16_16_8, shrd_32_32_8);
+ break;
+ case OP_XADD_rm_r_8:
+ decode_rm8_r8(env, xadd_8_8);
+ break;
+ case OP_XADD_rm_r:
+ decode_rm_r(env, xadd_16_16, xadd_32_32);
+ break;
+ default:
+ return InvalidOpcode;
+ }
+ return NoException;
+}
+
+BiosEmuExceptions decode_one_byte_opcode(BiosEmuEnvironment *env) {
+ BiosEmuExceptions exception = NoException;
+ OneByteOpcodes *opcode = env->cur_ip;
+ env->cur_ip++;
+ env->regs.eip++;
+ switch ((uint8_t)*opcode) {
+ case OP_AAA:
+ decode_aaa(env);
+ break;
+ case OP_AAD:
+ decode_aad(env);
+ break;
+ case OP_AAM:
+ decode_aam(env);
+ break;
+ case OP_AAS:
+ decode_aas(env);
+ break;
+ case OP_BOUND:
+ exception = decode_r_rm(env, bound_16_16, bound_32_32);
+ break;
+ case OP_CALL:
+ exception = decode_call(env);
+ break;
+ case OP_CALL_ptr:
+ exception = decode_call_ptr(env);
+ break;
+ case OP_CBW_CWDE:
+ decode_cbw_cwde(env);
+ break;
+ case OP_CLC:
+ CLC(env);
+ break;
+ case OP_CLD:
+ CLD(env);
+ break;
+ case OP_CLI:
+ CLI(env);
+ io_cli();
+ break;
+ case OP_CMC:
+ CMC(env);
+ break;
+ case OP_CMPS8: {
+ void *src = GET_REG_POINTER(env, ds, si);
+ void *dst = GET_REG_POINTER(env, es, di);
+ decode_string_instructions_8(env, dst, 1, src, 1, cmps_8);
+ break;
+ }
+ case OP_CMPS: {
+ void *src = GET_REG_POINTER(env, ds, si);
+ void *dst = GET_REG_POINTER(env, es, di);
+ decode_string_instructions_16(env, dst, 1, src, 1, cmps_16, cmps_32);
+ break;
+ }
+ case OP_CWD_CDQ:
+ decode_cwd_cdq(env);
+ break;
+ case OP_ENTER:
+ exception = decode_enter(env);
+ break;
+ case OP_DAA:
+ decode_daa(env);
+ break;
+ case OP_DAS:
+ decode_das(env);
+ break;
+ case OP_DEC ...(OP_DEC + 7):
+ decode_dec_r(env, *opcode);
+ break;
+ case OP_HLT:
+ exception = EventHalted;
+ break;
+ case OP_IMUL_imm8:
+ decode_imul_r_rm_imm8(env);
+ break;
+ case OP_IMUL_imm16:
+ decode_imul_r_rm_imm16(env);
+ break;
+ case OP_IN8:
+ decode_in8(env, *(uint8_t *)env->cur_ip);
+ env->cur_ip++;
+ env->regs.eip++;
+ break;
+ case OP_IN:
+ decode_in(env, *(uint8_t *)env->cur_ip);
+ env->cur_ip += 2;
+ env->regs.eip += 2;
+ break;
+ case OP_IN8_dx:
+ decode_in8(env, env->regs.dx);
+ break;
+ case OP_IN_dx:
+ decode_in(env, env->regs.dx);
+ break;
+ case OP_INS8: {
+ void *src = &env->regs.dx;
+ void *dst = GET_REG_POINTER(env, ds, si);
+ decode_string_instructions_8(env, dst, 0, src, 1, ins_8);
+ break;
+ }
+ case OP_INS: {
+ void *src = &env->regs.dx;
+ void *dst = GET_REG_POINTER(env, ds, si);
+ decode_string_instructions_16(env, dst, 0, src, 1, ins_16, ins_32);
+ break;
+ }
+ case OP_INC ...(OP_INC + 7):
+ decode_inc_r(env, *opcode);
+ break;
+ case OP_INT:
+ exception = decode_int(env, *(uint8_t *)env->cur_ip++);
+ break;
+ case OP_INTO:
+ if (env->regs.flags & BIT(OverflowFlagBit)) {
+ exception = decode_int(env, 4);
+ }
+ break;
+ case OP_IRET_IRETD:
+ exception = decode_iret(env);
+ break;
+ case OP_JE_JZ_8:
+ case OP_JG_JNLE_8:
+ case OP_JGE_JNL_8:
+ case OP_JL_JNGE_8:
+ case OP_JLE_JNG_8:
+ case OP_JBE_JNA_8:
+ case OP_JB_JC_JNAE_8:
+ case OP_JAE_JNB_JNC_8:
+ case OP_JA_JNBE_8:
+ case OP_JNE_JNZ_8:
+ case OP_JNO_8:
+ case OP_JNP_JPO_8:
+ case OP_JNS_8:
+ case OP_JO_8:
+ case OP_JP_JPE_8:
+ case OP_JS_8:
+ decode_jcc_8(env, condition_table[*opcode & 0x0f](env));
+ break;
+ case OP_JMP8:
+ decode_jmp8(env);
+ break;
+ case OP_JMP:
+ decode_jmp(env);
+ break;
+ case OP_LongJMP:
+ decode_long_jmp_ptr16(env);
+ break;
+ case OP_LAHF:
+ LAHF(env);
+ break;
+ case OP_LDS:
+ decode_r_rm(env, lds_16_16, lds_32_32);
+ break;
+ case OP_LEA:
+ exception = decode_lea(env);
+ break;
+ case OP_LEAVE:
+ decode_leave(env);
+ break;
+ case OP_LES:
+ decode_r_rm(env, les_16_16, les_32_32);
+ break;
+ case OP_LODS8: {
+ void *src = GET_REG_POINTER(env, ds, si);
+ void *dst = &env->regs.al;
+ decode_string_instructions_8(env, dst, 0, src, 1, movs_8);
+ break;
+ }
+ case OP_LODS: {
+ void *src = GET_REG_POINTER(env, ds, si);
+ void *dst = GET_REG_ADDR(env, ax);
+ decode_string_instructions_16(env, dst, 0, src, 1, movs_16, movs_32);
+ break;
+ }
+ case OP_LOOP: {
+ uint32_t count;
+ if (env->flags.operand_size == 0) {
+ env->regs.cx--;
+ count = env->regs.cx;
+ } else {
+ env->regs.ecx--;
+ count = env->regs.ecx;
+ }
+ if (count) decode_jmp8(env);
+ break;
+ }
+ case OP_LOOPE: {
+ uint32_t count;
+ if (env->flags.operand_size == 0) {
+ env->regs.cx--;
+ count = env->regs.cx;
+ } else {
+ env->regs.ecx--;
+ count = env->regs.ecx;
+ }
+ if (count) decode_jcc(env, condition_table[4](env));
+ break;
+ }
+ case OP_LOOPNE: {
+ uint32_t count;
+ if (env->flags.operand_size == 0) {
+ env->regs.cx--;
+ count = env->regs.cx;
+ } else {
+ env->regs.ecx--;
+ count = env->regs.ecx;
+ }
+ if (count) decode_jcc(env, condition_table[5](env));
+ break;
+ }
+ case OP_MOV_rm_r8:
+ exception = decode_rm8_r8(env, mov_8_8);
+ break;
+ case OP_MOV_rm_r:
+ exception = decode_rm_r(env, mov_16_16, mov_32_32);
+ break;
+ case OP_MOV_r_rm8:
+ exception = decode_r8_rm8(env, mov_8_8);
+ break;
+ case OP_MOV_r_rm:
+ exception = decode_r_rm(env, mov_16_16, mov_32_32);
+ break;
+ case OP_MOV_rm_sreg:
+ decode_mov_rm_sreg(env);
+ break;
+ case OP_MOV_sreg_rm:
+ decode_mov_sreg_rm(env);
+ break;
+ case OP_MOV_a_moffs8:
+ decode_mov_r_moffs_8(env);
+ break;
+ case OP_MOV_a_moffs:
+ decode_mov_r_moffs(env);
+ break;
+ case OP_MOV_moffs8_a:
+ decode_mov_moffs_r_8(env);
+ break;
+ case OP_MOV_moffs_a:
+ decode_mov_moffs_r(env);
+ break;
+ case OP_MOV_r_imm8 ...(OP_MOV_r_imm8 + 7):
+ decode_mov_r_imm8(env, *opcode);
+ break;
+ case OP_MOV_r_imm ...(OP_MOV_r_imm + 7):
+ decode_mov_r_imm(env, *opcode);
+ break;
+ case OP_MOV_rm_imm8:
+ exception = decode_rm_imm8(env, mov_16_16, mov_32_32);
+ break;
+ case OP_MOV_rm_imm:
+ decode_mov_rm_imm(env);
+ break;
+ case OP_MOVS8: {
+ void *src = GET_REG_POINTER(env, ds, si);
+ void *dst = GET_REG_POINTER(env, es, di);
+ decode_string_instructions_8(env, dst, 1, src, 1, movs_8);
+ break;
+ }
+ case OP_MOVS: {
+ void *src = GET_REG_POINTER(env, ds, si);
+ void *dst = GET_REG_POINTER(env, es, di);
+ decode_string_instructions_16(env, dst, 1, src, 1, movs_16, movs_32);
+ break;
+ }
+ case OP_NOP:
+ break;
+ case OP_OUT8:
+ decode_out8(env, *(uint8_t *)env->cur_ip);
+ env->cur_ip++;
+ env->regs.eip++;
+ break;
+ case OP_OUT:
+ decode_out(env, *(uint8_t *)env->cur_ip);
+ env->cur_ip += 2;
+ env->regs.eip += 2;
+ break;
+ case OP_OUT8_dx:
+ decode_out8(env, env->regs.dx);
+ break;
+ case OP_OUT_dx:
+ decode_out(env, env->regs.dx);
+ break;
+ case OP_OUTS8: {
+ void *src = GET_REG_POINTER(env, ds, si);
+ void *dst = &env->regs.dx;
+ decode_string_instructions_8(env, dst, 1, src, 0, outs_8);
+ break;
+ }
+ case OP_OUTS: {
+ void *src = GET_REG_POINTER(env, ds, si);
+ void *dst = &env->regs.dx;
+ decode_string_instructions_16(env, dst, 1, src, 0, outs_16, outs_32);
+ break;
+ }
+ case OP_POP_rm:
+ decode_pop_rm(env);
+ break;
+ case OP_POP_r ...(OP_POP_r + 7):
+ decode_pop_r(env, *opcode);
+ break;
+ case OP_POP_DS:
+ POP_SREG(env, ds);
+ break;
+ case OP_POP_ES:
+ POP_SREG(env, es);
+ break;
+ case OP_POP_SS:
+ POP_SREG(env, ss);
+ break;
+ case OP_POPA_POPAD:
+ decode_popa_popad(env);
+ break;
+ case OP_POPF_POPFD:
+ if (env->flags.operand_size == 0) {
+ POP(env, env->regs.flags, 2);
+ } else {
+ POP(env, env->regs.eflags, 4);
+ }
+ break;
+ case OP_PUSH_CS:
+ PUSH_SREG(env, cs);
+ break;
+ case OP_PUSH_SS:
+ PUSH_SREG(env, ss);
+ break;
+ case OP_PUSH_DS:
+ PUSH_SREG(env, ds);
+ break;
+ case OP_PUSH_ES:
+ PUSH_SREG(env, es);
+ break;
+ case OP_PUSH_imm8:
+ PUSH(env, *(uint8_t *)env->cur_ip, 1);
+ env->regs.eip++;
+ break;
+ case OP_PUSH_imm:
+ if (env->flags.operand_size == 0) {
+ PUSH(env, *(uint16_t *)env->cur_ip, 2);
+ env->regs.eip += 2;
+ env->cur_ip += 2;
+ } else {
+ PUSH(env, *(uint32_t *)env->cur_ip, 4);
+ env->regs.eip += 4;
+ env->cur_ip += 4;
+ }
+ break;
+ case OP_PUSH_r ...(OP_PUSH_r + 7):
+ if (env->flags.operand_size == 0) {
+ uint16_t *reg = PLUS_RW_REG(env, *opcode);
+ PUSH(env, *reg, 2);
+ } else {
+ uint32_t *reg = PLUS_RD_REG(env, *opcode);
+ PUSH(env, *reg, 4);
+ }
+ break;
+ case OP_PUSHA_PUSHAD:
+ decode_pusha_pushad(env);
+ break;
+ case OP_PUSHF_PUSHFD:
+ if (env->flags.operand_size == 0) {
+ PUSH(env, env->regs.flags, 2);
+ } else {
+ PUSH(env, env->regs.eflags & 0x00fcffff, 4);
+ }
+ break;
+ case OP_RET:
+ exception = decode_ret_near(env, 0);
+ break;
+ case OP_LongRET:
+ exception = decode_ret_far(env, 0);
+ break;
+ case OP_RET_imm16:
+ exception = decode_ret_imm16(env);
+ break;
+ case OP_LongRET_imm16:
+ exception = decode_ret_far_imm16(env);
+ break;
+ case OP_SAHF:
+ SAHF(env);
+ break;
+ case OP_SCAS8: {
+ void *src = GET_REG_POINTER(env, es, di);
+ void *dst = &env->regs.al;
+ decode_string_instructions_8(env, dst, 0, src, 1, cmps_8);
+ break;
+ }
+ case OP_SCAS: {
+ void *src = GET_REG_POINTER(env, es, di);
+ void *dst = GET_REG_ADDR(env, ax);
+ decode_string_instructions_16(env, dst, 0, src, 1, cmps_16, cmps_32);
+ break;
+ }
+ case OP_STC:
+ STC(env);
+ break;
+ case OP_STD:
+ STD(env);
+ break;
+ case OP_STI:
+ STI(env);
+ io_sti();
+ break;
+ case OP_STOS8: {
+ void *src = &env->regs.al;
+ void *dst = (void *)get_phy_addr(env, env->regs.es, env->regs.di);
+ decode_string_instructions_8(env, dst, 1, src, 0, movs_8);
+ break;
+ }
+ case OP_STOS: {
+ void *src = GET_REG_ADDR(env, ax);
+ void *dst = (void *)get_phy_addr(env, env->regs.es, env->regs.di);
+ decode_string_instructions_16(env, dst, 1, src, 0, movs_16, movs_32);
+ break;
+ }
+ case OP_TEST_imm8:
+ calc_a_imm8(env, CALC_TEST);
+ break;
+ case OP_TEST_imm:
+ calc_a_imm(env, CALC_TEST);
+ break;
+ case OP_TEST_rm_r_8:
+ calc_rm_r_8(env, CALC_TEST);
+ break;
+ case OP_TEST_rm_r:
+ calc_rm_r(env, CALC_TEST);
+ break;
+ case (OP_XCHG_r + 1)...(OP_XCHG_r + 7): // XCHG ax, ax机器码与NOP指令相同
+ exception = decode_r_rm(env, xchg_16_16, xchg_32_32);
+ break;
+ case OP_XCHG_8:
+ exception = decode_rm8_r8(env, xchg_8_8);
+ break;
+ case OP_XCHG:
+ exception = decode_rm_r(env, xchg_16_16, xchg_32_32);
+ break;
+ case OP_XLAT:
+ if (env->flags.operand_size == 0) {
+ env->regs.al = *(uint8_t *)get_phy_addr(
+ env, env->regs.ds, env->regs.bx + env->regs.al);
+ } else {
+ env->regs.al = *(uint32_t *)get_phy_addr(
+ env, env->regs.ds, env->regs.ebx + env->regs.al);
+ }
+ break;
+ ALU_CASE(ADC)
+ ALU_CASE(ADD)
+ ALU_CASE(AND)
+ ALU_CASE(XOR)
+ ALU_CASE(OR)
+ ALU_CASE(SBB)
+ ALU_CASE(SUB)
+ ALU_CASE(CMP)
+ case OP_TWO_BYTES:
+ exception = decode_two_bytes_opcode(env);
+ break;
+ case 0x80 ... 0x83:
+ exception = decode_0x80_0x83(env, *opcode);
+ break;
+ case 0xc0:
+ exception = decode_0xc0(env);
+ break;
+ case 0xc1:
+ exception = decode_0xc1(env);
+ break;
+ case 0xd0:
+ exception = decode_0xd0(env);
+ break;
+ case 0xd1:
+ exception = decode_0xd1(env);
+ break;
+ case 0xd2:
+ exception = decode_0xd2(env);
+ break;
+ case 0xd3:
+ exception = decode_0xd3(env);
+ break;
+ case 0xf6:
+ exception = decode_0xf6(env);
+ break;
+ case 0xf7:
+ exception = decode_0xf7(env);
+ break;
+ case 0xfe:
+ exception = decode_0xfe(env);
+ break;
+ case 0xff:
+ exception = decode_0xff(env);
+ break;
+ default:
+ env->regs.eip--;
+ env->cur_ip--;
+ return InvalidOpcode;
+ }
+ return exception;
+}
+
+BiosEmuExceptions emu_run_instruction(BiosEmuEnvironment *env) {
+ BiosEmuPrefixes prefix;
+ env->default_ss = &env->regs.ds;
+ env->flags.operand_size = env->flags.default_operand_size;
+ env->flags.address_size = env->flags.default_address_size;
+ env->flags.repeat = 0;
+ int flag = 1;
+ while (flag) {
+ prefix = *(BiosEmuPrefixes *)env->cur_ip;
+ env->cur_ip++;
+ env->regs.eip++;
+ switch ((uint8_t)prefix) {
+ case PREFIX_LOCK:
+ break;
+ case PREFIX_REPNE_REPNZ_BND:
+ env->flags.repeat = 1;
+ env->flags.rep_e_ne = 0;
+ break;
+ case PREFIX_REP_REPE_REPZ:
+ env->flags.repeat = 1;
+ env->flags.rep_e_ne = 1;
+ break;
+ case PREFIX_CS_OVERRIDE_BRANCH_NOT_TAKEN:
+ env->default_ss = &env->regs.cs;
+ break;
+ case PREFIX_SS_OVERRIDE:
+ env->default_ss = &env->regs.ss;
+ break;
+ case PREFIX_DS_OVERRIDE_BRANCH_TAKEN:
+ env->default_ss = &env->regs.ds;
+ break;
+ case PREFIX_ES_OVERRIDE:
+ env->default_ss = &env->regs.es;
+ break;
+ case PREFIX_FS_OVERRIDE:
+ env->default_ss = &env->regs.fs;
+ break;
+ case PREFIX_GS_OVERRIDE:
+ env->default_ss = &env->regs.gs;
+ break;
+ case PREFIX_OPERAND_SIZE_OVERRIDE:
+ env->flags.operand_size ^= 1;
+ break;
+ case PREFIX_ADDRSIZE_OVERRIDE:
+ env->flags.address_size ^= 1;
+ break;
+ default:
+ env->regs.eip--;
+ env->cur_ip--;
+ flag = 0;
+ break;
+ }
+ }
+ return decode_one_byte_opcode(env);
+}
+
+BiosEmuExceptions emu_run(BiosEmuEnvironment *env) {
+ BiosEmuExceptions exception = NoException;
+
+ while (exception == NoException) {
+ exception = emu_run_instruction(env);
+ if (exception != NoException) { break; }
+ }
+
+ return exception;
+}
diff --git a/src/arch/x86/bios_emu/includes/alu.h b/src/arch/x86/bios_emu/includes/alu.h
new file mode 100644
index 0000000..7afeec4
--- /dev/null
+++ b/src/arch/x86/bios_emu/includes/alu.h
@@ -0,0 +1,126 @@
+#ifndef _BIOS_EMU_ALU_H
+#define _BIOS_EMU_ALU_H
+
+#include
+#include
+
+typedef enum {
+ CALC_ADD = 0,
+ CALC_ADC,
+ CALC_AND,
+ CALC_XOR,
+ CALC_OR,
+ CALC_SUB,
+ CALC_SBB,
+ CALC_CMP,
+ CALC_TEST,
+} CalcIndex;
+
+typedef void (*Calc8)(BiosEmuEnvironment *env, uint8_t *dst, uint8_t src);
+typedef void (*Calc16)(BiosEmuEnvironment *env, uint16_t *dst, uint16_t src);
+typedef void (*Calc32)(BiosEmuEnvironment *env, uint32_t *dst, uint32_t src);
+
+void calc_a_imm8(BiosEmuEnvironment *env, CalcIndex index);
+void calc_a_imm(BiosEmuEnvironment *env, CalcIndex index);
+void calc_rm_imm_8(BiosEmuEnvironment *env, CalcIndex index);
+void calc_rm_imm(BiosEmuEnvironment *env, CalcIndex index);
+void calc_rm_imm8(BiosEmuEnvironment *env, CalcIndex index);
+void calc_rm_r_8(BiosEmuEnvironment *env, CalcIndex index);
+void calc_rm_r(BiosEmuEnvironment *env, CalcIndex index);
+void calc_r_rm_8(BiosEmuEnvironment *env, CalcIndex index);
+void calc_r_rm(BiosEmuEnvironment *env, CalcIndex index);
+
+#define ALU_CASE(name) \
+ case OP_##name##_imm8: \
+ calc_a_imm8(env, CALC_##name); \
+ break; \
+ case OP_##name##_imm: \
+ calc_a_imm(env, CALC_##name); \
+ break; \
+ case OP_##name##_rm_r_8: \
+ calc_rm_r_8(env, CALC_##name); \
+ break; \
+ case OP_##name##_rm_r: \
+ calc_rm_r(env, CALC_##name); \
+ break; \
+ case OP_##name##_r_rm_8: \
+ calc_r_rm_8(env, CALC_##name); \
+ break; \
+ case OP_##name##_r_rm: \
+ calc_r_rm(env, CALC_##name); \
+ break;
+
+void decode_inc_r(BiosEmuEnvironment *env, uint8_t opcode);
+void decode_dec_r(BiosEmuEnvironment *env, uint8_t opcode);
+void decode_inc_rm(BiosEmuEnvironment *env);
+void decode_dec_rm(BiosEmuEnvironment *env);
+void decode_inc_rm8(BiosEmuEnvironment *env);
+void decode_dec_rm8(BiosEmuEnvironment *env);
+
+void decode_aaa(BiosEmuEnvironment *env);
+void decode_aad(BiosEmuEnvironment *env);
+void decode_aam(BiosEmuEnvironment *env);
+void decode_aas(BiosEmuEnvironment *env);
+void decode_daa(BiosEmuEnvironment *env);
+void decode_das(BiosEmuEnvironment *env);
+
+BiosEmuExceptions div_8(BiosEmuEnvironment *env, uint8_t value);
+BiosEmuExceptions div_16(BiosEmuEnvironment *env, uint16_t value);
+BiosEmuExceptions div_32(BiosEmuEnvironment *env, uint32_t value);
+BiosEmuExceptions idiv_8(BiosEmuEnvironment *env, uint8_t value);
+BiosEmuExceptions idiv_16(BiosEmuEnvironment *env, uint16_t value);
+BiosEmuExceptions idiv_32(BiosEmuEnvironment *env, uint32_t value);
+
+void mul_8(BiosEmuEnvironment *env, uint8_t value);
+void mul_16(BiosEmuEnvironment *env, uint16_t value);
+void mul_32(BiosEmuEnvironment *env, uint32_t value);
+void imul_8(BiosEmuEnvironment *env, uint8_t value);
+void imul_16(
+ BiosEmuEnvironment *env, uint16_t *dst_hi, uint16_t *dst_lo, uint16_t src1,
+ uint16_t src2);
+void imul_32(
+ BiosEmuEnvironment *env, uint32_t *dst_hi, uint32_t *dst_lo, uint32_t src1,
+ uint32_t src2);
+
+void decode_imul_r_rm_imm8(BiosEmuEnvironment *env);
+void decode_imul_r_rm_imm16(BiosEmuEnvironment *env);
+void decode_imul_r_rm(BiosEmuEnvironment *env);
+
+void neg_8(BiosEmuEnvironment *env, uint8_t *value);
+void neg_16(BiosEmuEnvironment *env, uint16_t *value);
+void neg_32(BiosEmuEnvironment *env, uint32_t *value);
+
+void rcl_8(BiosEmuEnvironment *env, uint8_t *value, uint8_t count);
+void rcl_16(BiosEmuEnvironment *env, uint16_t *value, uint8_t count);
+void rcl_32(BiosEmuEnvironment *env, uint32_t *value, uint8_t count);
+void rcr_8(BiosEmuEnvironment *env, uint8_t *value, uint8_t count);
+void rcr_16(BiosEmuEnvironment *env, uint16_t *value, uint8_t count);
+void rcr_32(BiosEmuEnvironment *env, uint32_t *value, uint8_t count);
+void rol_8(BiosEmuEnvironment *env, uint8_t *value, uint8_t count);
+void rol_16(BiosEmuEnvironment *env, uint16_t *value, uint8_t count);
+void rol_32(BiosEmuEnvironment *env, uint32_t *value, uint8_t count);
+void ror_8(BiosEmuEnvironment *env, uint8_t *value, uint8_t count);
+void ror_16(BiosEmuEnvironment *env, uint16_t *value, uint8_t count);
+void ror_32(BiosEmuEnvironment *env, uint32_t *value, uint8_t count);
+
+void shl_sal_8(BiosEmuEnvironment *env, uint8_t *value, uint8_t count);
+void shl_sal_16(BiosEmuEnvironment *env, uint16_t *value, uint8_t count);
+void shl_sal_32(BiosEmuEnvironment *env, uint32_t *value, uint8_t count);
+void shr_8(BiosEmuEnvironment *env, uint8_t *value, uint8_t count);
+void shr_16(BiosEmuEnvironment *env, uint16_t *value, uint8_t count);
+void shr_32(BiosEmuEnvironment *env, uint32_t *value, uint8_t count);
+void sar_8(BiosEmuEnvironment *env, uint8_t *value, uint8_t count);
+void sar_16(BiosEmuEnvironment *env, uint16_t *value, uint8_t count);
+void sar_32(BiosEmuEnvironment *env, uint32_t *value, uint8_t count);
+
+void cmps_8(
+ BiosEmuEnvironment *env, void *dst, int delta_dst, void *src, int delta_src,
+ int repeat_times);
+void cmps_16(
+ BiosEmuEnvironment *env, void *dst, int delta_dst, void *src, int delta_src,
+ int repeat_times);
+void cmps_32(
+ BiosEmuEnvironment *env, void *dst, int delta_dst, void *src, int delta_src,
+ int repeat_times);
+
+#endif
\ No newline at end of file
diff --git a/src/arch/x86/bios_emu/includes/conditions.h b/src/arch/x86/bios_emu/includes/conditions.h
new file mode 100644
index 0000000..b4949c1
--- /dev/null
+++ b/src/arch/x86/bios_emu/includes/conditions.h
@@ -0,0 +1,8 @@
+#ifndef _BIOS_EMU_CONDITIONS_H
+#define _BIOS_EMU_CONDITIONS_H
+
+#include
+
+extern int (*condition_table[16])(BiosEmuEnvironment *env);
+
+#endif
\ No newline at end of file
diff --git a/src/arch/x86/bios_emu/includes/decode.h b/src/arch/x86/bios_emu/includes/decode.h
new file mode 100644
index 0000000..06959e2
--- /dev/null
+++ b/src/arch/x86/bios_emu/includes/decode.h
@@ -0,0 +1,90 @@
+#ifndef _BIOS_EMU_DECODE_H
+#define _BIOS_EMU_DECODE_H
+
+#include
+#include
+#define PLUS_RB_REG(env, reg) (env)->reg_lut_r8[(reg) & 0x07]
+
+#define PLUS_RW_REG(env, reg) (env)->reg_lut_r16[(reg) & 0x07]
+
+#define PLUS_RD_REG(env, reg) (env)->reg_lut_r32[(reg) & 0x07]
+
+typedef enum OperandNum {
+ OPNUM_0 = 0,
+ OPNUM_1,
+ OPNUM_2,
+ OPNUM_3,
+} OperandNum;
+
+typedef enum OperandDataType {
+ OPDT_Byte,
+ OPDT_Word,
+ OPDT_Dword,
+ OPDT_Qword,
+} OperandDataType;
+
+#define GET_REG_ADDR(env, reg) \
+ ({ \
+ void *addr; \
+ if (env->flags.operand_size == 0) { \
+ addr = &env->regs.reg; \
+ } else { \
+ addr = &env->regs.e##reg; \
+ } \
+ addr; \
+ })
+
+#define DEF_OP1(type) \
+ typedef BiosEmuExceptions (*Op1_##type)( \
+ BiosEmuEnvironment * env, uint##type##_t * value);
+
+#define DEF_OP2(type1, type2) \
+ typedef BiosEmuExceptions (*Op2_##type1##_##type2)( \
+ BiosEmuEnvironment * env, uint##type1##_t * value1, \
+ uint##type2##_t * value2);
+
+#define DEF_OP3_1(type, data_type_1, data_type2, data_type) \
+ typedef BiosEmuExceptions (*Op3_##type##data_type)( \
+ BiosEmuEnvironment * env, data_type_1 value1, data_type2 value2, \
+ uint##data_type##_t value3);
+
+#define DEF_OP3_2(type, data_type_1, data_type) \
+ DEF_OP3_1(type##data_type##_, data_type_1, uint##data_type##_t, 8); \
+ DEF_OP3_1(type##data_type##_, data_type_1, uint##data_type##_t, 16); \
+ DEF_OP3_1(type##data_type##_, data_type_1, uint##data_type##_t, 32);
+
+#define DEF_OP3_3(data_type) \
+ DEF_OP3_2(data_type##_, uint##data_type##_t *, 8); \
+ DEF_OP3_2(data_type##_, uint##data_type##_t *, 16); \
+ DEF_OP3_2(data_type##_, uint##data_type##_t *, 32);
+
+typedef BiosEmuExceptions (*Op0)(BiosEmuEnvironment *env);
+DEF_OP1(8);
+DEF_OP1(16);
+DEF_OP1(32);
+DEF_OP2(8, 8);
+DEF_OP2(8, 16);
+DEF_OP2(8, 32);
+DEF_OP2(16, 8);
+DEF_OP2(16, 16);
+DEF_OP2(16, 32);
+DEF_OP2(32, 8);
+DEF_OP2(32, 16);
+DEF_OP2(32, 32);
+DEF_OP3_3(8);
+DEF_OP3_3(16);
+DEF_OP3_3(32);
+
+BiosEmuExceptions decode_rm8_r8(BiosEmuEnvironment *env, Op2_8_8 func);
+BiosEmuExceptions decode_rm_r(
+ BiosEmuEnvironment *env, Op2_16_16 func16, Op2_32_32 func32);
+BiosEmuExceptions decode_rm_imm8(
+ BiosEmuEnvironment *env, Op2_16_16 func16, Op2_32_32 func32);
+BiosEmuExceptions decode_r_rm(
+ BiosEmuEnvironment *env, Op2_16_16 func16, Op2_32_32 func32);
+BiosEmuExceptions decode_rm_r_imm8(
+ BiosEmuEnvironment *env, Op3_16_16_8 func16, Op3_32_32_8 func32);
+BiosEmuExceptions decode_rm_r_cl(
+ BiosEmuEnvironment *env, Op3_16_16_8 func16, Op3_32_32_8 func32);
+
+#endif
\ No newline at end of file
diff --git a/src/arch/x86/bios_emu/includes/flags.h b/src/arch/x86/bios_emu/includes/flags.h
new file mode 100644
index 0000000..92296f2
--- /dev/null
+++ b/src/arch/x86/bios_emu/includes/flags.h
@@ -0,0 +1,37 @@
+#ifndef _BIOS_EMU_FLAGS_H
+#define _BIOS_EMU_FLAGS_H
+
+#include
+
+#define CarryFlagBit 0
+#define ParityFlagBit 2
+#define AuxiliaryCarryFlagBit 4
+#define ZeroFlagBit 6
+#define SignFlagBit 7
+#define TrapFlagBit 8
+#define InterruptEnableFlagBit 9
+#define DirectionFlagBit 10
+#define OverflowFlagBit 11
+#define IOPLFlagBit 12
+#define NestedTaskFlagBit 14
+
+#define ResumeFlagBit 16
+#define VirtualModeFlagBit 17
+#define AlignmentCheckFlagBit 18
+#define VirtualInterruptFlagBit 19
+#define VirtualInterruptPendingFlagBit 20
+#define IDFlagBit 21
+
+#define SET_FLAG(x, bit) \
+ env->regs.flags = \
+ (x) ? env->regs.flags | BIT(bit) : env->regs.flags & ~BIT(bit)
+
+#define SET_CARRY_FLAG(x) SET_FLAG(x, CarryFlagBit)
+#define SET_OVERFLOW_FLAG(x) SET_FLAG(x, OverflowFlagBit)
+#define SET_SIGN_FLAG(x) SET_FLAG(x, SignFlagBit)
+
+#define SIGN_FLAG8(x) SET_SIGN_FLAG(x >> 7)
+#define SIGN_FLAG16(x) SET_SIGN_FLAG(x >> 15)
+#define SIGN_FLAG32(x) SET_SIGN_FLAG(x >> 31)
+
+#endif
\ No newline at end of file
diff --git a/src/arch/x86/bios_emu/includes/instructions_1.h b/src/arch/x86/bios_emu/includes/instructions_1.h
new file mode 100644
index 0000000..163f9cb
--- /dev/null
+++ b/src/arch/x86/bios_emu/includes/instructions_1.h
@@ -0,0 +1,282 @@
+#ifndef _BIOS_EMU_INSTRUCTIONS_1_H
+#define _BIOS_EMU_INSTRUCTIONS_1_H
+
+typedef enum OneByteOpcodes {
+ // One Byte Opcode Instructions A-L
+ OP_AAA = 0x37,
+ OP_AAD = 0xD5,
+ OP_AAM = 0xD4,
+ OP_AAS = 0x3F,
+
+ OP_ADC_imm8 = 0x14,
+ OP_ADC_imm = 0x15,
+ OP_ADC_rm_r_8 = 0x10,
+ OP_ADC_rm_r = 0x11,
+ OP_ADC_r_rm_8 = 0x12,
+ OP_ADC_r_rm = 0x13,
+
+ OP_ADC_ADD_rm_imm_8 = 0x80,
+ OP_ADC_ADD_rm_imm = 0x81,
+ OP_ADC_ADD_rm_imm8 = 0x83,
+
+ OP_ADD_imm8 = 0x04,
+ OP_ADD_imm = 0x05,
+ OP_ADD_rm_r_8 = 0x00,
+ OP_ADD_rm_r = 0x01,
+ OP_ADD_r_rm_8 = 0x02,
+ OP_ADD_r_rm = 0x03,
+
+ OP_AND_imm8 = 0x24,
+ OP_AND_imm = 0x25,
+ OP_AND_rm_r_8 = 0x20,
+ OP_AND_rm_r = 0x21,
+ OP_AND_r_rm_8 = 0x22,
+ OP_AND_r_rm = 0x23,
+
+ OP_BOUND = 0x62,
+ OP_CALL = 0xE8,
+ OP_CALL_ptr = 0x9A,
+ OP_CBW_CWDE = 0x98,
+ OP_CLC = 0xF8,
+ OP_CLD = 0xFC,
+ OP_CLI = 0xFA,
+ OP_CMC = 0xF5,
+
+ OP_CMP_imm8 = 0x3c,
+ OP_CMP_imm = 0x3d,
+ OP_CMP_rm_r_8 = 0x38,
+ OP_CMP_rm_r = 0x39,
+ OP_CMP_r_rm_8 = 0x3A,
+ OP_CMP_r_rm = 0x3B,
+
+ OP_CMPS8 = 0xA6,
+ OP_CMPS = 0xA7,
+ OP_CWD_CDQ = 0x99,
+ OP_DAA = 0x27,
+ OP_DAS = 0x2F,
+
+ OP_DEC8 = 0xFE,
+ OP_DEC_rm = 0xFF,
+ OP_DEC = 0x48,
+
+ OP_DIV8 = 0xF6,
+ OP_DIV = 0xF6,
+
+ OP_ENTER = 0xC8,
+ OP_HLT = 0xF4,
+
+ OP_IDIV8 = 0xF6,
+ OP_IDIV = 0xF7,
+
+ OP_IMUL8 = 0xF6,
+ OP_IMUL = 0xF7,
+ OP_IMUL_imm8 = 0x6B,
+ OP_IMUL_imm16 = 0x69,
+
+ OP_IN8 = 0xE4,
+ OP_IN = 0xE5,
+ OP_IN8_dx = 0xEC,
+ OP_IN_dx = 0xED,
+
+ OP_INC8 = 0xFE,
+ OP_INC_rm16 = 0xFF,
+ OP_INC_rm32 = 0xFF,
+ OP_INC = 0x40,
+
+ OP_INS8 = 0x6C,
+ OP_INS = 0x6D,
+
+ OP_INT3 = 0xCC,
+ OP_INT = 0xCD,
+ OP_INTO = 0xCE,
+ OP_INT1 = 0xF1,
+
+ OP_IRET_IRETD = 0xCF,
+
+ OP_JCXZ_JECXZ_JRCXZ = 0xE3,
+
+ OP_JE_JZ_8 = 0x74,
+ OP_JG_JNLE_8 = 0x7F,
+ OP_JGE_JNL_8 = 0x7D,
+ OP_JL_JNGE_8 = 0x7C,
+ OP_JLE_JNG_8 = 0x7E,
+ OP_JBE_JNA_8 = 0x76,
+ OP_JB_JC_JNAE_8 = 0x72,
+ OP_JAE_JNB_JNC_8 = 0x73,
+ OP_JA_JNBE_8 = 0x77,
+ OP_JNE_JNZ_8 = 0x75,
+ OP_JNO_8 = 0x71,
+ OP_JNP_JPO_8 = 0x7B,
+ OP_JNS_8 = 0x79,
+ OP_JO_8 = 0x70,
+ OP_JP_JPE_8 = 0x7A,
+ OP_JS_8 = 0x78,
+
+ OP_JMP8 = 0xEB,
+ OP_JMP = 0xE9,
+ OP_JMP_rm = 0xFF,
+
+ OP_LongJMP = 0xEA,
+ OP_LongJMPm = 0xFF,
+
+ OP_LAHF = 0x9F,
+ OP_LDS = 0xC5,
+ OP_LES = 0xC4,
+ OP_LEA = 0x8D,
+ OP_LEAVE = 0xC9,
+ OP_LODS8 = 0xAC,
+ OP_LODS = 0xAD,
+
+ OP_LOOP = 0xE2,
+ OP_LOOPE = 0xE1,
+ OP_LOOPNE = 0xE0,
+
+ // One Byte Opcode Instructions M-U
+
+ OP_MOV_rm_r8 = 0x88,
+ OP_MOV_rm_r = 0x89,
+ OP_MOV_r_rm8 = 0x8A,
+ OP_MOV_r_rm = 0x8B,
+
+ OP_MOV_rm_sreg = 0x8C,
+ OP_MOV_sreg_rm = 0x8E,
+
+ OP_MOV_a_moffs8 = 0xA0,
+ OP_MOV_a_moffs = 0xA1,
+ OP_MOV_moffs8_a = 0xA2,
+ OP_MOV_moffs_a = 0xA3,
+
+ OP_MOV_r_imm8 = 0xB0,
+ OP_MOV_r_imm = 0xB8,
+ OP_MOV_rm_imm8 = 0xC6,
+ OP_MOV_rm_imm = 0xC7,
+
+ OP_MOVS8 = 0xA4,
+ OP_MOVS = 0xA5,
+
+ OP_MUL8 = 0xF6,
+ OP_MUL = 0xF7,
+
+ OP_NEG8 = 0xF6,
+ OP_NEG = 0xF7,
+ OP_NOP = 0x90,
+ OP_NOT8 = 0xF6,
+ OP_NOT = 0xF7,
+
+ OP_OR_rm_imm_8 = 0x80,
+ OP_OR_rm_imm = 0x81,
+ OP_OR_rm_imm8 = 0x83,
+
+ OP_OR_imm8 = 0x0C,
+ OP_OR_imm = 0x0D,
+ OP_OR_rm_r_8 = 0x08,
+ OP_OR_rm_r = 0x09,
+ OP_OR_r_rm_8 = 0x0A,
+ OP_OR_r_rm = 0x0B,
+
+ OP_OUT8 = 0xE6,
+ OP_OUT = 0xE7,
+ OP_OUT8_dx = 0xEE,
+ OP_OUT_dx = 0xEF,
+
+ OP_OUTS8 = 0x6E,
+ OP_OUTS = 0x6F,
+
+ OP_POP_rm = 0x8F,
+ OP_POP_r = 0x58,
+ OP_POP_DS = 0x1F,
+ OP_POP_ES = 0x07,
+ OP_POP_SS = 0x17,
+
+ OP_POPA_POPAD = 0x61,
+ OP_POPF_POPFD = 0x9D,
+
+ OP_PUSH_rm = 0xFF,
+ OP_PUSH_r = 0x50,
+ OP_PUSH_imm8 = 0x6A,
+ OP_PUSH_imm = 0x68,
+ OP_PUSH_CS = 0x0E,
+ OP_PUSH_SS = 0x16,
+ OP_PUSH_DS = 0x1E,
+ OP_PUSH_ES = 0x06,
+
+ OP_PUSHA_PUSHAD = 0x60,
+ OP_PUSHF_PUSHFD = 0x9C,
+
+ OP_RET = 0xC3,
+ OP_LongRET = 0xCB,
+ OP_RET_imm16 = 0xC2,
+ OP_LongRET_imm16 = 0xCA,
+
+ OP_SAHF = 0x9E,
+
+ OP_SAL_SAR_SHL_SHR_8_1 = 0xD0,
+ OP_SAL_SAR_SHL_SHR_8_cl = 0xD2,
+ OP_SAL_SAR_SHL_SHR_8_imm8 = 0xC0,
+
+ OP_SAL_SAR_SHL_SHR_1 = 0xD1,
+ OP_SAL_SAR_SHL_SHR_cl = 0xD3,
+ OP_SAL_SAR_SHL_SHR_imm8 = 0xC1,
+
+ OP_SBB_rm_imm_8 = 0x80,
+ OP_SBB_rm_imm = 0x81,
+ OP_SBB_rm_imm8 = 0x83,
+
+ OP_SBB_imm8 = 0x1C,
+ OP_SBB_imm = 0x1D,
+ OP_SBB_rm_r_8 = 0x18,
+ OP_SBB_rm_r = 0x19,
+ OP_SBB_r_rm_8 = 0x1A,
+ OP_SBB_r_rm = 0x1B,
+
+ OP_SCAS8 = 0xAE,
+ OP_SCAS = 0xAF,
+ OP_STC = 0xF9,
+ OP_STD = 0xFD,
+ OP_STI = 0xFB,
+ OP_STOS8 = 0xAA,
+ OP_STOS = 0xAB,
+
+ OP_SUB_rm_imm_8 = 0x80,
+ OP_SUB_rm_imm = 0x81,
+ OP_SUB_rm_imm8 = 0x83,
+
+ OP_SUB_imm8 = 0x2C,
+ OP_SUB_imm = 0x2D,
+ OP_SUB_rm_r_8 = 0x28,
+ OP_SUB_rm_r = 0x29,
+ OP_SUB_r_rm_8 = 0x2A,
+ OP_SUB_r_rm = 0x2B,
+
+ OP_TEST_imm8 = 0xA8,
+ OP_TEST_imm = 0xA9,
+ OP_TEST_rm_imm8 = 0xF6,
+ OP_TEST_rm_imm = 0xF7,
+ OP_TEST_rm_r_8 = 0x84,
+ OP_TEST_rm_r = 0x85,
+
+ // One Byte Opcode Instructions W-Z
+
+ OP_WAIT_FWAIT = 0x9B,
+
+ OP_XCHG_r = 0x90,
+ OP_XCHG_8 = 0x86,
+ OP_XCHG = 0x87,
+
+ OP_XLAT = 0xD7,
+
+ OP_XOR_rm_imm_8 = 0x80,
+ OP_XOR_rm_imm = 0x81,
+ OP_XOR_rm_imm8 = 0x83,
+
+ OP_XOR_imm8 = 0x34,
+ OP_XOR_imm = 0x35,
+ OP_XOR_rm_r_8 = 0x30,
+ OP_XOR_rm_r = 0x31,
+ OP_XOR_r_rm_8 = 0x32,
+ OP_XOR_r_rm = 0x33,
+
+ OP_TWO_BYTES = 0x0F,
+} OneByteOpcodes;
+
+#endif
\ No newline at end of file
diff --git a/src/arch/x86/bios_emu/includes/instructions_2.h b/src/arch/x86/bios_emu/includes/instructions_2.h
new file mode 100644
index 0000000..1fe599e
--- /dev/null
+++ b/src/arch/x86/bios_emu/includes/instructions_2.h
@@ -0,0 +1,81 @@
+#ifndef _BIOS_EMU_INSTRUCTIONS_2_H
+#define _BIOS_EMU_INSTRUCTIONS_2_H
+
+typedef enum TwoBytesOpcodes {
+ OP_LAR = 0x02,
+ OP_LSL = 0x03,
+ OP_SYSCALL = 0x05,
+ OP_CLTS = 0x06,
+ OP_SYSRET = 0x07,
+ OP_INVD = 0x08,
+ OP_WBINVD = 0x09,
+
+ OP_BNDCL_BNDCU_BNDLDX_BNDMOV = 0x1A,
+ OP_BNDCN_BNDMK_BNDSTX_BNDMOV = 0x1B,
+
+ OP_NOP_rm = 0x1F,
+
+ OP_MOV_r_cr = 0x20,
+ OP_MOV_cr_r = 0x22,
+ OP_MOV_r_dr = 0x21,
+ OP_MOV_dr_r = 0x23,
+
+ OP_WRMSR = 0x30,
+ OP_RDTSC = 0x31,
+ OP_RDMSR = 0x32,
+ OP_RDPMC = 0x33,
+ OP_SYSENTER = 0x34,
+ OP_SYSEXIT = 0x35,
+ OP_GETSEC = 0x36,
+
+ OP_CMOVcc = 0x40,
+
+ OP_MOVD_mm_rm32 = 0x6E,
+ OP_MOVD_rm32_mm = 0x7E,
+
+ OP_Jcc = 0x80,
+
+ OP_SETcc = 0x90,
+
+ OP_POP_FS = 0xA1,
+ OP_POP_GS = 0xA9,
+
+ OP_PUSH_FS = 0xA0,
+ OP_PUSH_GS = 0xA8,
+
+ OP_CPUID = 0xA2,
+ OP_BT = 0xA3,
+ OP_SHLD_imm8 = 0xA4,
+ OP_SHLD_cl = 0xA5,
+ OP_RSM = 0xAA,
+ OP_BTS = 0xAB,
+ OP_SHRD_imm8 = 0xAC,
+ OP_SHRD_cl = 0xAD,
+
+ OP_IMUL_r_rm = 0xAF,
+
+ OP_CMPXCHG8 = 0xB0,
+ OP_CMPXCHG = 0xB1,
+
+ OP_LSS = 0xB2,
+ OP_BTR = 0xB3,
+ OP_LFS = 0xB4,
+ OP_LGS = 0xB5,
+
+ OP_MOVZX_r_rm8 = 0xB6,
+ OP_MOVZX_r_rm16 = 0xB7,
+ OP_MOVSX_r_rm8 = 0xBE,
+ OP_MOVSX_r_rm16 = 0xBF,
+
+ OP_POPCNT = 0xB8,
+
+ OP_BTC = 0xBB,
+ OP_BSF_TZCNT = 0xBC,
+ OP_BSR_LZCNT = 0xBD,
+ OP_BSWAP = 0xC8,
+
+ OP_XADD_rm_r_8 = 0xC0,
+ OP_XADD_rm_r = 0xC1,
+} TwoBytesOpcodes;
+
+#endif
\ No newline at end of file
diff --git a/src/arch/x86/bios_emu/includes/mod_rm.h b/src/arch/x86/bios_emu/includes/mod_rm.h
new file mode 100644
index 0000000..dcbb7e0
--- /dev/null
+++ b/src/arch/x86/bios_emu/includes/mod_rm.h
@@ -0,0 +1,180 @@
+#ifndef _BIOS_EMU_MOD_RM_H
+#define _BIOS_EMU_MOD_RM_H
+
+#include "segment.h"
+#include
+#include
+
+// MODRM REG字段
+#define MODRM_REG(x) ((x) << 3)
+
+#define REG_AL (0b000)
+#define REG_CL (0b001)
+#define REG_DL (0b010)
+#define REG_BL (0b011)
+#define REG_AH (0b100)
+#define REG_CH (0b101)
+#define REG_DH (0b110)
+#define REG_BH (0b111)
+
+#define REG_AX REG_AL
+#define REG_CX REG_CL
+#define REG_DX REG_DL
+#define REG_BX REG_BL
+#define REG_SP REG_AH
+#define REG_BP REG_CH
+#define REG_SI REG_DH
+#define REG_DI REG_BH
+
+#define REG_EAX REG_AX
+#define REG_ECX REG_CX
+#define REG_EDX REG_DX
+#define REG_EBX REG_BX
+#define REG_ESP REG_SP
+#define REG_EBP REG_BP
+#define REG_ESI REG_SI
+#define REG_EDI REG_DI
+
+// MODRM MOD字段
+#define MOD_BASE 0b00
+#define MOD_BASE_DISP8 0b01
+#define MOD_BASE_DISP16 0b10
+#define MOD_BASE_DISP32 MOD_BASE_DISP16
+#define MOD_REG 0b11
+
+// MODRM RM字段
+// 16位
+// 1.base mod
+#define RM_BX_SI (0b000)
+#define RM_BX_DI (0b001)
+#define RM_BP_SI (0b010)
+#define RM_BP_DI (0b011)
+#define RM_SI (0b100)
+#define RM_DI (0b101)
+#define RM_BP (0b110)
+#define RM_BX (0b111)
+
+// 4.reg mod
+#define RM_REG_AL (0b000)
+#define RM_REG_CL (0b001)
+#define RM_REG_DL (0b010)
+#define RM_REG_BL (0b011)
+#define RM_REG_AH (0b100)
+#define RM_REG_CH (0b101)
+#define RM_REG_DH (0b110)
+#define RM_REG_BH (0b111)
+
+#define RM_REG_AX RM_REG_AL
+#define RM_REG_CX RM_REG_CL
+#define RM_REG_DX RM_REG_DL
+#define RM_REG_BX RM_REG_BL
+#define RM_REG_SP RM_REG_AH
+#define RM_REG_BP RM_REG_CH
+#define RM_REG_SI RM_REG_DH
+#define RM_REG_DI RM_REG_BH
+
+#define RM_REG_EAX RM_REG_AX
+#define RM_REG_ECX RM_REG_CX
+#define RM_REG_EDX RM_REG_DX
+#define RM_REG_EBX RM_REG_BX
+#define RM_REG_ESP RM_REG_SP
+#define RM_REG_EBP RM_REG_BP
+#define RM_REG_ESI RM_REG_SI
+#define RM_REG_EDI RM_REG_DI
+
+// 32位
+// 1.base mod
+#define RM_EAX (0b000)
+#define RM_ECX (0b001)
+#define RM_EDX (0b010)
+#define RM_EBX (0b011)
+#define RM_EBP (0b101)
+#define RM_ESI (0b110)
+#define RM_EDI (0b111)
+
+#define RM_SREG(env, reg) \
+ ({ \
+ void *var; \
+ switch (reg & 0x07) { \
+ case 0: \
+ var = &env->regs.es; \
+ break; \
+ case 1: \
+ var = &env->regs.cs; \
+ break; \
+ case 2: \
+ var = &env->regs.ss; \
+ break; \
+ case 3: \
+ var = &env->regs.ds; \
+ break; \
+ case 4: \
+ var = &env->regs.fs; \
+ break; \
+ case 5: \
+ var = &env->regs.gs; \
+ break; \
+ } \
+ var; \
+ })
+
+#define RM_ADDR(env, modrm) \
+ ({ \
+ void *p; \
+ uint8_t mod = modrm >> 6; \
+ if (mod == 0b11) { \
+ if (env->flags.operand_size == 0) { \
+ p = env->reg_lut_r16[modrm & 0b111]; \
+ } else { \
+ p = env->reg_lut_r32[modrm & 0b111]; \
+ } \
+ } else { \
+ uint32_t segment_base = get_segment_base(env, *env->default_ss); \
+ if (env->flags.address_size == 0) { \
+ p = (void *)(segment_base + decode_rm_address_16(env, modrm)); \
+ } else { \
+ p = (void *)(segment_base + decode_rm_address_32(env, modrm)); \
+ } \
+ } \
+ p; \
+ })
+
+#define RM_ADDR16(env, modrm) \
+ ({ \
+ void *p; \
+ uint8_t mod = modrm >> 6; \
+ if (mod == 0b11) { \
+ p = env->reg_lut_r16[modrm & 0b111]; \
+ } else { \
+ uint32_t segment_base = get_segment_base(env, *env->default_ss); \
+ if (env->flags.address_size == 0) { \
+ p = (void *)(segment_base + decode_rm_address_16(env, modrm)); \
+ } else { \
+ p = (void *)(segment_base + decode_rm_address_32(env, modrm)); \
+ } \
+ } \
+ p; \
+ })
+
+#define RM_ADDR32(env, modrm) \
+ ({ \
+ void *p; \
+ uint8_t mod = modrm >> 6; \
+ if (mod == 0b11) { \
+ p = env->reg_lut_r32[modrm & 0b111]; \
+ } else { \
+ uint32_t segment_base = get_segment_base(env, *env->default_ss); \
+ if (env->flags.address_size == 0) { \
+ p = (void *)(segment_base + decode_rm_address_16(env, modrm)); \
+ } else { \
+ p = (void *)(segment_base + decode_rm_address_32(env, modrm)); \
+ } \
+ } \
+ p; \
+ })
+
+size_t decode_rm_address_16(BiosEmuEnvironment *env, uint8_t modrm);
+size_t decode_rm_address_32(BiosEmuEnvironment *env, uint8_t modrm);
+size_t decode_rm_address(BiosEmuEnvironment *env, uint8_t modrm);
+
+#endif
\ No newline at end of file
diff --git a/src/arch/x86/bios_emu/includes/operations.h b/src/arch/x86/bios_emu/includes/operations.h
new file mode 100644
index 0000000..0e0668d
--- /dev/null
+++ b/src/arch/x86/bios_emu/includes/operations.h
@@ -0,0 +1,217 @@
+#ifndef _BIOS_EMU_OPERATIONS_H
+#define _BIOS_EMU_OPERATIONS_H
+
+#include "flags.h"
+#include
+#include
+#include
+
+#define CLI(env) env->regs.flags &= ~BIT(InterruptEnableFlagBit)
+#define STI(env) env->regs.flags |= BIT(InterruptEnableFlagBit)
+#define CLD(env) env->regs.flags &= ~BIT(DirectionFlagBit)
+#define STD(env) env->regs.flags |= BIT(DirectionFlagBit)
+#define CLC(env) env->regs.flags &= ~BIT(CarryFlagBit)
+#define STC(env) env->regs.flags |= BIT(CarryFlagBit)
+#define CMC(env) env->regs.flags ^= BIT(CarryFlagBit)
+
+#define LAHF(env) env->regs.ah = 0b00000010 | (env->regs.flags & 0b11010101)
+#define SAHF(env) env->regs.flags = 0b00000010 | (env->regs.ah & 0b00111110)
+
+int ptr_within_code_segment_limit(BiosEmuEnvironment *env, uint32_t address);
+
+BiosEmuExceptions decode_0x80_0x83(BiosEmuEnvironment *env, uint8_t opcode);
+BiosEmuExceptions decode_0xba(BiosEmuEnvironment *env);
+BiosEmuExceptions decode_0xf6(BiosEmuEnvironment *env);
+BiosEmuExceptions decode_0xf7(BiosEmuEnvironment *env);
+BiosEmuExceptions decode_0xfe(BiosEmuEnvironment *env);
+BiosEmuExceptions decode_0xff(BiosEmuEnvironment *env);
+
+void decode_pusha_pushad(BiosEmuEnvironment *env);
+
+BiosEmuExceptions mov_8_8(BiosEmuEnvironment *env, uint8_t *dst, uint8_t *src);
+BiosEmuExceptions mov_16_16(
+ BiosEmuEnvironment *env, uint16_t *dst, uint16_t *src);
+BiosEmuExceptions mov_32_32(
+ BiosEmuEnvironment *env, uint32_t *dst, uint32_t *src);
+void decode_mov_rm_sreg(BiosEmuEnvironment *env);
+void decode_mov_sreg_rm(BiosEmuEnvironment *env);
+void decode_mov_sreg_rm(BiosEmuEnvironment *env);
+void decode_mov_r_moffs_8(BiosEmuEnvironment *env);
+void decode_mov_r_moffs(BiosEmuEnvironment *env);
+void decode_mov_moffs_r_8(BiosEmuEnvironment *env);
+void decode_mov_moffs_r(BiosEmuEnvironment *env);
+void decode_mov_r_imm8(BiosEmuEnvironment *env, uint8_t opcode);
+void decode_mov_r_imm(BiosEmuEnvironment *env, uint8_t opcode);
+void decode_mov_rm_imm(BiosEmuEnvironment *env);
+
+void decode_movzx_r_rm8(BiosEmuEnvironment *env);
+void decode_movzx_r_rm16(BiosEmuEnvironment *env);
+void decode_movsx_r_rm8(BiosEmuEnvironment *env);
+void decode_movsx_r_rm16(BiosEmuEnvironment *env);
+
+void decode_jcc_8(BiosEmuEnvironment *env, int condition);
+void decode_jcc(BiosEmuEnvironment *env, int condition);
+void decode_jmp8(BiosEmuEnvironment *env);
+void decode_jmp_near(BiosEmuEnvironment *env, int32_t offset);
+void decode_jmp_far(BiosEmuEnvironment *env, uint16_t segment, uint32_t offset);
+void decode_jmp(BiosEmuEnvironment *env);
+void decode_long_jmp_ptr16(BiosEmuEnvironment *env);
+
+void decode_pop_rm(BiosEmuEnvironment *env);
+void decode_pop_r(BiosEmuEnvironment *env, uint8_t opcode);
+void decode_popa_popad(BiosEmuEnvironment *env);
+
+BiosEmuExceptions decode_call_near(BiosEmuEnvironment *env, uint32_t address);
+BiosEmuExceptions decode_call(BiosEmuEnvironment *env);
+BiosEmuExceptions decode_call_far(
+ BiosEmuEnvironment *env, uint16_t segment, uint32_t offset);
+BiosEmuExceptions decode_call_ptr(BiosEmuEnvironment *env);
+
+BiosEmuExceptions decode_int(BiosEmuEnvironment *env, uint8_t vector);
+BiosEmuExceptions decode_iret(BiosEmuEnvironment *env);
+
+BiosEmuExceptions decode_ret_near(BiosEmuEnvironment *env, int bytes);
+BiosEmuExceptions decode_ret_far(BiosEmuEnvironment *env, int bytes);
+BiosEmuExceptions decode_ret_imm16(BiosEmuEnvironment *env);
+BiosEmuExceptions decode_ret_far_imm16(BiosEmuEnvironment *env);
+
+void decode_in8(BiosEmuEnvironment *env, uint8_t port);
+void decode_in(BiosEmuEnvironment *env, uint16_t port);
+void decode_out8(BiosEmuEnvironment *env, uint8_t port);
+void decode_out(BiosEmuEnvironment *env, uint16_t port);
+
+BiosEmuExceptions decode_lea(BiosEmuEnvironment *env);
+
+void decode_setcc(BiosEmuEnvironment *env, int condition);
+
+BiosEmuExceptions decode_0xc0(BiosEmuEnvironment *env);
+BiosEmuExceptions decode_0xc1(BiosEmuEnvironment *env);
+BiosEmuExceptions decode_0xd0(BiosEmuEnvironment *env);
+BiosEmuExceptions decode_0xd1(BiosEmuEnvironment *env);
+BiosEmuExceptions decode_0xd2(BiosEmuEnvironment *env);
+BiosEmuExceptions decode_0xd3(BiosEmuEnvironment *env);
+
+BiosEmuExceptions xchg_8_8(
+ BiosEmuEnvironment *env, uint8_t *addr1, uint8_t *addr2);
+BiosEmuExceptions xchg_16_16(
+ BiosEmuEnvironment *env, uint16_t *addr1, uint16_t *addr2);
+BiosEmuExceptions xchg_32_32(
+ BiosEmuEnvironment *env, uint32_t *addr1, uint32_t *addr2);
+
+BiosEmuExceptions cmpxchg_8_8(
+ BiosEmuEnvironment *env, uint8_t *addr1, uint8_t *addr2);
+BiosEmuExceptions cmpxchg_16_16(
+ BiosEmuEnvironment *env, uint16_t *addr1, uint16_t *addr2);
+BiosEmuExceptions cmpxchg_32_32(
+ BiosEmuEnvironment *env, uint32_t *addr1, uint32_t *addr2);
+
+BiosEmuExceptions xadd_8_8(
+ BiosEmuEnvironment *env, uint8_t *addr1, uint8_t *addr2);
+BiosEmuExceptions xadd_16_16(
+ BiosEmuEnvironment *env, uint16_t *addr1, uint16_t *addr2);
+BiosEmuExceptions xadd_32_32(
+ BiosEmuEnvironment *env, uint32_t *addr1, uint32_t *addr2);
+
+BiosEmuExceptions lds_16_16(
+ BiosEmuEnvironment *env, uint16_t *reg, uint16_t *addr);
+BiosEmuExceptions lds_32_32(
+ BiosEmuEnvironment *env, uint32_t *reg, uint32_t *addr);
+BiosEmuExceptions lss_16_16(
+ BiosEmuEnvironment *env, uint16_t *reg, uint16_t *addr);
+BiosEmuExceptions lss_32_32(
+ BiosEmuEnvironment *env, uint32_t *reg, uint32_t *addr);
+BiosEmuExceptions les_16_16(
+ BiosEmuEnvironment *env, uint16_t *reg, uint16_t *addr);
+BiosEmuExceptions les_32_32(
+ BiosEmuEnvironment *env, uint32_t *reg, uint32_t *addr);
+BiosEmuExceptions lfs_16_16(
+ BiosEmuEnvironment *env, uint16_t *reg, uint16_t *addr);
+BiosEmuExceptions lfs_32_32(
+ BiosEmuEnvironment *env, uint32_t *reg, uint32_t *addr);
+BiosEmuExceptions lgs_16_16(
+ BiosEmuEnvironment *env, uint16_t *reg, uint16_t *addr);
+BiosEmuExceptions lgs_32_32(
+ BiosEmuEnvironment *env, uint32_t *reg, uint32_t *addr);
+
+BiosEmuExceptions shld_16_16_8(
+ BiosEmuEnvironment *env, uint16_t *dest, uint16_t reg, uint8_t count);
+BiosEmuExceptions shld_32_32_8(
+ BiosEmuEnvironment *env, uint32_t *dest, uint32_t reg, uint8_t count);
+BiosEmuExceptions shrd_16_16_8(
+ BiosEmuEnvironment *env, uint16_t *dest, uint16_t reg, uint8_t count);
+BiosEmuExceptions shrd_32_32_8(
+ BiosEmuEnvironment *env, uint32_t *dest, uint32_t reg, uint8_t count);
+
+void decode_cbw_cwde(BiosEmuEnvironment *env);
+void decode_cwd_cdq(BiosEmuEnvironment *env);
+
+BiosEmuExceptions bt_16_16(
+ BiosEmuEnvironment *env, uint16_t *addr, uint16_t *bit);
+BiosEmuExceptions bt_32_32(
+ BiosEmuEnvironment *env, uint32_t *addr, uint32_t *bit);
+BiosEmuExceptions btc_16_16(
+ BiosEmuEnvironment *env, uint16_t *addr, uint16_t *bit);
+BiosEmuExceptions btc_32_32(
+ BiosEmuEnvironment *env, uint32_t *addr, uint32_t *bit);
+BiosEmuExceptions btr_16_16(
+ BiosEmuEnvironment *env, uint16_t *addr, uint16_t *bit);
+BiosEmuExceptions btr_32_32(
+ BiosEmuEnvironment *env, uint32_t *addr, uint32_t *bit);
+BiosEmuExceptions bts_16_16(
+ BiosEmuEnvironment *env, uint16_t *addr, uint16_t *bit);
+BiosEmuExceptions bts_32_32(
+ BiosEmuEnvironment *env, uint32_t *addr, uint32_t *bit);
+
+typedef void (*OpStr)(
+ BiosEmuEnvironment *env, void *dst, int delta_dst, void *src, int delta_src,
+ int repeat_times);
+void decode_movs(BiosEmuEnvironment *env, OpStr movs_16, OpStr movs_32);
+void movs_8(
+ BiosEmuEnvironment *env, void *dst, int delta_dst, void *src, int delta_src,
+ int repeat_times);
+void movs_16(
+ BiosEmuEnvironment *env, void *dst, int delta_dst, void *src, int delta_src,
+ int repeat_times);
+void movs_32(
+ BiosEmuEnvironment *env, void *dst, int delta_dst, void *src, int delta_src,
+ int repeat_times);
+
+void ins_8(
+ BiosEmuEnvironment *env, void *dst, int delta_dst, void *src, int delta_src,
+ int repeat_times);
+void ins_16(
+ BiosEmuEnvironment *env, void *dst, int delta_dst, void *src, int delta_src,
+ int repeat_times);
+void ins_32(
+ BiosEmuEnvironment *env, void *dst, int delta_dst, void *src, int delta_src,
+ int repeat_times);
+void outs_8(
+ BiosEmuEnvironment *env, void *dst, int delta_dst, void *src, int delta_src,
+ int repeat_times);
+void outs_16(
+ BiosEmuEnvironment *env, void *dst, int delta_dst, void *src, int delta_src,
+ int repeat_times);
+void outs_32(
+ BiosEmuEnvironment *env, void *dst, int delta_dst, void *src, int delta_src,
+ int repeat_times);
+
+BiosEmuExceptions bsf_16_16(
+ BiosEmuEnvironment *env, uint16_t *dst, uint16_t *src);
+BiosEmuExceptions bsf_32_32(
+ BiosEmuEnvironment *env, uint32_t *dst, uint32_t *src);
+BiosEmuExceptions bsr_16_16(
+ BiosEmuEnvironment *env, uint16_t *dst, uint16_t *src);
+BiosEmuExceptions bsr_32_32(
+ BiosEmuEnvironment *env, uint32_t *dst, uint32_t *src);
+
+BiosEmuExceptions bswap_32(BiosEmuEnvironment *env, uint32_t *addr);
+
+BiosEmuExceptions decode_enter(BiosEmuEnvironment *env);
+BiosEmuExceptions decode_leave(BiosEmuEnvironment *env);
+
+BiosEmuExceptions bound_16_16(
+ BiosEmuEnvironment *env, uint16_t *reg, uint16_t *src);
+BiosEmuExceptions bound_32_32(
+ BiosEmuEnvironment *env, uint32_t *reg, uint32_t *src);
+
+#endif
\ No newline at end of file
diff --git a/src/arch/x86/bios_emu/includes/prefix.h b/src/arch/x86/bios_emu/includes/prefix.h
new file mode 100644
index 0000000..f6d1724
--- /dev/null
+++ b/src/arch/x86/bios_emu/includes/prefix.h
@@ -0,0 +1,20 @@
+#ifndef _BIOS_EMU_PREFIX_H
+#define _BIOS_EMU_PREFIX_H
+
+typedef enum BiosEmuPrefixs {
+ PREFIX_LOCK = 0xF0,
+ PREFIX_REPNE_REPNZ_BND = 0xF2,
+ PREFIX_REP_REPE_REPZ = 0xF3,
+
+ PREFIX_CS_OVERRIDE_BRANCH_NOT_TAKEN = 0x2E,
+ PREFIX_SS_OVERRIDE = 0x36,
+ PREFIX_DS_OVERRIDE_BRANCH_TAKEN = 0x3E,
+ PREFIX_ES_OVERRIDE = 0x26,
+ PREFIX_FS_OVERRIDE = 0x64,
+ PREFIX_GS_OVERRIDE = 0x65,
+
+ PREFIX_OPERAND_SIZE_OVERRIDE = 0x66,
+ PREFIX_ADDRSIZE_OVERRIDE = 0x67,
+} BiosEmuPrefixes;
+
+#endif
\ No newline at end of file
diff --git a/src/arch/x86/bios_emu/includes/segment.h b/src/arch/x86/bios_emu/includes/segment.h
new file mode 100644
index 0000000..0cfff57
--- /dev/null
+++ b/src/arch/x86/bios_emu/includes/segment.h
@@ -0,0 +1,27 @@
+#ifndef _BIOS_EMU_SEGMENT_H
+#define _BIOS_EMU_SEGMENT_H
+
+#include
+#include
+
+size_t get_segment_base(BiosEmuEnvironment *env, uint32_t segment);
+size_t get_phy_addr(BiosEmuEnvironment *env, uint32_t segment, size_t addr);
+
+uint8_t fetch_data_8(BiosEmuEnvironment *env, uint32_t segment, size_t addr);
+uint8_t fetch_data_16(BiosEmuEnvironment *env, uint32_t segment, size_t addr);
+uint8_t fetch_data_32(BiosEmuEnvironment *env, uint32_t segment, size_t addr);
+
+#define GET_REG_POINTER(env, segment, reg) \
+ ({ \
+ void *addr; \
+ if (env->flags.operand_size == 0) { \
+ addr = \
+ (void *)get_phy_addr(env, env->regs.segment, env->regs.reg); \
+ } else { \
+ addr = (void *)get_phy_addr( \
+ env, env->regs.segment, env->regs.e##reg); \
+ } \
+ addr; \
+ })
+
+#endif
\ No newline at end of file
diff --git a/src/arch/x86/bios_emu/includes/stack.h b/src/arch/x86/bios_emu/includes/stack.h
new file mode 100644
index 0000000..1d6318f
--- /dev/null
+++ b/src/arch/x86/bios_emu/includes/stack.h
@@ -0,0 +1,73 @@
+#ifndef _BIOS_EMU_STACK_H
+#define _BIOS_EMU_STACK_H
+
+#define STACK_POINTER16(env) ((env->regs.ss << 4) + env->regs.sp)
+#define STACK_POINTER32(env) env->regs.esp
+
+#define PUSH16(env, data, size) \
+ { \
+ env->regs.sp -= size; \
+ if (size == 1) { *(uint8_t *)STACK_POINTER16(env) = data; } \
+ if (size == 2) { *(uint16_t *)STACK_POINTER16(env) = data; } \
+ if (size == 4) { *(uint32_t *)STACK_POINTER16(env) = data; } \
+ }
+#define PUSH32(env, data, size) \
+ { \
+ env->regs.esp -= size; \
+ if (size == 1) { *(uint8_t *)STACK_POINTER32(env) = data; } \
+ if (size == 2) { *(uint16_t *)STACK_POINTER32(env) = data; } \
+ if (size == 4) { *(uint32_t *)STACK_POINTER32(env) = data; } \
+ }
+
+#define POP16(env, data, size) \
+ { \
+ if (size == 1) { \
+ (data) = *(uint8_t *)STACK_POINTER16(env); \
+ } else if (size == 2) { \
+ (data) = *(uint16_t *)STACK_POINTER16(env); \
+ } else if (size == 4) { \
+ (data) = *(uint32_t *)STACK_POINTER16(env); \
+ } \
+ env->regs.sp += size; \
+ }
+#define POP32(env, data, size) \
+ { \
+ if (size == 1) { \
+ (data) = *(uint8_t *)STACK_POINTER32(env); \
+ } else if (size == 2) { \
+ (data) = *(uint16_t *)STACK_POINTER32(env); \
+ } else if (size == 4) { \
+ (data) = *(uint32_t *)STACK_POINTER32(env); \
+ } \
+ env->regs.esp += size; \
+ }
+
+#define PUSH(env, data, size) \
+ if (env->flags.stack_size == 0) { \
+ PUSH16(env, data, size); \
+ } else { \
+ PUSH32(env, data, size); \
+ }
+
+#define POP(env, data, size) \
+ if (env->flags.stack_size == 0) { \
+ POP16(env, data, size); \
+ } else { \
+ POP32(env, data, size); \
+ }
+
+#define PUSH_SREG(env, sreg) \
+ if (env->flags.operand_size == 0) { \
+ PUSH(env, env->regs.sreg, 2); \
+ } else { \
+ PUSH(env, env->regs.sreg, 4); \
+ }
+
+#define POP_SREG(env, sreg) \
+ if (env->flags.operand_size == 0) { \
+ POP(env, env->regs.sreg, 2); \
+ } else { \
+ POP(env, env->regs.sreg, 4); \
+ }
+
+#endif
\ No newline at end of file
diff --git a/src/arch/x86/bios_emu/mod_rm.c b/src/arch/x86/bios_emu/mod_rm.c
new file mode 100644
index 0000000..7c177db
--- /dev/null
+++ b/src/arch/x86/bios_emu/mod_rm.c
@@ -0,0 +1,135 @@
+#include "includes/mod_rm.h"
+#include
+#include
+
+size_t decode_rm_address_16(BiosEmuEnvironment *env, uint8_t modrm) {
+ uint8_t mod = (modrm >> 6) & 0b11;
+ uint8_t rm = modrm & 0b111;
+
+ uint16_t offset;
+ switch (rm) {
+ case RM_BX_SI: // [BX + SI]
+ offset = env->regs.bx + env->regs.si;
+ break;
+ case RM_BX_DI: // [BX + DI]
+ offset = env->regs.bx + env->regs.di;
+ break;
+ case RM_BP_SI: // [BP + SI]
+ offset = env->regs.bp + env->regs.si;
+ break;
+ case RM_BP_DI: // [BP + DI]
+ offset = env->regs.bp + env->regs.di;
+ break;
+ case RM_SI: // [SI]
+ offset = env->regs.si;
+ break;
+ case RM_DI: // [DI]
+ offset = env->regs.di;
+ break;
+ case RM_BP: // [BP]
+ offset = env->regs.bp;
+ break;
+ case RM_BX: // [BX]
+ offset = env->regs.bx;
+ break;
+ }
+
+ switch (mod) {
+ case MOD_BASE:
+ if (rm == 0b110) {
+ // disp16
+ offset = *(uint16_t *)env->cur_ip;
+ env->cur_ip += 2;
+ env->regs.eip += 2;
+ env->regs.eip &= 0xffff;
+ env->cur_ip = (void *)((env->regs.cs << 4) + env->regs.eip);
+ } else if (rm == 0b111) {
+ // [BX]
+ offset = env->regs.bx;
+ }
+ break;
+ case MOD_BASE_DISP8:
+ offset += *(int8_t *)env->cur_ip;
+ env->cur_ip += 1;
+ env->regs.eip += 1;
+ env->regs.eip &= 0xffff;
+ env->cur_ip = (void *)((env->regs.cs << 4) + env->regs.eip);
+ break;
+ case MOD_BASE_DISP16:
+ offset += *(uint16_t *)env->cur_ip;
+ env->cur_ip += 2;
+ env->regs.eip += 2;
+ env->regs.eip &= 0xffff;
+ env->cur_ip = (void *)((env->regs.cs << 4) + env->regs.eip);
+ break;
+ default:
+ break;
+ }
+
+ return offset;
+}
+
+size_t decode_rm_address_32(BiosEmuEnvironment *env, uint8_t modrm) {
+ uint8_t mod = (modrm >> 6) & 0b11;
+ uint8_t rm = modrm & 0b111;
+
+ uint32_t offset = 0;
+ if (mod != 0b11) {
+ switch (rm) {
+ case RM_EAX: // [EAX]
+ offset = env->regs.eax;
+ break;
+ case RM_ECX: // [ECX]
+ offset = env->regs.ecx;
+ break;
+ case RM_EDX: // [EDX]
+ offset = env->regs.edx;
+ break;
+ case RM_EBX: // [EBX]
+ offset = env->regs.ebx;
+ break;
+ case RM_EBP: // [EBP]
+ offset = env->regs.ebp;
+ break;
+ case RM_ESI: // [DSI]
+ offset = env->regs.esi;
+ break;
+ case RM_EDI: // [EDI]
+ offset = env->regs.edi;
+ break;
+ }
+ }
+
+ switch (mod) {
+ case MOD_BASE:
+ if (rm == 0b101) {
+ // disp32
+ offset = *(uint32_t *)env->cur_ip;
+ env->cur_ip += 4;
+ env->regs.eip += 4;
+ }
+ break;
+ case MOD_BASE_DISP8:
+ offset += *(int8_t *)env->cur_ip;
+ env->cur_ip += 1;
+ env->regs.eip += 1;
+ break;
+ case MOD_BASE_DISP32:
+ offset += *(uint32_t *)env->cur_ip;
+ env->cur_ip += 4;
+ env->regs.eip += 4;
+ break;
+ default:
+ break;
+ }
+
+ return offset;
+}
+
+size_t decode_rm_address(BiosEmuEnvironment *env, uint8_t modrm) {
+ if (env->flags.address_size == 0) {
+ return decode_rm_address_16(env, modrm);
+ } else {
+ return decode_rm_address_32(env, modrm);
+ }
+}
diff --git a/src/arch/x86/bios_emu/operations.c b/src/arch/x86/bios_emu/operations.c
new file mode 100644
index 0000000..5f71d92
--- /dev/null
+++ b/src/arch/x86/bios_emu/operations.c
@@ -0,0 +1,683 @@
+#include "includes/operations.h"
+#include "bios_emu/exceptions.h"
+#include "includes/alu.h"
+#include "includes/decode.h"
+#include "includes/mod_rm.h"
+#include "includes/segment.h"
+#include "includes/stack.h"
+#include "kernel/func.h"
+#include
+#include
+
+int ptr_within_code_segment_limit(BiosEmuEnvironment *env, uint32_t address) {
+ // uint32_t segment = env->regs.cs;
+ // if (env->flags.address_size == 0) {
+ // return (address < (segment << 4) + 0xffff) && address >= (segment << 4);
+ // }
+ return 1;
+}
+
+BiosEmuExceptions decode_0x80_0x83(BiosEmuEnvironment *env, uint8_t opcode) {
+ static const CalcIndex index_table[8] = {
+ /* 0b000 */ CALC_ADD,
+ /* 0b001 */ CALC_OR,
+ /* 0b010 */ CALC_ADC,
+ /* 0b011 */ CALC_SBB,
+ /* 0b100 */ CALC_AND,
+ /* 0b101 */ CALC_SUB,
+ /* 0b110 */ CALC_XOR,
+ /* 0b111 */ CALC_CMP};
+ uint8_t modrm = *(uint8_t *)env->cur_ip;
+ uint8_t sel = (modrm >> 3) & 0b111;
+ CalcIndex index = index_table[sel & 0b111];
+
+ switch (opcode & 0b11) {
+ case 0b00:
+ calc_rm_imm_8(env, index);
+ break;
+ case 0b01:
+ calc_rm_imm(env, index);
+ break;
+ case 0b10:
+ return InvalidOpcode;
+ case 0b11:
+ calc_rm_imm8(env, index);
+ break;
+ }
+ return NoException;
+}
+
+BiosEmuExceptions decode_0xba(BiosEmuEnvironment *env) {
+ uint8_t modrm = *(uint8_t *)env->cur_ip;
+ uint8_t sel = (modrm >> 3) & 0b111;
+
+ switch (sel) {
+ case 0b100:
+ decode_rm_imm8(env, bt_16_16, bt_32_32);
+ break;
+ case 0b101:
+ decode_rm_imm8(env, bts_16_16, bts_32_32);
+ break;
+ case 0b110:
+ decode_rm_imm8(env, btr_16_16, btr_32_32);
+ break;
+ case 0b111:
+ decode_rm_imm8(env, btc_16_16, btc_32_32);
+ break;
+ default:
+ env->cur_ip--;
+ env->regs.eip--;
+ return InvalidOpcode;
+ }
+ return NoException;
+}
+
+void (*rotate_shift_8[8])(
+ BiosEmuEnvironment *env, uint8_t *value, uint8_t count) = {
+ rol_8, ror_8, rcl_8, rcr_8, shl_sal_8, shr_8, shl_sal_8, sar_8};
+void (*rotate_shift16[8])(
+ BiosEmuEnvironment *env, uint16_t *value, uint8_t count) = {
+ rol_16, ror_16, rcl_16, rcr_16, shl_sal_16, shr_16, shl_sal_16, sar_16};
+void (*rotate_shift32[8])(
+ BiosEmuEnvironment *env, uint32_t *value, uint8_t count) = {
+ rol_32, ror_32, rcl_32, rcr_32, shl_sal_32, shr_32, shl_sal_32, sar_32};
+
+BiosEmuExceptions decode_0xc0(BiosEmuEnvironment *env) {
+ uint8_t modrm = *(uint8_t *)env->cur_ip;
+ env->cur_ip++;
+ env->regs.eip++;
+ uint8_t sel = (modrm >> 3) & 0b111;
+
+ rotate_shift_8[sel](env, RM_ADDR(env, modrm), *(uint8_t *)env->cur_ip);
+ env->regs.eip++;
+ env->cur_ip++;
+
+ return NoException;
+}
+
+BiosEmuExceptions decode_0xc1(BiosEmuEnvironment *env) {
+ uint8_t modrm = *(uint8_t *)env->cur_ip;
+ env->cur_ip++;
+ env->regs.eip++;
+ uint8_t sel = (modrm >> 3) & 0b111;
+
+ if (env->flags.operand_size == 0) {
+ rotate_shift16[sel](env, RM_ADDR(env, modrm), *(uint8_t *)env->cur_ip);
+ env->regs.eip++;
+ env->cur_ip++;
+ } else {
+ rotate_shift32[sel](env, RM_ADDR(env, modrm), *(uint8_t *)env->cur_ip);
+ env->regs.eip++;
+ env->cur_ip++;
+ }
+
+ return NoException;
+}
+
+BiosEmuExceptions decode_0xd0(BiosEmuEnvironment *env) {
+ uint8_t modrm = *(uint8_t *)env->cur_ip;
+ env->cur_ip++;
+ env->regs.eip++;
+ uint8_t sel = (modrm >> 3) & 0b111;
+
+ rotate_shift_8[sel](env, RM_ADDR(env, modrm), 1);
+
+ return NoException;
+}
+
+BiosEmuExceptions decode_0xd1(BiosEmuEnvironment *env) {
+ uint8_t modrm = *(uint8_t *)env->cur_ip;
+ env->cur_ip++;
+ env->regs.eip++;
+ uint8_t sel = (modrm >> 3) & 0b111;
+
+ if (env->flags.operand_size == 0) {
+ rotate_shift16[sel](env, RM_ADDR(env, modrm), 1);
+ } else {
+ rotate_shift32[sel](env, RM_ADDR(env, modrm), 1);
+ }
+
+ return NoException;
+}
+
+BiosEmuExceptions decode_0xd2(BiosEmuEnvironment *env) {
+ uint8_t modrm = *(uint8_t *)env->cur_ip;
+ env->cur_ip++;
+ env->regs.eip++;
+ uint8_t sel = (modrm >> 3) & 0b111;
+
+ rotate_shift_8[sel](env, RM_ADDR(env, modrm), env->regs.cl);
+
+ return NoException;
+}
+
+BiosEmuExceptions decode_0xd3(BiosEmuEnvironment *env) {
+ uint8_t modrm = *(uint8_t *)env->cur_ip;
+ env->cur_ip++;
+ env->regs.eip++;
+ uint8_t sel = (modrm >> 3) & 0b111;
+
+ if (env->flags.operand_size == 0) {
+ rotate_shift16[sel](env, RM_ADDR(env, modrm), env->regs.cl);
+ } else {
+ rotate_shift32[sel](env, RM_ADDR(env, modrm), env->regs.cl);
+ }
+
+ return NoException;
+}
+
+BiosEmuExceptions decode_0xf6(BiosEmuEnvironment *env) {
+ uint8_t modrm = *(uint8_t *)env->cur_ip;
+ env->cur_ip++;
+ env->regs.eip++;
+ uint8_t sel = (modrm >> 3) & 0b111;
+
+ if (sel == 0) {
+ env->cur_ip--;
+ env->regs.eip--;
+ calc_rm_imm8(env, CALC_TEST);
+ return NoException;
+ }
+
+ void *p = RM_ADDR(env, modrm);
+ uint8_t *addr = env->flags.operand_size == 0
+ ? (uint8_t *)((env->regs.cs << 4) + (size_t)p)
+ : p;
+
+ BiosEmuExceptions exception = NoException;
+ switch (sel) {
+ case 0b010:
+ *addr = ~(*addr);
+ break;
+ case 0b011:
+ neg_8(env, addr);
+ break;
+ case 0b100:
+ mul_8(env, *addr);
+ break;
+ case 0b101:
+ imul_8(env, *addr);
+ break;
+ case 0b110:
+ exception = div_8(env, *addr);
+ break;
+ case 0b111:
+ exception = idiv_8(env, *addr);
+ break;
+ }
+ return exception;
+}
+
+BiosEmuExceptions decode_0xf7(BiosEmuEnvironment *env) {
+ uint8_t modrm = *(uint8_t *)env->cur_ip;
+ env->cur_ip++;
+ env->regs.eip++;
+ uint8_t sel = (modrm >> 3) & 0b111;
+
+ uint8_t *p = (uint8_t *)RM_ADDR(env, modrm);
+
+ BiosEmuExceptions exception = NoException;
+ switch (sel) {
+ case 0b000:
+ env->cur_ip--;
+ env->regs.eip--;
+ calc_rm_imm(env, CALC_TEST);
+ break;
+ case 0b010:
+ if (env->flags.operand_size == 0) {
+ *(uint16_t *)p = ~(*(uint16_t *)p);
+ } else {
+ *(uint32_t *)p = ~(*(uint32_t *)p);
+ }
+ break;
+ case 0b011:
+ if (env->flags.operand_size == 0) {
+ neg_16(env, (uint16_t *)p);
+ } else {
+ neg_32(env, (uint32_t *)p);
+ }
+ break;
+ case 0b100:
+ if (env->flags.operand_size == 0) {
+ mul_16(env, *(uint16_t *)p);
+ } else {
+ mul_32(env, *(uint32_t *)p);
+ }
+ break;
+ case 0b101:
+ if (env->flags.operand_size == 0) {
+ imul_16(
+ env, &env->regs.dx, &env->regs.ax, env->regs.ax,
+ *(uint16_t *)p);
+ } else {
+ imul_32(
+ env, &env->regs.edx, &env->regs.eax, env->regs.eax,
+ *(uint16_t *)p);
+ }
+ break;
+ case 0b110:
+ exception = !env->flags.operand_size ? div_16(env, *(uint16_t *)p)
+ : div_32(env, *(uint32_t *)p);
+ break;
+ case 0b111:
+ exception = !env->flags.operand_size ? idiv_16(env, *(uint16_t *)p)
+ : idiv_32(env, *(uint32_t *)p);
+ break;
+ }
+ return exception;
+}
+
+BiosEmuExceptions decode_0xfe(BiosEmuEnvironment *env) {
+ uint8_t modrm = *(uint8_t *)env->cur_ip++;
+ env->regs.eip++;
+ switch ((modrm >> 3) & 0b111) {
+ case 0b000:
+ // INC r/m
+ decode_inc_rm8(env);
+ break;
+ case 0b001:
+ // DEC r/m
+ decode_dec_rm8(env);
+ break;
+ default:
+ env->regs.eip--;
+ env->cur_ip--;
+ return InvalidOpcode;
+ }
+ return NoException;
+}
+
+BiosEmuExceptions decode_0xff(BiosEmuEnvironment *env) {
+ BiosEmuExceptions exception = NoException;
+ uint8_t modrm = *(uint8_t *)env->cur_ip++;
+ uint8_t sel = (modrm >> 3) & 0b111;
+ env->regs.eip++;
+ switch (sel) {
+ case 0b000:
+ // INC r/m
+ decode_inc_rm(env);
+ break;
+ case 0b001:
+ // DEC r/m
+ decode_dec_rm(env);
+ break;
+ case 0b010:
+ // CALL r/m
+ if (modrm >> 6 == 0b11) {
+ if (env->flags.operand_size == 0) {
+ uint16_t *reg = env->reg_lut_r16[modrm & 0b111];
+ decode_call_near(env, *reg);
+ } else {
+ uint32_t *reg = env->reg_lut_r32[modrm & 0b111];
+ decode_call_near(env, *reg);
+ }
+ } else {
+ if (env->flags.operand_size == 0) {
+ uint16_t address = decode_rm_address_16(env, modrm);
+ address = fetch_data_16(env, *env->default_ss, address);
+ decode_call_near(env, address);
+ } else {
+ uint32_t address = decode_rm_address_32(env, modrm);
+ address = fetch_data_32(env, *env->default_ss, address);
+ decode_call_near(env, address);
+ }
+ }
+ break;
+ case 0b011:
+ // CALL m16:16/32
+ if (env->flags.operand_size == 0) {
+ uint16_t address = decode_rm_address_16(env, modrm);
+ address = fetch_data_16(env, *env->default_ss, address);
+ uint16_t segment =
+ fetch_data_16(env, *env->default_ss, address + 2);
+ decode_call_far(env, segment, address);
+ } else {
+ uint32_t address = decode_rm_address_32(env, modrm);
+ address = fetch_data_32(env, *env->default_ss, address);
+ uint32_t segment =
+ fetch_data_32(env, *env->default_ss, address + 4);
+ decode_call_far(env, segment, address);
+ }
+ break;
+ case 0b100:
+ // JMP r/m
+ if (modrm >> 6 == 0b11) {
+ if (env->flags.operand_size == 0) {
+ uint16_t *reg = env->reg_lut_r16[modrm & 0b111];
+ decode_jmp_near(env, *reg);
+ } else {
+ uint32_t *reg = env->reg_lut_r32[modrm & 0b111];
+ decode_jmp_near(env, *reg);
+ }
+ } else {
+ if (env->flags.operand_size == 0) {
+ uint16_t address = decode_rm_address_16(env, modrm);
+ address = fetch_data_16(env, *env->default_ss, address);
+ decode_jmp_near(env, (int16_t)address);
+ } else {
+ uint32_t address = decode_rm_address_32(env, modrm);
+ address = fetch_data_32(env, *env->default_ss, address);
+ decode_jmp_near(env, (int32_t)address);
+ }
+ }
+ break;
+ case 0b101:
+ // Long JMP
+ if (env->flags.operand_size == 0) {
+ uint16_t address = decode_rm_address_16(env, modrm);
+ address = fetch_data_16(env, *env->default_ss, address);
+ uint16_t segment =
+ fetch_data_16(env, *env->default_ss, address + 2);
+ decode_jmp_far(env, segment, address);
+ } else {
+ uint32_t address = decode_rm_address_32(env, modrm);
+ address = fetch_data_32(env, *env->default_ss, address);
+ uint32_t segment =
+ fetch_data_32(env, *env->default_ss, address + 4);
+ decode_jmp_far(env, segment, address);
+ }
+ break;
+ case 0b110:
+ // PUSH r/m16
+ if (modrm >> 6 == 0b11) {
+ // PUSH r16
+ if (env->flags.operand_size == 0) {
+ uint16_t *reg = env->reg_lut_r16[modrm & 0b111];
+ PUSH(env, *reg, 2);
+ } else {
+ uint32_t *reg = env->reg_lut_r32[modrm & 0b111];
+ PUSH(env, *reg, 4);
+ }
+ } else {
+ // PUSH [r/m16]
+ if (env->flags.operand_size == 0) {
+ uint16_t val = decode_rm_address_16(env, modrm);
+ val = fetch_data_16(env, *env->default_ss, val);
+ PUSH(env, val, 2);
+ } else {
+ uint32_t val = decode_rm_address_32(env, modrm);
+ val = fetch_data_32(env, *env->default_ss, val);
+ PUSH(env, val, 4);
+ }
+ }
+ break;
+ default:
+ env->regs.eip--;
+ env->cur_ip--;
+ exception = InvalidOpcode;
+ }
+ return exception;
+}
+
+void decode_in8(BiosEmuEnvironment *env, uint8_t port) {
+ env->regs.al = io_in8(port);
+}
+
+void decode_in(BiosEmuEnvironment *env, uint16_t port) {
+ if (env->flags.operand_size == 0) {
+ env->regs.ax = io_in16(port);
+ } else {
+ env->regs.eax = io_in32(port);
+ }
+}
+
+void decode_out8(BiosEmuEnvironment *env, uint8_t port) {
+ io_out8(port, env->regs.al);
+}
+
+void decode_out(BiosEmuEnvironment *env, uint16_t port) {
+ if (env->flags.operand_size == 0) {
+ io_out16(port, env->regs.ax);
+ } else {
+ io_out32(port, env->regs.eax);
+ }
+}
+
+void ins_8(
+ BiosEmuEnvironment *env, void *dst, int delta_dst, void *src, int delta_src,
+ int repeat_times) {
+ __asm__ volatile("cld;"
+ "rep insb;"
+ :
+ : "D"(dst), "S"(src), "c"(env->regs.cx), "d"(env->regs.dx)
+ : "cc", "memory");
+}
+
+void ins_16(
+ BiosEmuEnvironment *env, void *dst, int delta_dst, void *src, int delta_src,
+ int repeat_times) {
+ __asm__ volatile("cld;"
+ "rep insw;"
+ :
+ : "D"(dst), "S"(src), "c"(env->regs.cx), "d"(env->regs.dx)
+ : "cc", "memory");
+}
+
+void ins_32(
+ BiosEmuEnvironment *env, void *dst, int delta_dst, void *src, int delta_src,
+ int repeat_times) {
+ __asm__ volatile("cld;"
+ "rep insl;"
+ :
+ : "D"(dst), "S"(src), "c"(env->regs.ecx), "d"(env->regs.dx)
+ : "cc", "memory");
+}
+
+void outs_8(
+ BiosEmuEnvironment *env, void *dst, int delta_dst, void *src, int delta_src,
+ int repeat_times) {
+ __asm__ volatile("cld;"
+ "rep outsb;"
+ :
+ : "D"(dst), "S"(src), "c"(env->regs.cx), "d"(env->regs.dx)
+ : "cc", "memory");
+}
+
+void outs_16(
+ BiosEmuEnvironment *env, void *dst, int delta_dst, void *src, int delta_src,
+ int repeat_times) {
+ __asm__ volatile("cld;"
+ "rep outsw;"
+ :
+ : "D"(dst), "S"(src), "c"(env->regs.cx), "d"(env->regs.dx)
+ : "cc", "memory");
+}
+
+void outs_32(
+ BiosEmuEnvironment *env, void *dst, int delta_dst, void *src, int delta_src,
+ int repeat_times) {
+ __asm__ volatile("cld;"
+ "rep outsl;"
+ :
+ : "D"(dst), "S"(src), "c"(env->regs.ecx), "d"(env->regs.dx)
+ : "cc", "memory");
+}
+
+BiosEmuExceptions decode_lea(BiosEmuEnvironment *env) {
+ uint8_t modrm = *(uint8_t *)env->cur_ip++;
+ env->regs.eip++;
+ uint8_t reg = (modrm >> 3) & 0b111;
+
+ size_t address;
+ if (modrm >> 6 == 0b11) { return InvalidOpcode; }
+ if (env->flags.address_size == 0) {
+ address = decode_rm_address_16(env, modrm);
+ } else {
+ address = decode_rm_address_32(env, modrm);
+ }
+ if (env->flags.operand_size == 0) {
+ uint16_t *dst = env->reg_lut_r16[reg];
+ *dst = (uint16_t)address;
+ } else {
+ uint32_t *dst = env->reg_lut_r32[reg];
+ *dst = (uint32_t)address;
+ }
+ return NoException;
+}
+
+void decode_setcc(BiosEmuEnvironment *env, int condition) {
+ uint8_t modrm = *(uint8_t *)env->cur_ip++;
+ env->regs.eip++;
+
+ uint8_t *addr = RM_ADDR(env, modrm);
+ *addr = condition ? 1 : 0;
+ return;
+}
+
+void decode_cbw_cwde(BiosEmuEnvironment *env) {
+ if (env->flags.operand_size == 0) {
+ env->regs.ax = (int16_t)(int8_t)env->regs.al;
+ } else {
+ env->regs.eax = (int32_t)(int16_t)env->regs.ax;
+ }
+ return;
+}
+
+void decode_cwd_cdq(BiosEmuEnvironment *env) {
+ if (env->flags.operand_size == 0) {
+ env->regs.dx = ((int32_t)(int16_t)env->regs.ax) >> 16;
+ } else {
+ env->regs.edx = (env->regs.eax >> 31) ? 0xffffffff : 0;
+ }
+ return;
+}
+
+BiosEmuExceptions bsf_16_16(
+ BiosEmuEnvironment *env, uint16_t *dst, uint16_t *src) {
+ uint16_t x = *src;
+ for (int i = 0; i < 16; i++) {
+ if (x & 1) {
+ *dst = i;
+ return NoException;
+ }
+ x >>= 1;
+ }
+ return NoException;
+}
+
+BiosEmuExceptions bsf_32_32(
+ BiosEmuEnvironment *env, uint32_t *dst, uint32_t *src) {
+ uint32_t x = *src;
+ for (int i = 0; i < 32; i++) {
+ if (x & 1) {
+ *dst = i;
+ return NoException;
+ }
+ x >>= 1;
+ }
+ return NoException;
+}
+
+BiosEmuExceptions bsr_16_16(
+ BiosEmuEnvironment *env, uint16_t *dst, uint16_t *src) {
+ uint16_t x = *src;
+ for (int i = 15; i >= 0; i--) {
+ if (x >> i) {
+ *dst = i;
+ return NoException;
+ }
+ }
+ return NoException;
+}
+
+BiosEmuExceptions bsr_32_32(
+ BiosEmuEnvironment *env, uint32_t *dst, uint32_t *src) {
+ uint32_t x = *src;
+ for (int i = 31; i >= 0; i--) {
+ if (x >> i) {
+ *dst = i;
+ return NoException;
+ }
+ }
+ return NoException;
+}
+
+BiosEmuExceptions decode_enter(BiosEmuEnvironment *env) {
+ uint16_t alloc_size = *(uint16_t *)env->cur_ip;
+ env->cur_ip += 2;
+ env->regs.eip += 2;
+
+ uint8_t nesting_level = *(uint8_t *)env->cur_ip++;
+ env->regs.eip++;
+
+ uint32_t frame_temp;
+ if (env->flags.operand_size == 0) {
+ PUSH(env, env->regs.bp, 2);
+ frame_temp = env->regs.sp;
+ } else {
+ PUSH(env, env->regs.ebp, 4);
+ frame_temp = env->regs.esp;
+ }
+
+ if (nesting_level == 0) {
+ nesting_level = 1;
+ } else {
+ if (env->flags.operand_size == 0) {
+ if (env->flags.stack_size == 0) {
+ for (int i = 1; i < nesting_level; i++) {
+ env->regs.bp -= 2;
+ PUSH16(env, env->regs.bp, 2);
+ }
+ PUSH16(env, frame_temp, 2);
+ } else {
+ for (int i = 1; i < nesting_level; i++) {
+ env->regs.ebp -= 2;
+ PUSH32(env, env->regs.ebp, 4);
+ }
+ PUSH32(env, frame_temp, 2);
+ }
+ } else {
+ if (env->flags.stack_size == 0) {
+ for (int i = 1; i < nesting_level; i++) {
+ env->regs.bp -= 4;
+ PUSH16(env, env->regs.bp, 2);
+ }
+ PUSH16(env, frame_temp, 4);
+ } else {
+ for (int i = 1; i < nesting_level; i++) {
+ env->regs.ebp -= 4;
+ PUSH32(env, env->regs.ebp, 4);
+ }
+ PUSH32(env, frame_temp, 4);
+ }
+ }
+ }
+
+ if (env->flags.operand_size == 0) {
+ env->regs.bp = frame_temp;
+ env->regs.sp -= alloc_size;
+ } else {
+ env->regs.ebp = frame_temp;
+ env->regs.esp -= alloc_size;
+ }
+ return NoException;
+}
+
+BiosEmuExceptions decode_leave(BiosEmuEnvironment *env) {
+ if (env->flags.operand_size == 0) {
+ env->regs.sp = env->regs.bp;
+ POP(env, env->regs.bp, 2);
+ } else {
+ env->regs.esp = env->regs.ebp;
+ POP(env, env->regs.ebp, 4);
+ }
+ return NoException;
+}
+
+BiosEmuExceptions bound_16_16(
+ BiosEmuEnvironment *env, uint16_t *reg, uint16_t *src) {
+ uint16_t lower_bound = src[0];
+ uint16_t upper_bound = src[1];
+
+ if (*reg < lower_bound || *reg > upper_bound) { return BOUNDRangeExceeded; }
+ return NoException;
+}
+
+BiosEmuExceptions bound_32_32(
+ BiosEmuEnvironment *env, uint32_t *reg, uint32_t *src) {
+ uint32_t lower_bound = src[0];
+ uint32_t upper_bound = src[1];
+
+ if (*reg < lower_bound || *reg > upper_bound) { return BOUNDRangeExceeded; }
+ return NoException;
+}
diff --git a/src/arch/x86/bios_emu/ops/Makefile b/src/arch/x86/bios_emu/ops/Makefile
new file mode 100644
index 0000000..786ad17
--- /dev/null
+++ b/src/arch/x86/bios_emu/ops/Makefile
@@ -0,0 +1,10 @@
+SRC += mov.c
+SRC += alu.c
+SRC += jmp.c
+SRC += stack.c
+SRC += call.c
+SRC += conditions.c
+SRC += int.c
+SRC += xchg.c
+SRC += segment.c
+SRC += bt.c
\ No newline at end of file
diff --git a/src/arch/x86/bios_emu/ops/alu.c b/src/arch/x86/bios_emu/ops/alu.c
new file mode 100644
index 0000000..24dc33b
--- /dev/null
+++ b/src/arch/x86/bios_emu/ops/alu.c
@@ -0,0 +1,1339 @@
+#include "../includes/alu.h"
+#include "../includes/decode.h"
+#include "../includes/flags.h"
+#include "../includes/mod_rm.h"
+#include "bits.h"
+#include
+#include
+#include
+
+static inline uint8_t calc_parity(uint8_t x) {
+ x ^= x >> 4;
+ x &= 0x0F;
+ return (0x6996 >> x) & 1;
+}
+
+void set_test_flag(BiosEmuEnvironment *env, uint32_t x) {
+ env->regs.flags = x == 0 ? env->regs.flags | BIT(ZeroFlagBit)
+ : env->regs.flags & ~BIT(ZeroFlagBit);
+ env->regs.flags =
+ (calc_parity(x) ? env->regs.flags | BIT(ParityFlagBit)
+ : env->regs.flags & ~BIT(ParityFlagBit));
+ env->regs.flags &= ~BIT(CarryFlagBit);
+ env->regs.flags &= ~BIT(OverflowFlagBit);
+ return;
+}
+
+static void test_8(BiosEmuEnvironment *env, uint8_t *dst, uint8_t src) {
+ uint8_t temp = *dst & src;
+
+ SIGN_FLAG8(temp);
+ set_test_flag(env, temp);
+ return;
+}
+
+static void test_16(BiosEmuEnvironment *env, uint16_t *dst, uint16_t src) {
+ uint16_t temp = *dst & src;
+
+ SIGN_FLAG16(temp);
+ set_test_flag(env, temp);
+ return;
+}
+
+static void test_32(BiosEmuEnvironment *env, uint32_t *dst, uint32_t src) {
+ uint32_t temp = *dst & src;
+
+ SIGN_FLAG32(temp);
+ set_test_flag(env, temp);
+ return;
+}
+
+void set_zf_pf(BiosEmuEnvironment *env, uint32_t x) {
+ env->regs.flags = x == 0 ? env->regs.flags | BIT(ZeroFlagBit)
+ : env->regs.flags & ~BIT(ZeroFlagBit);
+ env->regs.flags =
+ (calc_parity(x) ? env->regs.flags | BIT(ParityFlagBit)
+ : env->regs.flags & ~BIT(ParityFlagBit));
+ return;
+}
+
+static void add_8(BiosEmuEnvironment *env, uint8_t *dst, uint8_t src) {
+ uint8_t ans;
+ int overflow = __builtin_add_overflow(*dst, src, &ans);
+
+ SET_CARRY_FLAG(*dst > ~src);
+ SET_OVERFLOW_FLAG(overflow);
+ SIGN_FLAG8(ans);
+ set_zf_pf(env, ans);
+ *dst = ans;
+ return;
+}
+
+static void add_16(BiosEmuEnvironment *env, uint16_t *dst, uint16_t src) {
+ uint16_t ans;
+ int overflow = __builtin_add_overflow(*dst, src, &ans);
+
+ SET_CARRY_FLAG(*dst > ~src);
+ SET_OVERFLOW_FLAG(overflow);
+ SIGN_FLAG16(ans);
+ set_zf_pf(env, ans);
+ *dst = ans;
+ return;
+}
+
+static void add_32(BiosEmuEnvironment *env, uint32_t *dst, uint32_t src) {
+ uint32_t ans;
+ int overflow = __builtin_add_overflow(*dst, src, &ans);
+
+ SET_CARRY_FLAG(*dst > ~src);
+ SET_OVERFLOW_FLAG(overflow);
+ SIGN_FLAG32(ans);
+ set_zf_pf(env, ans);
+ *dst = ans;
+ return;
+}
+
+static void adc_8(BiosEmuEnvironment *env, uint8_t *dst, uint8_t src) {
+ uint8_t carry = !!(env->regs.flags & BIT(CarryFlagBit));
+ add_8(env, dst, src + carry);
+ return;
+}
+
+static void adc_16(BiosEmuEnvironment *env, uint16_t *dst, uint16_t src) {
+ uint8_t carry = !!(env->regs.flags & BIT(CarryFlagBit));
+ add_16(env, dst, src + carry);
+ return;
+}
+
+static void adc_32(BiosEmuEnvironment *env, uint32_t *dst, uint32_t src) {
+ uint8_t carry = !!(env->regs.flags & BIT(CarryFlagBit));
+ add_32(env, dst, src + carry);
+ return;
+}
+
+static void sub_8(BiosEmuEnvironment *env, uint8_t *dst, uint8_t src) {
+ uint8_t ans;
+ int overflow = __builtin_sub_overflow(*dst, src, &ans);
+
+ SET_CARRY_FLAG(*dst < src);
+ SET_OVERFLOW_FLAG(overflow);
+ SIGN_FLAG8(ans);
+ set_zf_pf(env, ans);
+ *dst = ans;
+ return;
+}
+
+static void sub_16(BiosEmuEnvironment *env, uint16_t *dst, uint16_t src) {
+ uint16_t ans;
+ int overflow = __builtin_sub_overflow(*dst, src, &ans);
+
+ SET_CARRY_FLAG(*dst < src);
+ SET_OVERFLOW_FLAG(overflow);
+ SIGN_FLAG16(ans);
+ set_zf_pf(env, ans);
+ *dst = ans;
+ return;
+}
+
+static void sub_32(BiosEmuEnvironment *env, uint32_t *dst, uint32_t src) {
+ uint32_t ans;
+ int overflow = __builtin_sub_overflow(*dst, src, &ans);
+
+ SET_CARRY_FLAG(*dst < src);
+ SET_OVERFLOW_FLAG(overflow);
+ SIGN_FLAG32(ans);
+ set_zf_pf(env, ans);
+ *dst = ans;
+ return;
+}
+
+static void sbb_8(BiosEmuEnvironment *env, uint8_t *dst, uint8_t src) {
+ uint8_t carry = !!(env->regs.flags & BIT(CarryFlagBit));
+ sub_8(env, dst, src + carry);
+ return;
+}
+
+static void sbb_16(BiosEmuEnvironment *env, uint16_t *dst, uint16_t src) {
+ uint8_t carry = !!(env->regs.flags & BIT(CarryFlagBit));
+ sub_16(env, dst, src + carry);
+ return;
+}
+
+static void sbb_32(BiosEmuEnvironment *env, uint32_t *dst, uint32_t src) {
+ uint8_t carry = !!(env->regs.flags & BIT(CarryFlagBit));
+ sub_32(env, dst, src + carry);
+ return;
+}
+
+static void and_8(BiosEmuEnvironment *env, uint8_t *dst, uint8_t src) {
+ uint8_t ans = *dst & src;
+
+ SIGN_FLAG8(ans);
+ set_test_flag(env, ans);
+ *dst = ans;
+ return;
+}
+
+static void and_16(BiosEmuEnvironment *env, uint16_t *dst, uint16_t src) {
+ uint16_t ans = *dst & src;
+
+ SIGN_FLAG16(ans);
+ set_test_flag(env, ans);
+ *dst = ans;
+ return;
+}
+
+static void and_32(BiosEmuEnvironment *env, uint32_t *dst, uint32_t src) {
+ uint32_t ans = *dst & src;
+
+ SIGN_FLAG32(ans);
+ set_test_flag(env, ans);
+ *dst = ans;
+ return;
+}
+
+static void xor_8(BiosEmuEnvironment *env, uint8_t *dst, uint8_t src) {
+ uint8_t ans = *dst ^ src;
+
+ SIGN_FLAG8(ans);
+ set_test_flag(env, ans);
+ *dst = ans;
+ return;
+}
+
+static void xor_16(BiosEmuEnvironment *env, uint16_t *dst, uint16_t src) {
+ uint16_t ans = *dst ^ src;
+
+ SIGN_FLAG16(ans);
+ set_test_flag(env, ans);
+ *dst = ans;
+ return;
+}
+
+static void xor_32(BiosEmuEnvironment *env, uint32_t *dst, uint32_t src) {
+ uint32_t ans = *dst ^ src;
+
+ SIGN_FLAG32(ans);
+ set_test_flag(env, ans);
+ *dst = ans;
+ return;
+}
+
+static void or_8(BiosEmuEnvironment *env, uint8_t *dst, uint8_t src) {
+ uint8_t ans = *dst | src;
+
+ SIGN_FLAG8(ans);
+ set_test_flag(env, ans);
+ *dst = ans;
+ return;
+}
+
+static void or_16(BiosEmuEnvironment *env, uint16_t *dst, uint16_t src) {
+ uint16_t ans = *dst | src;
+
+ SIGN_FLAG16(ans);
+ set_test_flag(env, ans);
+ *dst = ans;
+ return;
+}
+
+static void or_32(BiosEmuEnvironment *env, uint32_t *dst, uint32_t src) {
+ uint32_t ans = *dst | src;
+
+ SIGN_FLAG32(ans);
+ set_test_flag(env, ans);
+ *dst = ans;
+ return;
+}
+
+static void cmp_8(BiosEmuEnvironment *env, uint8_t *dst, uint8_t src) {
+ uint16_t ans;
+ int overflow = __builtin_sub_overflow(*dst, src, &ans);
+
+ SET_CARRY_FLAG(*dst < src);
+ SET_OVERFLOW_FLAG(overflow);
+ SIGN_FLAG16(ans);
+ set_zf_pf(env, ans);
+ return;
+}
+
+static void cmp_16(BiosEmuEnvironment *env, uint16_t *dst, uint16_t src) {
+ uint16_t ans;
+ int overflow = __builtin_sub_overflow(*dst, src, &ans);
+
+ SET_CARRY_FLAG(*dst < src);
+ SET_OVERFLOW_FLAG(overflow);
+ SIGN_FLAG16(ans);
+ set_zf_pf(env, ans);
+ return;
+}
+
+static void cmp_32(BiosEmuEnvironment *env, uint32_t *dst, uint32_t src) {
+ uint32_t ans;
+ int overflow = __builtin_sub_overflow(*dst, src, &ans);
+
+ SET_CARRY_FLAG(*dst < src);
+ SET_OVERFLOW_FLAG(overflow);
+ SIGN_FLAG32(ans);
+ set_zf_pf(env, ans);
+ return;
+}
+
+Calc8 calc8[] = {
+ [CALC_ADD] = add_8, [CALC_ADC] = adc_8, [CALC_AND] = and_8,
+ [CALC_XOR] = xor_8, [CALC_OR] = or_8, [CALC_SBB] = sbb_8,
+ [CALC_SUB] = sub_8, [CALC_CMP] = cmp_8, [CALC_TEST] = test_8,
+};
+
+Calc16 calc16[] = {
+ [CALC_ADD] = add_16, [CALC_ADC] = adc_16, [CALC_AND] = and_16,
+ [CALC_XOR] = xor_16, [CALC_OR] = or_16, [CALC_SBB] = sbb_16,
+ [CALC_SUB] = sub_16, [CALC_CMP] = cmp_16, [CALC_TEST] = test_16,
+};
+
+Calc32 calc32[] = {
+ [CALC_ADD] = add_32, [CALC_ADC] = adc_32, [CALC_AND] = and_32,
+ [CALC_XOR] = xor_32, [CALC_OR] = or_32, [CALC_SBB] = sbb_32,
+ [CALC_SUB] = sub_32, [CALC_CMP] = cmp_32, [CALC_TEST] = test_32,
+};
+
+void calc_a_imm8(BiosEmuEnvironment *env, CalcIndex index) {
+ uint8_t imm = *(uint8_t *)env->cur_ip++;
+ env->regs.eip++;
+
+ calc8[index](env, &env->regs.al, imm);
+ return;
+}
+
+void calc_a_imm(BiosEmuEnvironment *env, CalcIndex index) {
+ if (env->flags.operand_size == 0) {
+ uint16_t imm = *(uint16_t *)env->cur_ip;
+ env->regs.eip += 2;
+ env->cur_ip += 2;
+ calc16[index](env, &env->regs.ax, imm);
+ } else {
+ uint32_t imm = *(uint32_t *)env->cur_ip;
+ env->regs.eip += 4;
+ env->cur_ip += 4;
+ calc32[index](env, &env->regs.eax, imm);
+ }
+ return;
+}
+
+void calc_rm_imm_8(BiosEmuEnvironment *env, CalcIndex index) {
+ uint8_t modrm = *(uint8_t *)env->cur_ip++;
+ env->regs.eip++;
+
+ uint8_t *dst = RM_ADDR(env, modrm);
+ uint8_t imm = *(uint8_t *)env->cur_ip++;
+ env->regs.eip++;
+
+ calc8[index](env, dst, imm);
+ return;
+}
+
+void calc_rm_imm(BiosEmuEnvironment *env, CalcIndex index) {
+ uint8_t modrm = *(uint8_t *)env->cur_ip++;
+ env->regs.eip++;
+
+ if (env->flags.operand_size == 0) {
+ uint16_t *dst = RM_ADDR(env, modrm);
+ uint16_t imm = *(uint16_t *)env->cur_ip;
+ env->cur_ip += 2;
+ env->regs.eip += 2;
+
+ calc16[index](env, dst, imm);
+ } else {
+ uint32_t *dst = RM_ADDR(env, modrm);
+ uint32_t imm = *(uint32_t *)env->cur_ip;
+ env->cur_ip += 4;
+ env->regs.eip += 4;
+
+ calc32[index](env, dst, imm);
+ }
+ return;
+}
+
+void calc_rm_imm8(BiosEmuEnvironment *env, CalcIndex index) {
+ uint8_t modrm = *(uint8_t *)env->cur_ip++;
+ env->regs.eip++;
+
+ if (env->flags.operand_size == 0) {
+ uint16_t *dst = RM_ADDR(env, modrm);
+ uint8_t imm = *(uint8_t *)env->cur_ip;
+ env->cur_ip++;
+ env->regs.eip++;
+
+ calc16[index](env, dst, (uint16_t)imm);
+ } else {
+ uint32_t *dst = RM_ADDR(env, modrm);
+ uint8_t imm = *(uint8_t *)env->cur_ip;
+ env->cur_ip++;
+ env->regs.eip++;
+
+ calc32[index](env, dst, (uint32_t)imm);
+ }
+ return;
+}
+
+void calc_rm_r_8(BiosEmuEnvironment *env, CalcIndex index) {
+ uint8_t modrm = *(uint8_t *)env->cur_ip++;
+ env->regs.eip++;
+ uint8_t reg = (modrm >> 3) & 0b111;
+
+ uint8_t *dst = RM_ADDR(env, modrm);
+ uint8_t *src = env->reg_lut_r8[reg];
+
+ calc8[index](env, dst, *src);
+ return;
+}
+
+void calc_rm_r(BiosEmuEnvironment *env, CalcIndex index) {
+ uint8_t modrm = *(uint8_t *)env->cur_ip++;
+ env->regs.eip++;
+ uint8_t reg = (modrm >> 3) & 0b111;
+
+ if (env->flags.operand_size == 0) {
+ uint16_t *dst = RM_ADDR(env, modrm);
+ uint16_t *src = env->reg_lut_r16[reg];
+
+ calc16[index](env, dst, *src);
+ } else {
+ uint32_t *dst = RM_ADDR(env, modrm);
+ uint32_t *src = env->reg_lut_r32[reg];
+
+ calc32[index](env, dst, *src);
+ }
+ return;
+}
+void calc_r_rm_8(BiosEmuEnvironment *env, CalcIndex index) {
+ uint8_t modrm = *(uint8_t *)env->cur_ip++;
+ env->regs.eip++;
+ uint8_t reg = (modrm >> 3) & 0b111;
+
+ uint8_t *dst = env->reg_lut_r8[reg];
+ uint8_t *src = RM_ADDR(env, modrm);
+
+ calc8[index](env, dst, *src);
+ return;
+}
+
+void calc_r_rm(BiosEmuEnvironment *env, CalcIndex index) {
+ uint8_t modrm = *(uint8_t *)env->cur_ip++;
+ env->regs.eip++;
+ uint8_t reg = (modrm >> 3) & 0b111;
+
+ if (env->flags.operand_size == 0) {
+ uint16_t *dst = env->reg_lut_r16[reg];
+ uint16_t *src = RM_ADDR(env, modrm);
+
+ calc16[index](env, dst, *src);
+ } else {
+ uint32_t *dst = env->reg_lut_r32[reg];
+ uint32_t *src = RM_ADDR(env, modrm);
+
+ calc32[index](env, dst, *src);
+ }
+ return;
+}
+
+void decode_inc_r(BiosEmuEnvironment *env, uint8_t opcode) {
+ if (env->flags.operand_size == 0) {
+ uint16_t *dst = PLUS_RW_REG(env, opcode);
+ int overflow = __builtin_add_overflow(*dst, 1, dst);
+ SET_OVERFLOW_FLAG(overflow);
+ set_zf_pf(env, *dst);
+ } else {
+ uint32_t *dst = PLUS_RD_REG(env, opcode);
+ __builtin_add_overflow(*dst, 1, dst);
+ int overflow = __builtin_add_overflow(*dst, 1, dst);
+ SET_OVERFLOW_FLAG(overflow);
+ set_zf_pf(env, *dst);
+ }
+ return;
+}
+
+void decode_dec_r(BiosEmuEnvironment *env, uint8_t opcode) {
+ if (env->flags.operand_size == 0) {
+ uint16_t *dst = PLUS_RW_REG(env, opcode);
+ int overflow = __builtin_sub_overflow(*dst, 1, dst);
+ SET_OVERFLOW_FLAG(overflow);
+ set_zf_pf(env, *dst);
+ } else {
+ uint32_t *dst = PLUS_RD_REG(env, opcode);
+ int overflow = __builtin_sub_overflow(*dst, 1, dst);
+ SET_OVERFLOW_FLAG(overflow);
+ set_zf_pf(env, *dst);
+ }
+ return;
+}
+
+void decode_inc_rm(BiosEmuEnvironment *env) {
+ uint8_t modrm = *(uint8_t *)env->cur_ip++;
+ env->regs.eip++;
+ uint8_t mod = modrm >> 6;
+
+ if (mod == 0b11) {
+ uint8_t reg = modrm & 0b111;
+ if (env->flags.operand_size == 0) {
+ uint16_t *dst = env->reg_lut_r16[reg];
+ int overflow = __builtin_add_overflow(*dst, 1, dst);
+ SET_OVERFLOW_FLAG(overflow);
+ set_zf_pf(env, *dst);
+ } else {
+ uint32_t *dst = env->reg_lut_r32[reg];
+ int overflow = __builtin_add_overflow(*dst, 1, dst);
+ SET_OVERFLOW_FLAG(overflow);
+ set_zf_pf(env, *dst);
+ }
+ return;
+ } else {
+ if (env->flags.operand_size == 0) {
+ uint16_t *dst = RM_ADDR16(env, modrm);
+ int overflow = __builtin_add_overflow(*dst, 1, dst);
+ SET_OVERFLOW_FLAG(overflow);
+ set_zf_pf(env, *dst);
+ } else {
+ uint32_t *dst = RM_ADDR32(env, modrm);
+ int overflow = __builtin_add_overflow(*dst, 1, dst);
+ SET_OVERFLOW_FLAG(overflow);
+ set_zf_pf(env, *dst);
+ }
+ }
+ return;
+}
+
+void decode_dec_rm(BiosEmuEnvironment *env) {
+ uint8_t modrm = *(uint8_t *)env->cur_ip++;
+ env->regs.eip++;
+ uint8_t mod = modrm >> 6;
+
+ if (mod == 0b11) {
+ uint8_t reg = modrm & 0b111;
+ if (env->flags.operand_size == 0) {
+ uint16_t *dst = env->reg_lut_r16[reg];
+ int overflow = __builtin_sub_overflow(*dst, 1, dst);
+ SET_OVERFLOW_FLAG(overflow);
+ set_zf_pf(env, *dst);
+ } else {
+ uint32_t *dst = env->reg_lut_r32[reg];
+ int overflow = __builtin_sub_overflow(*dst, 1, dst);
+ SET_OVERFLOW_FLAG(overflow);
+ set_zf_pf(env, *dst);
+ }
+ return;
+ } else {
+ if (env->flags.operand_size == 0) {
+ uint16_t *dst = RM_ADDR16(env, modrm);
+ int overflow = __builtin_sub_overflow(*dst, 1, dst);
+ SET_OVERFLOW_FLAG(overflow);
+ set_zf_pf(env, *dst);
+ } else {
+ uint32_t *dst = RM_ADDR32(env, modrm);
+ int overflow = __builtin_sub_overflow(*dst, 1, dst);
+ SET_OVERFLOW_FLAG(overflow);
+ set_zf_pf(env, *dst);
+ }
+ }
+ return;
+}
+
+void decode_inc_rm8(BiosEmuEnvironment *env) {
+ uint8_t modrm = *(uint8_t *)env->cur_ip++;
+ env->regs.eip++;
+ uint8_t mod = modrm >> 6;
+
+ if (mod == 0b11) {
+ uint8_t reg = modrm & 0b111;
+ uint8_t *dst = env->reg_lut_r8[reg];
+ int overflow = __builtin_add_overflow(*dst, 1, dst);
+ SET_OVERFLOW_FLAG(overflow);
+ set_zf_pf(env, *dst);
+ } else {
+ uint8_t *dst = RM_ADDR(env, modrm);
+ int overflow = __builtin_add_overflow(*dst, 1, dst);
+ SET_OVERFLOW_FLAG(overflow);
+ set_zf_pf(env, *dst);
+ }
+ return;
+}
+
+void decode_dec_rm8(BiosEmuEnvironment *env) {
+ uint8_t modrm = *(uint8_t *)env->cur_ip++;
+ env->regs.eip++;
+ uint8_t mod = modrm >> 6;
+
+ if (mod == 0b11) {
+ uint8_t reg = modrm & 0b111;
+ uint8_t *dst = env->reg_lut_r8[reg];
+ int overflow = __builtin_sub_overflow(*dst, 1, dst);
+ SET_OVERFLOW_FLAG(overflow);
+ set_zf_pf(env, *dst);
+ } else {
+ uint8_t *dst = RM_ADDR(env, modrm);
+ int overflow = __builtin_sub_overflow(*dst, 1, dst);
+ SET_OVERFLOW_FLAG(overflow);
+ set_zf_pf(env, *dst);
+ }
+ return;
+}
+
+void decode_aaa(BiosEmuEnvironment *env) {
+ if (env->regs.al > 0x9f || env->regs.flags & BIT(AuxiliaryCarryFlagBit)) {
+ env->regs.ax += 0x106;
+ SET_FLAG(1, AuxiliaryCarryFlagBit);
+ } else {
+ SET_FLAG(0, AuxiliaryCarryFlagBit);
+ }
+ return;
+}
+
+void decode_aad(BiosEmuEnvironment *env) {
+ uint8_t base = *(uint8_t *)env->cur_ip++;
+ env->regs.eip++;
+ env->regs.al = (env->regs.al + (env->regs.ah * base)) & 0xff;
+ env->regs.ah = 0;
+
+ SIGN_FLAG8(env->regs.al);
+ SET_FLAG(env->regs.al == 0, ZeroFlagBit);
+ SET_FLAG(calc_parity(env->regs.al), ParityFlagBit);
+ return;
+}
+
+void decode_aam(BiosEmuEnvironment *env) {
+ uint8_t base = *(uint8_t *)env->cur_ip++;
+ env->regs.eip++;
+ env->regs.ah = env->regs.al / base;
+ env->regs.al = env->regs.al % base;
+
+ SIGN_FLAG8(env->regs.al);
+ SET_FLAG(env->regs.al == 0, ZeroFlagBit);
+ SET_FLAG(calc_parity(env->regs.al), ParityFlagBit);
+ return;
+}
+
+void decode_aas(BiosEmuEnvironment *env) {
+ if (env->regs.al > 0x0f || env->regs.flags & BIT(AuxiliaryCarryFlagBit)) {
+ env->regs.al -= 6;
+ env->regs.ah -= 1;
+ env->regs.al &= 0x0f;
+ env->regs.flags |= BIT(AuxiliaryCarryFlagBit) | BIT(CarryFlagBit);
+ } else {
+ env->regs.flags &= ~(BIT(AuxiliaryCarryFlagBit) | BIT(CarryFlagBit));
+ env->regs.al &= 0x0f;
+ }
+ return;
+}
+
+void decode_daa(BiosEmuEnvironment *env) {
+ uint8_t old_al = env->regs.al;
+ uint8_t old_cf = env->regs.flags & BIT(CarryFlagBit);
+ SET_CARRY_FLAG(0);
+ if ((env->regs.al & 0x0f) > 9 ||
+ env->regs.flags & BIT(AuxiliaryCarryFlagBit)) {
+ env->regs.al += 0x06;
+
+ env->regs.flags |= old_cf | BIT(AuxiliaryCarryFlagBit);
+ /* (uint8_t)~6 == 255 - 6*/
+ /* old_al > 255 - 6 => old_al + 6 > 255 */
+ (old_al > (uint8_t)~6) ? (env->regs.flags |= BIT(CarryFlagBit))
+ : (env->regs.flags &= ~BIT(CarryFlagBit));
+ } else {
+ SET_FLAG(0, AuxiliaryCarryFlagBit);
+ }
+ if (env->regs.al > 0x99 || old_cf) {
+ env->regs.al += 0x60;
+ SET_CARRY_FLAG(1);
+ } else {
+ SET_CARRY_FLAG(0);
+ }
+ return;
+}
+
+void decode_das(BiosEmuEnvironment *env) {
+ uint8_t old_al = env->regs.al;
+ uint8_t old_cf = env->regs.flags & BIT(CarryFlagBit);
+ SET_CARRY_FLAG(0);
+ if ((env->regs.al & 0x0f) > 9 ||
+ env->regs.flags & BIT(AuxiliaryCarryFlagBit)) {
+ env->regs.al -= 0x06;
+
+ env->regs.flags |= old_cf | BIT(AuxiliaryCarryFlagBit);
+ (old_al < (uint8_t)-6) ? (env->regs.flags |= BIT(CarryFlagBit))
+ : (env->regs.flags &= ~BIT(CarryFlagBit));
+ } else {
+ SET_FLAG(0, AuxiliaryCarryFlagBit);
+ }
+ if (env->regs.al > 0x99 || old_cf) {
+ env->regs.al -= 0x60;
+ SET_CARRY_FLAG(1);
+ }
+}
+
+BiosEmuExceptions div_8(BiosEmuEnvironment *env, uint8_t value) {
+ if (value == 0) { return DivideError; }
+
+ uint16_t dividend = env->regs.ax;
+ uint8_t divisor = env->regs.al;
+
+ uint16_t temp1 = dividend / divisor;
+ uint16_t temp2 = dividend % divisor;
+
+ if (temp1 > 0xff) {
+ return DivideError;
+ } else {
+ env->regs.al = temp1;
+ env->regs.ah = temp2;
+ }
+ return NoException;
+}
+
+BiosEmuExceptions div_16(BiosEmuEnvironment *env, uint16_t value) {
+ if (value == 0) { return DivideError; }
+
+ uint32_t dividend = env->regs.dx << 16 | env->regs.ax;
+
+ uint32_t temp1 = dividend / value;
+ uint16_t temp2 = dividend % value;
+ if (temp1 > 0xffff) {
+ return DivideError;
+ } else {
+ env->regs.ax = temp1;
+ env->regs.dx = temp2;
+ }
+
+ return NoException;
+}
+
+void div_64_32(
+ uint64_t a, uint32_t b, uint64_t *quotient, uint32_t *remainder) {
+ int ans = 0;
+ uint64_t tmp = 0;
+ int max = 64;
+ if (b > a) {
+ *quotient = 0;
+ *remainder = a;
+ return;
+ }
+ for (int i = 0; i < 64; i++) {
+ int j = 0;
+ do {
+ tmp = b << j;
+ j++;
+ } while (tmp < a && j < max);
+ j--;
+ if (j == 0) break;
+ ans |= 1 << (j - 1);
+ a -= b << (j - 1);
+ }
+ *quotient = ans;
+ *remainder = a;
+}
+
+BiosEmuExceptions div_32(BiosEmuEnvironment *env, uint32_t value) {
+ if (value == 0) { return DivideError; }
+
+ uint64_t dividend = ((uint64_t)env->regs.edx << 32) | env->regs.eax;
+
+ uint64_t temp1;
+ uint32_t temp2;
+ div_64_32(dividend, value, &temp1, &temp2);
+ if (temp1 > 0xffffffff) {
+ return DivideError;
+ } else {
+ env->regs.eax = temp1;
+ env->regs.edx = temp2;
+ }
+
+ return NoException;
+}
+
+BiosEmuExceptions idiv_8(BiosEmuEnvironment *env, uint8_t value) {
+ if (value == 0) { return DivideError; }
+
+ uint16_t dividend = env->regs.ax;
+ uint8_t divisor = env->regs.al;
+
+ uint16_t temp1 = dividend / divisor;
+ uint16_t temp2 = dividend % divisor;
+
+ if (temp1 >> 7 && temp1 >> 7 != -1) {
+ return DivideError;
+ } else {
+ env->regs.al = temp1;
+ env->regs.ah = temp2;
+ }
+ return NoException;
+}
+
+BiosEmuExceptions idiv_16(BiosEmuEnvironment *env, uint16_t value) {
+ if (value == 0) { return DivideError; }
+
+ uint32_t dividend = env->regs.dx << 16 | env->regs.ax;
+
+ uint32_t temp1 = dividend / value;
+ uint16_t temp2 = dividend % value;
+ if (temp1 >> 15 && temp1 >> 15 != -1) {
+ return DivideError;
+ } else {
+ env->regs.ax = temp1;
+ env->regs.dx = temp2;
+ }
+
+ return NoException;
+}
+
+BiosEmuExceptions idiv_32(BiosEmuEnvironment *env, uint32_t value) {
+ if (value == 0) { return DivideError; }
+
+ uint64_t dividend = ((uint64_t)env->regs.edx << 32) | env->regs.eax;
+
+ uint64_t temp1;
+ uint32_t temp2;
+ div_64_32(dividend, value, &temp1, &temp2);
+ if (temp1 >> 31 && temp1 >> 31 != -1) {
+ return DivideError;
+ } else {
+ env->regs.eax = temp1;
+ env->regs.edx = temp2;
+ }
+
+ return NoException;
+}
+
+void mul_8(BiosEmuEnvironment *env, uint8_t value) {
+ uint16_t ans = env->regs.al * value;
+ env->regs.ax = ans;
+ SET_OVERFLOW_FLAG(ans >> 8);
+}
+
+void mul_16(BiosEmuEnvironment *env, uint16_t value) {
+ uint32_t ans = env->regs.ax * value;
+ env->regs.ax = ans & 0xffff;
+ env->regs.dx = ans >> 16;
+ SET_OVERFLOW_FLAG(ans >> 16);
+}
+
+void mul_32(BiosEmuEnvironment *env, uint32_t value) {
+ uint64_t ans = env->regs.eax * value;
+ env->regs.ax = ans & 0xffffffff;
+ env->regs.dx = ans >> 32;
+ SET_OVERFLOW_FLAG(ans >> 32);
+}
+
+void imul_8(BiosEmuEnvironment *env, uint8_t value) {
+ int16_t ans = (int16_t)(int8_t)env->regs.al * (int16_t)(int8_t)value;
+ env->regs.ax = ans;
+ SET_OVERFLOW_FLAG(ans >> 7 != 0 && ans >> 7 != -1);
+}
+
+void imul_16(
+ BiosEmuEnvironment *env, uint16_t *dst_hi, uint16_t *dst_lo, uint16_t src1,
+ uint16_t src2) {
+ int32_t ans = (int32_t)(int16_t)src1 * (int32_t)(int16_t)src2;
+ *dst_hi = ans >> 16;
+ *dst_lo = ans & 0xffff;
+ SET_OVERFLOW_FLAG(ans >> 15 != 0 && ans >> 15 != -1);
+}
+
+void imul_32(
+ BiosEmuEnvironment *env, uint32_t *dst_hi, uint32_t *dst_lo, uint32_t src1,
+ uint32_t src2) {
+ int64_t ans = (int64_t)(int32_t)src1 * (int64_t)(int32_t)src2;
+ *dst_hi = ans >> 32;
+ *dst_lo = ans & 0xffffffff;
+ SET_OVERFLOW_FLAG(ans >> 31 != 0 && ans >> 31 != -1);
+}
+
+void decode_imul_r_rm_imm8(BiosEmuEnvironment *env) {
+ uint8_t modrm = *(uint8_t *)env->cur_ip++;
+ env->regs.eip++;
+ uint8_t reg = (modrm >> 3) & 0b111;
+ uint8_t imm = *(uint8_t *)env->cur_ip;
+ env->cur_ip++;
+ env->regs.eip++;
+
+ if (env->flags.operand_size == 0) {
+ uint16_t tmp;
+ uint16_t *dst = env->reg_lut_r16[reg];
+ uint16_t *value = RM_ADDR(env, modrm);
+ imul_16(env, &tmp, dst, *value, imm);
+ } else {
+ uint32_t tmp;
+ uint32_t *dst = env->reg_lut_r32[reg];
+ uint32_t *value = RM_ADDR(env, modrm);
+ imul_32(env, &tmp, dst, *value, imm);
+ }
+ return;
+}
+
+void decode_imul_r_rm_imm16(BiosEmuEnvironment *env) {
+ uint8_t modrm = *(uint8_t *)env->cur_ip++;
+ env->regs.eip++;
+ uint8_t reg = (modrm >> 3) & 0b111;
+
+ if (env->flags.operand_size == 0) {
+ uint16_t tmp;
+ uint16_t *dst = env->reg_lut_r16[reg];
+ uint16_t *value = RM_ADDR(env, modrm);
+ uint16_t imm = *(uint16_t *)env->cur_ip;
+ env->cur_ip += 2;
+ env->regs.eip += 2;
+ imul_16(env, &tmp, dst, *value, imm);
+ } else {
+ uint32_t tmp;
+ uint32_t *dst = env->reg_lut_r32[reg];
+ uint32_t *value = RM_ADDR(env, modrm);
+ uint32_t imm = *(uint32_t *)env->cur_ip;
+ env->cur_ip += 4;
+ env->regs.eip += 4;
+ imul_32(env, &tmp, dst, *value, imm);
+ }
+ return;
+}
+
+void decode_imul_r_rm(BiosEmuEnvironment *env) {
+ uint8_t modrm = *(uint8_t *)env->cur_ip++;
+ env->regs.eip++;
+ uint8_t reg = (modrm >> 3) & 0b111;
+
+ if (env->flags.operand_size == 0) {
+ uint16_t tmp;
+ uint16_t *dst = env->reg_lut_r16[reg];
+ uint16_t *value = RM_ADDR(env, modrm);
+ imul_16(env, &tmp, dst, *dst, *value);
+ } else {
+ uint32_t tmp;
+ uint32_t *dst = env->reg_lut_r32[reg];
+ uint32_t *value = RM_ADDR(env, modrm);
+ imul_32(env, &tmp, dst, *dst, *value);
+ }
+ return;
+}
+
+void neg_8(BiosEmuEnvironment *env, uint8_t *value) {
+ int8_t ans = 0 - *value;
+ SET_CARRY_FLAG(ans == 0);
+ *value = ans;
+ return;
+}
+
+void neg_16(BiosEmuEnvironment *env, uint16_t *value) {
+ int16_t ans = 0 - (int16_t)*value;
+ SET_CARRY_FLAG(ans == 0);
+ *value = ans;
+ return;
+}
+
+void neg_32(BiosEmuEnvironment *env, uint32_t *value) {
+ int32_t ans = 0 - (int32_t)*value;
+ SET_CARRY_FLAG(ans == 0);
+ *value = ans;
+ return;
+}
+
+void rcl_8(BiosEmuEnvironment *env, uint8_t *value, uint8_t count) {
+ uint8_t temp_count = (count & 0x1f) % 9;
+ if (temp_count == 0) return;
+
+ uint8_t old_carry = (env->regs.flags >> CarryFlagBit) & 1;
+ uint8_t new_carry = (*value >> (8 - temp_count)) & 1;
+ uint8_t ans = (*value << temp_count) | (old_carry << (temp_count - 1));
+
+ ans |= (*value >> (8 - temp_count + 1));
+
+ SET_CARRY_FLAG(new_carry);
+ if ((count & 0x1f) == 1) SET_OVERFLOW_FLAG((ans >> 7) ^ new_carry);
+ *value = ans;
+ return;
+}
+
+void rcl_16(BiosEmuEnvironment *env, uint16_t *value, uint8_t count) {
+ uint8_t temp_count = (count & 0x1f) % 17;
+ if (temp_count == 0) return;
+
+ uint8_t old_carry = (env->regs.flags >> CarryFlagBit) & 1;
+ uint8_t new_carry = (*value >> (16 - temp_count)) & 1;
+ uint16_t ans =
+ ((*value << temp_count) & 0xff) | (old_carry << (temp_count - 1));
+
+ ans |= (*value >> (16 - temp_count + 1));
+
+ SET_CARRY_FLAG(new_carry);
+ if ((count & 0x1f) == 1) SET_OVERFLOW_FLAG((ans >> 15) ^ new_carry);
+ *value = ans;
+ return;
+}
+
+void rcl_32(BiosEmuEnvironment *env, uint32_t *value, uint8_t count) {
+ uint8_t temp_count = (count & 0x1f) % 33;
+ if (temp_count == 0) return;
+
+ uint8_t old_carry = (env->regs.flags >> CarryFlagBit) & 1;
+ uint8_t new_carry = (*value >> (32 - temp_count)) & 1;
+ uint32_t ans =
+ ((*value << temp_count) & 0xff) | (old_carry << (temp_count - 1));
+
+ ans |= (*value >> (32 - temp_count + 1));
+
+ SET_CARRY_FLAG(new_carry);
+ if ((count & 0x1f) == 1) SET_OVERFLOW_FLAG((ans >> 31) ^ new_carry);
+ *value = ans;
+ return;
+}
+
+void rcr_8(BiosEmuEnvironment *env, uint8_t *value, uint8_t count) {
+ uint8_t temp_count = (count & 0x1f) % 9;
+ if (temp_count == 0) return;
+
+ uint8_t old_carry = (env->regs.flags >> CarryFlagBit) & 1;
+ uint8_t new_carry = (*value >> (temp_count - 1)) & 1;
+ uint8_t ans = (*value >> temp_count) | (old_carry << (8 - temp_count));
+
+ ans |= (*value << (8 - temp_count + 1));
+
+ SET_CARRY_FLAG(new_carry);
+ if ((*value & 0x1f) == 1) SET_OVERFLOW_FLAG((ans >> 7) ^ old_carry);
+ *value = ans;
+ return;
+}
+
+void rcr_16(BiosEmuEnvironment *env, uint16_t *value, uint8_t count) {
+ uint8_t temp_count = (count & 0x1f) % 17;
+ if (temp_count == 0) return;
+
+ uint8_t old_carry = (env->regs.flags >> CarryFlagBit) & 1;
+ uint8_t new_carry = (*value >> (temp_count - 1)) & 1;
+ uint16_t ans = (*value >> temp_count) | (old_carry << (16 - temp_count));
+
+ ans |= (*value << (16 - temp_count + 1));
+
+ SET_CARRY_FLAG(new_carry);
+ if ((*value & 0x1f) == 1) SET_OVERFLOW_FLAG((ans >> 15) ^ old_carry);
+ *value = ans;
+ return;
+}
+
+void rcr_32(BiosEmuEnvironment *env, uint32_t *value, uint8_t count) {
+ uint8_t temp_count = (count & 0x1f) % 33;
+ if (temp_count == 0) return;
+
+ uint8_t old_carry = (env->regs.flags >> CarryFlagBit) & 1;
+ uint8_t new_carry = (*value >> (temp_count - 1)) & 1;
+ uint32_t ans = (*value >> temp_count) | (old_carry << (32 - temp_count));
+
+ ans |= (*value << (32 - temp_count + 1));
+
+ SET_CARRY_FLAG(new_carry);
+ if ((*value & 0x1f) == 1) SET_OVERFLOW_FLAG((ans >> 31) ^ old_carry);
+ *value = ans;
+ return;
+}
+
+void rol_8(BiosEmuEnvironment *env, uint8_t *value, uint8_t count) {
+ uint8_t temp_count = (count & 0x1f) % 9;
+ if (temp_count == 0) return;
+
+ uint8_t ans = (*value << temp_count) | (*value >> (8 - temp_count));
+
+ if (ans & 0x1f) {
+ SET_CARRY_FLAG(ans & 1);
+ if ((ans & 0x1f) == 1) SET_OVERFLOW_FLAG((ans >> 7) ^ (ans & 1));
+ }
+ *value = ans;
+ return;
+}
+
+void rol_16(BiosEmuEnvironment *env, uint16_t *value, uint8_t count) {
+ uint8_t temp_count = (count & 0x1f) % 17;
+ if (temp_count == 0) return;
+
+ uint16_t ans = (*value << temp_count) | (*value >> (16 - temp_count));
+
+ if (ans & 0x1f) {
+ SET_CARRY_FLAG(ans & 1);
+ if ((ans & 0x1f) == 1) SET_OVERFLOW_FLAG((ans >> 15) ^ (ans & 1));
+ }
+ *value = ans;
+ return;
+}
+
+void rol_32(BiosEmuEnvironment *env, uint32_t *value, uint8_t count) {
+ uint8_t temp_count = (count & 0x1f) % 17;
+ if (temp_count == 0) return;
+
+ uint32_t ans = (*value << temp_count) | (*value >> (32 - temp_count));
+
+ if (ans & 0x1f) {
+ SET_CARRY_FLAG(ans & 1);
+ if ((ans & 0x1f) == 1) SET_OVERFLOW_FLAG((ans >> 31) ^ (ans & 1));
+ }
+ *value = ans;
+ return;
+}
+
+void ror_8(BiosEmuEnvironment *env, uint8_t *value, uint8_t count) {
+ uint8_t temp_count = (count & 0x1f) % 9;
+ if (temp_count == 0) return;
+
+ uint8_t ans = (*value >> temp_count) | (*value << (8 - temp_count));
+
+ uint8_t msb = ans >> 7;
+ if (ans & 0x1f) {
+ SET_CARRY_FLAG(msb);
+ if ((ans & 0x1f) == 1) SET_OVERFLOW_FLAG(msb ^ (ans >> 6));
+ }
+ *value = ans;
+ return;
+}
+
+void ror_16(BiosEmuEnvironment *env, uint16_t *value, uint8_t count) {
+ uint8_t temp_count = (count & 0x1f) % 17;
+ if (temp_count == 0) return;
+
+ uint16_t ans = (*value >> temp_count) | (*value << (16 - temp_count));
+
+ uint8_t msb = ans >> 15;
+ if (ans & 0x1f) {
+ SET_CARRY_FLAG(msb);
+ if ((ans & 0x1f) == 1) SET_OVERFLOW_FLAG(msb ^ (ans >> 14));
+ }
+ *value = ans;
+ return;
+}
+
+void ror_32(BiosEmuEnvironment *env, uint32_t *value, uint8_t count) {
+ uint8_t temp_count = (count & 0x1f) % 17;
+ if (temp_count == 0) return;
+
+ uint32_t ans = (*value >> temp_count) | (*value << (32 - temp_count));
+
+ uint8_t msb = ans >> 31;
+ if (ans & 0x1f) {
+ SET_CARRY_FLAG(msb);
+ if ((ans & 0x1f) == 1) SET_OVERFLOW_FLAG(msb ^ (ans >> 30));
+ }
+ *value = ans;
+ return;
+}
+
+void shl_sal_8(BiosEmuEnvironment *env, uint8_t *value, uint8_t count) {
+ uint8_t temp_count = (count & 0x1f) % 9;
+ if (temp_count == 0) return;
+
+ uint8_t ans = (*value << temp_count);
+
+ uint8_t carry = (*value >> (8 - temp_count)) & 1;
+ SET_CARRY_FLAG(carry);
+ if ((count & 0x1f) == 1) SET_OVERFLOW_FLAG((ans >> 7) ^ carry);
+ *value = ans;
+ return;
+}
+
+void shl_sal_16(BiosEmuEnvironment *env, uint16_t *value, uint8_t count) {
+ uint8_t temp_count = (count & 0x1f) % 17;
+ if (temp_count == 0) return;
+
+ uint16_t ans = (*value << temp_count);
+
+ uint8_t carry = (*value >> (16 - temp_count)) & 1;
+ SET_CARRY_FLAG(carry);
+ if ((count & 0x1f) == 1) SET_OVERFLOW_FLAG((ans >> 15) ^ carry);
+ *value = ans;
+ return;
+}
+
+void shl_sal_32(BiosEmuEnvironment *env, uint32_t *value, uint8_t count) {
+ uint8_t temp_count = (count & 0x1f) % 33;
+ if (temp_count == 0) return;
+
+ uint16_t ans = (*value << temp_count);
+
+ uint8_t carry = (*value >> (32 - temp_count)) & 1;
+ SET_CARRY_FLAG(carry);
+ if ((count & 0x1f) == 1) SET_OVERFLOW_FLAG((ans >> 31) ^ carry);
+ *value = ans;
+ return;
+}
+
+void shr_8(BiosEmuEnvironment *env, uint8_t *value, uint8_t count) {
+ uint8_t temp_count = (count & 0x1f) % 9;
+ if (temp_count == 0) return;
+
+ uint8_t ans = (*value >> temp_count);
+
+ uint8_t carry = (*value >> (temp_count - 1)) & 1;
+ SET_CARRY_FLAG(carry);
+ if ((count & 0x1f) == 1) SET_OVERFLOW_FLAG(*value >> 7);
+ *value = ans;
+ return;
+}
+
+void shr_16(BiosEmuEnvironment *env, uint16_t *value, uint8_t count) {
+ uint8_t temp_count = (count & 0x1f) % 17;
+ if (temp_count == 0) return;
+
+ uint16_t ans = (*value >> temp_count);
+
+ uint8_t carry = (*value >> (temp_count - 1)) & 1;
+ SET_CARRY_FLAG(carry);
+ if ((count & 0x1f) == 1) SET_OVERFLOW_FLAG(*value >> 15);
+ *value = ans;
+ return;
+}
+
+void shr_32(BiosEmuEnvironment *env, uint32_t *value, uint8_t count) {
+ uint8_t temp_count = (count & 0x1f) % 33;
+ if (temp_count == 0) return;
+
+ uint32_t ans = (*value >> temp_count);
+
+ uint8_t carry = (*value >> (temp_count - 1)) & 1;
+ SET_CARRY_FLAG(carry);
+ if ((count & 0x1f) == 1) SET_OVERFLOW_FLAG(*value >> 31);
+ *value = ans;
+ return;
+}
+
+void sar_8(BiosEmuEnvironment *env, uint8_t *value, uint8_t count) {
+ uint8_t temp_count = (count & 0x1f) % 9;
+ if (temp_count == 0) return;
+
+ uint8_t ans = ((int8_t)*value >> temp_count);
+
+ uint8_t carry = ((int8_t)*value >> (temp_count - 1)) & 1;
+ SET_CARRY_FLAG(carry);
+ if ((count & 0x1f) == 1) SET_OVERFLOW_FLAG(0);
+ *value = ans;
+ return;
+}
+
+void sar_16(BiosEmuEnvironment *env, uint16_t *value, uint8_t count) {
+ uint8_t temp_count = (count & 0x1f) % 17;
+ if (temp_count == 0) return;
+
+ uint16_t ans = ((int16_t)*value >> temp_count);
+
+ uint8_t carry = ((int16_t)*value >> (temp_count - 1)) & 1;
+ SET_CARRY_FLAG(carry);
+ if ((count & 0x1f) == 1) SET_OVERFLOW_FLAG(0);
+ *value = ans;
+ return;
+}
+
+void sar_32(BiosEmuEnvironment *env, uint32_t *value, uint8_t count) {
+ uint8_t temp_count = (count & 0x1f) % 33;
+ if (temp_count == 0) return;
+
+ uint32_t ans = ((int32_t)*value >> temp_count);
+
+ uint8_t carry = ((int32_t)*value >> (temp_count - 1)) & 1;
+ SET_CARRY_FLAG(carry);
+ if ((count & 0x1f) == 1) SET_OVERFLOW_FLAG(0);
+ *value = ans;
+ return;
+}
+
+BiosEmuExceptions shld_16_16_8(
+ BiosEmuEnvironment *env, uint16_t *dest, uint16_t reg, uint8_t count) {
+ uint8_t temp_count = count % 32;
+ if (temp_count == 0 || count > 16) return NoException;
+
+ uint16_t ans = (*dest << temp_count) | (reg >> (16 - temp_count));
+
+ uint8_t carry = (reg >> (16 - temp_count)) & 1;
+ SET_CARRY_FLAG(carry);
+ set_zf_pf(env, ans);
+ *dest = ans;
+ return NoException;
+}
+
+BiosEmuExceptions shld_32_32_8(
+ BiosEmuEnvironment *env, uint32_t *dest, uint32_t reg, uint8_t count) {
+ uint8_t temp_count = count % 32;
+ if (temp_count == 0 || count > 32) return NoException;
+
+ uint32_t ans = (*dest << temp_count) | (reg >> (32 - temp_count));
+
+ uint8_t carry = (reg >> (32 - temp_count)) & 1;
+ SET_CARRY_FLAG(carry);
+ set_zf_pf(env, ans);
+ *dest = ans;
+ return NoException;
+}
+
+BiosEmuExceptions shrd_16_16_8(
+ BiosEmuEnvironment *env, uint16_t *dest, uint16_t reg, uint8_t count) {
+ uint8_t temp_count = count % 32;
+ if (temp_count == 0 || count > 16) return NoException;
+
+ uint16_t ans = (*dest >> temp_count) | (reg << (16 - temp_count));
+
+ uint8_t carry = (reg >> (temp_count - 1)) & 1;
+ SET_CARRY_FLAG(carry);
+ set_zf_pf(env, ans);
+ *dest = ans;
+ return NoException;
+}
+
+BiosEmuExceptions shrd_32_32_8(
+ BiosEmuEnvironment *env, uint32_t *dest, uint32_t reg, uint8_t count) {
+ uint8_t temp_count = count % 32;
+ if (temp_count == 0 || count > 32) return NoException;
+
+ uint32_t ans = (*dest >> temp_count) | (reg << (32 - temp_count));
+
+ uint8_t carry = (reg >> (temp_count - 1)) & 1;
+ SET_CARRY_FLAG(carry);
+ set_zf_pf(env, ans);
+ *dest = ans;
+ return NoException;
+}
+
+void cmps_8(
+ BiosEmuEnvironment *env, void *dst, int delta_dst, void *src, int delta_src,
+ int repeat_times) {
+ int condition = 1;
+ int i;
+ for (i = repeat_times; i > 0 && condition; i--) {
+ cmp_8(env, dst, *(uint8_t *)src);
+
+ dst += delta_dst;
+ src += delta_src;
+ condition =
+ ((env->regs.flags >> ZeroFlagBit) & 1) == env->flags.rep_e_ne;
+ }
+ env->regs.cx = (env->flags.repeat) ? i : env->regs.cx;
+}
+
+void cmps_16(
+ BiosEmuEnvironment *env, void *dst, int delta_dst, void *src, int delta_src,
+ int repeat_times) {
+ int condition = 1;
+ int i;
+ for (i = repeat_times; i > 0 && condition; i--) {
+ cmp_32(env, dst, *(uint16_t *)src);
+
+ dst += delta_dst;
+ src += delta_src;
+ condition =
+ ((env->regs.flags >> ZeroFlagBit) & 1) == env->flags.rep_e_ne;
+ }
+ env->regs.cx = (env->flags.repeat) ? i : env->regs.cx;
+}
+
+void cmps_32(
+ BiosEmuEnvironment *env, void *dst, int delta_dst, void *src, int delta_src,
+ int repeat_times) {
+ int condition = 1;
+ int i;
+ for (i = repeat_times; i > 0 && condition; i--) {
+ cmp_32(env, dst, *(uint32_t *)src);
+
+ dst += delta_dst;
+ src += delta_src;
+ condition =
+ ((env->regs.flags >> ZeroFlagBit) & 1) == env->flags.rep_e_ne;
+ }
+ env->regs.ecx = (env->flags.repeat) ? i : env->regs.ecx;
+}
diff --git a/src/arch/x86/bios_emu/ops/bt.c b/src/arch/x86/bios_emu/ops/bt.c
new file mode 100644
index 0000000..9bf28cd
--- /dev/null
+++ b/src/arch/x86/bios_emu/ops/bt.c
@@ -0,0 +1,76 @@
+#include "../includes/flags.h"
+#include
+#include
+#include
+#include
+#include
+
+BiosEmuExceptions bt_16_16(
+ BiosEmuEnvironment *env, uint16_t *addr, uint16_t *bit) {
+ uint16_t mask = 1 << (*bit & 0x0f);
+ env->regs.flags &= ~BIT(CarryFlagBit);
+ if (*addr & mask) { env->regs.flags |= BIT(CarryFlagBit); }
+ return NoException;
+}
+
+BiosEmuExceptions bt_32_32(
+ BiosEmuEnvironment *env, uint32_t *addr, uint32_t *bit) {
+ uint32_t mask = 1 << (*bit & 0x1f);
+ env->regs.flags &= ~BIT(CarryFlagBit);
+ if (*addr & mask) { env->regs.flags |= BIT(CarryFlagBit); }
+ return NoException;
+}
+
+BiosEmuExceptions btc_16_16(
+ BiosEmuEnvironment *env, uint16_t *addr, uint16_t *bit) {
+ uint16_t mask = 1 << (*bit & 0x0f);
+ env->regs.flags &= ~BIT(CarryFlagBit);
+ if (*addr & mask) { env->regs.flags |= BIT(CarryFlagBit); }
+ *addr ^= mask;
+ return NoException;
+}
+
+BiosEmuExceptions btc_32_32(
+ BiosEmuEnvironment *env, uint32_t *addr, uint32_t *bit) {
+ uint32_t mask = 1 << (*bit & 0x1f);
+ env->regs.flags &= ~BIT(CarryFlagBit);
+ if (*addr & mask) { env->regs.flags |= BIT(CarryFlagBit); }
+ *addr ^= mask;
+ return NoException;
+}
+
+BiosEmuExceptions btr_16_16(
+ BiosEmuEnvironment *env, uint16_t *addr, uint16_t *bit) {
+ uint16_t mask = 1 << (*bit & 0x0f);
+ env->regs.flags &= ~BIT(CarryFlagBit);
+ if (*addr & mask) { env->regs.flags |= BIT(CarryFlagBit); }
+ *addr &= ~mask;
+ return NoException;
+}
+
+BiosEmuExceptions btr_32_32(
+ BiosEmuEnvironment *env, uint32_t *addr, uint32_t *bit) {
+ uint32_t mask = 1 << (*bit & 0x1f);
+ env->regs.flags &= ~BIT(CarryFlagBit);
+ if (*addr & mask) { env->regs.flags |= BIT(CarryFlagBit); }
+ *addr &= ~mask;
+ return NoException;
+}
+
+BiosEmuExceptions bts_16_16(
+ BiosEmuEnvironment *env, uint16_t *addr, uint16_t *bit) {
+ uint16_t mask = 1 << (*bit & 0x0f);
+ env->regs.flags &= ~BIT(CarryFlagBit);
+ if (*addr & mask) { env->regs.flags |= BIT(CarryFlagBit); }
+ *addr |= mask;
+ return NoException;
+}
+
+BiosEmuExceptions bts_32_32(
+ BiosEmuEnvironment *env, uint32_t *addr, uint32_t *bit) {
+ uint32_t mask = 1 << (*bit & 0x1f);
+ env->regs.flags &= ~BIT(CarryFlagBit);
+ if (*addr & mask) { env->regs.flags |= BIT(CarryFlagBit); }
+ *addr |= mask;
+ return NoException;
+}
diff --git a/src/arch/x86/bios_emu/ops/call.c b/src/arch/x86/bios_emu/ops/call.c
new file mode 100644
index 0000000..a1306b7
--- /dev/null
+++ b/src/arch/x86/bios_emu/ops/call.c
@@ -0,0 +1,216 @@
+#include "../includes/operations.h"
+#include "../includes/stack.h"
+#include
+#include
+#include
+
+BiosEmuExceptions decode_call_near(BiosEmuEnvironment *env, uint32_t address) {
+ if (env->flags.operand_size == 0) {
+ if (!ptr_within_code_segment_limit(env, address))
+ return GeneralProtection;
+ if (env->flags.stack_size == 0) {
+ if (STACK_POINTER16(env) < env->stack_bottom + 2) {
+ return StackFault;
+ }
+ } else {
+ if (STACK_POINTER32(env) < env->stack_bottom + 2) {
+ return StackFault;
+ }
+ }
+ PUSH(env, env->regs.ip, 2);
+ env->cur_ip = (void *)((env->regs.cs << 4) + address);
+ env->regs.eip = address;
+ } else {
+ if (!ptr_within_code_segment_limit(env, address))
+ return GeneralProtection;
+ if (env->flags.stack_size == 0) {
+ if (STACK_POINTER16(env) < env->stack_bottom + 4) {
+ return StackFault;
+ }
+ } else {
+ if (STACK_POINTER32(env) < env->stack_bottom + 4) {
+ return StackFault;
+ }
+ }
+ PUSH(env, env->regs.eip, 4);
+ env->cur_ip = (void *)address;
+ env->regs.eip = address;
+ }
+ return NoException;
+}
+
+BiosEmuExceptions decode_call(BiosEmuEnvironment *env) {
+ if (env->flags.operand_size == 0) {
+ uint16_t offset = *(uint16_t *)env->cur_ip;
+ env->cur_ip += 2;
+ env->regs.eip += 2;
+ env->regs.eip &= 0xffff;
+ env->cur_ip = (void *)((env->regs.cs << 4) + env->regs.eip);
+ return decode_call_near(env, (env->regs.eip + offset) & 0xffff);
+ } else {
+ uint32_t offset = *(uint32_t *)env->cur_ip;
+ env->cur_ip += 4;
+ env->regs.eip += 4;
+ return decode_call_near(env, env->regs.eip + offset);
+ }
+}
+
+BiosEmuExceptions decode_call_far(
+ BiosEmuEnvironment *env, uint16_t segment, uint32_t offset) {
+ if (env->flags.operand_size == 0) {
+ if (env->flags.stack_size == 0) {
+ if (STACK_POINTER16(env) < env->stack_bottom + 4) {
+ return StackFault;
+ }
+ PUSH16(env, env->regs.cs, 2);
+ PUSH16(env, env->regs.ip, 2);
+ } else {
+ if (STACK_POINTER32(env) < env->stack_bottom + 4) {
+ return StackFault;
+ }
+ PUSH32(env, env->regs.cs, 2);
+ PUSH32(env, env->regs.ip, 2);
+ }
+ env->regs.cs = segment;
+ env->regs.eip = offset & 0xffff;
+ env->cur_ip = (void *)((segment << 4) + env->regs.eip);
+ } else {
+ if (offset >> 16 != 0) return GeneralProtection; // 实模式
+ if (env->flags.stack_size == 0) {
+ if (STACK_POINTER16(env) < env->stack_bottom + 6) {
+ return StackFault;
+ }
+ PUSH16(env, env->regs.cs, 4);
+ PUSH16(env, env->regs.eip, 4);
+ } else {
+ if (STACK_POINTER32(env) < env->stack_bottom + 6) {
+ return StackFault;
+ }
+ PUSH32(env, env->regs.cs, 4);
+ PUSH32(env, env->regs.eip, 4);
+ }
+ env->regs.cs = segment;
+ env->regs.eip = offset;
+ env->cur_ip = (void *)env->regs.eip;
+ }
+ return NoException;
+}
+
+BiosEmuExceptions decode_call_ptr(BiosEmuEnvironment *env) {
+ uint16_t segment = *(uint16_t *)env->cur_ip;
+ if (env->flags.operand_size == 0) {
+ uint16_t offset = *(uint16_t *)(env->cur_ip + 2);
+ env->cur_ip += 4;
+ env->regs.eip += 4;
+ env->regs.eip &= 0xffff;
+ env->cur_ip = (void *)((env->regs.cs << 4) + env->regs.eip);
+ return decode_call_far(env, segment, offset);
+ } else {
+ uint32_t offset = *(uint32_t *)env->cur_ip;
+ env->cur_ip += 6;
+ env->regs.eip += 6;
+ return decode_call_far(env, segment, offset);
+ }
+}
+
+BiosEmuExceptions decode_ret_near(BiosEmuEnvironment *env, int bytes) {
+ uint32_t temp_eip;
+ if (env->flags.operand_size == 0) {
+ if (env->flags.stack_size == 0) {
+ if (STACK_POINTER16(env) < env->stack_bottom + 2) {
+ return StackFault;
+ }
+ POP16(env, temp_eip, 2);
+ env->regs.sp += bytes;
+ } else {
+ if (STACK_POINTER32(env) < env->stack_bottom + 2) {
+ return StackFault;
+ }
+ POP32(env, temp_eip, 2);
+ env->regs.esp += bytes;
+ }
+ temp_eip &= 0xffff;
+ if (!ptr_within_code_segment_limit(env, temp_eip))
+ return GeneralProtection;
+ env->regs.eip = temp_eip;
+ env->cur_ip = (void *)((env->regs.cs << 4) + env->regs.eip);
+ } else {
+ if (env->flags.stack_size == 0) {
+ if (STACK_POINTER16(env) < env->stack_bottom + 4) {
+ return StackFault;
+ }
+ POP16(env, temp_eip, 4);
+ env->regs.sp += bytes;
+ } else {
+ if (STACK_POINTER32(env) < env->stack_bottom + 4) {
+ return StackFault;
+ }
+ POP32(env, temp_eip, 4);
+ env->regs.esp += bytes;
+ }
+ env->regs.eip = temp_eip;
+ env->cur_ip = (void *)env->regs.eip;
+ }
+ return NoException;
+}
+
+BiosEmuExceptions decode_ret_far(BiosEmuEnvironment *env, int bytes) {
+ uint16_t segment;
+ uint32_t temp_eip;
+ if (env->flags.operand_size == 0) {
+ if (env->flags.stack_size == 0) {
+ if (STACK_POINTER16(env) < env->stack_bottom + 4) {
+ return StackFault;
+ }
+ POP16(env, temp_eip, 2);
+ POP16(env, segment, 2);
+ env->regs.sp += bytes;
+ } else {
+ if (STACK_POINTER32(env) < env->stack_bottom + 4) {
+ return StackFault;
+ }
+ POP32(env, temp_eip, 2);
+ POP32(env, segment, 2);
+ env->regs.esp += bytes;
+ }
+ temp_eip &= 0xffff;
+ if (!ptr_within_code_segment_limit(env, temp_eip))
+ return GeneralProtection;
+ env->regs.cs = segment;
+ env->regs.eip = temp_eip;
+ env->cur_ip = (void *)((segment << 4) + env->regs.eip);
+ } else {
+ if (env->flags.stack_size == 0) {
+ if (STACK_POINTER16(env) < env->stack_bottom + 8) {
+ return StackFault;
+ }
+ POP16(env, env->regs.eip, 4);
+ POP16(env, segment, 4);
+ env->regs.sp += bytes;
+ } else {
+ if (STACK_POINTER32(env) < env->stack_bottom + 8) {
+ return StackFault;
+ }
+ POP32(env, env->regs.eip, 4);
+ POP32(env, segment, 4);
+ env->regs.esp += bytes;
+ }
+ env->regs.cs = segment;
+ env->cur_ip = (void *)env->regs.eip;
+ }
+ return NoException;
+}
+
+BiosEmuExceptions decode_ret_imm16(BiosEmuEnvironment *env) {
+ uint16_t offset = *(uint16_t *)env->cur_ip;
+ env->cur_ip += 2;
+ env->regs.eip += 2;
+ return decode_ret_near(env, offset);
+}
+
+BiosEmuExceptions decode_ret_far_imm16(BiosEmuEnvironment *env) {
+ uint16_t offset = *(uint16_t *)env->cur_ip;
+ env->cur_ip += 2;
+ env->regs.eip += 2;
+ return decode_ret_far(env, offset);
+}
diff --git a/src/arch/x86/bios_emu/ops/conditions.c b/src/arch/x86/bios_emu/ops/conditions.c
new file mode 100644
index 0000000..5356209
--- /dev/null
+++ b/src/arch/x86/bios_emu/ops/conditions.c
@@ -0,0 +1,98 @@
+#include "../includes/flags.h"
+#include
+#include
+#include
+
+int condition_o(BiosEmuEnvironment *env) {
+ // OF=1
+ return env->regs.flags & BIT(OverflowFlagBit);
+}
+
+int condition_no(BiosEmuEnvironment *env) {
+ // OF=0
+ return !(env->regs.flags & BIT(OverflowFlagBit));
+}
+
+int condition_b_c_nae(BiosEmuEnvironment *env) {
+ // CF=1
+ return env->regs.flags & BIT(CarryFlagBit);
+}
+
+int condition_ae_nb_nc(BiosEmuEnvironment *env) {
+ // CF=0
+ return !(env->regs.flags & BIT(CarryFlagBit));
+}
+
+int condition_e_z(BiosEmuEnvironment *env) {
+ // ZF=1
+ return env->regs.flags & BIT(ZeroFlagBit);
+}
+
+int condition_ne_nz(BiosEmuEnvironment *env) {
+ // ZF=0
+ return !(env->regs.flags & BIT(ZeroFlagBit));
+}
+
+int condition_be_na(BiosEmuEnvironment *env) {
+ // CF=1 && ZF=1
+ return (env->regs.flags & BIT(CarryFlagBit)) &&
+ (env->regs.flags & BIT(ZeroFlagBit));
+}
+
+int condition_a_nbe(BiosEmuEnvironment *env) {
+ // CF=0 && ZF=0
+ return !(env->regs.flags & BIT(CarryFlagBit)) &&
+ !(env->regs.flags & BIT(ZeroFlagBit));
+}
+
+int condition_s(BiosEmuEnvironment *env) {
+ // SF=1
+ return env->regs.flags & BIT(SignFlagBit);
+}
+
+int condition_ns(BiosEmuEnvironment *env) {
+ // SF=0
+ return !(env->regs.flags & BIT(SignFlagBit));
+}
+
+int condition_p_pe(BiosEmuEnvironment *env) {
+ // PF=1
+ return env->regs.flags & BIT(ParityFlagBit);
+}
+
+int condition_np_po(BiosEmuEnvironment *env) {
+ // PF=0
+ return !(env->regs.flags & BIT(ParityFlagBit));
+}
+
+int condition_l_nge(BiosEmuEnvironment *env) {
+ // SF!=OF
+ return !!(env->regs.flags & BIT(SignFlagBit)) !=
+ !!(env->regs.flags & BIT(OverflowFlagBit));
+}
+
+int condition_nl_ge(BiosEmuEnvironment *env) {
+ // SF=OF
+ return !!(env->regs.flags & BIT(SignFlagBit)) ==
+ !!(env->regs.flags & BIT(OverflowFlagBit));
+}
+
+int condition_le_ng(BiosEmuEnvironment *env) {
+ // ZF=1 || SF!=OF
+ return (env->regs.flags & BIT(ZeroFlagBit)) ||
+ !!(env->regs.flags & BIT(SignFlagBit)) !=
+ !!(env->regs.flags & BIT(OverflowFlagBit));
+}
+
+int condition_nle_g(BiosEmuEnvironment *env) {
+ // ZF=0 && SF=OF
+ return !(env->regs.flags & BIT(ZeroFlagBit)) &&
+ !!(env->regs.flags & BIT(SignFlagBit)) ==
+ !!(env->regs.flags & BIT(OverflowFlagBit));
+}
+
+int (*condition_table[16])(BiosEmuEnvironment *env) = {
+ condition_o, condition_no, condition_b_c_nae, condition_ae_nb_nc,
+ condition_e_z, condition_ne_nz, condition_be_na, condition_a_nbe,
+ condition_s, condition_ns, condition_p_pe, condition_np_po,
+ condition_l_nge, condition_nl_ge, condition_le_ng, condition_nle_g};
diff --git a/src/arch/x86/bios_emu/ops/config.toml b/src/arch/x86/bios_emu/ops/config.toml
new file mode 100644
index 0000000..0976020
--- /dev/null
+++ b/src/arch/x86/bios_emu/ops/config.toml
@@ -0,0 +1,12 @@
+c = [
+ "alu.c",
+ "bt.c",
+ "call.c",
+ "conditions.c",
+ "int.c",
+ "jmp.c",
+ "mov.c",
+ "segment.c",
+ "stack.c",
+ "xchg.c",
+]
diff --git a/src/arch/x86/bios_emu/ops/int.c b/src/arch/x86/bios_emu/ops/int.c
new file mode 100644
index 0000000..d1f89aa
--- /dev/null
+++ b/src/arch/x86/bios_emu/ops/int.c
@@ -0,0 +1,71 @@
+#include "../includes/flags.h"
+#include "../includes/operations.h"
+#include "../includes/stack.h"
+#include
+#include
+#include
+#include
+#include
+
+BiosEmuExceptions emu_interrupt(int vector) {
+ BiosEmuEnvironment *env = &bios_emu_env;
+ env->stop_condition = IntDone;
+ env->int_entry_stack = STACK_POINTER16(env);
+
+ decode_int(env, vector);
+
+ return emu_run(env);
+}
+
+BiosEmuExceptions decode_int(BiosEmuEnvironment *env, uint8_t vector) {
+ env->regs.eip++;
+ if (vector > 255) return GeneralProtection;
+ if (env->stack_bottom + 6 > STACK_POINTER16(env)) return StackFault;
+
+ PUSH(env, env->regs.flags, 2);
+ env->regs.flags = BIN_DIS(
+ env->regs.flags, BIT(InterruptEnableFlagBit) | BIT(TrapFlagBit) |
+ BIT(AlignmentCheckFlagBit));
+ PUSH(env, env->regs.cs, 2);
+ PUSH(env, env->regs.ip, 2);
+
+ env->regs.cs = env->ivt[vector].segment;
+ env->regs.ip = env->ivt[vector].offset;
+
+ env->cur_ip = (void *)((env->regs.cs << 4) + env->regs.ip);
+
+ return NoException;
+}
+
+BiosEmuExceptions decode_iret(BiosEmuEnvironment *env) {
+ if (env->flags.operand_size == 0) {
+ if (env->flags.stack_size == 0) {
+ POP16(env, env->regs.eip, 2);
+ POP16(env, env->regs.cs, 2);
+ POP16(env, env->regs.flags, 2);
+ } else {
+ POP32(env, env->regs.eip, 2);
+ POP32(env, env->regs.cs, 2);
+ POP32(env, env->regs.flags, 2);
+ }
+ } else {
+ if (env->flags.stack_size == 0) {
+ POP16(env, env->regs.eip, 4);
+ POP16(env, env->regs.cs, 4);
+ POP16(env, env->regs.eflags, 4);
+ } else {
+ uint32_t temp_eflags;
+ POP32(env, env->regs.eip, 4);
+ POP32(env, env->regs.cs, 4);
+ POP32(env, temp_eflags, 4);
+ env->regs.eflags =
+ (temp_eflags & 0x257FD5) | (env->regs.eflags & 0x1A0000);
+ }
+ }
+ BiosEmuExceptions exception = NoException;
+ // 通过栈地址检测是否完成中断功能调用
+ if (env->int_entry_stack == STACK_POINTER16(env)) {
+ exception = EventInterruptDone;
+ }
+ return exception;
+}
\ No newline at end of file
diff --git a/src/arch/x86/bios_emu/ops/jmp.c b/src/arch/x86/bios_emu/ops/jmp.c
new file mode 100644
index 0000000..37ddbae
--- /dev/null
+++ b/src/arch/x86/bios_emu/ops/jmp.c
@@ -0,0 +1,117 @@
+#include "../includes/operations.h"
+#include
+#include
+#include
+
+void decode_jcc_8(BiosEmuEnvironment *env, int condition) {
+ int8_t offset = *(int8_t *)env->cur_ip++;
+ env->regs.eip++;
+ if (env->flags.operand_size == 0) {
+ if (condition) {
+ env->cur_ip += offset;
+ env->regs.eip += offset;
+ env->regs.eip &= 0xffff;
+ env->cur_ip = (void *)((env->regs.cs << 4) + env->regs.eip);
+ }
+ } else {
+ if (condition) {
+ env->cur_ip += offset;
+ env->regs.eip += offset;
+ }
+ }
+ return;
+}
+
+void decode_jcc(BiosEmuEnvironment *env, int condition) {
+ if (env->flags.address_size == 0) {
+ int16_t offset = *(int16_t *)env->cur_ip;
+ env->cur_ip += 2;
+ env->regs.eip += 2;
+ if (condition) {
+ env->cur_ip += offset;
+ env->regs.eip += offset;
+ env->regs.eip &= 0xffff;
+ env->cur_ip = (void *)((env->regs.cs << 4) + env->regs.eip);
+ }
+ } else {
+ int32_t offset = *(int32_t *)env->cur_ip;
+ env->cur_ip += 4;
+ env->regs.eip += 4;
+ if (condition) {
+ env->cur_ip += offset;
+ env->regs.eip += offset;
+ }
+ }
+ return;
+}
+
+void decode_jmp8(BiosEmuEnvironment *env) {
+ int8_t offset = *(int8_t *)env->cur_ip++;
+ env->regs.eip++;
+ env->cur_ip += offset;
+ env->regs.eip += offset;
+ if (env->flags.operand_size == 0) {
+ env->regs.eip &= 0xffff;
+ env->cur_ip = (void *)((env->regs.cs << 4) + env->regs.eip);
+ }
+ return;
+}
+
+void decode_jmp_near(BiosEmuEnvironment *env, int32_t offset) {
+ if (env->flags.operand_size == 0) {
+ env->cur_ip += offset;
+ env->regs.eip += offset;
+ env->regs.eip &= 0xffff;
+ env->cur_ip = (void *)((env->regs.cs << 4) + env->regs.eip);
+ } else {
+ env->cur_ip += offset;
+ env->regs.eip += offset;
+ }
+ return;
+}
+
+void decode_jmp_far(
+ BiosEmuEnvironment *env, uint16_t segment, uint32_t offset) {
+ env->regs.cs = segment;
+ if (env->flags.operand_size == 0) {
+ env->regs.eip = offset & 0xffff;
+ env->cur_ip = (void *)((segment << 4) + env->regs.eip);
+ } else {
+ env->regs.eip = offset;
+ env->cur_ip = (void *)env->regs.eip;
+ }
+ return;
+}
+
+void decode_jmp(BiosEmuEnvironment *env) {
+ if (env->flags.address_size == 0) {
+ int16_t offset = *(int16_t *)env->cur_ip;
+ env->cur_ip += 2;
+ env->regs.eip += 2;
+ decode_jmp_near(env, offset);
+ } else {
+ int32_t offset = *(int32_t *)env->cur_ip;
+ env->cur_ip += 4;
+ env->regs.eip += 4;
+ decode_jmp_near(env, offset);
+ }
+}
+
+void decode_long_jmp_ptr16(BiosEmuEnvironment *env) {
+ uint16_t segment = *(uint16_t *)env->cur_ip;
+ env->cur_ip += 2;
+ env->regs.eip += 2;
+ if (env->flags.operand_size == 0) {
+ uint16_t offset = *(uint16_t *)env->cur_ip;
+ env->cur_ip += 2;
+ env->regs.eip += 2;
+ env->regs.eip &= 0xffff;
+ env->cur_ip = (void *)((env->regs.cs << 4) + env->regs.eip);
+ decode_jmp_far(env, segment, offset);
+ } else {
+ uint32_t offset = *(uint32_t *)env->cur_ip;
+ env->cur_ip += 4;
+ env->regs.eip += 4;
+ decode_jmp_far(env, segment, offset);
+ }
+}
diff --git a/src/arch/x86/bios_emu/ops/mov.c b/src/arch/x86/bios_emu/ops/mov.c
new file mode 100644
index 0000000..290d87a
--- /dev/null
+++ b/src/arch/x86/bios_emu/ops/mov.c
@@ -0,0 +1,258 @@
+#include "../includes/decode.h"
+#include "../includes/mod_rm.h"
+#include "../includes/operations.h"
+#include
+#include
+#include
+
+BiosEmuExceptions mov_8_8(BiosEmuEnvironment *env, uint8_t *dst, uint8_t *src) {
+ *dst = *src;
+ return NoException;
+}
+
+BiosEmuExceptions mov_16_16(
+ BiosEmuEnvironment *env, uint16_t *dst, uint16_t *src) {
+ *dst = *src;
+ return NoException;
+}
+
+BiosEmuExceptions mov_32_32(
+ BiosEmuEnvironment *env, uint32_t *dst, uint32_t *src) {
+ *dst = *src;
+ return NoException;
+}
+
+void decode_mov_rm_sreg(BiosEmuEnvironment *env) {
+ uint8_t modrm = *(uint8_t *)env->cur_ip++;
+ env->regs.eip++;
+ uint8_t reg = (modrm >> 3) & 0b111;
+
+ void *dst = RM_ADDR(env, modrm);
+ if (env->flags.operand_size == 0) {
+ uint16_t *src = RM_SREG(env, reg);
+ *(uint16_t *)dst = *src;
+ } else {
+ uint32_t *src = RM_SREG(env, reg);
+ *(uint32_t *)dst = *src;
+ }
+ return;
+}
+
+void decode_mov_sreg_rm(BiosEmuEnvironment *env) {
+ uint8_t modrm = *(uint8_t *)env->cur_ip++;
+ env->regs.eip++;
+ uint8_t reg = (modrm >> 3) & 0b111;
+
+ uint16_t *dst = RM_SREG(env, reg);
+ uint16_t *src = RM_ADDR(env, modrm);
+ *dst = *src;
+ return;
+}
+
+void decode_mov_r_moffs_8(BiosEmuEnvironment *env) {
+ uint32_t segment = *env->default_ss;
+
+ void *src = (void *)get_segment_base(env, segment);
+ uint32_t offset;
+ if (env->flags.address_size == 0) {
+ offset = *(uint16_t *)env->cur_ip;
+ env->regs.eip += 2;
+ env->cur_ip += 2;
+ } else {
+ offset = *(uint32_t *)env->cur_ip;
+ env->regs.eip += 4;
+ env->cur_ip += 4;
+ }
+ src = (void *)((size_t)src + offset);
+ env->regs.al = *(uint8_t *)src;
+ return;
+}
+
+void decode_mov_r_moffs(BiosEmuEnvironment *env) {
+ uint32_t segment = *env->default_ss;
+
+ void *src = (void *)get_segment_base(env, segment);
+ uint32_t offset;
+ if (env->flags.address_size == 0) {
+ offset = *(uint16_t *)env->cur_ip;
+ env->regs.eip += 2;
+ env->cur_ip += 2;
+ } else {
+ offset = *(uint32_t *)env->cur_ip;
+ env->regs.eip += 4;
+ env->cur_ip += 4;
+ }
+ src = (void *)((size_t)src + offset);
+ if (env->flags.operand_size == 0) env->regs.ax = *(uint16_t *)src;
+ else env->regs.eax = *(uint32_t *)src;
+ return;
+}
+
+void decode_mov_moffs_r_8(BiosEmuEnvironment *env) {
+ uint32_t segment = *env->default_ss;
+
+ void *dst = (void *)get_segment_base(env, segment);
+ uint32_t offset;
+ if (env->flags.address_size == 0) {
+ offset = *(uint16_t *)env->cur_ip;
+ env->regs.eip += 2;
+ env->cur_ip += 2;
+ } else {
+ offset = *(uint32_t *)env->cur_ip;
+ env->regs.eip += 4;
+ env->cur_ip += 4;
+ }
+ dst = (void *)((size_t)dst + offset);
+
+ *(uint8_t *)dst = env->regs.al;
+ return;
+}
+
+void decode_mov_moffs_r(BiosEmuEnvironment *env) {
+ uint32_t segment = *env->default_ss;
+
+ void *dst = (void *)get_segment_base(env, segment);
+ uint32_t offset;
+ if (env->flags.address_size == 0) {
+ offset = *(uint16_t *)env->cur_ip;
+ env->regs.eip += 2;
+ env->cur_ip += 2;
+ } else {
+ offset = *(uint32_t *)env->cur_ip;
+ env->regs.eip += 4;
+ env->cur_ip += 4;
+ }
+ dst = (void *)((size_t)dst + offset);
+ if (env->flags.operand_size == 0) *(uint16_t *)dst = env->regs.ax;
+ else *(uint32_t *)dst = env->regs.eax;
+ return;
+}
+
+void decode_mov_r_imm8(BiosEmuEnvironment *env, uint8_t opcode) {
+ uint8_t *reg = PLUS_RB_REG(env, opcode);
+ *reg = *(uint8_t *)env->cur_ip++;
+ env->regs.eip++;
+}
+
+void decode_mov_r_imm(BiosEmuEnvironment *env, uint8_t opcode) {
+ if (env->flags.operand_size == 0) {
+ uint16_t *reg = PLUS_RW_REG(env, opcode);
+ *reg = *(uint16_t *)env->cur_ip;
+ env->cur_ip += 2;
+ env->regs.eip += 2;
+ } else {
+ uint32_t *reg = PLUS_RD_REG(env, opcode);
+ *reg = *(uint32_t *)env->cur_ip;
+ env->cur_ip += 4;
+ env->regs.eip += 4;
+ }
+}
+
+void decode_mov_rm_imm(BiosEmuEnvironment *env) {
+ uint8_t modrm = *(uint8_t *)env->cur_ip++;
+ env->regs.eip++;
+
+ if (env->flags.operand_size == 0) {
+ uint16_t *val = RM_ADDR16(env, modrm);
+
+ *val = *(uint16_t *)env->cur_ip;
+ env->cur_ip += 2;
+ env->regs.eip += 2;
+ } else {
+ uint32_t *val = RM_ADDR32(env, modrm);
+
+ *val = *(uint32_t *)env->cur_ip;
+ env->cur_ip += 4;
+ env->regs.eip += 4;
+ }
+}
+
+void decode_movzx_r_rm8(BiosEmuEnvironment *env) {
+ uint8_t modrm = *(uint8_t *)env->cur_ip++;
+ env->regs.eip++;
+ uint8_t reg = (modrm >> 3) & 0b111;
+
+ if (env->flags.operand_size == 0) {
+ uint16_t *dst = env->reg_lut_r16[reg];
+ uint8_t *src = RM_ADDR16(env, modrm);
+ *dst = (uint16_t)*src;
+ } else {
+ uint32_t *dst = env->reg_lut_r32[reg];
+ uint8_t *src = RM_ADDR32(env, modrm);
+ *dst = (uint32_t)*src;
+ }
+ return;
+}
+
+void decode_movzx_r_rm16(BiosEmuEnvironment *env) {
+ uint8_t modrm = *(uint8_t *)env->cur_ip++;
+ env->regs.eip++;
+ uint8_t reg = (modrm >> 3) & 0b111;
+
+ uint32_t *dst = env->reg_lut_r32[reg];
+ uint16_t *src = RM_ADDR32(env, modrm);
+ *dst = (uint32_t)*src;
+ return;
+}
+
+void decode_movsx_r_rm8(BiosEmuEnvironment *env) {
+ uint8_t modrm = *(uint8_t *)env->cur_ip++;
+ env->regs.eip++;
+ uint8_t reg = (modrm >> 3) & 0b111;
+
+ if (env->flags.operand_size == 0) {
+ uint16_t *dst = env->reg_lut_r16[reg];
+ int8_t *src = RM_ADDR16(env, modrm);
+ *dst = (int16_t)*src;
+ } else {
+ uint32_t *dst = env->reg_lut_r32[reg];
+ int8_t *src = RM_ADDR32(env, modrm);
+ *dst = (int32_t)*src;
+ }
+ return;
+}
+
+void decode_movsx_r_rm16(BiosEmuEnvironment *env) {
+ uint8_t modrm = *(uint8_t *)env->cur_ip++;
+ env->regs.eip++;
+ uint8_t reg = (modrm >> 3) & 0b111;
+
+ uint32_t *dst = env->reg_lut_r32[reg];
+ int16_t *src = RM_ADDR32(env, modrm);
+ *dst = (int32_t)*src;
+ return;
+}
+
+void movs_8(
+ BiosEmuEnvironment *env, void *dst, int delta_dst, void *src, int delta_src,
+ int repeat_times) {
+ for (int i = 0; i < repeat_times; i++) {
+ *(uint8_t *)dst = *(uint8_t *)src;
+
+ dst += delta_dst;
+ src += delta_src;
+ }
+ return;
+}
+
+void movs_16(
+ BiosEmuEnvironment *env, void *dst, int delta_dst, void *src, int delta_src,
+ int repeat_times) {
+ for (int i = 0; i < repeat_times; i++) {
+ *(uint16_t *)dst = *(uint16_t *)src;
+
+ dst += delta_dst;
+ src += delta_src;
+ }
+}
+
+void movs_32(
+ BiosEmuEnvironment *env, void *dst, int delta_dst, void *src, int delta_src,
+ int repeat_times) {
+ for (int i = 0; i < repeat_times; i++) {
+ *(uint32_t *)dst = *(uint32_t *)src;
+
+ dst += delta_dst;
+ src += delta_src;
+ }
+}
diff --git a/src/arch/x86/bios_emu/ops/segment.c b/src/arch/x86/bios_emu/ops/segment.c
new file mode 100644
index 0000000..0258b72
--- /dev/null
+++ b/src/arch/x86/bios_emu/ops/segment.c
@@ -0,0 +1,24 @@
+#include
+#include
+#include
+#include
+
+#define DEF_LXS(sreg) \
+ BiosEmuExceptions l##sreg##_16_16( \
+ BiosEmuEnvironment *env, uint16_t *reg, uint16_t *addr) { \
+ env->regs.sreg = *addr++; \
+ *reg = *addr; \
+ return NoException; \
+ } \
+ BiosEmuExceptions l##sreg##_32_32( \
+ BiosEmuEnvironment *env, uint32_t *reg, uint32_t *addr) { \
+ env->regs.ds = *(uint16_t *)addr; \
+ addr = (uint32_t *)((uint16_t *)addr + 1); \
+ return NoException; \
+ }
+
+DEF_LXS(ds)
+DEF_LXS(ss)
+DEF_LXS(es)
+DEF_LXS(fs)
+DEF_LXS(gs)
\ No newline at end of file
diff --git a/src/arch/x86/bios_emu/ops/stack.c b/src/arch/x86/bios_emu/ops/stack.c
new file mode 100644
index 0000000..744e1d6
--- /dev/null
+++ b/src/arch/x86/bios_emu/ops/stack.c
@@ -0,0 +1,126 @@
+#include "../includes/stack.h"
+#include "../includes/decode.h"
+#include "../includes/mod_rm.h"
+#include "../includes/operations.h"
+#include
+#include
+#include
+
+void decode_pusha_pushad(BiosEmuEnvironment *env) {
+ if (env->flags.operand_size == 0) {
+ if (env->flags.stack_size == 0) {
+ uint16_t temp_sp = env->regs.sp;
+ PUSH16(env, env->regs.ax, 2);
+ PUSH16(env, env->regs.cx, 2);
+ PUSH16(env, env->regs.dx, 2);
+ PUSH16(env, env->regs.bx, 2);
+ PUSH16(env, temp_sp, 2);
+ PUSH16(env, env->regs.bp, 2);
+ PUSH16(env, env->regs.si, 2);
+ PUSH16(env, env->regs.di, 2);
+ } else {
+ uint16_t temp_sp = env->regs.sp;
+ PUSH32(env, env->regs.eax, 2);
+ PUSH32(env, env->regs.ecx, 2);
+ PUSH32(env, env->regs.edx, 2);
+ PUSH32(env, env->regs.ebx, 2);
+ PUSH32(env, temp_sp, 2);
+ PUSH32(env, env->regs.ebp, 2);
+ PUSH32(env, env->regs.esi, 2);
+ PUSH32(env, env->regs.edi, 2);
+ }
+ } else {
+ if (env->flags.stack_size == 0) {
+ uint32_t temp_esp = env->regs.esp;
+ PUSH16(env, env->regs.eax, 4);
+ PUSH16(env, env->regs.ecx, 4);
+ PUSH16(env, env->regs.edx, 4);
+ PUSH16(env, env->regs.ebx, 4);
+ PUSH16(env, temp_esp, 4);
+ PUSH16(env, env->regs.ebp, 4);
+ PUSH16(env, env->regs.esi, 4);
+ PUSH16(env, env->regs.edi, 4);
+ } else {
+ uint32_t temp_esp = env->regs.esp;
+ PUSH32(env, env->regs.eax, 4);
+ PUSH32(env, env->regs.ecx, 4);
+ PUSH32(env, env->regs.edx, 4);
+ PUSH32(env, env->regs.ebx, 4);
+ PUSH32(env, temp_esp, 4);
+ PUSH32(env, env->regs.ebp, 4);
+ PUSH32(env, env->regs.esi, 4);
+ PUSH32(env, env->regs.edi, 4);
+ }
+ }
+ return;
+}
+
+void decode_pop_rm(BiosEmuEnvironment *env) {
+ uint8_t modrm = *(uint8_t *)env->cur_ip++;
+ env->regs.eip++;
+
+ if (env->flags.operand_size == 0) {
+ uint16_t *addr = RM_ADDR16(env, modrm);
+ POP(env, *addr, 2);
+ } else {
+ uint32_t *addr = RM_ADDR32(env, modrm);
+ POP(env, *addr, 4);
+ }
+ return;
+}
+
+void decode_pop_r(BiosEmuEnvironment *env, uint8_t opcode) {
+ if (env->flags.operand_size == 0) {
+ uint16_t *dst = PLUS_RW_REG(env, opcode);
+ POP(env, *dst, 2);
+ } else {
+ uint32_t *dst = PLUS_RD_REG(env, opcode);
+ POP(env, *dst, 4);
+ }
+ return;
+}
+
+void decode_popa_popad(BiosEmuEnvironment *env) {
+ if (env->flags.operand_size == 0) {
+ if (env->flags.stack_size == 0) {
+ POP16(env, env->regs.di, 2);
+ POP16(env, env->regs.si, 2);
+ POP16(env, env->regs.bp, 2);
+ env->regs.sp += 2;
+ POP16(env, env->regs.bx, 2);
+ POP16(env, env->regs.dx, 2);
+ POP16(env, env->regs.cx, 2);
+ POP16(env, env->regs.ax, 2);
+ } else {
+ POP32(env, env->regs.di, 2);
+ POP32(env, env->regs.si, 2);
+ POP32(env, env->regs.bp, 2);
+ env->regs.esp += 2;
+ POP32(env, env->regs.bx, 2);
+ POP32(env, env->regs.dx, 2);
+ POP32(env, env->regs.cx, 2);
+ POP32(env, env->regs.ax, 2);
+ }
+ } else {
+ if (env->flags.stack_size == 0) {
+ POP16(env, env->regs.edi, 4);
+ POP16(env, env->regs.esi, 4);
+ POP16(env, env->regs.ebp, 4);
+ env->regs.sp += 4;
+ POP16(env, env->regs.ebx, 4);
+ POP16(env, env->regs.edx, 4);
+ POP16(env, env->regs.ecx, 4);
+ POP16(env, env->regs.eax, 4);
+ } else {
+ POP32(env, env->regs.edi, 4);
+ POP32(env, env->regs.esi, 4);
+ POP32(env, env->regs.ebp, 4);
+ env->regs.esp += 4;
+ POP32(env, env->regs.ebx, 4);
+ POP32(env, env->regs.edx, 4);
+ POP32(env, env->regs.ecx, 4);
+ POP32(env, env->regs.eax, 4);
+ }
+ }
+ return;
+}
\ No newline at end of file
diff --git a/src/arch/x86/bios_emu/ops/xchg.c b/src/arch/x86/bios_emu/ops/xchg.c
new file mode 100644
index 0000000..9921765
--- /dev/null
+++ b/src/arch/x86/bios_emu/ops/xchg.c
@@ -0,0 +1,99 @@
+#include "../includes/flags.h"
+#include
+#include
+#include
+#include
+
+BiosEmuExceptions xchg_8_8(
+ BiosEmuEnvironment *env, uint8_t *addr1, uint8_t *addr2) {
+ uint8_t tmp = *addr1;
+ *addr1 = *addr2;
+ *addr2 = tmp;
+
+ return NoException;
+}
+
+BiosEmuExceptions xchg_16_16(
+ BiosEmuEnvironment *env, uint16_t *addr1, uint16_t *addr2) {
+ uint16_t tmp = *addr1;
+ *addr1 = *addr2;
+ *addr2 = tmp;
+
+ return NoException;
+}
+
+BiosEmuExceptions xchg_32_32(
+ BiosEmuEnvironment *env, uint16_t *addr1, uint16_t *addr2) {
+ uint16_t tmp = *addr1;
+ *addr1 = *addr2;
+ *addr2 = tmp;
+
+ return NoException;
+}
+
+BiosEmuExceptions cmpxchg_8_8(
+ BiosEmuEnvironment *env, uint8_t *addr1, uint8_t *addr2) {
+ if (*addr1 == *addr2) {
+ env->regs.al = *addr2;
+ SET_FLAG(1, ZeroFlagBit);
+ } else {
+ env->regs.al = *addr1;
+ SET_FLAG(0, ZeroFlagBit);
+ }
+ return NoException;
+}
+
+BiosEmuExceptions cmpxchg_16_16(
+ BiosEmuEnvironment *env, uint16_t *addr1, uint16_t *addr2) {
+ if (*addr1 == *addr2) {
+ env->regs.ax = *addr2;
+ SET_FLAG(1, ZeroFlagBit);
+ } else {
+ env->regs.ax = *addr1;
+ SET_FLAG(0, ZeroFlagBit);
+ }
+ return NoException;
+}
+
+BiosEmuExceptions cmpxchg_32_32(
+ BiosEmuEnvironment *env, uint32_t *addr1, uint32_t *addr2) {
+ if (*addr1 == *addr2) {
+ env->regs.eax = *addr2;
+ SET_FLAG(1, ZeroFlagBit);
+ } else {
+ env->regs.eax = *addr1;
+ SET_FLAG(0, ZeroFlagBit);
+ }
+ return NoException;
+}
+
+BiosEmuExceptions xadd_8_8(
+ BiosEmuEnvironment *env, uint8_t *addr1, uint8_t *addr2) {
+ uint8_t tmp = *addr1;
+ *addr1 = *addr2 + *addr1;
+ *addr2 = tmp;
+ return NoException;
+}
+
+BiosEmuExceptions xadd_16_16(
+ BiosEmuEnvironment *env, uint16_t *addr1, uint16_t *addr2) {
+ uint16_t tmp = *addr1;
+ *addr1 = *addr2 + *addr1;
+ *addr2 = tmp;
+ return NoException;
+}
+
+BiosEmuExceptions xadd_32_32(
+ BiosEmuEnvironment *env, uint32_t *addr1, uint32_t *addr2) {
+ uint32_t tmp = *addr1;
+ *addr1 = *addr2 + *addr1;
+ *addr2 = tmp;
+ return NoException;
+}
+
+BiosEmuExceptions bswap_32(BiosEmuEnvironment *env, uint32_t *addr) {
+ uint32_t tmp = *addr;
+ *addr = ((tmp & 0x000000FF) << 24) | ((tmp & 0x0000FF00) << 8) |
+ ((tmp & 0x00FF0000) >> 8) | ((tmp & 0xFF000000) >> 24);
+ return NoException;
+}
diff --git a/src/arch/x86/bios_emu/segment.c b/src/arch/x86/bios_emu/segment.c
new file mode 100644
index 0000000..79c6b27
--- /dev/null
+++ b/src/arch/x86/bios_emu/segment.c
@@ -0,0 +1,26 @@
+#include
+#include
+
+size_t get_segment_base(BiosEmuEnvironment *env, uint32_t segment) {
+ return segment << 4;
+}
+
+size_t get_phy_addr(BiosEmuEnvironment *env, uint32_t segment, size_t addr) {
+ size_t segment_base = get_segment_base(env, segment);
+ return segment_base + addr;
+}
+
+uint8_t fetch_data_8(BiosEmuEnvironment *env, uint32_t segment, size_t addr) {
+ size_t segment_base = get_segment_base(env, segment);
+ return *(uint8_t *)(segment_base + addr);
+}
+
+uint8_t fetch_data_16(BiosEmuEnvironment *env, uint32_t segment, size_t addr) {
+ size_t segment_base = get_segment_base(env, segment);
+ return *(uint16_t *)(segment_base + addr);
+}
+
+uint8_t fetch_data_32(BiosEmuEnvironment *env, uint32_t segment, size_t addr) {
+ size_t segment_base = get_segment_base(env, segment);
+ return *(uint32_t *)(segment_base + addr);
+}
\ No newline at end of file
diff --git a/src/arch/x86/bios_emu/todo.md b/src/arch/x86/bios_emu/todo.md
new file mode 100644
index 0000000..4770c9e
--- /dev/null
+++ b/src/arch/x86/bios_emu/todo.md
@@ -0,0 +1,205 @@
+## 英特尔手册中列出的实模式下可用的指令及已实现的指令(部分指令未验证是否正确执行):
+
+The following instructions make up the core instruction set for the 8086 processor. If backwards compatibility to the Intel 286 and Intel 8086 processors is required, only these instructions should be used in a new program written to run in real-address mode.
+
+ - Move (MOV) instructions that move operands between general-purpose registers, segment registers, and between memory and general-purpose registers.
+ - [x] MOV
+
+ - The exchange (XCHG) instruction.
+ - [x] XCHG
+
+ - Load segment register instructions LDS and LES.
+ - [x] LDS
+ - [x] LES
+
+ - Arithmetic instructions ADD, ADC, SUB, SBB, MUL, IMUL, DIV, IDIV, INC, DEC, CMP, and NEG.
+ - [x] ADD
+ - [x] ADC
+ - [x] SUB
+ - [x] SBB
+ - [x] MUL
+ - [x] IMUL
+ - [x] DIV
+ - [x] IDIV
+ - [x] INC
+ - [x] DEC
+ - [x] CMP
+ - [x] NEG
+
+ - Logical instructions AND, OR, XOR, and NOT.
+ - [x] AND
+ - [x] OR
+ - [x] XOR
+ - [x] NOT
+
+ - Decimal instructions DAA, DAS, AAA, AAS, AAM, and AAD.
+ - [x] DAA
+ - [x] DAS
+ - [x] AAA
+ - [x] AAS
+ - [x] AAM
+ - [x] AAD
+
+ - Stack instructions PUSH and POP (to general-purpose registers and segment registers).
+ - [x] PUSH
+ - [x] POP
+
+ - Type conversion instructions CWD, CDQ, CBW, and CWDE.
+ - [x] CWD
+ - [x] CDQ
+ - [x] CBW
+ - [x] CWDE
+
+ - Shift and rotate instructions SAL, SHL, SHR, SAR, ROL, ROR, RCL, and RCR.
+ - [x] SAL
+ - [x] SHL
+ - [x] SHR
+ - [x] SAR
+ - [x] ROL
+ - [x] ROR
+ - [x] RCL
+ - [x] RCR
+
+ - TEST instruction.
+ - [x] TEST
+
+ - Control instructions JMP, Jcc, CALL, RET, LOOP, LOOPE, and LOOPNE.
+ - [x] JMP
+ - [x] Jcc
+ - [x] CALL
+ - [x] RET
+ - [x] LOOP
+ - [x] LOOPE
+ - [x] LOOPNE
+
+ - Interrupt instructions INT n, INTO, and IRET.
+ - [x] INT n
+ - [x] INTO
+ - [x] IRET
+
+ - EFLAGS control instructions STC, CLC, CMC, CLD, STD, LAHF, SAHF, PUSHF, and POPF.
+ - [x] STC
+ - [x] CLC
+ - [x] CMC
+ - [x] CLD
+ - [x] STD
+ - [x] LAHF
+ - [x] SAHF
+ - [x] PUSHF
+ - [x] POPF
+
+ - I/O instructions IN, INS, OUT, and OUTS.
+ - [x] IN
+ - [x] INS
+ - [x] OUT
+ - [x] OUTS
+
+ - Load effective address (LEA) instruction, and translate (XLATB) instruction.
+ - [x] LEA
+ - [x] XLATB
+
+ - LOCK prefix.
+ - [ ] LOCK
+
+ - Repeat prefixes REP, REPE, REPZ, REPNE, and REPNZ.
+ - [x] REP
+ - [x] REPE
+ - [x] REPZ
+ - [x] REPNE
+ - [x] REPNZ
+
+ - Processor halt (HLT) instruction.
+ - [x] HLT
+
+ - No operation (NOP) instruction.
+ - [x] NOP
+
+The following instructions, added to later IA-32 processors (some in the Intel 286 processor and the remainder in the Intel386 processor), can be executed in real-address mode, if backwards compatibility to the Intel 8086 processor is not required.
+
+ - Move (MOV) instructions that operate on the control and debug registers.
+ - [ ] MOV
+
+ - Load segment register instructions LSS, LFS, and LGS.
+ - [x] LSS
+ - [x] LFS
+ - [x] LGS
+
+ - Generalized multiply instructions and multiply immediate data.
+ - [x]
+
+ - Shift and rotate by immediate counts.
+ - [x]
+
+ - Stack instructions PUSHA, PUSHAD, POPA, POPAD, and PUSH immediate data.
+ - [x] PUSHA
+ - [x] PUSHAD
+ - [x] POPA
+ - [x] POPAD
+ - [x] PUSH
+
+ - Move with sign extension instructions MOVSX and MOVZX.
+ - [x] MOVSX
+ - [x] MOVZX
+
+ - Long-displacement Jcc instructions.
+ - [x] Jcc
+
+ - Exchange instructions CMPXCHG, CMPXCHG8B, and XADD.
+ - [x] CMPXCHG
+ - [ ] CMPXCHG8B
+ - [x] XADD
+
+ - String instructions MOVS, CMPS, SCAS, LODS, and STOS.
+ - [x] MOVS
+ - [x] CMPS
+ - [x] SCAS
+ - [x] LODS
+ - [x] STOS
+
+ - Bit test and bit scan instructions BT, BTS, BTR, BTC, BSF, and BSR; the byte-set-on condition instruction SETcc; and the byte swap (BSWAP) instruction.
+ - [x] BT
+ - [x] BTS
+ - [x] BTR
+ - [x] BTC
+ - [x] BSF
+ - [x] BSR
+ - [x] SETcc
+ - [x] BSWAP
+
+ - Double shift instructions SHLD and SHRD.
+ - [x] SHLD
+ - [x] SHRD
+
+ - EFLAGS control instructions PUSHF and POPF.
+ - [x] PUSHF
+ - [x] POPF
+
+ - ENTER and LEAVE control instructions.
+ - [x] ENTER
+ - [x] LEAVE
+
+ - BOUND instruction.
+ - [x] BOUND
+
+ - CPU identification (CPUID) instruction.
+ - [ ] CPUID
+
+ - System instructions CLTS, INVD, WINVD, INVLPG, LGDT, SGDT, LIDT, SIDT, LMSW, SMSW, RDMSR, WRMSR, RDTSC, and RDPMC.
+ - [ ] CLTS
+ - [ ] INVD
+ - [ ] WINVD
+ - [ ] INVLPG
+ - [ ] LGDT
+ - [ ] SGDT
+ - [ ] LIDT
+ - [ ] SIDT
+ - [ ] LMSW
+ - [ ] SMSW
+ - [ ] RDMSR
+ - [ ] WRMSR
+ - [ ] RDTSC
+ - [ ] RDPMC
+
+---
+
+### (也许?)遥远的未来可能的改进方向:采用转译而非模拟的方式执行
\ No newline at end of file
diff --git a/src/arch/x86/boot/config.toml b/src/arch/x86/boot/config.toml
new file mode 100644
index 0000000..ebf3ef0
--- /dev/null
+++ b/src/arch/x86/boot/config.toml
@@ -0,0 +1 @@
+asm = ["boot.asm", "loader.asm"]
diff --git a/src/arch/x86/config.toml b/src/arch/x86/config.toml
new file mode 100644
index 0000000..f609394
--- /dev/null
+++ b/src/arch/x86/config.toml
@@ -0,0 +1 @@
+dir = ["multiboot2/", "bios_emu/", "drivers/", "kernel/"]
diff --git a/src/arch/x86/drivers/8042.c b/src/arch/x86/drivers/8042.c
deleted file mode 100644
index 56490dc..0000000
--- a/src/arch/x86/drivers/8042.c
+++ /dev/null
@@ -1,185 +0,0 @@
-/**
- * @file 8042.c
- * @author Ryan Wang (ryan1202@foxmail.com)
- * @brief 8042控制器的驱动
- * @version 0.1
- * @date 2021-06
- */
-#include "kernel/driver.h"
-#include
-#include
-#include
-#include
-#include
-
-static status_t i8042_enter(driver_t *drv_obj);
-static status_t i8042_exit(driver_t *drv_obj);
-
-#define DRV_NAME "General PS/2 Driver"
-#define DEV_NAME "ps2controller"
-
-typedef struct {
- bool is_dual_channel;
- bool is_p1_avail, is_p2_avail;
-
- uint8_t p1_dev_type, p2_dev_type;
-} device_extension_t;
-
-driver_func_t i8042_driver = {
- .driver_enter = i8042_enter,
- .driver_exit = i8042_exit,
- .driver_open = NULL,
- .driver_close = NULL,
- .driver_read = NULL,
- .driver_write = NULL,
- .driver_devctl = NULL,
-};
-
-int i8042_get_status(uint8_t type) {
- int data = io_in8(I8042_PORT_STAT);
- return data & type;
-}
-
-void i8042_wait_ctr_send_ready(void) {
- for (;;) {
- if ((io_in8(I8042_PORT_STAT) & I8042_STAT_INBUF) == 0) { // 输入缓存区为空
- return;
- }
- }
-}
-
-void i8042_send_cmd(int command) {
- io_out8(I8042_PORT_CMD, command);
- i8042_wait_ctr_send_ready();
-}
-
-int i8042_read_data(void) {
- return io_in8(I8042_PORT_DATA);
-}
-
-void i8042_write_data(int data) {
- io_out8(I8042_PORT_DATA, data);
-}
-
-static status_t i8042_enter(driver_t *drv_obj) {
- device_t *devobj;
- device_extension_t *devext;
-
- device_create(drv_obj, sizeof(device_extension_t), DEV_NAME, DEV_MANAGER, &devobj);
- devext = devobj->device_extension;
-
- // 1.禁用设备
- i8042_send_cmd(I8042_CMD_DISABLE_P1); // 禁用第一个PS/2端口
- i8042_send_cmd(I8042_CMD_DISABLE_P2); // 禁用第二个PS/2端口(如果有)
-
- // 2.配置控制器
- i8042_send_cmd(I8042_CMD_WRITE);
- i8042_write_data(I8042_CFG_TRANS1 | I8042_CFG_SYS_FLAG | I8042_CFG_INT2 | I8042_CFG_INT1);
-
- // 3.控制器自检
- i8042_send_cmd(I8042_CMD_TEST_CTL);
- if (i8042_read_data() != 0x55) {
- printk("[i8042]PS/2 Controller Self test failed!\n");
- device_delete(devobj);
- return FAILED;
- }
-
- // 4.检测是否为双通道
- i8042_send_cmd(I8042_CMD_ENABLE_P2);
- devext->is_dual_channel = (i8042_read_data() & I8042_CFG_CLK2) == 0;
- if (devext->is_dual_channel) { // 存在第二个通道则禁用第二个通道
- i8042_send_cmd(I8042_CMD_DISABLE_P2);
-
- i8042_send_cmd(I8042_CMD_READ);
- uint8_t tmp = i8042_read_data();
-
- i8042_send_cmd(I8042_CMD_WRITE);
- i8042_write_data(tmp & ~I8042_CFG_INT2 | I8042_CFG_CLK2);
- }
-
- // 5.接口测试
- i8042_send_cmd(I8042_CMD_TEST_P1);
- if (i8042_read_data() != 0x00) {
- printk("[i8042]PS/2 Port 1 test failed!\n");
- devext->is_p1_avail = false;
- } else {
- devext->is_p1_avail = true;
- }
- if (devext->is_dual_channel) {
- i8042_send_cmd(I8042_CMD_TEST_P1);
- if (i8042_read_data() != 0x00) {
- printk("[i8042]PS/2 Port 2 test failed!\n");
- devext->is_p2_avail = false;
- } else {
- devext->is_p2_avail = true;
- }
- }
-
- int i = 0;
- if (devext->is_p1_avail) {
- // 6.启用端口
- i8042_send_cmd(I8042_CMD_ENABLE_P1);
- // 7.重置设备
- i8042_write_data(I8042_CMD_RESET_DEV);
-
- for (i = 0; i < 2; i++) {
- if (i8042_read_data() == 0xfc) { printk("[i8042]PS/2 Port1 Device reset failed!\n"); }
- }
- if (i8042_get_status(I8042_STAT_OUTBUF)) {
- devext->p1_dev_type = i8042_read_data();
- } else { // AT键盘没有设备类型的响应
- devext->p2_dev_type = 0xff;
- printk("[i8042]Found PS/2 device 1.Type: AT Keyboard\n");
- }
- }
- if (devext->is_p2_avail) {
- // 6.启用端口
- i8042_send_cmd(I8042_CMD_ENABLE_P2);
-
- i8042_send_cmd(I8042_CMD_READ);
- uint8_t tmp = i8042_read_data();
-
- i8042_send_cmd(I8042_CMD_WRITE);
- i8042_write_data(tmp | I8042_CFG_INT2);
- // 7.重置设备
- i8042_send_cmd(I8042_CMD_SEND_TO_P2);
- i8042_write_data(I8042_CMD_RESET_DEV);
-
- for (i = 0; i < 2; i++) {
- if (i8042_read_data() == 0xfc) { printk("[i8042]PS/2 Port1 Device reset failed!\n"); }
- }
- if (i8042_get_status(I8042_STAT_OUTBUF)) {
- devext->p2_dev_type = i8042_read_data();
- if (devext->p2_dev_type == 0x00) {
- printk("[i8042]Found PS/2 device 2.Type: Mouse\n");
- i8042_send_cmd(I8042_CMD_SEND_TO_P2);
- i8042_write_data(0xf4);
- if (i8042_read_data() != 0xfa) { printk("[i8042]PS/2 Port2 Device: mouse enable failed!\n"); }
- } else {
- printk("[i8042]Found PS/2 device 2.Type: %#0X\n", devext->p2_dev_type);
- }
- } else { // AT键盘没有设备类型的响应
- devext->p2_dev_type = 0xff;
- printk("[i8042]Found PS/2 device 2.Type: AT Keyboard\n");
- }
- }
- return SUCCUESS;
-}
-
-static status_t i8042_exit(driver_t *drv_obj) {
- device_t *devobj, *next;
- // device_extension_t *ext;
- list_for_each_owner_safe (devobj, next, &drv_obj->device_list, list) {
- device_delete(devobj);
- }
- string_del(&drv_obj->name);
- return SUCCUESS;
-}
-
-static __init void i8042_driver_entry(void) {
- if (driver_create(i8042_driver, DRV_NAME) < 0) {
- printk(COLOR_RED "[driver] %s driver create failed!\n", __func__);
- }
-}
-
-driver_initcall(i8042_driver_entry);
\ No newline at end of file
diff --git a/src/arch/x86/drivers/8259a.c b/src/arch/x86/drivers/8259a.c
deleted file mode 100644
index 30348c2..0000000
--- a/src/arch/x86/drivers/8259a.c
+++ /dev/null
@@ -1,61 +0,0 @@
-/**
- * @file 8259a.c
- * @author Ryan Wang (ryan1202@foxmail.com)
- * @brief PIC驱动
- * @version 1.1
- * @date 2022-07-31
- *
- */
-#include
-#include
-#include
-#include
-
-void init_8259a(void)
-{
- io_out8(PIC0_IMR, 0xff); // 屏蔽主PIC的所有中断
- io_out8(PIC1_IMR, 0xff); // 屏蔽从PIC的所有中断
-
- io_out8(PIC0_ICW1, 0x11); // 级联,边沿触发
- io_out8(PIC0_ICW2, 0x20); // 起始中断向量号位0x20(0x00~0x1f为内部中断)
- io_out8(PIC0_ICW3, 1 << 2); // IRQ2用于连接从PIC
- io_out8(PIC0_ICW4, 0x01); // 全嵌套模式,非缓冲模式,手动结束中断,x86处理器
-
- io_out8(PIC1_ICW1, 0x11); // 级联,边沿触发
- io_out8(PIC1_ICW2, 0x28); // 起始中断向量号位0x28
- io_out8(PIC1_ICW3, 0x02); // 连接到主PIC的IRQ2
- io_out8(PIC1_ICW4, 0x01); // 全嵌套模式,非缓冲模式,手动结束中断,x86处理器
-
- io_out8(PIC0_IMR, 0xfb); // 开启IRQ2(从PIC)中断
- io_out8(PIC1_IMR, 0xff); // 屏蔽从PIC的所有中断
-
- use_apic = 0;
-
- return;
-}
-
-void mask_8259a(void)
-{
- io_out8(PIC0_IMR, 0xff);
- io_out8(PIC1_IMR, 0xff);
-}
-
-void pic_enable_irq(int irq)
-{
- uint8_t data;
- if (irq < 8) {
- data = io_in8(PIC0_IMR);
- io_out8(PIC0_IMR, data & ~(1 << irq));
- } else {
- data = io_in8(PIC1_IMR);
- io_out8(PIC1_IMR, data & ~(1 << (irq % 8)));
- }
-}
-
-void pic_eoi(int irq)
-{
- if (irq >= 8) {
- io_out8(PIC1_OCW1, PIC_EOI);
- }
- io_out8(PIC0_OCW1, PIC_EOI);
-}
diff --git a/src/arch/x86/drivers/Makefile b/src/arch/x86/drivers/Makefile
index 8d0beca..24c98e1 100644
--- a/src/arch/x86/drivers/Makefile
+++ b/src/arch/x86/drivers/Makefile
@@ -1,18 +1,15 @@
-SRC += 8042.c
-SRC += 8259a.c
-SRC += acpi.c
-SRC += apic.c
-SRC += cpufreq.c
-SRC += disk.c
-SRC += dma.c
-SRC += ide.c
-SRC += keyboard.c
-SRC += mouse.c
+#SRC += acpi.c
+#SRC += cpufreq.c
SRC += msr.c
-SRC += pci.c
-SRC += pit.c
-SRC += smbios.c
-SRC += video.c
-SRC += network/
+SRC += serial.c
+#SRC += smbios.c
+SRC += cmos.c
+SRC += network/
SRC += sound/
-SRC += usb/
\ No newline at end of file
+SRC += usb/
+SRC += bus/
+SRC += disk/
+SRC += interrupt/
+SRC += timer/
+SRC += framebuffer/
+SRC += input/
\ No newline at end of file
diff --git a/src/arch/x86/drivers/acpi.c b/src/arch/x86/drivers/acpi.c
index 4cbd488..3ede1e6 100644
--- a/src/arch/x86/drivers/acpi.c
+++ b/src/arch/x86/drivers/acpi.c
@@ -5,13 +5,16 @@
* @version 0.1
* @date 2021-06
*/
+#include
#include
#include
#include
#include
#include
#include
+#include
#include
+#include
#include
struct ACPI_RSDP *RSDP;
@@ -22,113 +25,105 @@ struct ACPI_RSDP *RSDP;
static status_t acpi_enter(driver_t *drv_obj);
static status_t acpi_exit(driver_t *drv_obj);
-typedef struct
-{
- struct ACPI_RSDT *RSDT;
- struct ACPI_FADT *FADT;
+typedef struct {
+ struct ACPI_RSDT *RSDT;
+ struct ACPI_FADT *FADT;
} device_extension_t;
driver_func_t acpi_driver = {
- .driver_enter = acpi_enter,
- .driver_exit = acpi_exit,
- .driver_open = NULL,
- .driver_close = NULL,
- .driver_read = NULL,
- .driver_write = NULL,
- .driver_devctl = NULL
-};
-
-char checksum(uint8_t *addr, uint32_t length)
-{
- unsigned char sum = 0;
-
- for (int i = 0; i < length; i++) {
- sum += ((char *)addr)[i];
- }
-
- return sum == 0;
+ .driver_enter = acpi_enter,
+ .driver_exit = acpi_exit,
+ .driver_open = NULL,
+ .driver_close = NULL,
+ .driver_read = NULL,
+ .driver_write = NULL,
+ .driver_devctl = NULL};
+
+char checksum(uint8_t *addr, uint32_t length) {
+ unsigned char sum = 0;
+
+ for (int i = 0; i < length; i++) {
+ sum += ((char *)addr)[i];
+ }
+
+ return sum == 0;
}
-uint32_t *acpi_find_rsdp(void)
-{
- uint32_t addr;
-
- for (addr = 0x000e0000; addr < 0x00100000; addr++) {
- if (memcmp((void *)addr, "RSD PTR ", 8) == 0) {
- if (checksum((uint8_t *)addr, ((struct ACPI_RSDP *)addr)->Length)) {
- return (uint32_t *)addr;
- }
- }
- }
- return NULL;
+uint32_t *acpi_find_rsdp(void) {
+ uint32_t addr;
+
+ for (addr = 0x000e0000; addr < 0x00100000; addr++) {
+ if (memcmp((void *)addr, "RSD PTR ", 8) == 0) {
+ if (checksum((uint8_t *)addr, ((struct ACPI_RSDP *)addr)->Length)) {
+ return (uint32_t *)addr;
+ }
+ }
+ }
+ return NULL;
}
-uint32_t acpi_find_table(device_extension_t *devext, char *Signature)
-{
- int i, length = (devext->RSDT->header.Length - sizeof(devext->RSDT->header)) / 4;
- struct ACPISDTHeader *header;
- for (i = 0; i < length; i++) {
- header = remap(devext->RSDT->Entry + i * 4, sizeof(struct ACPISDTHeader));
- if (memcmp(header->Signature, Signature, 4) == 0) {
- return (uint32_t)header;
- }
- }
- return 0;
+uint32_t acpi_find_table(device_extension_t *devext, char *Signature) {
+ int i, length =
+ (devext->RSDT->header.Length - sizeof(devext->RSDT->header)) / 4;
+ struct ACPISDTHeader *header;
+ for (i = 0; i < length; i++) {
+ // TODO: memory result
+ MEMORY_RESULT_PRINT_CALL(
+ remap, devext->RSDT->Entry + i * 4, sizeof(struct ACPISDTHeader),
+ (uint32_t *)&header);
+ if (memcmp(header->Signature, Signature, 4) == 0) {
+ return (uint32_t)header;
+ }
+ }
+ return 0;
}
-static status_t acpi_enter(driver_t *drv_obj)
-{
- device_t *devobj;
- device_extension_t *devext;
-
- device_create(drv_obj, sizeof(device_extension_t), DEV_NAME, DEV_MANAGER, &devobj);
- if (drv_obj == NULL) {
- return FAILED;
- }
- devext = devobj->device_extension;
- if (devext == NULL) {
- return FAILED;
- }
-
- RSDP = (struct ACPI_RSDP *)acpi_find_rsdp();
- if (RSDP == NULL) {
- return NODEV;
- }
- unsigned int *ptr = remap(RSDP->RsdtAddress, sizeof(struct ACPI_RSDT));
- if (ptr == NULL) {
- return FAILED;
- }
- devext->RSDT = (struct ACPI_RSDT *)ptr;
- // checksum(RSDT, RSDT->header.Length);
- if (!checksum((uint8_t *)devext->RSDT, devext->RSDT->header.Length))
- return FAILED;
-
- devext->FADT = (struct ACPI_FADT *)acpi_find_table(devext, "FACP");
- if (devext->FADT == NULL) {
- return FAILED;
- }
- if (!checksum((uint8_t *)devext->FADT, devext->FADT->h.Length))
- return FAILED;
-
- if (!(io_in16(devext->FADT->PM1aControlBlock) & 1)) {
- if (devext->FADT->SMI_CommandPort && devext->FADT->AcpiEnable) {
- io_out8(devext->FADT->SMI_CommandPort, devext->FADT->AcpiEnable);
- int i;
- for (i = 0; i < 300; i++) {
- if (io_in16(devext->FADT->PM1aControlBlock) & 1)
- break;
- delay(1);
- }
- if (devext->FADT->PM1bControlBlock) {
- for (; i < 300; i++) {
- if (io_in16(devext->FADT->PM1bControlBlock) & 1)
- break;
- delay(1);
- }
- }
- }
- }
- return SUCCUESS;
+static status_t acpi_enter(driver_t *drv_obj) {
+ device_t *devobj;
+ device_extension_t *devext;
+ Timer timer;
+
+ timer_init(&timer);
+
+ device_create(
+ drv_obj, sizeof(device_extension_t), DEV_NAME, DEV_MANAGER, &devobj);
+ if (drv_obj == NULL) { return FAILED; }
+ devext = devobj->device_extension;
+ if (devext == NULL) { return FAILED; }
+
+ RSDP = (struct ACPI_RSDP *)acpi_find_rsdp();
+ if (RSDP == NULL) { return NODEV; }
+ uint32_t *ptr;
+ MEMORY_RESULT_PRINT_CALL(
+ remap, RSDP->RsdtAddress, sizeof(struct ACPI_RSDT), (uint32_t *)&ptr);
+ if (ptr == NULL) { return FAILED; }
+ devext->RSDT = (struct ACPI_RSDT *)ptr;
+ // checksum(RSDT, RSDT->header.Length);
+ if (!checksum((uint8_t *)devext->RSDT, devext->RSDT->header.Length))
+ return FAILED;
+
+ devext->FADT = (struct ACPI_FADT *)acpi_find_table(devext, "FACP");
+ if (devext->FADT == NULL) { return FAILED; }
+ if (!checksum((uint8_t *)devext->FADT, devext->FADT->h.Length))
+ return FAILED;
+
+ if (!(io_in16(devext->FADT->PM1aControlBlock) & 1)) {
+ if (devext->FADT->SMI_CommandPort && devext->FADT->AcpiEnable) {
+ io_out8(devext->FADT->SMI_CommandPort, devext->FADT->AcpiEnable);
+ int i;
+ for (i = 0; i < 300; i++) {
+ if (io_in16(devext->FADT->PM1aControlBlock) & 1) break;
+ delay_ms(&timer, 1);
+ }
+ if (devext->FADT->PM1bControlBlock) {
+ for (; i < 300; i++) {
+ if (io_in16(devext->FADT->PM1bControlBlock) & 1) break;
+ delay_ms(&timer, 1);
+ }
+ }
+ }
+ }
+ return SUCCUESS;
}
/*
@@ -137,8 +132,9 @@ static status_t acpi_enter(driver_t *drv_obj)
* NameOP | \(可选) | _ | S | 5 | _
* 08 | 5A | 5F | 53 | 35 | 5F
* -----------------------------------
- * PackageOP | PkgLength | NumElements | prefix Num | prefix Num | prefix Num | prefix Num
- * 12 | 0A | 04 | 0A 05 | 0A 05 | 0A 05 | 0A 05
+ * PackageOP | PkgLength | NumElements | prefix Num | prefix Num | prefix Num |
+ * prefix Num 12 | 0A | 04 | 0A 05 | 0A 05 | 0A
+ * 05 | 0A 05
* -----------------------------------
* PkgLength: bit6~7为长度的字节数-1;bit4~5保留;bit0~3为长度的低4位
* prefix: 0A Byte
@@ -151,59 +147,59 @@ static status_t acpi_enter(driver_t *drv_obj)
/*
void acpi_shutdown(device_extension_t *devext)
{
- int i;
- uint16_t SLP_TYPa, SLP_TYPb;
- struct ACPISDTHeader *header = (struct ACPISDTHeader *)acpi_find_table(devext, "DSDT");
-
- char *S5Addr = (char *)header;
- int dsdtLength = (header->Length - sizeof(struct ACPISDTHeader))/4;
-
- for(i = 0; i < dsdtLength; i++)
- {
- if (memcmp(S5Addr, "_S5_", 4) == 0) break;
- S5Addr++;
- }
- if (i < dsdtLength)
- {
- if ( ( *(S5Addr-1) == 0x08 || ( *(S5Addr-2) == 0x08 && *(S5Addr-1) == '\\') ) && *(S5Addr+4) == 0x12 )
- {
- S5Addr+=5;
- S5Addr+=((*S5Addr&0xc0)>>6)+2;
-
- if (*S5Addr == 0x0a) S5Addr++;
- SLP_TYPa = *(S5Addr)<<10;
- S5Addr++;
-
- if (*S5Addr == 0x0a) S5Addr++;
- SLP_TYPb = *(S5Addr)<<10;
- S5Addr++;
- }
- // 关于PM1x_CNT_BLK的描述见 ACPI Specification Ver6.3 4.8.3.2.1
- io_out16(devext->FADT->PM1aControlBlock, SLP_TYPa | 1<<13);
- if (devext->FADT->PM1bControlBlock != 0)
- {
- io_out16(devext->FADT->PM1bControlBlock, SLP_TYPb | 1<<13);
- }
- }
+ int i;
+ uint16_t SLP_TYPa, SLP_TYPb;
+ struct ACPISDTHeader *header = (struct ACPISDTHeader
+*)acpi_find_table(devext, "DSDT");
+
+ char *S5Addr = (char *)header;
+ int dsdtLength = (header->Length - sizeof(struct ACPISDTHeader))/4;
+
+ for(i = 0; i < dsdtLength; i++)
+ {
+ if (memcmp(S5Addr, "_S5_", 4) == 0) break;
+ S5Addr++;
+ }
+ if (i < dsdtLength)
+ {
+ if ( ( *(S5Addr-1) == 0x08 || ( *(S5Addr-2) == 0x08 && *(S5Addr-1) ==
+'\\') ) && *(S5Addr+4) == 0x12 )
+ {
+ S5Addr+=5;
+ S5Addr+=((*S5Addr&0xc0)>>6)+2;
+
+ if (*S5Addr == 0x0a) S5Addr++;
+ SLP_TYPa = *(S5Addr)<<10;
+ S5Addr++;
+
+ if (*S5Addr == 0x0a) S5Addr++;
+ SLP_TYPb = *(S5Addr)<<10;
+ S5Addr++;
+ }
+ // 关于PM1x_CNT_BLK的描述见 ACPI Specification Ver6.3 4.8.3.2.1
+ io_out16(devext->FADT->PM1aControlBlock, SLP_TYPa | 1<<13);
+ if (devext->FADT->PM1bControlBlock != 0)
+ {
+ io_out16(devext->FADT->PM1bControlBlock, SLP_TYPb | 1<<13);
+ }
+ }
}
*/
-static status_t acpi_exit(driver_t *drv_obj)
-{
- device_t *devobj, *next;
- // device_extension_t *ext;
- list_for_each_owner_safe (devobj, next, &drv_obj->device_list, list) {
- device_delete(devobj);
- }
- string_del(&drv_obj->name);
- return SUCCUESS;
+static status_t acpi_exit(driver_t *drv_obj) {
+ device_t *devobj, *next;
+ // device_extension_t *ext;
+ list_for_each_owner_safe (devobj, next, &drv_obj->device_list, list) {
+ device_delete(devobj);
+ }
+ string_del(&drv_obj->name);
+ return SUCCUESS;
}
-static __init void acpi_driver_entry(void)
-{
- if (driver_create(acpi_driver, DRV_NAME) < 0) {
- printk(COLOR_RED "[driver] %s driver create failed!\n", __func__);
- }
+static __init void acpi_driver_entry(void) {
+ if (driver_create(acpi_driver, DRV_NAME) < 0) {
+ printk(COLOR_RED "[driver] %s driver create failed!\n", __func__);
+ }
}
driver_initcall(acpi_driver_entry);
diff --git a/src/arch/x86/drivers/apic.c b/src/arch/x86/drivers/apic.c
deleted file mode 100644
index 341fcb2..0000000
--- a/src/arch/x86/drivers/apic.c
+++ /dev/null
@@ -1,152 +0,0 @@
-/**
- * @file apic.c
- * @author Ryan Wang (ryan1202@foxmail.com)
- * @brief APIC驱动(参考xv6)
- * @version 0.1 Alpha
- * @date 2021-06
- */
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-
-void apic_timer_handler(void);
-
-uint32_t *lapic;
-char use_apic;
-
-volatile struct ioapic {
- uint32_t reg;
- uint32_t pad[3];
- uint32_t data;
-} *ioapic;
-
-// 检查是否支持x2APIC
-int check_apic_support(void) {
- uint32_t a, b, c, d;
- get_cpuid(1, 0, &a, &b, &c, &d);
- printk("CPUID 01H: eax:%x ebx:%x ecx:%x edx:%x\n", a, b, c, d);
- if (!(d & (1 << 9))) {
- printk(COLOR_RED "No Support APIC!\n");
- return -1;
- }
- return 0;
-}
-
-uint32_t io_apic_read(uint32_t reg) {
- ioapic->reg = reg;
- return ioapic->data;
-}
-
-void io_apic_write(uint32_t reg, uint32_t data) {
- ioapic->reg = reg;
- ioapic->data = data;
-}
-
-void lapic_write(int index, int value) {
- lapic[index / 4] = value;
- lapic[APIC_ID / 4];
-}
-
-uint32_t lapic_read(int index) {
- return lapic[index / 4];
-}
-
-void init_apic(void) {
- if (check_apic_support()) {
- init_8259a();
- return;
- }
- mask_8259a();
- use_apic = 1;
- // cpu_RDMSR(IA32_APIC_BASE, &l, &h);
- // printk("APIC Base:%#08x%08x\n", h, l);
- // cpu_WRMSR(IA32_APIC_BASE, l | (1<<10) | (1<<11), h);
- // //APIC全局使能,启用APIC
- lapic = remap(0xfee00000, 0x3ff);
- ioapic = remap(0xfec00000, 0xfff00);
- io_cli();
- lapic_write(APIC_SIVR, 1 << 8);
- // 设定Loacl APIC定时器
- lapic_write(APIC_TIMER_DCR, 0x0b); // divide by 16
- lapic_write(
- APIC_LVT_TIMER, (1 << 17) | (0x20 + LAPIC_TIMER_IRQ)); // 周期性计时
- int a, b, c, d;
- get_cpuid(
- 0x15, 0x00, (unsigned int *)&a, (unsigned int *)&b, (unsigned int *)&c,
- (unsigned int *)&d);
-
- lapic_write(APIC_TIMER_ICT, 100000);
-
- // 获取APICID
- /*
- * xAPIC Mode(Address:FEE0 0020H)
- * P6 family and Pentium processors: 24~27bit
- * Pentium 4 processors, Xeon processors, and later processors: 24~31bit
- *
- * x2APIC Mode(MSR Address: 802H):0~31bit
- */
- int apicid = lapic_read(APIC_ID);
- printk("APICID:%#x \n", apicid);
- // 获取APIC版本
- /*
- * 16~23位 Max LVT Entry
- * 0~7位 Version
- */
- printk("APIC Ver:%04x \n", lapic_read(APIC_Ver));
- // 屏蔽LVT
- // lapic_write(APIC_LVT_CMCI, 1<<16);
- // lapic_write(APIC_LVT_THMR, 1<<16);
- if (((lapic[APIC_Ver / 4] >> 16) & 0xff) >= 4) {
- lapic_write(APIC_LVT_PMCR, 1 << 16);
- }
- lapic_write(APIC_LVT_LINT0, 1 << 16);
- lapic_write(APIC_LVT_LINT1, 1 << 16);
- lapic_write(APIC_LVT_ERROR, 0xfe);
- lapic_write(APIC_ESR, 0);
- lapic_write(APIC_ESR, 0);
- lapic_write(APIC_EOI, 0);
-
- lapic_write(APIC_ICR_HIGH, 0);
- lapic_write(APIC_ICR_LOW, (1 << 19) | (1 << 15) | (1 << 10) | (1 << 8));
- while (lapic[APIC_ICR_LOW / 4] & (1 << 12))
- ;
-
- lapic_write(APIC_TPR, 0);
-
- int i, count = (io_apic_read(IOAPIC_VER) >> 16) & 0xff;
- for (i = 0; i <= count; i++) {
- io_apic_write(IOAPIC_TBL + i * 2, APIC_INT_DISABLE | (0x20 + i));
- io_apic_write(IOAPIC_TBL + i * 2 + 1, 0);
- }
-
- put_irq_handler(LAPIC_TIMER_IRQ, (irq_handler_t)apic_timer_handler);
- apic_enable_irq(LAPIC_TIMER_IRQ);
-}
-
-void apic_timer_handler(void) {
- struct task_s *cur_thread = get_current_thread();
- cur_thread->elapsed_ticks++;
-
- if (cur_thread->ticks == 0) {
- schedule();
- } else {
- cur_thread->ticks--;
- }
-}
-
-void apic_enable_irq(int irq) {
- io_apic_write(IOAPIC_TBL + irq * 2, 0x20 + irq);
- io_apic_write(IOAPIC_TBL + irq * 2 + 1, 0);
-}
-
-void apic_eoi(void) {
- lapic_write(APIC_EOI, 0);
-}
\ No newline at end of file
diff --git a/src/arch/x86/drivers/bus/Makefile b/src/arch/x86/drivers/bus/Makefile
new file mode 100644
index 0000000..5bda361
--- /dev/null
+++ b/src/arch/x86/drivers/bus/Makefile
@@ -0,0 +1,2 @@
+SRC += pci/
+SRC += isa/
\ No newline at end of file
diff --git a/src/arch/x86/drivers/bus/config.toml b/src/arch/x86/drivers/bus/config.toml
new file mode 100644
index 0000000..8d07c67
--- /dev/null
+++ b/src/arch/x86/drivers/bus/config.toml
@@ -0,0 +1 @@
+dir = ["isa/", "pci/"]
diff --git a/src/arch/x86/drivers/bus/isa/Makefile b/src/arch/x86/drivers/bus/isa/Makefile
new file mode 100644
index 0000000..df21898
--- /dev/null
+++ b/src/arch/x86/drivers/bus/isa/Makefile
@@ -0,0 +1,2 @@
+SRC += isa.c
+SRC += dma.c
\ No newline at end of file
diff --git a/src/arch/x86/drivers/bus/isa/config.toml b/src/arch/x86/drivers/bus/isa/config.toml
new file mode 100644
index 0000000..160f80d
--- /dev/null
+++ b/src/arch/x86/drivers/bus/isa/config.toml
@@ -0,0 +1 @@
+c = ["dma.c", "isa.c"]
diff --git a/src/arch/x86/drivers/bus/isa/dma.c b/src/arch/x86/drivers/bus/isa/dma.c
new file mode 100644
index 0000000..f87c0cc
--- /dev/null
+++ b/src/arch/x86/drivers/bus/isa/dma.c
@@ -0,0 +1,191 @@
+/**
+ * @file dma.c
+ * @author Ryan Wang (ryan1202@foxmail.com)
+ * @brief (ISA)DMA驱动
+ * @version 0.1
+ * @date 2021-7
+ */
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+
+DmaOps isa_dma_ops = {
+ .dma_alloc = dma_alloc_region,
+ .dma_free = dma_free_region,
+};
+
+#define DMA_MEM_BASE_ADDR 0x800000
+
+LogicalDevice *dma_channels[8]; // 使用DMA通道的设备
+
+struct mmap dma_mem_mmap;
+spinlock_t dma_spin_lock;
+
+int dma_lock() {
+ return spin_lock_irqsave(&dma_spin_lock);
+}
+
+void dma_unlock(int flags) {
+ spin_unlock_irqrestore(&dma_spin_lock, flags);
+}
+
+void dma_init() {
+ spinlock_init(&dma_spin_lock);
+ dma_mem_mmap.bits = kmalloc(DMA_MAX_REGION_COUNT / 8);
+ dma_mem_mmap.len = DMA_MAX_REGION_COUNT / 8;
+ memset(dma_mem_mmap.bits, 0, dma_mem_mmap.len);
+}
+
+void *dma_alloc_region(Dma *dma, uint32_t size) {
+ int cnt = DIV_ROUND_UP(size, 64 * 1024);
+ int idx = mmap_search(&dma_mem_mmap, cnt);
+ if (idx == -1) return NULL;
+
+ for (int i = 0; i < cnt; i++) {
+ mmap_set(&dma_mem_mmap, idx + i, 1);
+ }
+ return (void *)(DMA_MEM_BASE_ADDR + idx * DMA_REGION_SIZE);
+}
+
+DriverResult dma_free_region(Dma *dma, void *ptr, uint32_t size) {
+ int cnt = DIV_ROUND_UP(size, 64 * 1024);
+ int idx = ((uint32_t)ptr - DMA_MEM_BASE_ADDR) / DMA_REGION_SIZE;
+ for (int i = 0; i < cnt; i++) {
+ mmap_set(&dma_mem_mmap, idx + i, 0);
+ }
+ return DRIVER_OK;
+}
+
+uint32_t get_dma_count(int channel) {
+ uint16_t count;
+ uint8_t port;
+ if (channel < 4) {
+ port = DMA0 + (channel << 1) + 1;
+ } else {
+ port = DMA1 + ((channel & 3) << 2) + 2;
+ }
+ count = io_in8(port);
+ count += io_in8(port) << 8;
+ count++;
+ return channel < 4 ? count : count << 1;
+}
+
+uint32_t dma_pointer(int channel, uint32_t size) {
+ uint32_t result;
+
+ int flags = dma_lock();
+ dma_ff_reset(channel);
+ result = get_dma_count(channel);
+ dma_unlock(flags);
+
+ if (result >= size || result == 0) return 0;
+ else return size - result;
+}
+
+int dma_channel_use(LogicalDevice *device, int *possible_ch, int len) {
+ for (int i = 0; i < len; i++) {
+ if (dma_channels[possible_ch[i]] == NULL) {
+ dma_channels[possible_ch[i]] = device;
+ return possible_ch[i];
+ }
+ }
+ return -1;
+}
+
+void dma_channel_unuse(LogicalDevice *device, uint8_t channel) {
+ if (channel < 8) {
+ if (dma_channels[channel] == device) dma_channels[channel] = NULL;
+ }
+}
+
+void dma_enable(unsigned int channel) {
+ if (channel < 4) {
+ io_out8(DMA1_REG_MASK, channel);
+ } else {
+ io_out8(DMA2_REG_MASK, channel & 3);
+ }
+}
+
+void dma_disable(unsigned int channel) {
+ if (channel < 4) {
+ io_out8(DMA1_REG_MASK, channel | 4);
+ } else {
+ io_out8(DMA2_REG_MASK, (channel & 3) | 4);
+ }
+}
+
+void dma_ff_reset(unsigned int channel) {
+ if (channel < 4) {
+ io_out8(DMA1_REG_FF_RESET, 0);
+ } else {
+ io_out8(DMA2_REG_FF_RESET, 0);
+ }
+}
+
+void dma_set_mode(unsigned int channel, char mode) {
+ if (channel < 4) {
+ io_out8(DMA1_REG_MODE, mode | channel);
+ } else {
+ io_out8(DMA2_REG_MODE, mode | (channel & 3));
+ }
+}
+
+void dma_set_page(unsigned int channel, char page) {
+ switch (channel) {
+ case 0:
+ io_out8(DMA_PAGE0, page);
+ break;
+ case 1:
+ io_out8(DMA_PAGE1, page);
+ break;
+ case 2:
+ io_out8(DMA_PAGE2, page);
+ break;
+ case 3:
+ io_out8(DMA_PAGE3, page);
+ break;
+ case 5:
+ io_out8(DMA_PAGE5, page & 0xfe);
+ break;
+ case 6:
+ io_out8(DMA_PAGE6, page & 0xfe);
+ break;
+ case 7:
+ io_out8(DMA_PAGE7, page & 0xfe);
+ break;
+
+ default:
+ break;
+ }
+}
+
+void dma_set_addr(unsigned int channel, unsigned int addr) {
+ dma_set_page(channel, addr >> 16);
+ if (channel <= 3) {
+ io_out8(DMA0 + ((channel & 3) << 1), addr & 0xff);
+ io_out8(DMA0 + ((channel & 3) << 1), (addr >> 8) & 0xff);
+ } else {
+ io_out8(DMA1 + ((channel & 3) << 2), (addr >> 1) & 0xff);
+ io_out8(DMA1 + ((channel & 3) << 2), (addr >> 9) & 0xff);
+ }
+}
+
+void dma_set_count(unsigned int channel, unsigned int count) {
+ count--;
+ if (channel <= 3) {
+ io_out8(DMA0 + ((channel & 3) << 1) + 1, count & 0xff);
+ io_out8(DMA0 + ((channel & 3) << 1) + 1, (count >> 8) & 0xff);
+ } else {
+ io_out8(DMA1 + ((channel & 3) << 2) + 2, (count >> 1) & 0xff);
+ io_out8(DMA1 + ((channel & 3) << 2) + 2, (count >> 9) & 0xff);
+ }
+}
diff --git a/src/arch/x86/drivers/bus/isa/isa.c b/src/arch/x86/drivers/bus/isa/isa.c
new file mode 100644
index 0000000..aabe7d6
--- /dev/null
+++ b/src/arch/x86/drivers/bus/isa/isa.c
@@ -0,0 +1,94 @@
+#include "kernel/initcall.h"
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+LIST_HEAD(isa_driver_lh);
+
+DriverResult isa_driver_init(Driver *driver);
+DriverResult isa_probe(BusDriver *bus_driver, Bus *bus);
+DriverResult isa_init_bus(BusDriver *bus_driver);
+
+BusOps isa_bus_ops = {
+ .scan_bus = NULL,
+ .probe_device = isa_probe,
+};
+
+DriverDependency isa_dependencies[] = {
+ {
+ .in_type = DRIVER_DEPENDENCY_TYPE_BUS,
+ .dependency_in_bus = {BUS_TYPE_PLATFORM, 0},
+ .out_bus = NULL,
+ },
+};
+Driver isa_driver = {
+ .short_name = STRING_INIT("IsaDriver"),
+};
+DeviceDriver isa_device_driver;
+BusDriver isa_bus_driver = {
+ .name = STRING_INIT("ISA"),
+};
+Bus *isa_bus;
+
+DriverResult isa_register_device_driver(
+ DeviceDriver *device_driver, IsaOps *ops) {
+ IsaDeviceDriver *isa_device_driver = kmalloc(sizeof(IsaDeviceDriver));
+ if (isa_device_driver == NULL) { return DRIVER_ERROR_OUT_OF_MEMORY; }
+
+ isa_device_driver->device_driver = device_driver;
+ isa_device_driver->ops = ops;
+ list_add_tail(&isa_device_driver->list, &isa_driver_lh);
+
+ return DRIVER_OK;
+}
+
+DriverResult isa_probe(BusDriver *bus_driver, Bus *bus) {
+ IsaDeviceDriver *isa_device_driver;
+ list_for_each_owner (isa_device_driver, &isa_driver_lh, list) {
+ isa_device_driver->bus_driver = bus_driver;
+ isa_device_driver->bus = bus;
+ isa_device_driver->ops->probe(isa_device_driver);
+ }
+ return DRIVER_OK;
+}
+
+static void __init isa_initcall(void) {
+ DriverResult result;
+ ObjectAttr attr = driver_object_attr;
+
+ result = register_driver(&isa_driver);
+ if (result != DRIVER_OK) goto failed_register_driver;
+
+ result = register_device_driver(&isa_driver, &isa_device_driver);
+ if (result != DRIVER_OK) goto failed_register_device_driver;
+
+ result =
+ register_bus_driver(&isa_driver, BUS_TYPE_ISA, &isa_bus_driver, &attr);
+ if (result != DRIVER_OK) goto failed_resgister_bus_driver;
+
+ result = create_bus(&isa_bus, &isa_bus_driver, &isa_bus_ops);
+ if (result != DRIVER_OK) goto failed_create_bus;
+
+ return;
+
+failed_create_bus:
+ unregister_bus_driver(&isa_bus_driver);
+
+failed_resgister_bus_driver:
+ unregister_device_driver(&isa_device_driver);
+
+failed_register_device_driver:
+ unregister_driver(&isa_driver);
+
+failed_register_driver:
+ return;
+}
+
+driver_initcall(isa_initcall);
diff --git a/src/arch/x86/drivers/bus/pci/Makefile b/src/arch/x86/drivers/bus/pci/Makefile
new file mode 100644
index 0000000..7a5d8a6
--- /dev/null
+++ b/src/arch/x86/drivers/bus/pci/Makefile
@@ -0,0 +1 @@
+SRC += pci.c
\ No newline at end of file
diff --git a/src/arch/x86/drivers/bus/pci/config.toml b/src/arch/x86/drivers/bus/pci/config.toml
new file mode 100644
index 0000000..b90a931
--- /dev/null
+++ b/src/arch/x86/drivers/bus/pci/config.toml
@@ -0,0 +1 @@
+c = ["pci.c"]
diff --git a/src/arch/x86/drivers/bus/pci/pci.c b/src/arch/x86/drivers/bus/pci/pci.c
new file mode 100644
index 0000000..04dd934
--- /dev/null
+++ b/src/arch/x86/drivers/bus/pci/pci.c
@@ -0,0 +1,616 @@
+/**
+ * @file pci.c
+ * @author Ryan Wang (ryan1202@foxmail.com)
+ * @brief
+ * @version 0.1
+ * @date 2020-07
+ */
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+LIST_HEAD(pci_driver_lh);
+
+PciDevice pci_devices[PCI_MAX_DEVICE];
+
+DriverResult pci_device_init(void *device);
+DriverResult pci_scan_bus(BusDriver *bus_driver, Bus *bus);
+DriverResult pci_init_bus(BusDriver *bus_driver);
+DriverResult pci_probe(BusDriver *bus_driver, Bus *bus);
+
+DeviceOps pci_device_ops = {
+ .init = pci_device_init,
+ .start = NULL,
+ .stop = NULL,
+ .destroy = NULL,
+};
+BusOps pci_bus_ops = {
+ .scan_bus = pci_scan_bus,
+ .probe_device = pci_probe,
+};
+
+DriverDependency pci_dependencies[] = {
+ {
+ .in_type = DRIVER_DEPENDENCY_TYPE_BUS,
+ .dependency_in_bus = {BUS_TYPE_PLATFORM, 0},
+ .out_bus = NULL,
+ },
+};
+Driver pci_driver = {
+ .short_name = STRING_INIT("PciDriver"),
+};
+DeviceDriver pci_device_driver;
+BusDriver pci_bus_driver = {
+ .name = STRING_INIT("PCI"),
+};
+
+DEF_PCI_RW(8)
+DEF_PCI_RW(16)
+DEF_PCI_RW(32)
+DEF_PCI_RW_DEVICE(8)
+DEF_PCI_RW_DEVICE(16)
+DEF_PCI_RW_DEVICE(32)
+
+void fill_pci_device_info(
+ PciDevice *dev, uint8_t bus, uint8_t device, uint8_t func,
+ uint16_t vendorID, uint16_t deviceID, uint32_t classcode,
+ uint8_t revisionID, uint8_t multifunction, uint8_t header_type,
+ uint8_t bist, uint8_t latency_timer, uint8_t cache_line_size) {
+ int i;
+
+ dev->bus_num = bus;
+ dev->dev_num = device;
+ dev->function_num = func;
+ dev->vendor_id = vendorID;
+ dev->device_id = deviceID;
+ dev->classcode = classcode >> 16;
+ dev->subclass = (classcode & 0xff00) >> 8;
+ dev->prog_if = classcode & 0xff;
+ dev->revision_id = revisionID;
+ dev->multifunction = multifunction;
+ dev->header_type = header_type;
+ dev->bist = bist;
+ dev->latency_timer = latency_timer;
+ dev->cache_line_size = cache_line_size;
+
+ for (i = 0; i < PCI_MAX_BAR; i++) {
+ dev->common.bar[i].type = PCI_BAR_TYPE_INVALID;
+ }
+ dev->irqline = -1;
+}
+void pci_enable_bus_mastering(PciDevice *pci_device) {
+ uint32_t value = pci_read32(
+ pci_device->bus_num, pci_device->dev_num, pci_device->function_num,
+ 0x04);
+ value |= 4;
+ pci_write32(
+ pci_device->bus_num, pci_device->dev_num, pci_device->function_num,
+ 0x04, value);
+}
+
+void pci_enable_io_space(PciDevice *pci_device) {
+ uint32_t value = pci_read32(
+ pci_device->bus_num, pci_device->dev_num, pci_device->function_num,
+ 0x04);
+ value |= 1;
+ pci_write32(
+ pci_device->bus_num, pci_device->dev_num, pci_device->function_num,
+ 0x04, value);
+}
+
+void pci_enable_mem_space(PciDevice *pci_device) {
+ uint32_t value = pci_read32(
+ pci_device->bus_num, pci_device->dev_num, pci_device->function_num,
+ 0x04);
+ value |= 2;
+ pci_write32(
+ pci_device->bus_num, pci_device->dev_num, pci_device->function_num,
+ 0x04, value);
+}
+
+uint32_t pci_device_get_mem_addr(PciDevice *pci_device) {
+ int i;
+
+ if (pci_device->header_type == 0x0) {
+ for (i = 0; i < PCI_MAX_BAR; i++) {
+ if (pci_device->common.bar[i].type == PCI_BAR_TYPE_MEM) {
+ return pci_device->common.bar[i].base_addr;
+ }
+ }
+ } else if (pci_device->header_type == 0x1) {
+ for (i = 0; i < 2; i++) {
+ if (pci_device->pci2pci_bridge.bar[i].type == PCI_BAR_TYPE_MEM) {
+ return pci_device->pci2pci_bridge.bar[i].base_addr;
+ }
+ }
+ }
+ return -1;
+}
+
+uint32_t pci_device_get_io_addr(PciDevice *pci_device) {
+ int i;
+
+ if (pci_device->header_type == 0x0) {
+ for (i = 0; i < PCI_MAX_BAR; i++) {
+ if (pci_device->common.bar[i].type == PCI_BAR_TYPE_IO) {
+ return pci_device->common.bar[i].base_addr;
+ }
+ }
+ } else if (pci_device->header_type == 0x1) {
+ for (i = 0; i < 2; i++) {
+ if (pci_device->pci2pci_bridge.bar[i].type == PCI_BAR_TYPE_IO) {
+ return pci_device->pci2pci_bridge.bar[i].base_addr;
+ }
+ }
+ }
+ return -1;
+}
+
+DriverResult pci_scan_bus(BusDriver *bus_driver, Bus *bus) {
+ int i, j;
+ PciDevice *pci_device;
+ print_info(
+ "PCI", "device id\tvendor id\theader "
+ "type\tclasscode\tsubclass\tprogif\trevision id\n");
+ for (i = 0; i < PCI_MAX_DEV; i++) {
+ for (j = 0; j < PCI_MAX_FUNC; j++) {
+ DriverResult result =
+ pci_scan_device(bus, bus->bus_num, i, j, &pci_device);
+ if (result == DRIVER_ERROR_NOT_EXIST) {
+ continue;
+ } else if (result == DRIVER_ERROR_NULL_POINTER) {
+ print_error_with_position(
+ "pci_probe_bus: pci device(%d:%d:%d) alloc failed!\n",
+ bus->bus_num, i, j);
+ continue;
+ } else if (result == DRIVER_ERROR_UNSUPPORT_DEVICE) {
+ print_error_with_position(
+ "pci_probe_bus: pci device(%d:%d:%d) unsupport! Header "
+ "Type:%d\n",
+ bus->bus_num, i, j, pci_device->header_type);
+ continue;
+ }
+
+ pci_device->status = PCI_DEVICE_STATUS_UNUSED;
+ print_info(
+ "PCI",
+ "%#06x\t\t%#06x\t\t%#04x\t\t%#04x\t\t%#04x\t\t%#04x\t%#04x\n",
+ pci_device->device_id, pci_device->vendor_id,
+ pci_device->header_type, pci_device->classcode,
+ pci_device->subclass, pci_device->prog_if,
+ pci_device->revision_id);
+ if (!pci_device->multifunction) {
+ // 没有多个功能就枚举下一个设备
+ break;
+ }
+
+ if (pci_device->header_type == 1) { // 为PCI-to-PCI桥
+ Bus *new_bus;
+
+ DRV_RESULT_PRINT_CALL(
+ create_bus(&new_bus, &pci_bus_driver, &pci_bus_ops));
+ }
+ }
+ }
+ return DRIVER_OK;
+}
+
+PciDevice *pci_alloc_device(void) {
+ int i;
+
+ for (i = 0; i < PCI_MAX_DEVICE; i++) {
+ if (pci_devices[i].status == PCI_DEVICE_STATUS_INVALID) {
+ pci_devices[i].status = PCI_DEVICE_STATUS_USING;
+ return &pci_devices[i];
+ }
+ }
+ return NULL;
+}
+
+uint32_t pci_get_device_connected(void) {
+ int i;
+ PciDevice *device;
+ for (i = 0; i < PCI_MAX_BAR; i++) {
+ device = &pci_devices[i];
+ if (device->status != PCI_DEVICE_STATUS_USING) { break; }
+ }
+ return i;
+}
+
+int pci_free_device(PciDevice *dev) {
+ int i;
+
+ for (i = 0; i < PCI_MAX_DEVICE; i++) {
+ if (&pci_devices[i] == dev) {
+ dev->status = PCI_DEVICE_STATUS_INVALID;
+ return 0;
+ }
+ }
+ return -1;
+}
+
+void get_pci_bar_info(PciDeviceBar *bar, uint32_t addr, uint32_t len) {
+ if (addr == 0xffffffff) { addr = 0; }
+ if (addr & 1) // I/O内存
+ {
+ bar->type = PCI_BAR_TYPE_IO;
+ bar->base_addr = addr & PCI_BAR_IO_MASK;
+ bar->length = ~(len & PCI_BAR_IO_MASK) + 1;
+ } else {
+ bar->type = PCI_BAR_TYPE_MEM;
+ bar->base_addr = addr & PCI_BAR_MEM_MASK;
+ bar->length = ~(len & PCI_BAR_MEM_MASK) + 1;
+ }
+}
+
+DriverResult pci_scan_device(
+ Bus *bus, uint8_t bus_num, uint8_t device_num, uint8_t function_num,
+ PciDevice **out_pci_device) {
+ uint32_t value = pci_read32(bus_num, device_num, function_num, 0);
+ uint16_t vendorID = value & 0xffff;
+ uint16_t deviceID = value >> 16;
+ if (vendorID == 0xffff) { return DRIVER_ERROR_NOT_EXIST; }
+
+ value = pci_read32(bus_num, device_num, function_num, 0x0c);
+ uint8_t bist = value >> 24;
+ uint8_t multifunction = (value >> 23) & 0x01;
+ uint8_t header_type = (value >> 16) & 0x7f;
+ uint8_t latency_timer = value >> 8;
+ uint8_t cache_line_size = value & 0xff;
+
+ value = pci_read32(bus_num, device_num, function_num, 8);
+ uint32_t classcode = value >> 8;
+ uint8_t revisionID = value & 0xff;
+
+ PciDevice *pci_device = pci_alloc_device();
+ if (pci_device == NULL) { return DRIVER_ERROR_NULL_POINTER; }
+ *out_pci_device = pci_device;
+ pci_device->device = NULL;
+ fill_pci_device_info(
+ pci_device, bus_num, device_num, function_num, vendorID, deviceID,
+ classcode, revisionID, multifunction, header_type, bist, latency_timer,
+ cache_line_size);
+
+ if (header_type == 0x00) {
+ int bar;
+ for (bar = 0; bar < PCI_MAX_BAR; bar++) {
+ value = pci_read32(bus_num, device_num, function_num, PCI_BAR(bar));
+ pci_write32(
+ bus_num, device_num, function_num, PCI_BAR(bar), 0xffffffff);
+ uint32_t len =
+ pci_read32(bus_num, device_num, function_num, PCI_BAR(bar));
+ pci_write32(bus_num, device_num, function_num, PCI_BAR(bar), value);
+
+ if (len != 0 && len != 0xffffffff) {
+ get_pci_bar_info(&pci_device->common.bar[bar], value, len);
+ }
+ }
+
+ value = pci_read32(bus_num, device_num, function_num, 0x28);
+ pci_device->common.cardbus_cis_pointer = value;
+
+ value = pci_read32(bus_num, device_num, function_num, 0x2c);
+ pci_device->common.subsystem_id = value >> 16;
+ pci_device->common.subsystem_vendor_id = value & 0xffff;
+
+ value = pci_read32(bus_num, device_num, function_num, 0x30);
+ pci_device->common.expension_rom_base_address = value;
+
+ value = pci_read32(bus_num, device_num, function_num, 0x34);
+ pci_device->common.capabilities_pointer = value & 0xff;
+
+ value = pci_read32(bus_num, device_num, function_num, 0x3c);
+ pci_device->common.max_latency = value >> 24;
+ pci_device->common.min_grant = value >> 16;
+ } else if (header_type == 0x01) {
+ int bar;
+ for (bar = 0; bar < 2; bar++) {
+ value = pci_read32(bus_num, device_num, function_num, PCI_BAR(bar));
+ pci_write32(
+ bus_num, device_num, function_num, PCI_BAR(bar), 0xffffffff);
+ uint32_t len =
+ pci_read32(bus_num, device_num, function_num, PCI_BAR(bar));
+ pci_write32(bus_num, device_num, function_num, PCI_BAR(bar), value);
+
+ if (len != 0 && len != 0xffffffff) {
+ get_pci_bar_info(&pci_device->common.bar[bar], value, len);
+ }
+ }
+
+ value = pci_read32(bus_num, device_num, function_num, 0x18);
+ pci_device->pci2pci_bridge.secondary_latency_timer = value >> 24;
+ pci_device->pci2pci_bridge.subordinate_bus_number = value >> 16;
+ pci_device->pci2pci_bridge.secondary_bus_number = value >> 8;
+ pci_device->pci2pci_bridge.primary_bus_number = value & 0xff;
+
+ value = pci_read32(bus_num, device_num, function_num, 0x1c);
+ pci_device->pci2pci_bridge.secondary_status = value >> 16;
+ pci_device->pci2pci_bridge.io_limit = value >> 8;
+ pci_device->pci2pci_bridge.io_base = value & 0xff;
+
+ value = pci_read32(bus_num, device_num, function_num, 0x20);
+ pci_device->pci2pci_bridge.memory_limit = value >> 16;
+ pci_device->pci2pci_bridge.memory_base = value & 0xffff;
+
+ value = pci_read32(bus_num, device_num, function_num, 0x24);
+ pci_device->pci2pci_bridge.prefetchable_memory_limit = value >> 16;
+ pci_device->pci2pci_bridge.prefetchable_memory_base = value & 0xffff;
+
+ value = pci_read32(bus_num, device_num, function_num, 0x28);
+ pci_device->pci2pci_bridge.prefetchable_base_upper = value;
+ value = pci_read32(bus_num, device_num, function_num, 0x2c);
+ pci_device->pci2pci_bridge.prefetchable_limit_upper = value;
+
+ value = pci_read32(bus_num, device_num, function_num, 0x30);
+ pci_device->pci2pci_bridge.io_limit_upper = value >> 16;
+ pci_device->pci2pci_bridge.io_base_upper = value & 0xffff;
+
+ value = pci_read32(bus_num, device_num, function_num, 0x34);
+ pci_device->pci2pci_bridge.capabilities_pointer = value & 0xff;
+
+ value = pci_read32(bus_num, device_num, function_num, 0x38);
+ pci_device->pci2pci_bridge.expension_rom_base_address = value;
+
+ value = pci_read32(bus_num, device_num, function_num, 0x3c);
+ pci_device->pci2pci_bridge.bridge_control = value >> 16;
+ } else if (header_type == 0x02) {
+ value = pci_read32(bus_num, device_num, function_num, 0x10);
+ pci_device->pci2cardbus_bridge.cardbus_socket_base_address = value;
+
+ value = pci_read32(bus_num, device_num, function_num, 0x14);
+ pci_device->pci2cardbus_bridge.secondary_status = value >> 16;
+ pci_device->pci2cardbus_bridge.capabilities_offset = value & 0xff;
+
+ value = pci_read32(bus_num, device_num, function_num, 0x18);
+ pci_device->pci2cardbus_bridge.cardbus_latency_timer = value >> 24;
+ pci_device->pci2cardbus_bridge.subordiante_bus_number = value >> 16;
+ pci_device->pci2cardbus_bridge.cardbus_bus_number = value >> 8;
+ pci_device->pci2cardbus_bridge.pci_bus_number = value & 0xff;
+
+ value = pci_read32(bus_num, device_num, function_num, 0x1c);
+ pci_device->pci2cardbus_bridge.memory_base0 = value;
+ value = pci_read32(bus_num, device_num, function_num, 0x20);
+ pci_device->pci2cardbus_bridge.memory_limit0 = value;
+
+ value = pci_read32(bus_num, device_num, function_num, 0x24);
+ pci_device->pci2cardbus_bridge.memory_base1 = value;
+ value = pci_read32(bus_num, device_num, function_num, 0x28);
+ pci_device->pci2cardbus_bridge.memory_limit1 = value;
+
+ value = pci_read32(bus_num, device_num, function_num, 0x2c);
+ pci_device->pci2cardbus_bridge.io_base0 = value;
+ value = pci_read32(bus_num, device_num, function_num, 0x30);
+ pci_device->pci2cardbus_bridge.io_limit0 = value;
+
+ value = pci_read32(bus_num, device_num, function_num, 0x34);
+ pci_device->pci2cardbus_bridge.io_base1 = value;
+ value = pci_read32(bus_num, device_num, function_num, 0x38);
+ pci_device->pci2cardbus_bridge.io_limit1 = value;
+
+ value = pci_read32(bus_num, device_num, function_num, 0x40);
+ pci_device->pci2cardbus_bridge.subsystem_vendor_id = value >> 16;
+ pci_device->pci2cardbus_bridge.subsystem_device_id = value & 0xffff;
+
+ value = pci_read32(bus_num, device_num, function_num, 0x44);
+ pci_device->pci2cardbus_bridge.legacy_base_address = value;
+
+ value = pci_read32(bus_num, device_num, function_num, 0x3c);
+ pci_device->pci2cardbus_bridge.bridge_control = value >> 16;
+ } else {
+ print_error_with_position(
+ "unsupport PCI Header Type: %d\n", header_type);
+ return DRIVER_ERROR_UNSUPPORT_DEVICE;
+ }
+ pci_device->irqline = value & 0xff;
+ pci_device->irqpin = value >> 8;
+
+ PciDriver *pci_driver;
+ list_for_each_owner (pci_driver, &pci_driver_lh, pci_driver_list) {
+ if (pci_driver->pci_device != NULL) { continue; }
+ if (pci_driver->find_type == FIND_BY_VENDORID_DEVICEID) {
+ if (pci_driver->vendor_device.vendor_id == vendorID &&
+ pci_driver->vendor_device.device_id == deviceID) {
+ pci_device->pci_driver = pci_driver;
+ pci_driver->pci_device = pci_device;
+ break;
+ }
+ } else if (pci_driver->find_type == FIND_BY_CLASSCODE_SUBCLASS) {
+ if (pci_driver->class_subclass.classcode == classcode &&
+ pci_driver->class_subclass.subclass == pci_device->subclass) {
+ pci_device->pci_driver = pci_driver;
+ pci_driver->pci_device = pci_device;
+ break;
+ }
+ } else if (pci_driver->find_type == FIND_BY_CLASSCODE_SUBCLASS_PROGIF) {
+ if (pci_driver->class_subclass_progif.classcode == classcode &&
+ pci_driver->class_subclass_progif.subclass ==
+ pci_device->subclass &&
+ pci_driver->class_subclass_progif.progif ==
+ pci_device->prog_if) {
+ pci_device->pci_driver = pci_driver;
+ pci_driver->pci_device = pci_device;
+ break;
+ }
+ }
+ }
+
+ return DRIVER_OK;
+}
+
+bool pci_match_driver(PciDriver *pci_driver, PciDriver *new_pci_driver) {
+ if (new_pci_driver->find_type == FIND_BY_VENDORID_DEVICEID) {
+ if (new_pci_driver->vendor_device.vendor_id ==
+ pci_driver->vendor_device.vendor_id &&
+ new_pci_driver->vendor_device.device_id ==
+ pci_driver->vendor_device.device_id) {
+ return true;
+ }
+ } else if (new_pci_driver->find_type == FIND_BY_CLASSCODE_SUBCLASS) {
+ if (new_pci_driver->class_subclass.classcode ==
+ pci_driver->class_subclass.classcode &&
+ new_pci_driver->class_subclass.subclass ==
+ pci_driver->class_subclass.subclass) {
+ return true;
+ }
+ } else if (new_pci_driver->find_type == FIND_BY_CLASSCODE_SUBCLASS_PROGIF) {
+ if (new_pci_driver->class_subclass_progif.classcode ==
+ pci_driver->class_subclass_progif.classcode &&
+ new_pci_driver->class_subclass_progif.subclass ==
+ pci_driver->class_subclass_progif.subclass &&
+ new_pci_driver->class_subclass_progif.progif ==
+ pci_driver->class_subclass_progif.progif) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool pci_match_device(PciDriver *pci_driver, PciDevice *pci_device) {
+ if (pci_driver->find_type == FIND_BY_VENDORID_DEVICEID) {
+ if (pci_driver->vendor_device.vendor_id == pci_device->vendor_id &&
+ pci_driver->vendor_device.device_id == pci_device->device_id) {
+ return true;
+ }
+ } else if (pci_driver->find_type == FIND_BY_CLASSCODE_SUBCLASS) {
+ if (pci_driver->class_subclass.classcode == pci_device->classcode &&
+ pci_driver->class_subclass.subclass == pci_device->subclass) {
+ return true;
+ }
+ } else if (pci_driver->find_type == FIND_BY_CLASSCODE_SUBCLASS_PROGIF) {
+ if (pci_driver->class_subclass_progif.classcode ==
+ pci_device->classcode &&
+ pci_driver->class_subclass_progif.subclass ==
+ pci_device->subclass &&
+ pci_driver->class_subclass_progif.progif == pci_device->prog_if) {
+ return true;
+ }
+ }
+ return false;
+}
+
+DriverResult pci_register_driver(Driver *driver, PciDriver *new_pci_driver) {
+ PciDriver *old_pci_driver;
+ list_for_each_owner (old_pci_driver, &pci_driver_lh, pci_driver_list) {
+ if (new_pci_driver->find_type == old_pci_driver->find_type) {
+ if (pci_match_driver(old_pci_driver, new_pci_driver)) {
+ return DRIVER_ERROR_CONFLICT;
+ }
+ break;
+ } else if (
+ new_pci_driver->find_type == FIND_BY_CLASSCODE_SUBCLASS_PROGIF &&
+ old_pci_driver->find_type == FIND_BY_CLASSCODE_SUBCLASS) {
+ if (new_pci_driver->class_subclass_progif.classcode ==
+ old_pci_driver->class_subclass_progif.classcode &&
+ new_pci_driver->class_subclass_progif.subclass ==
+ old_pci_driver->class_subclass_progif.subclass &&
+ new_pci_driver->class_subclass_progif.progif ==
+ old_pci_driver->class_subclass_progif.progif) {
+ list_del(&old_pci_driver->pci_driver_list);
+ break;
+ }
+ } else if (
+ new_pci_driver->find_type == FIND_BY_CLASSCODE_SUBCLASS &&
+ old_pci_driver->find_type == FIND_BY_CLASSCODE_SUBCLASS_PROGIF) {
+ if (new_pci_driver->class_subclass.classcode ==
+ old_pci_driver->class_subclass.classcode &&
+ new_pci_driver->class_subclass.subclass ==
+ old_pci_driver->class_subclass.subclass) {
+ return DRIVER_ERROR_CONFLICT;
+ }
+ }
+ }
+
+ list_add_tail(&new_pci_driver->pci_driver_list, &pci_driver_lh);
+ return DRIVER_OK;
+}
+
+DriverResult pci_device_init(void *device) {
+ int i;
+ for (i = 0; i < PCI_MAX_DEVICE; i++) {
+ pci_devices[i].status = PCI_DEVICE_STATUS_INVALID;
+ }
+ return DRIVER_OK;
+}
+
+DriverResult pci_probe(BusDriver *bus_driver, Bus *bus) {
+ ObjectAttr attr = device_object_attr;
+ PciDriver *pci_driver, *select;
+ PhysicalDevice *device;
+ DriverResult result;
+ for (int i = 0; i < PCI_MAX_DEVICE; i++) {
+ if (pci_devices[i].status == PCI_DEVICE_STATUS_UNUSED) {
+ if (pci_devices[i].device == NULL) {
+ result = create_physical_device(&device, bus, &attr);
+ if (result != DRIVER_OK) continue;
+ pci_devices[i].device = device;
+ device->bus_ext = &pci_devices[i];
+ }
+
+ select = NULL;
+ list_for_each_owner (pci_driver, &pci_driver_lh, pci_driver_list) {
+ if (pci_match_device(pci_driver, &pci_devices[i])) {
+ select = pci_driver;
+ }
+ }
+ if (select != NULL) {
+ pci_devices[i].status = PCI_DEVICE_STATUS_USING;
+ pci_devices[i].pci_driver = select;
+ pci_devices[i].bus = bus;
+ select->pci_device = &pci_devices[i];
+
+ select->ops->probe(&pci_devices[i], device);
+ }
+ }
+ }
+ return DRIVER_OK;
+}
+
+static __init void pci_initcall(void) {
+ DriverResult result;
+
+ result = register_driver(&pci_driver);
+ if (result != DRIVER_OK) goto failed_register_driver;
+
+ result = register_device_driver(&pci_driver, &pci_device_driver);
+ if (result != DRIVER_OK) goto failed_register_device_driver;
+
+ ObjectAttr attr = driver_object_attr;
+ result =
+ register_bus_driver(&pci_driver, BUS_TYPE_PCI, &pci_bus_driver, &attr);
+ if (result != DRIVER_OK) goto failed_register_bus_driver;
+
+ Bus *bus;
+ result = create_bus(&bus, &pci_bus_driver, &pci_bus_ops);
+ if (result != DRIVER_OK) goto failed_create_bus;
+
+ return;
+failed_create_bus:
+ unregister_bus_driver(&pci_bus_driver);
+
+failed_register_bus_driver:
+ unregister_device_driver(&pci_device_driver);
+
+failed_register_device_driver:
+ unregister_driver(&pci_driver);
+
+failed_register_driver:
+ return;
+}
+
+driver_initcall(pci_initcall);
diff --git a/src/arch/x86/drivers/cmos.c b/src/arch/x86/drivers/cmos.c
new file mode 100644
index 0000000..dbbd405
--- /dev/null
+++ b/src/arch/x86/drivers/cmos.c
@@ -0,0 +1,93 @@
+#include
+#include
+#include
+#include
+#include
+#include
+
+extern Driver core_driver;
+
+DriverResult rtc_get_time(TimeDevice *time_device, TimeType type, Time *time);
+
+DeviceOps cmos_device_ops = {
+ .init = NULL,
+ .start = NULL,
+ .stop = NULL,
+ .destroy = NULL,
+};
+DeviceOps rtc_device_ops = {
+ .init = NULL,
+ .start = NULL,
+ .stop = NULL,
+ .destroy = NULL,
+};
+TimeOps rtc_time_device_ops = {
+ .get_time = rtc_get_time,
+ .set_time = NULL,
+};
+
+DeviceDriver cmos_device_driver;
+PhysicalDevice *cmos_device;
+TimeDevice *rtc_time_device;
+
+DriverResult register_cmos(void) {
+ register_device_driver(&core_driver, &cmos_device_driver);
+
+ ObjectAttr attr = driver_object_attr;
+ DRIVER_RESULT_PASS(
+ create_physical_device(&cmos_device, platform_bus, &attr));
+ register_physical_device(cmos_device, &cmos_device_ops);
+
+ DRIVER_RESULT_PASS(create_time_device(
+ &rtc_time_device, &rtc_time_device_ops, &rtc_device_ops, cmos_device,
+ &cmos_device_driver));
+
+ rtc_time_device->type = TIME_TYPE_LOCAL;
+
+ return DRIVER_OK;
+}
+
+static inline int rtc_guess_year(int year) {
+ return 2000 + year;
+}
+
+static inline bool rtc_is_updating(void) {
+ return (CMOS_READ(CMOS_STATUS_A) & 0x80);
+}
+
+static inline bool rtc_is_bcd(void) {
+ return !(CMOS_READ(CMOS_STATUS_B) & 0x04);
+}
+
+DriverResult rtc_get_time(TimeDevice *time_device, TimeType type, Time *time) {
+ while (rtc_is_updating())
+ ;
+ int second = CMOS_READ(CMOS_SECONDS);
+ int minute = CMOS_READ(CMOS_MINUTES);
+ int hour = CMOS_READ(CMOS_HOURS);
+ int day = CMOS_READ(CMOS_DAY_OF_MONTH);
+ int month = CMOS_READ(CMOS_MONTH);
+ int year = CMOS_READ(CMOS_YEAR);
+
+ if (rtc_is_bcd()) {
+ second = BCD2BIN(second);
+ minute = BCD2BIN(minute);
+ hour = BCD2BIN(hour);
+ day = BCD2BIN(day);
+ month = BCD2BIN(month);
+ year = BCD2BIN(year);
+ }
+
+ time->time.year = rtc_guess_year(year);
+ time->time.month = month;
+ time->time.day = day;
+ time->time.hour = hour;
+ time->time.minute = minute;
+ time->time.second = second;
+
+ return DRIVER_OK;
+}
+
+DriverResult rtc_set_time(TimeDevice *device, TimeType type, Time *time) {
+ return DRIVER_OK;
+}
diff --git a/src/arch/x86/drivers/config.toml b/src/arch/x86/drivers/config.toml
new file mode 100644
index 0000000..25805d8
--- /dev/null
+++ b/src/arch/x86/drivers/config.toml
@@ -0,0 +1,12 @@
+dir = [
+ "bus/",
+ "disk/",
+ "framebuffer/",
+ "input/",
+ "interrupt/",
+ "network/",
+ "sound/",
+ "timer/",
+ "usb/",
+]
+c = ["cmos.c", "msr.c", "serial.c"]
diff --git a/src/arch/x86/drivers/cpufreq.c b/src/arch/x86/drivers/cpufreq.c
index 0236ad8..d9213f9 100644
--- a/src/arch/x86/drivers/cpufreq.c
+++ b/src/arch/x86/drivers/cpufreq.c
@@ -20,21 +20,21 @@ unsigned int cpu_get_freq(void) {
struct fifo fifo;
char fifo_buf[4];
fifo_init(&fifo, 4, (int *)fifo_buf);
- timer = timer_alloc();
- timer_init(timer, &fifo, 128);
+ // timer = timer_alloc();
+ // timer_init(timer, &fifo, 128);
- timer_settime(timer, 100);
+ // timer_settime(timer, 100);
while (fifo_status(&fifo) == 0)
io_hlt();
fifo_get(&fifo);
- timer_settime(timer, 100);
+ // timer_settime(timer, 100);
__asm__ __volatile__("rdtsc \n\t" : "=A"(tsc));
while (fifo_status(&fifo) == 0)
;
fifo_get(&fifo);
__asm__ __volatile__("rdtsc \n\t" : "=A"(tsc2));
- timer_free(timer);
+ // timer_free(timer);
return (tsc2 - tsc) / 1000 / 1000;
}
\ No newline at end of file
diff --git a/src/arch/x86/drivers/disk/Makefile b/src/arch/x86/drivers/disk/Makefile
new file mode 100644
index 0000000..144fe69
--- /dev/null
+++ b/src/arch/x86/drivers/disk/Makefile
@@ -0,0 +1 @@
+SRC += ata/
\ No newline at end of file
diff --git a/src/arch/x86/drivers/disk/ata/Makefile b/src/arch/x86/drivers/disk/ata/Makefile
new file mode 100644
index 0000000..bb76895
--- /dev/null
+++ b/src/arch/x86/drivers/disk/ata/Makefile
@@ -0,0 +1,4 @@
+SRC += ata_driver.c
+SRC += ide.c
+SRC += ide_controller.c
+SRC += dma.c
\ No newline at end of file
diff --git a/src/arch/x86/drivers/disk/ata/ata_driver.c b/src/arch/x86/drivers/disk/ata/ata_driver.c
new file mode 100644
index 0000000..94925e8
--- /dev/null
+++ b/src/arch/x86/drivers/disk/ata/ata_driver.c
@@ -0,0 +1,34 @@
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "include/ata_driver.h"
+#include "include/ide_controller.h"
+
+DriverDependency ata_dependencies[] = {
+ {
+ .in_type = DRIVER_DEPENDENCY_TYPE_BUS,
+ .dependency_in_bus = {BUS_TYPE_PCI, 0},
+ .out_bus = NULL,
+ },
+};
+
+Driver ata_driver = {
+ .short_name = STRING_INIT("AtaDriver"),
+};
+
+static __init void ata_driver_initcall(void) {
+ register_driver(&ata_driver);
+ register_device_driver(&ata_driver, &ide_controller_device_driver);
+ pci_register_driver(&ata_driver, &ide_pci_driver);
+}
+
+driver_initcall(ata_driver_initcall);
\ No newline at end of file
diff --git a/src/arch/x86/drivers/disk/ata/config.toml b/src/arch/x86/drivers/disk/ata/config.toml
new file mode 100644
index 0000000..705a9cc
--- /dev/null
+++ b/src/arch/x86/drivers/disk/ata/config.toml
@@ -0,0 +1 @@
+c = ["ata_driver.c", "dma.c", "ide_controller.c", "ide.c"]
diff --git a/src/arch/x86/drivers/disk/ata/dma.c b/src/arch/x86/drivers/disk/ata/dma.c
new file mode 100644
index 0000000..f50c886
--- /dev/null
+++ b/src/arch/x86/drivers/disk/ata/dma.c
@@ -0,0 +1,93 @@
+#include "include/dma.h"
+#include "include/ide.h"
+#include "include/ide_controller.h"
+#include "kernel/driver.h"
+#include "kernel/list.h"
+#include "kernel/memory.h"
+#include "stdint.h"
+#include
+#include
+#include
+#include
+
+/**
+ * 配置DMA
+ */
+void ata_bmdma_set_prdt(IdeDevice *device, AtaDma *ata_dma, int rw) {
+ IdeChannel *channel = device->channel;
+
+ PhysicalRegionDescriptor *prds = ata_dma->prds;
+ DmaSegment *seg;
+
+ int i = 0, size, left_size;
+ uint32_t addr, offset;
+ list_for_each_owner (seg, &ata_dma->segment_lh, list) {
+ left_size = seg->size;
+ addr = seg->addr;
+ while (left_size > 0 && i < IDE_MAX_PRDT_COUNT) {
+ offset = addr & 0xffff; // 缓冲区不能跨越64K边界
+ size = MIN(left_size, 0x10000 - offset);
+ prds[i].base_addr = addr;
+ prds[i].count = size & 0xffff;
+ prds[i].sign = 0;
+ left_size -= size;
+ addr += size;
+ i++;
+ }
+ }
+ prds[i - 1].sign = BIT(15);
+
+ io_out_dword(channel->bmide + IDE_REG_BM_PRDT, ata_dma->prdt_phy_addr);
+
+ uint8_t data;
+ data = io_in_byte(channel->bmide + IDE_REG_BM_COMMAND);
+ data = (rw == 0) ? BIN_EN(data, IDE_BMCMD_READ_WRITE)
+ : BIN_DIS(data, IDE_BMCMD_READ_WRITE);
+ io_out_byte(channel->bmide + IDE_REG_BM_COMMAND, data);
+
+ data = io_in_byte(channel->bmide + IDE_REG_BM_STATUS);
+ io_out_byte(
+ channel->bmide + IDE_REG_BM_STATUS,
+ BIN_EN(data, IDE_BMSTATUS_INT | IDE_BMSTATUS_ERROR));
+}
+
+DriverResult ata_bmdma_map_buffer(AtaDma *ata_dma, void *ptr, uint32_t size) {
+ size_t addr;
+ addr = (size_t)ptr;
+
+ if (addr & 3) {
+ // 申请一个小的临时缓冲区处理未对齐的部分
+ int size = 32 - (addr & 0x1f);
+ void *tmp_buf = kmalloc(size);
+ if (tmp_buf == NULL) { return DRIVER_ERROR_OUT_OF_MEMORY; }
+ memcpy(tmp_buf, ptr, size);
+
+ DmaSegment *seg = kmalloc(sizeof(DmaSegment));
+ seg->vaddr = (size_t)tmp_buf;
+ seg->addr = vir2phy((uint32_t)tmp_buf);
+ seg->size = size;
+ list_add_tail(&seg->list, &ata_dma->segment_lh);
+ ptr += size;
+ }
+
+ dma_split_mem(&ata_dma->segment_lh, ptr, size, ata_dma->max_segment_size);
+ return DRIVER_OK;
+}
+
+void ata_bmdma_unmap_buffer(AtaDma *ata_dma, void *ptr, uint32_t size) {
+ DmaSegment *seg, *next;
+ size_t start_ptr = (size_t)ptr;
+ size_t end_ptr = start_ptr + size;
+ void *addr = ptr;
+
+ list_for_each_owner_safe (seg, next, &ata_dma->segment_lh, list) {
+ if (start_ptr > seg->vaddr || seg->vaddr >= end_ptr) {
+ memcpy(addr, (void *)seg->vaddr, seg->size);
+ // 释放临时缓冲区
+ kfree((void *)seg->vaddr);
+ }
+ addr += seg->size;
+ list_del(&seg->list);
+ kfree(seg);
+ }
+}
diff --git a/src/arch/x86/drivers/disk/ata/ide.c b/src/arch/x86/drivers/disk/ata/ide.c
new file mode 100644
index 0000000..1d75c13
--- /dev/null
+++ b/src/arch/x86/drivers/disk/ata/ide.c
@@ -0,0 +1,395 @@
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "include/ata.h"
+#include "include/ata_cmd.h"
+#include "include/ata_driver.h"
+#include "include/dma.h"
+#include "include/ide.h"
+#include "include/ide_controller.h"
+
+DriverResult ide_device_init(void *device);
+
+DriverResult ide_device_read_sectors(
+ StorageDevice *storage_device, StorageRequest *request);
+DriverResult ide_device_write_sectors(
+ StorageDevice *storage_device, StorageRequest *request);
+bool ide_device_is_busy(StorageDevice *storage_device);
+
+StorageDeviceOps ide_storage_device_ops = {
+ .submit_read_request = ide_device_read_sectors,
+ .submit_write_request = ide_device_write_sectors,
+ .is_busy = ide_device_is_busy,
+};
+DeviceOps ide_device_ops = {
+ .init = ide_device_init,
+ .start = NULL,
+ .stop = NULL,
+ .destroy = NULL,
+};
+
+DeviceDriver ide_device_driver;
+
+void ide_handle_interrupt(IdeChannel *channel) {
+ int status = io_in_byte(channel->bmide + IDE_REG_BM_STATUS);
+ if (!(status & IDE_BMSTATUS_INT)) return;
+ io_out_byte(channel->bmide + IDE_REG_BM_STATUS, IDE_BMSTATUS_INT);
+
+ status = io_in_byte(channel->io_base + ATA_REG_STATUS);
+ if (status & ATA_STATUS_ERR) {
+ print_error("IDE", "IDE device error!");
+ ide_print_error(channel);
+ }
+
+ IdeDevice *ide_device = channel->ide_devices[channel->selected_device];
+ if (ide_device == NULL) { return; }
+
+ int flags = spin_lock_irqsave(&ide_device->request_lock);
+ StorageRequest *request = ide_device->current_request;
+ ide_device->current_request = NULL;
+ spin_unlock_irqrestore(&ide_device->request_lock, flags);
+
+ if (ide_device->mode == TRANSFER_MODE_DMA) {
+ uint8_t data = io_in_byte(channel->bmide + IDE_REG_BM_COMMAND);
+ io_out_byte(
+ channel->bmide + IDE_REG_BM_COMMAND,
+ BIN_DIS(data, IDE_BMCMD_START_STOP_BM));
+
+ if (request->rw == 0) { storage_solve_read_request(request); }
+ // if (request->buf != request->real_buf) { kfree(request->real_buf); }
+ ata_bmdma_unmap_buffer(
+ channel->dma, request->buf, request->count * SECTOR_SIZE);
+ }
+ storage_finish_request(request);
+}
+
+void ide_irq_handler(void *channel) {
+ IdeChannel *ide_channel = channel;
+
+ ide_handle_interrupt(ide_channel);
+}
+
+void ide_sync(IdeChannel *channel) {
+ // 保证先前的命令执行,而不是在缓存中
+ io_in_byte(channel->control_base + ATA_REG_ALTSTATUS);
+}
+
+void ide_pause(IdeChannel *channel) {
+ ide_sync(channel);
+ delay_ms(&channel->timer, 1);
+}
+
+void ide_device_probe(IdeChannel *channel) {
+ int i, status, err = 0;
+ AtaDeviceType type = ATA_DEVICE_TYPE_ATA;
+
+ timer_init(&channel->timer);
+ channel->device_count = 0;
+
+ StorageDevice *device[2] = {NULL, NULL};
+ for (i = 0; i < 2; i++) {
+ // 1.选择设备
+ ide_select_device(channel, i);
+ ide_pause(channel);
+
+ // 2.发送IDENTIFY命令
+ io_out_byte(
+ channel->io_base + ATA_REG_COMMAND, ATA_CMD_IDENTIFY_DEVICE);
+
+ // 3.检查设备状态
+ if (io_in_byte(channel->io_base + ATA_REG_STATUS) == 0) {
+ continue; // 设备不存在
+ }
+ while (true) {
+ status = io_in_byte(channel->io_base + ATA_REG_STATUS);
+ if (BIN_IS_EN(status, ATA_STATUS_ERR)) {
+ err = 1;
+ break;
+ }
+ if (BIN_IS_DIS(status, ATA_STATUS_BUSY) &&
+ BIN_IS_EN(status, ATA_STATUS_DRQ)) {
+ break;
+ }
+ }
+
+ // 4.检查设备类型
+ if (err != 0) {
+ uint8_t cl = io_in_byte(channel->io_base + ATA_REG_LBA1);
+ uint8_t ch = io_in_byte(channel->io_base + ATA_REG_LBA2);
+
+ if (cl == ~ch && (cl == 0x14 || cl == 0x69)) {
+ type = ATA_DEVICE_TYPE_ATAPI;
+ io_out_byte(
+ channel->io_base + ATA_REG_COMMAND,
+ ATA_CMD_IDENTIFY_PACKET_DEVICE);
+ ide_wait(channel);
+ } else {
+ continue;
+ }
+ }
+
+ // 5.读取设备信息
+ AtaIdentifyInfo *identify = kmalloc(SECTOR_SIZE);
+ io_stream_in_word(
+ channel->io_base + ATA_REG_DATA, (uint32_t)identify,
+ sizeof(AtaIdentifyInfo) / 2);
+
+ // 6.注册设备
+ create_storage_device(
+ &device[i], &ide_storage_device_ops, &ide_device_ops,
+ channel->physical_device, &ide_device_driver);
+
+ IdeDevice *ide_device = kmalloc(sizeof(IdeDevice));
+ device[i]->device->private_data = ide_device;
+ device[i]->block_size = SECTOR_SIZE;
+ device[i]->max_block_per_request = 256;
+ device[i]->max_segment = IDE_MAX_PRDT_COUNT;
+ device[i]->type = STORAGE_DEVICE_TYPE_HARDDISK;
+
+ ide_device->device = device[i]->device;
+ ide_device->channel = channel;
+ ide_device->type = type;
+ ide_device->info = identify;
+ ide_device->device_num = i;
+ ide_device->current_request = NULL;
+ spinlock_init(&ide_device->request_lock);
+
+ channel->ide_devices[i] = ide_device;
+
+ channel->device_count++;
+ }
+ if (channel->device_count) {
+ uint8_t data = io_in_byte(channel->control_base + ATA_REG_CONTROL);
+ io_out_byte(
+ channel->control_base + ATA_REG_CONTROL,
+ BIN_DIS(data, ATA_CONTROL_NIEN));
+
+ channel->dma = kmalloc(sizeof(AtaDma));
+ channel->dma->prds =
+ kmalloc(sizeof(PhysicalRegionDescriptor) * IDE_MAX_PRDT_COUNT);
+ channel->dma->prdt_phy_addr = vir2phy((uint32_t)channel->dma->prds);
+ channel->dma->prdt_status = 0;
+ channel->dma->max_segment_size = 65536;
+ list_init(&channel->dma->segment_lh);
+
+ enable_device_irq(channel->irq);
+
+ for (i = 0; i < 2; i++) {
+ if (device[i] != NULL) {
+ init_and_start_logical_device(device[i]->device);
+ }
+ }
+ }
+}
+
+DriverResult ide_device_init(void *_device) {
+ LogicalDevice *device = _device;
+ IdeDevice *ide_device = device->private_data;
+ AtaIdentifyInfo *identify = ide_device->info;
+
+ if (identify->capabilities.dma_supported) {
+ ide_device->mode = TRANSFER_MODE_DMA;
+ ide_device->cmdset[ATA_CMDSET_READ_EXT] = ATA_CMD_READ_DMA_EXT;
+ ide_device->cmdset[ATA_CMDSET_WRITE_EXT] = ATA_CMD_WRITE_DMA_EXT;
+ ide_device->cmdset[ATA_CMDSET_READ] = ATA_CMD_READ_DMA;
+ ide_device->cmdset[ATA_CMDSET_WRITE] = ATA_CMD_WRITE_DMA;
+ } else if (identify->pio_modes_supported) {
+ ide_device->mode = TRANSFER_MODE_PIO;
+ ide_device->cmdset[ATA_CMDSET_READ_EXT] = ATA_CMD_READ_PIO_EXT;
+ ide_device->cmdset[ATA_CMDSET_WRITE_EXT] = ATA_CMD_WRITE_PIO_EXT;
+ ide_device->cmdset[ATA_CMDSET_READ] = ATA_CMD_READ_PIO;
+ ide_device->cmdset[ATA_CMDSET_WRITE] = ATA_CMD_WRITE_PIO;
+ } else {
+ return DRIVER_ERROR_UNSUPPORT_FEATURE;
+ }
+
+ return DRIVER_OK;
+}
+
+void ide_set_sector_lba28(IdeChannel *channel, uint32_t lba0, uint8_t count) {
+ io_out_byte(channel->io_base + ATA_REG_SECCOUNT0, count);
+ io_out_byte(channel->io_base + ATA_REG_LBA0, lba0 & 0xff);
+ io_out_byte(channel->io_base + ATA_REG_LBA1, (lba0 >> 8) & 0xff);
+ io_out_byte(channel->io_base + ATA_REG_LBA2, (lba0 >> 16) & 0xff);
+}
+
+void ide_set_sector_lba48(
+ IdeChannel *channel, uint32_t lba0, uint32_t lba1, uint16_t count) {
+ io_out_byte(channel->io_base + ATA_REG_SECCOUNT1, count >> 8);
+ io_out_byte(channel->io_base + ATA_REG_LBA3, lba1 & 0xff);
+ io_out_byte(channel->io_base + ATA_REG_LBA4, (lba1 >> 8) & 0xff);
+ io_out_byte(channel->io_base + ATA_REG_LBA5, (lba1 >> 16) & 0xff);
+
+ io_out_byte(channel->io_base + ATA_REG_SECCOUNT0, count);
+ io_out_byte(channel->io_base + ATA_REG_LBA0, lba0 & 0xff);
+ io_out_byte(channel->io_base + ATA_REG_LBA1, (lba0 >> 8) & 0xff);
+ io_out_byte(channel->io_base + ATA_REG_LBA2, (lba0 >> 16) & 0xff);
+}
+
+/**
+ * 通过PIO方式接收数据
+ */
+void ide_device_recv_pio(IdeDevice *device, uint32_t *buf, uint32_t count) {
+ IdeChannel *channel = device->channel;
+
+ ide_wait(channel);
+ io_stream_in_word(
+ channel->io_base + ATA_REG_DATA, (uint32_t)buf,
+ count << 8 /* count * 512 / 2 */);
+}
+
+/**
+ * 通过PIO方式发送数据
+ */
+void ide_device_send_pio(IdeDevice *device, uint32_t *buf, uint32_t count) {
+ IdeChannel *channel = device->channel;
+
+ ide_wait(channel);
+ io_stream_out_word(
+ channel->io_base + ATA_REG_DATA, (uint32_t)buf,
+ count << 8 /* count * 512 / 2 */);
+}
+
+/**
+ * 从设备读取扇区,调用方保证buf与count的合法性
+ *
+ * lba0 & lba1: lba地址,最大支持48位
+ *
+ * count: 扇区数,最大为65535
+ */
+DriverResult ide_device_read_sectors(
+ StorageDevice *storage_device, StorageRequest *request) {
+ IdeDevice *ide_device = storage_device->device->private_data;
+ IdeChannel *channel = ide_device->channel;
+
+ bool flag = false;
+
+ request->count = MIN(request->count, IDE_MAX_PRDT_COUNT * 128 - 1);
+ // 因为没有实现对28位地址的处理,所以超过24位都使用48位地址
+ if ((request->position < 0x1000000) || request->count <= 0x100) {
+ flag = true;
+ }
+
+ if (ide_device->mode == TRANSFER_MODE_DMA) {
+ ata_bmdma_map_buffer(
+ channel->dma, request->buf, request->count * SECTOR_SIZE);
+ ata_bmdma_set_prdt(ide_device, channel->dma, request->rw);
+ }
+
+ ide_select_device(channel, ide_device->device_num);
+ ide_wait(channel);
+
+ uint8_t cmd;
+ if (flag) {
+ ide_set_sector_lba28(channel, request->position, request->count);
+ cmd = ide_device->cmdset[ATA_CMDSET_READ];
+ } else {
+ ide_set_sector_lba48(
+ channel, request->position & 0xffffff, request->position >> 24,
+ request->count);
+ cmd = ide_device->cmdset[ATA_CMDSET_READ_EXT];
+ }
+
+ ide_wait(channel);
+ io_out_byte(channel->io_base + ATA_REG_COMMAND, cmd);
+
+ int flags = spin_lock_irqsave(&ide_device->request_lock);
+ ide_device->current_request = request;
+ if (ide_device->mode == TRANSFER_MODE_PIO) {
+ ide_device_recv_pio(
+ ide_device, (uint32_t *)request->buf, request->count);
+ } else {
+ uint8_t data = io_in_byte(channel->bmide + IDE_REG_BM_COMMAND);
+ io_out_byte(
+ channel->bmide + IDE_REG_BM_COMMAND,
+ BIN_EN(data, IDE_BMCMD_START_STOP_BM));
+ }
+ spin_unlock_irqrestore(&ide_device->request_lock, flags);
+ return DRIVER_OK;
+}
+
+/**
+ * 向设备写入扇区,调用方保证buf与count的合法性
+ *
+ * lba0 & lba1: lba地址,最大支持48位
+ *
+ * count: 扇区数,最大为65535
+ */
+DriverResult ide_device_write_sectors(
+ StorageDevice *storage_device, StorageRequest *request) {
+ IdeDevice *ide_device = storage_device->device->private_data;
+ IdeChannel *channel = ide_device->channel;
+
+ bool flag = false;
+
+ // 因为没有实现对28位地址的处理,所以超过24位都使用48位地址
+ if ((request->position < 0x1000000) || request->count < 0x100) {
+ flag = true;
+ }
+
+ if (ide_device->mode == TRANSFER_MODE_DMA) {
+ storage_solve_write_request(request);
+ ata_bmdma_map_buffer(
+ channel->dma, request->buf, request->count * SECTOR_SIZE);
+ ata_bmdma_set_prdt(ide_device, channel->dma, request->rw);
+ }
+
+ ide_select_device(channel, ide_device->device_num);
+ ide_wait(channel);
+
+ uint8_t cmd;
+ if (flag) {
+ ide_set_sector_lba28(channel, request->position, request->count);
+ cmd = ide_device->cmdset[ATA_CMDSET_WRITE];
+ } else {
+ ide_set_sector_lba48(
+ channel, request->position & 0xffffff, request->position >> 24,
+ request->count);
+ cmd = ide_device->cmdset[ATA_CMDSET_WRITE_EXT];
+ }
+
+ ide_wait(channel);
+ io_out_byte(channel->io_base + ATA_REG_COMMAND, cmd);
+
+ int flags = spin_lock_irqsave(&ide_device->request_lock);
+ ide_device->current_request = request;
+ if (ide_device->mode == TRANSFER_MODE_PIO) {
+ ide_device_send_pio(
+ ide_device, (uint32_t *)request->buf, request->count);
+ } else {
+ uint8_t data = io_in_byte(channel->bmide + IDE_REG_BM_COMMAND);
+ io_out_byte(
+ channel->bmide + IDE_REG_BM_COMMAND,
+ BIN_EN(data, IDE_BMCMD_START_STOP_BM));
+ }
+ spin_unlock_irqrestore(&ide_device->request_lock, flags);
+ return DRIVER_OK;
+}
+
+bool ide_device_is_busy(StorageDevice *storage_device) {
+ LogicalDevice *device = storage_device->device;
+ IdeDevice *ide_device = device->private_data;
+
+ int flags = spin_lock_irqsave(&ide_device->request_lock);
+ bool result = ide_device->current_request != NULL;
+ spin_unlock_irqrestore(&ide_device->request_lock, flags);
+
+ return result;
+}
diff --git a/src/arch/x86/drivers/disk/ata/ide_controller.c b/src/arch/x86/drivers/disk/ata/ide_controller.c
new file mode 100644
index 0000000..7c1c0c7
--- /dev/null
+++ b/src/arch/x86/drivers/disk/ata/ide_controller.c
@@ -0,0 +1,203 @@
+#include "include/ide_controller.h"
+#include "include/ata_driver.h"
+#include "include/ide.h"
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+DriverResult ide_controller_probe(
+ PciDevice *pci_device, PhysicalDevice *physical_device);
+DriverResult ide_controller_init(void *device);
+
+DeviceDriver ide_controller_device_driver;
+
+DeviceOps ide_controller_device_ops = {
+ .init = ide_controller_init,
+ .start = NULL,
+ .stop = NULL,
+ .destroy = NULL,
+};
+
+PciDriverOps ide_pci_driver_ops = {
+ .probe = ide_controller_probe,
+};
+PciDriver ide_pci_driver = {
+ .find_type = FIND_BY_CLASSCODE_SUBCLASS,
+ .class_subclass = {IDE_CONTROLLER_CLASSCODE, IDE_CONTROLLER_SUBCLASS},
+ .device_driver = &ide_controller_device_driver,
+ .driver = &ata_driver,
+ .ops = &ide_pci_driver_ops,
+};
+
+void ide_detect_channel_mode(
+ IdeChannel *channel, PciDevice *pci_device, int i) {
+ int bit = 1 << (i * 2);
+ if (pci_device->prog_if & bit) {
+ if (pci_device->prog_if & (bit << 1)) {
+ channel->channel_num = i;
+ channel->mode = IDE_NATIVE_MODE;
+ pci_device->prog_if |= bit;
+ pci_device_write8(pci_device, PCI_REG_PROGIF, pci_device->prog_if);
+ } else {
+ channel->channel_num = i;
+ channel->mode = IDE_COMPATITY_MODE;
+ }
+ }
+}
+
+DriverResult ide_controller_probe(
+ PciDevice *pci_device, PhysicalDevice *physical_device) {
+ IdeControllerInfo *info = kmalloc(sizeof(IdeControllerInfo));
+
+ register_physical_device(physical_device, &ide_controller_device_ops);
+
+ physical_device->private_data = info;
+ info->pci_device = pci_device;
+ info->dma_support = pci_device->prog_if >> 7;
+ info->bus_master_base = pci_device->common.bar[4].base_addr;
+
+ return DRIVER_OK;
+}
+
+void ide_controller_setup_legacy_mode(
+ PhysicalDevice *physical_device, IdeChannel *channel) {
+ channel->io_base =
+ (channel->channel_num ? ATA_SECONDARY_PORT : ATA_PRIMARY_PORT);
+ channel->control_base =
+ (channel->channel_num ? ATA_SECONDARY_CONTROL_PORT
+ : ATA_PRIMARY_CONTROL_PORT);
+ register_device_irq(
+ &channel->irq, physical_device, channel,
+ (channel->channel_num ? IDE_IRQ1 : IDE_IRQ0), ide_irq_handler,
+ IRQ_MODE_SHARED);
+}
+
+void ide_controller_setup_pci_mode(PciDevice *pci_device, IdeChannel *channel) {
+ channel->io_base =
+ pci_device->common.bar[channel->channel_num * 2].base_addr;
+ channel->control_base =
+ pci_device->common.bar[channel->channel_num * 2 + 1].base_addr;
+ register_device_irq(
+ &channel->irq, pci_device->device, channel, pci_device->irqline,
+ ide_irq_handler, IRQ_MODE_SHARED);
+}
+
+DriverResult ide_controller_init(void *_device) {
+ PhysicalDevice *device = _device;
+ IdeControllerInfo *info = device->private_data;
+
+ for (int i = 0; i < 2; i++) {
+ IdeChannel *channel = &info->channels[i];
+
+ channel->physical_device = device;
+ channel->channel_num = i;
+ channel->selected_device = 0;
+ // 检查是否支持PCI Native模式
+ ide_detect_channel_mode(channel, info->pci_device, i);
+
+ if (channel->mode == IDE_COMPATITY_MODE) {
+ ide_controller_setup_legacy_mode(device, channel);
+ } else {
+ ide_controller_setup_pci_mode(info->pci_device, channel);
+ }
+
+ if (BIN_IS_EN(info->pci_device->prog_if, BIT(7))) {
+ channel->bmide = info->pci_device->common.bar[4].base_addr;
+ channel->bmide += (channel->channel_num ? 8 : 0);
+ pci_enable_bus_mastering(info->pci_device);
+ }
+
+ // 禁用并注册IRQ
+ io_out_byte(channel->control_base + ATA_REG_CONTROL, ATA_CONTROL_NIEN);
+
+ ide_device_probe(channel);
+ }
+
+ return DRIVER_OK;
+}
+
+void ide_print_error(IdeChannel *channel) {
+ int status = io_in_byte(channel->io_base + ATA_REG_STATUS);
+ if (status & ATA_STATUS_DF) {
+ print_error("IDE", "Device Fault!\n");
+ } else if (status & ATA_STATUS_ERR) {
+ int err = io_in_byte(channel->io_base + ATA_REG_ERROR);
+ if (err & ATA_ERROR_AMNF) {
+ print_error("IDE", "No Address Mark Found\n");
+ }
+ if (err & ATA_ERROR_TK0NF) {
+ print_error("IDE", "No Media or Media Mark Found\n");
+ }
+ if (err & ATA_ERROR_ABRT) { print_error("IDE", "Command Aborted\n"); }
+ if (err & ATA_ERROR_MCR) {
+ print_error("IDE", "No Media or Media Error\n");
+ }
+ if (err & ATA_ERROR_IDNF) { print_error("IDE", "ID mark not Found\n"); }
+ if (err & ATA_ERROR_MC) {
+ print_error("IDE", "No Media or Media Error\n");
+ }
+ if (err & ATA_ERROR_UNC) {
+ print_error("IDE", "Uncorrectable Data Error\n");
+ }
+ if (err & ATA_ERROR_BBK) { print_error("IDE", "Bad Sectors\n"); }
+ } else if (status & ATA_STATUS_DRQ) {
+ print_error("IDE", "Reads Nothing\n");
+ }
+}
+
+void ide_reset_drive(IdeChannel *channel) {
+ uint8_t data = io_in_byte(channel->control_base + ATA_REG_CONTROL);
+ io_out_byte(channel->control_base + ATA_REG_CONTROL, BIN_EN(data, BIT(2)));
+
+ // 等待重置
+ int i;
+ for (i = 0; i < 50; i++) {
+ io_in_byte(channel->io_base + ATA_REG_STATUS);
+ }
+ io_out_byte(channel->control_base + ATA_REG_CONTROL, data);
+ channel->selected_device = 0;
+}
+
+void ide_select_device(IdeChannel *channel, int device_num) {
+ io_out_byte(
+ channel->io_base + ATA_REG_HDDEV_SEL,
+ device_num << 4 | BIT(6) | BIT(5) | BIT(7));
+ channel->selected_device = device_num;
+}
+
+int ide_wait(IdeChannel *channel) {
+ int status;
+ do {
+ status = io_in_byte(channel->io_base + ATA_REG_STATUS);
+ } while (BIN_IS_EN(status, ATA_STATUS_BUSY));
+ return 0;
+}
+
+void ide_polling(IdeChannel *channel) {
+
+ // 等待400ns
+ for (int i = 0; i < 4; i++) {
+ io_in_byte(
+ channel->control_base + ATA_REG_ALTSTATUS); // 读一次需要100ns
+ }
+
+ int status;
+ do {
+ status = io_in_byte(channel->io_base + ATA_REG_STATUS);
+ } while (BIN_IS_EN(status, ATA_STATUS_BUSY));
+
+ if (BIN_IS_EN(status, ATA_STATUS_ERR)) {
+ print_error_with_position("in ide_select_device(): IDE Error!\n");
+ }
+}
diff --git a/src/arch/x86/drivers/disk/ata/include/ata.h b/src/arch/x86/drivers/disk/ata/include/ata.h
new file mode 100644
index 0000000..5121958
--- /dev/null
+++ b/src/arch/x86/drivers/disk/ata/include/ata.h
@@ -0,0 +1,12 @@
+#ifndef _ATA_H
+#define _ATA_H
+
+typedef enum AtaCmdIndex {
+ ATA_CMDSET_READ,
+ ATA_CMDSET_READ_EXT,
+ ATA_CMDSET_WRITE,
+ ATA_CMDSET_WRITE_EXT,
+ ATA_CMDSET_MAX,
+} AtaCmdIndex;
+
+#endif
\ No newline at end of file
diff --git a/src/arch/x86/drivers/disk/ata/include/ata_cmd.h b/src/arch/x86/drivers/disk/ata/include/ata_cmd.h
new file mode 100644
index 0000000..306c736
--- /dev/null
+++ b/src/arch/x86/drivers/disk/ata/include/ata_cmd.h
@@ -0,0 +1,99 @@
+#ifndef _ATA_CMD_H
+#define _ATA_CMD_H
+
+#define ATA_CMD_CFA_ERASE_SECTORS 0xc0
+#define ATA_CMD_CFA_REQUEST_EXTENDED_ERROR 0x03
+#define ATA_CMD_CFA_TRANSLATE_SECTOR 0x87
+#define ATA_CMD_CFA_WRITE_MULTIPLE_WITHOUT_ERASE 0xcd
+#define ATA_CMD_CFA_WRITE_SECTORS_WITHOUT_ERASE 0x38
+
+#define ATA_CMD_CHECK_MEDIA_CARD_TYPE 0xd1
+#define ATA_CMD_CHECK_POWER_MODE 0xe5
+
+#define ATA_CMD_CONFIG_STREAM 0x51
+#define ATA_CMD_CONFIG_FREEZE_LOCK 0xb1
+#define ATA_CMD_CONFIG_IDENTIFY 0xb1
+#define ATA_CMD_CONFIG_RESTORE 0xb1
+#define ATA_CMD_CONFIG_SET 0xb1
+
+#define ATA_CMD_DEVICE_RESET 0x08
+#define ATA_CMD_DOWNLOAD_MICROCODE 0x92
+#define ATA_CMD_EXEC_DEVICE_DIAGNOSTIC 0x90
+
+#define ATA_CMD_FLUSH_CACHE 0xe7
+#define ATA_CMD_FLUSH_CACHE_EXT 0xea
+
+#define ATA_CMD_GET_MEDIA_STATUS 0xda
+#define ATA_CMD_MEDIA_EJECT 0xed
+#define ATA_CMD_MEDIA_LOCK 0xde
+#define ATA_CMD_MEDIA_UNLOCK 0xdf
+#define ATA_CMD_STANDBY_IMMEDIATE 0xe0
+#define ATA_CMD_IDLE_IMMEDIATE 0xe1
+#define ATA_CMD_STANDBY 0xe2
+#define ATA_CMD_IDLE 0xe3
+
+#define ATA_CMD_NOP 0x00
+#define ATA_CMD_SLEEP 0xe6
+#define ATA_CMD_IDENTIFY_DEVICE 0xec
+#define ATA_CMD_IDENTIFY_PACKET_DEVICE 0xa1
+#define ATA_CMD_SET_FEATURES 0xef
+#define ATA_CMD_PACKET 0xa0
+#define ATA_CMD_SERVICE 0xa2
+
+#define ATA_CMD_READ_BUFFER 0xe4
+#define ATA_CMD_READ_PIO 0x20
+#define ATA_CMD_READ_PIO_EXT 0x24
+#define ATA_CMD_READ_DMA 0xc8
+#define ATA_CMD_READ_DMA_EXT 0x25
+#define ATA_CMD_READ_DMA_QUEUED 0xc7
+#define ATA_CMD_READ_DMA_QUEUED_EXT 0x26
+#define ATA_CMD_READ_STREAM_DMA_EXT 0x2a
+#define ATA_CMD_READ_STREAM_EXT 0x2b
+#define ATA_CMD_READ_VERIFY_SECTORS 0x40
+#define ATA_CMD_READ_VERIFY_SECTORS_EXT 0x42
+
+#define ATA_CMD_WRITE_BUFFER 0xe8
+#define ATA_CMD_WRITE_PIO 0x30
+#define ATA_CMD_WRITE_PIO_EXT 0x34
+#define ATA_CMD_WRITE_DMA 0xca
+#define ATA_CMD_WRITE_DMA_EXT 0x35
+#define ATA_CMD_WRITE_DMA_QUEUED 0xcc
+#define ATA_CMD_WRITE_DMA_QUEUED_EXT 0x36
+#define ATA_CMD_WRITE_DMA_MAX_ADDR_EXT 0x37
+#define ATA_CMD_WRITE_STREAM_DMA_EXT 0x3a
+#define ATA_CMD_WRITE_STREAM_EXT 0x3b
+
+#define ATA_CMD_READ_NATIVE_MAX_ADDR 0xf8
+#define ATA_CMD_READ_NATIVE_MAX_ADDR_EXT 0x27
+#define ATA_CMD_SET_MAX_ADDR 0xf9
+
+#define ATA_CMD_READ_LOG_EXT 0x2f
+#define ATA_CMD_WRITE_LOG_EXT 0x3f
+
+#define ATA_CMD_WRITE_DMA_FUA_EXT 0x3d
+#define ATA_CMD_WRITE_DMA_QUEUED_FUA_EXT 0x3e
+#define ATA_CMD_WRITE_FUA 0xce
+
+#define ATA_CMD_SET_MULTIPLE_MODE 0xc6
+#define ATA_CMD_READ_MULTIPLE 0xc4
+#define ATA_CMD_READ_MULTIPLE_EXT 0x29
+#define ATA_CMD_WRITE_MULTIPLE 0xc5
+#define ATA_CMD_WRITE_MULTIPLE_EXT 0x39
+
+#define ATA_CMD_SECURITY_SET_PASSWORD 0xf1
+#define ATA_CMD_SECURITY_UNLOCK 0xf2
+#define ATA_CMD_SECURITY_ERASE_PREPARE 0xf3
+#define ATA_CMD_SECURITY_ERASE_UNIT 0xf4
+#define ATA_CMD_SECURITY_FREEZE_LOCK 0xf5
+#define ATA_CMD_SECURITY_DISABLE_PASSWORD 0xf6
+
+#define ATA_CMD_SMART_DISABLE_OPERATIONS 0xb0
+#define ATA_CMD_SMART_EN_DIS_AUTOSAVE 0xb0
+#define ATA_CMD_SMART_ENABLE_OPERATIONS 0xb0
+#define ATA_CMD_SMART_EXECUTE_OFFLINE_IMMEDIATE 0xb0
+#define ATA_CMD_SMART_READ_DATA 0xb0
+#define ATA_CMD_SMART_READ_LOG 0xb0
+#define ATA_CMD_SMART_RETURN_STATUS 0xb0
+#define ATA_CMD_SMART_WRITE_LOG 0xb0
+
+#endif
\ No newline at end of file
diff --git a/src/arch/x86/drivers/disk/ata/include/ata_driver.h b/src/arch/x86/drivers/disk/ata/include/ata_driver.h
new file mode 100644
index 0000000..a96c817
--- /dev/null
+++ b/src/arch/x86/drivers/disk/ata/include/ata_driver.h
@@ -0,0 +1,262 @@
+#ifndef _ATA_DRIVER_H
+#define _ATA_DRIVER_H
+
+#include "bits.h"
+#include
+
+#define ATA_PRIMARY_PORT 0x1f0
+#define ATA_SECONDARY_PORT 0x170
+
+#define ATA_PRIMARY_CONTROL_PORT 0x3f6
+#define ATA_SECONDARY_CONTROL_PORT 0x376
+
+typedef enum AtaDeviceType {
+ ATA_DEVICE_TYPE_ATA,
+ ATA_DEVICE_TYPE_ATAPI,
+} AtaDeviceType;
+
+#define ATA_STATUS_BUSY 0x80 // 驱动器忙
+#define ATA_STATUS_READY 0x40 // 驱动器就绪
+#define ATA_STATUS_DF 0x20 // 驱动器写故障
+#define ATA_STATUS_SEEK 0x10 // 驱动器查找完成
+#define ATA_STATUS_DRQ 0x08 // 请求数据
+#define ATA_STATUS_CORR 0x04 // Correct data
+#define ATA_STATUS_INDEX 0x02 // 索引
+#define ATA_STATUS_ERR 0x01 // 错误
+
+#define ATA_ERROR_BBK 0x80 // 错误块
+#define ATA_ERROR_UNC 0x40 // 无法矫正的数据
+#define ATA_ERROR_MC 0x20 // 媒体更改
+#define ATA_ERROR_IDNF 0x10 // 找不到ID标记
+#define ATA_ERROR_MCR 0x08 // 媒体更改请求
+#define ATA_ERROR_ABRT 0x04 // 命令终止
+#define ATA_ERROR_TK0NF 0x02 // 找不到磁道0
+#define ATA_ERROR_AMNF 0x01 // 没有地址标记
+
+#define ATA_CONTROL_NIEN BIT(1) // 禁止中断
+#define ATA_CONTROL_SRST BIT(2) // 软复位
+#define ATA_CONTROL_HOB BIT(7) // 高字节优先(大端字节序)
+
+#define ATA_REG_DATA 0x00
+#define ATA_REG_ERROR 0x01
+#define ATA_REG_FEATURES 0x01
+#define ATA_REG_SECCOUNT0 0x02
+#define ATA_REG_LBA0 0x03
+#define ATA_REG_LBA1 0x04
+#define ATA_REG_LBA2 0x05
+#define ATA_REG_HDDEV_SEL 0x06
+#define ATA_REG_COMMAND 0x07
+#define ATA_REG_STATUS 0x07
+
+#define ATA_REG_SECCOUNT1 0x02
+#define ATA_REG_LBA3 0x03
+#define ATA_REG_LBA4 0x04
+#define ATA_REG_LBA5 0x05
+
+#define ATA_REG_CONTROL 0x00
+#define ATA_REG_ALTSTATUS 0x00
+#define ATA_REG_DEVADDRESS 0x01
+
+#define ATA_PRIMARY 0x00
+#define ATA_SECONDARY 0x01
+
+#define ATA_MASTER 0x00
+#define ATA_SLAVE 0x01
+
+typedef struct AtaIdentifyInfo {
+ struct {
+ uint8_t reserved1 : 1;
+ uint8_t retired1 : 1;
+ uint8_t response_incomplete : 1;
+ uint8_t retired2 : 3;
+ uint8_t obsolete : 1;
+ uint8_t removable : 1;
+ uint8_t retired3 : 7;
+ uint8_t device_type : 1;
+ } general_config;
+ uint16_t obsolete1;
+ uint16_t specific_config;
+ uint16_t obsolete2;
+ uint32_t retired1;
+ uint16_t obsolete3;
+ uint32_t reserved1;
+ uint16_t retired2;
+ uint8_t serial_number[20];
+ uint32_t retired3;
+ uint16_t obsolete4;
+ uint8_t firmware_revision[8];
+ uint8_t model_number[40];
+ uint8_t max_block_transfer;
+ uint8_t reserved2;
+ uint16_t reserved3;
+ struct {
+ uint8_t retired;
+ uint8_t dma_supported : 1;
+ uint8_t lba_supported : 1;
+ uint8_t ioready_disabled : 1;
+ uint8_t ioready_supported : 1;
+ uint8_t reserved1 : 1;
+ uint8_t standby_timer_supported : 1;
+ uint8_t reserved2 : 2;
+ } capabilities;
+ uint16_t reserved4;
+ uint32_t obsolete5;
+ uint16_t translation_field_valid : 3;
+ uint16_t reserved5 : 13;
+ uint16_t obsolete6[5];
+ uint8_t current_block;
+ uint8_t multiple_sector_valid : 1;
+ uint8_t reserved6 : 7;
+ uint32_t total_sectors;
+ uint16_t obsolete7;
+ struct {
+ uint8_t dma_modes_supported : 3;
+ uint8_t reserved1 : 5;
+ uint8_t dma_modes_select : 3;
+ uint8_t reserved2 : 5;
+ } multiword_dma;
+ uint8_t pio_modes_supported;
+ uint8_t reserved7;
+ uint16_t min_multiword_dma_cycle_time;
+ uint16_t recommended_multiword_dma_cycle_time;
+ uint16_t min_pio_cycle_time;
+ uint16_t min_pio_cycle_time_ioready;
+ uint32_t reserved8;
+ uint16_t reserved9[4];
+ uint16_t max_queue_depth : 5;
+ uint16_t reserved10 : 11;
+ uint16_t reserved_for_sata[4];
+ uint16_t major_version;
+ uint16_t minor_version;
+ struct {
+ uint8_t smart_supported : 1;
+ uint8_t security_supported : 1;
+ uint8_t removable_media : 1;
+ uint8_t power_management_supported : 1;
+ uint8_t reserved1 : 1;
+ uint8_t write_cache_supported : 1;
+ uint8_t look_ahead_supported : 1;
+ uint8_t release_interrupt_supported : 1;
+ uint8_t service_interrupt_supported : 1;
+ uint8_t device_reset_supported : 1;
+ uint8_t host_protected_area_supported : 1;
+ uint8_t obsolete1 : 1;
+ uint8_t write_buffer_command_supported : 1;
+ uint8_t read_buffer_command_supported : 1;
+ uint8_t nop_command_supported : 1;
+ uint8_t obsolete : 1;
+ uint8_t download_microcode_supported : 1;
+ uint8_t rw_dma_queued_supported : 1;
+ uint8_t cfa_supported : 1;
+ uint8_t advanced_power_management : 1;
+ uint8_t removable_media_status_notification_supported : 1;
+ uint8_t powerup_in_standby_supported : 1;
+ uint8_t set_features_required_to_spinup_after_powerup : 1;
+ uint8_t obsolete2 : 1;
+ uint8_t set_max_security_supported : 1;
+ uint8_t auto_acoustic_management_supported : 1;
+ uint8_t addressing_48bit_supported : 1;
+ uint8_t device_config_overlay_supported : 1;
+ uint8_t mandatory_flush_cache_supported : 1;
+ uint8_t flush_cache_ext_supported : 1;
+ uint8_t reserved2 : 2;
+ uint8_t smart_error_log_supported : 1;
+ uint8_t smart_self_test_supported : 1;
+ uint8_t media_serial_number_supported : 1;
+ uint8_t media_card_pass_through_supported : 1;
+ uint8_t streaming_feature_supported : 1;
+ uint8_t general_purpose_logging_supported : 1;
+ uint8_t write_fua_ext_supported : 1;
+ uint8_t write_queued_fua_ext_supported : 1;
+ uint8_t name_64bit_supported : 1;
+ uint8_t urg_gor_read_stream_dma_supported : 1;
+ uint8_t urg_for_write_stream_dma_supported : 1;
+ uint8_t reserved3 : 2;
+ uint8_t idle_immediate_supported : 1;
+ uint8_t reserved4 : 2;
+ uint8_t smart_enabled : 1;
+ uint8_t security_mode_enabled : 1;
+ uint8_t removablemedia_enabled : 1;
+ uint8_t power_management_enabled : 1;
+ uint8_t reserved5 : 1;
+ uint8_t write_cache_enabled : 1;
+ uint8_t look_ahead_enabled : 1;
+ uint8_t release_interrupt_enabled : 1;
+ uint8_t service_interrupt_enabled : 1;
+ uint8_t device_reset_enabled : 1;
+ uint8_t host_protected_area_enabled : 1;
+ uint8_t obsolete3 : 1;
+ uint8_t write_buffer_command_enabled : 1;
+ uint8_t read_buffer_command_enabled : 1;
+ uint8_t nop_command_enabled : 1;
+ uint8_t obsolete4 : 1;
+ uint8_t download_microcode_enabled : 1;
+ uint8_t rw_dma_queued_enabled : 1;
+ uint8_t cfa_enabled : 1;
+ uint8_t advanced_power_management_enabled : 1;
+ uint8_t removable_media_status_notification_enabled : 1;
+ uint8_t powerup_in_standby_enabled : 1;
+ uint8_t set_features_required_to_spinup_after_powerup_enabled : 1;
+ uint8_t obsolete5 : 1;
+ uint8_t set_max_security_enabled : 1;
+ uint8_t auto_acoustic_management_enabled : 1;
+ uint8_t addressing_48bit_enabled : 1;
+ uint8_t device_config_overlay_enabled : 1;
+ uint8_t mandatory_flush_cache_enabled : 1;
+ uint8_t flush_cache_ext_enabled : 1;
+ uint8_t reserved6 : 2;
+ uint8_t smart_error_log_enabled : 1;
+ uint8_t smart_self_test_enabled : 1;
+ uint8_t media_serial_number_enabled : 1;
+ uint8_t media_card_pass_through_enabled : 1;
+ uint8_t streaming_feature_enabled : 1;
+ uint8_t general_purpose_logging_enabled : 1;
+ uint8_t write_fua_ext_enabled : 1;
+ uint8_t write_queued_fua_ext_enabled : 1;
+ uint8_t reserved7 : 2;
+ uint8_t idle_immediate_enabled : 1;
+ uint8_t reserved8 : 2;
+ } command_set_feature_support;
+ uint8_t udma_mode_support;
+ uint8_t udma_mode_select;
+ uint16_t time_required_for_security_erase;
+ uint16_t time_required_for_enhanced_security_erase;
+ uint16_t current_advanced_power_management_value;
+ uint16_t master_password_revision_code;
+ uint16_t hardware_reset_result;
+ uint8_t current_AAM_value;
+ uint8_t recommended_AAM_value;
+ uint16_t stream_min_request_size;
+ uint16_t streaming_transfer_time_DMA;
+ uint16_t streaming_access_latency_DMA_PIO;
+ uint16_t streaming_performance_granularity[2];
+ uint16_t max_lba48_addressable_sectors[4];
+ uint16_t streaming_transfer_time_PIO;
+ uint16_t reserved11;
+ uint16_t physical_logical_sector_size : 4;
+ uint16_t reserved12 : 8;
+ uint16_t device_logical_sector_is_longer_than_256 : 1;
+ uint16_t device_has_multiple_logical_sectors : 1;
+ uint16_t reserved13 : 2;
+ uint16_t inter_seek_delay;
+ uint32_t unique_id1;
+ uint16_t unique_id2 : 4;
+ uint32_t ieee_oui : 24;
+ uint16_t naa : 4;
+ uint16_t world_wide_name[4];
+ uint16_t reserved14;
+ uint16_t words_per_logical_sector[2];
+ uint16_t reserved15[8];
+ uint16_t removable_media_status;
+ uint16_t security_status;
+ uint16_t vendor_specific[31];
+ uint16_t CFA_power_mode;
+ uint16_t reserved16[15];
+ uint8_t current_media_serial_number[60];
+ uint16_t reserved17[49];
+ uint16_t integrity_word;
+} __attribute__((packed)) AtaIdentifyInfo;
+
+extern struct Driver ata_driver;
+
+#endif
\ No newline at end of file
diff --git a/src/arch/x86/drivers/disk/ata/include/dma.h b/src/arch/x86/drivers/disk/ata/include/dma.h
new file mode 100644
index 0000000..d737f3c
--- /dev/null
+++ b/src/arch/x86/drivers/disk/ata/include/dma.h
@@ -0,0 +1,28 @@
+#ifndef _ATA_DMA_H
+#define _ATA_DMA_H
+
+#include "ide.h"
+#include
+
+typedef struct PhysicalRegionDescriptor {
+ uint32_t base_addr;
+ uint16_t count;
+ uint16_t sign;
+} __attribute__((packed)) PhysicalRegionDescriptor;
+
+typedef struct AtaDma {
+ list_t segment_lh;
+
+ int prdt_status;
+ int max_segment_size;
+
+ struct PhysicalRegionDescriptor *prds;
+
+ uint32_t prdt_phy_addr;
+} AtaDma;
+
+void ata_bmdma_set_prdt(IdeDevice *device, AtaDma *ata_dma, int rw);
+DriverResult ata_bmdma_map_buffer(AtaDma *ata_dma, void *ptr, uint32_t size);
+void ata_bmdma_unmap_buffer(AtaDma *ata_dma, void *ptr, uint32_t size);
+
+#endif
\ No newline at end of file
diff --git a/src/arch/x86/drivers/disk/ata/include/ide.h b/src/arch/x86/drivers/disk/ata/include/ide.h
new file mode 100644
index 0000000..25bf4c4
--- /dev/null
+++ b/src/arch/x86/drivers/disk/ata/include/ide.h
@@ -0,0 +1,45 @@
+#ifndef _ATA_IDE_H
+#define _ATA_IDE_H
+
+#include "ata.h"
+#include "ata_driver.h"
+#include "ide_controller.h"
+#include
+#include
+#include
+#include
+
+#define IDE_IRQ0 14
+#define IDE_IRQ1 15
+
+#define IDE_MAX_PRDT_COUNT 16
+
+typedef struct IdeOps {
+ void (*set_sector)(
+ struct PhysicalDevice *device, uint32_t lba0, uint32_t lba1,
+ uint32_t count);
+} IdeOps;
+
+typedef struct IdeDevice {
+ LogicalDevice *device;
+ IdeChannel *channel;
+ AtaIdentifyInfo *info;
+ AtaDeviceType type;
+ uint8_t device_num;
+ enum {
+ TRANSFER_MODE_PIO,
+ TRANSFER_MODE_DMA,
+ } mode;
+
+ spinlock_t request_lock;
+ StorageRequest *current_request;
+
+ AtaCmdIndex cmdset[ATA_CMDSET_MAX];
+} IdeDevice;
+
+extern struct DeviceDriver ide_device_driver;
+
+void ide_irq_handler(void *channel);
+void ide_device_probe(IdeChannel *channel);
+
+#endif
\ No newline at end of file
diff --git a/src/arch/x86/drivers/disk/ata/include/ide_controller.h b/src/arch/x86/drivers/disk/ata/include/ide_controller.h
new file mode 100644
index 0000000..317ea8d
--- /dev/null
+++ b/src/arch/x86/drivers/disk/ata/include/ide_controller.h
@@ -0,0 +1,71 @@
+#ifndef _ATA_IDE_CONTROLL_H
+#define _ATA_IDE_CONTROLL_H
+
+#include "kernel/device.h"
+#include
+#include
+#include
+#include
+#include
+
+#define IDE_CONTROLLER_CLASSCODE 0x01
+#define IDE_CONTROLLER_SUBCLASS 0x01
+
+#define IDE_REG_BM_COMMAND 0x00
+#define IDE_REG_BM_STATUS 0x02
+#define IDE_REG_BM_PRDT 0x04
+
+#define IDE_BMCMD_START_STOP_BM BIT(0)
+#define IDE_BMCMD_READ_WRITE BIT(3)
+
+#define IDE_BMSTATUS_ACTIVE BIT(0)
+#define IDE_BMSTATUS_ERROR BIT(1)
+#define IDE_BMSTATUS_INT BIT(2)
+#define IDE_BMSTATUS_DMA0_CAP BIT(5)
+#define IDE_BMSTATUS_DMA1_CAP BIT(6)
+
+extern struct BusDriverOps ide_bus_driver_ops;
+extern struct BusDriver ide_bus_driver;
+
+extern struct PciDriver ide_pci_driver;
+
+typedef struct IdeChannelInfo {
+ enum {
+ IDE_COMPATITY_MODE,
+ IDE_NATIVE_MODE,
+ } mode;
+ PhysicalDevice *physical_device;
+
+ DeviceIrq *irq;
+ uint16_t io_base;
+ uint16_t control_base;
+ uint16_t bmide;
+ uint8_t channel_num;
+ uint8_t device_count;
+
+ Timer timer;
+
+ int selected_device;
+ struct IdeDevice *ide_devices[2];
+
+ struct AtaDma *dma;
+} IdeChannel;
+
+typedef struct IdeControllerInfo {
+ uint8_t dma_support;
+
+ PciDevice *pci_device;
+ uint32_t bus_master_base;
+
+ IdeChannel channels[2];
+} IdeControllerInfo;
+
+extern struct DeviceDriver ide_controller_device_driver;
+extern struct BusControllerDeviceOps ide_bus_controller_device_ops;
+
+int ide_wait(IdeChannel *channel);
+void ide_print_error(IdeChannel *channel);
+void ide_reset_drive(IdeChannel *channel);
+void ide_select_device(IdeChannel *channel, int device_num);
+
+#endif
\ No newline at end of file
diff --git a/src/arch/x86/drivers/disk/config.toml b/src/arch/x86/drivers/disk/config.toml
new file mode 100644
index 0000000..62b46df
--- /dev/null
+++ b/src/arch/x86/drivers/disk/config.toml
@@ -0,0 +1 @@
+dir = ["ata/"]
diff --git a/src/arch/x86/drivers/dma.c b/src/arch/x86/drivers/dma.c
deleted file mode 100644
index cd96e7c..0000000
--- a/src/arch/x86/drivers/dma.c
+++ /dev/null
@@ -1,98 +0,0 @@
-/**
- * @file dma.c
- * @author Ryan Wang (ryan1202@foxmail.com)
- * @brief (ISA)DMA驱动
- * @version 0.1
- * @date 2021-7
- */
-#include
-#include
-
-void dma_enable(unsigned int channel)
-{
- if (channel < 4) {
- io_out8(DMA1_REG_MASK, channel);
- } else {
- io_out8(DMA2_REG_MASK, channel & 3);
- }
-}
-
-void dma_disable(unsigned int channel)
-{
- if (channel < 4) {
- io_out8(DMA1_REG_MASK, channel | 4);
- } else {
- io_out8(DMA2_REG_MASK, (channel & 3) | 4);
- }
-}
-
-void dma_ff_reset(unsigned int channel)
-{
- if (channel < 4) {
- io_out8(DMA1_REG_FF_RESET, 0);
- } else {
- io_out8(DMA2_REG_FF_RESET, 0);
- }
-}
-
-void dma_set_mode(unsigned int channel, char mode)
-{
- if (channel < 4) {
- io_out8(DMA1_REG_MODE, mode | channel);
- } else {
- io_out8(DMA2_REG_MODE, mode | (channel & 3));
- }
-}
-
-void dma_set_page(unsigned int channel, char page)
-{
- switch (channel) {
- case 0:
- io_out8(DMA_PAGE0, page);
- break;
- case 1:
- io_out8(DMA_PAGE1, page);
- break;
- case 2:
- io_out8(DMA_PAGE2, page);
- break;
- case 3:
- io_out8(DMA_PAGE3, page);
- break;
- case 5:
- io_out8(DMA_PAGE5, page & 0xfe);
- break;
- case 6:
- io_out8(DMA_PAGE6, page & 0xfe);
- break;
- case 7:
- io_out8(DMA_PAGE7, page & 0xfe);
- break;
-
- default:
- break;
- }
-}
-
-void dma_set_addr(unsigned int channel, unsigned int addr)
-{
- if (channel <= 3) {
- io_out8(DMA0 + (channel << 1), addr & 0xff);
- io_out8(DMA0 + (channel << 1), (addr >> 8) & 0xff);
- } else {
- io_out8(DMA1 + ((channel & 3) << 2), (addr >> 1) & 0xff);
- io_out8(DMA1 + ((channel & 3) << 2), (addr >> 9) & 0xff);
- }
-}
-
-void dma_set_count(unsigned int channel, unsigned int count)
-{
- count--;
- if (channel <= 3) {
- io_out8(DMA0 + (channel << 1) + 1, count & 0xff);
- io_out8(DMA0 + (channel << 1) + 1, (count >> 8) & 0xff);
- } else {
- io_out8(DMA1 + ((channel & 3) << 2) + 2, count & 0xff);
- io_out8(DMA1 + ((channel & 3) << 2) + 2, (count >> 8) & 0xff);
- }
-}
diff --git a/src/arch/x86/drivers/framebuffer/Makefile b/src/arch/x86/drivers/framebuffer/Makefile
new file mode 100644
index 0000000..7b30860
--- /dev/null
+++ b/src/arch/x86/drivers/framebuffer/Makefile
@@ -0,0 +1 @@
+SRC += vesa_display.c
\ No newline at end of file
diff --git a/src/arch/x86/drivers/framebuffer/config.toml b/src/arch/x86/drivers/framebuffer/config.toml
new file mode 100644
index 0000000..f0d20c3
--- /dev/null
+++ b/src/arch/x86/drivers/framebuffer/config.toml
@@ -0,0 +1 @@
+c = ["vesa_display.c"]
diff --git a/src/arch/x86/drivers/framebuffer/vesa_display.c b/src/arch/x86/drivers/framebuffer/vesa_display.c
new file mode 100644
index 0000000..7bd00c7
--- /dev/null
+++ b/src/arch/x86/drivers/framebuffer/vesa_display.c
@@ -0,0 +1,67 @@
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+extern Driver core_driver;
+struct VesaDisplayInfo vesa_display_info;
+
+DriverResult vesa_display_device_init(void *device);
+DriverResult vesa_display_device_start(void *device);
+
+DeviceOps vesa_display_device_ops = {
+ .init = vesa_display_device_init,
+ .start = vesa_display_device_start,
+ .stop = NULL,
+ .destroy = NULL,
+};
+
+DeviceDriver vesa_display_device_driver;
+
+DriverResult register_vesa_display(void) {
+ FrameBufferDevice *fb_device;
+ register_device_driver(&core_driver, &vesa_display_device_driver);
+
+ DriverResult result = create_framebuffer_device(
+ &fb_device, &vesa_display_device_ops, platform_device,
+ &vesa_display_device_driver);
+ if (result != DRIVER_OK) { return result; }
+
+ return DRIVER_OK;
+}
+
+#define SEG_ADDR2LINEAR_ADDR(addr) \
+ ((unsigned int *)(((unsigned int)(addr) >> 12) & 0xffff0) + \
+ ((unsigned int)(addr) & 0xffff))
+
+DriverResult vesa_display_device_init(void *device) {
+ vesa_display_info.vbe_mode_info->OemStringPtr =
+ SEG_ADDR2LINEAR_ADDR(vesa_display_info.vbe_mode_info->OemStringPtr);
+ vesa_display_info.vbe_mode_info->VideoModePtr =
+ SEG_ADDR2LINEAR_ADDR(vesa_display_info.vbe_mode_info->VideoModePtr);
+ vesa_display_info.vbe_mode_info->OemVendorNamePtr =
+ SEG_ADDR2LINEAR_ADDR(vesa_display_info.vbe_mode_info->OemVendorNamePtr);
+ vesa_display_info.vbe_mode_info->OemProduceRevPtr =
+ SEG_ADDR2LINEAR_ADDR(vesa_display_info.vbe_mode_info->OemProduceRevPtr);
+ vesa_display_info.vbe_mode_info->OemProductNamePtr = SEG_ADDR2LINEAR_ADDR(
+ vesa_display_info.vbe_mode_info->OemProductNamePtr);
+ return DRIVER_OK;
+}
+
+DriverResult vesa_display_device_start(void *device) {
+ vesa_display_info.vram = (uint8_t *)VRAM_VIR_ADDR;
+ FrameBufferDevice *fb_device = ((LogicalDevice *)device)->dm_ext;
+ fb_device->mode_info.width = vesa_display_info.width;
+ fb_device->mode_info.height = vesa_display_info.height;
+ fb_device->mode_info.bits_per_pixel = vesa_display_info.BitsPerPixel;
+ fb_device->mode_info.bytes_per_pixel = vesa_display_info.BitsPerPixel / 8;
+ fb_device->framebuffer_address = vesa_display_info.vram;
+
+ return DRIVER_OK;
+}
diff --git a/src/arch/x86/drivers/ide.c b/src/arch/x86/drivers/ide.c
deleted file mode 100644
index 9f0babd..0000000
--- a/src/arch/x86/drivers/ide.c
+++ /dev/null
@@ -1,756 +0,0 @@
-/**
- * @file ide.c
- * @author Ryan Wang (ryan1202@foxmail.com)
- * @brief IDE驱动
- * @version 1.2
- * @date 2023-01-23
- */
-
-// #define IDE_DMA_MODE
-
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-
-#define ATA_PRIMARY_PORT 0x1f0
-#define ATA_SECONDARY_PORT 0x170
-
-#define ATA_STATUS_BUSY 0x80 // 驱动器忙
-#define ATA_STATUS_READY 0x40 // 驱动器就绪
-#define ATA_STATUS_DF 0x20 // 驱动器写故障
-#define ATA_STATUS_SEEK 0x10 // 驱动器查找完成
-#define ATA_STATUS_DRQ 0x08 // 请求数据
-#define ATA_STATUS_CORR 0x04 // Correct data
-#define ATA_STATUS_INDEX 0x02 // 索引
-#define ATA_STATUS_ERR 0x01 // 错误
-
-#define ATA_ERROR_BBK 0x80 // 错误块
-#define ATA_ERROR_UNC 0x40 // 无法矫正的数据
-#define ATA_ERROR_MC 0x20 // 媒体更改
-#define ATA_ERROR_IDNF 0x10 // 找不到ID标记
-#define ATA_ERROR_MCR 0x08 // 媒体更改请求
-#define ATA_ERROR_ABRT 0x04 // 命令终止
-#define ATA_ERROR_TK0NF 0x02 // 找不到磁道0
-#define ATA_ERROR_AMNF 0x01 // 没有地址标记
-
-#define ATA_CMD_RESTORE 0x10
-#define ATA_CMD_READ_PIO 0x20
-#define ATA_CMD_READ_PIO_EXT 0x24
-#define ATA_CMD_READ_DMA 0xc8
-#define ATA_CMD_READ_DMA_EXT 0x25
-#define ATA_CMD_WRITE_PIO 0x30
-#define ATA_CMD_WRITE_PIO_EXT 0x34
-#define ATA_CMD_WRITE_DMA 0xca
-#define ATA_CMD_WRITE_DMA_EXT 0x35
-#define ATA_CMD_CACHE_FLUSH 0xe7
-#define ATA_CMD_CACHE_FLUSH_EXT 0xea
-#define ATA_CMD_PACKET 0xa0
-#define ATA_CMD_IDENTIFY_PACKET 0xa1
-#define ATA_CMD_IDENTIFY 0xec
-#define ATAPI_CMD_READ 0xA8
-#define ATAPI_CMD_EJECT 0x1B
-
-#define IDE_ATA 0x00
-#define IDE_ATAPI 0x01
-
-#define ATA_PRIMARY 0x00
-#define ATA_SECONDARY 0x01
-
-#define IDE_READ 0x01
-#define IDE_WRITE 0x02
-
-#define ATA_MASTER 0x00
-#define ATA_SLAVE 0x01
-
-#define ATA_REG_DATA(channel) (channel->base + 0)
-#define ATA_REG_FEATURE(channel) (channel->base + 1)
-#define ATA_REG_ERROR(channel) (channel->base + 1)
-#define ATA_REG_SECTOR_CNT(channel) (channel->base + 2)
-#define ATA_REG_SECTOR_LOW(channel) (channel->base + 3)
-#define ATA_REG_SECTOR_MID(channel) (channel->base + 4)
-#define ATA_REG_SECTOR_HIGH(channel) (channel->base + 5)
-#define ATA_REG_DEVICE(channel) (channel->base + 6)
-#define ATA_REG_STATUS(channel) (channel->base + 7)
-#define ATA_REG_CMD(channel) (channel->base + 7)
-#define ATA_REG_ALT_STATUS(channel) (channel->base + 0x206)
-#define ATA_REG_CTL(channel) (channel->base + 0x206)
-
-// UDMA寄存器(Bus Master IDE Register)
-
-#define IDE_BM_REG_CMD(channel) (channel->channel_num * 8 + 0)
-#define IDE_BM_REG_SPEC0(channel) (channel->channel_num * 8 + 1)
-#define IDE_BM_REG_STATUS(channel) (channel->channel_num * 8 + 2)
-#define IDE_BM_REG_SPEC1(channel) (channel->channel_num * 8 + 3)
-#define IDE_BM_REG_PRDT_ADDR(channel) (channel->channel_num * 8 + 4)
-
-// Bus Master IDE Command Register
-
-#define IDE_BMCR_START 0x01
-#define IDE_BMCR_RW 0x08
-
-// Bus Master IDE Status Register
-
-#define IDE_BMSR_ACTIVE 0x01
-#define IDE_BMSR_ERROR 0x02
-#define IDE_BMSR_INTERRUPT 0x04
-#define IDE_BMSR_DMA0_CAPABLE 0x20
-#define IDE_BMSR_DMA1_CAPABLE 0x40
-#define IDE_BMSR_SIMPLEX_ONLY 0x80
-
-#define IDE_DISK_CNT 0x475 // BIOS数据区中此处保存了磁盘数
-#define IDE_MAX_CHANNEL_NUM 2
-#define IDE_MAX_DEV_PER_CNL 2
-
-#define SECTOR_SIZE 512
-
-#define IDE0_IRQ 14
-#define IDE1_IRQ 15
-
-#define IDE_SEND_CMD(channel, cmd) io_out8(ATA_REG_CMD(channel), cmd)
-
-struct physicalRegionDescriptor {
- uint32_t base_addr;
- uint16_t count;
- uint16_t EOT;
-};
-
-struct ide_identify_info {
- unsigned short general_config;
- unsigned short obsolete0;
- unsigned short specific_config;
- unsigned short obsolete1;
- unsigned short retired0[2];
- unsigned short obsolete2;
- unsigned short compact_flash[2];
- unsigned short retired1;
- unsigned short serial_number[10];
- unsigned short retired2[2];
- unsigned short obsolete3;
- unsigned short firmware_version[4];
- unsigned short model_number[20];
- unsigned short max_logical_transferred_per_DRQ;
- unsigned short trusted_computing_feature_set_options;
- unsigned short capabilities0;
- unsigned short capabilities1;
- unsigned short obsolete4[2];
- unsigned short report_88_70to_64_valid;
- unsigned short obsolete5[5];
- unsigned short mul_sesc_setting_valid;
- unsigned short lba28sectors[2];
- unsigned short obsolete6;
- unsigned short multword_DMA_select;
- unsigned short PIO_mode_supported;
- unsigned short min_mulword_DMA_cycle_time_per_word;
- unsigned short manufacture_recommend_multiword_DMA_cycle_time;
- unsigned short min_PIO_cycle_time_flow_control;
- unsigned short min_PIO_cycle_time_IORDY_flow_control;
- unsigned short reserved1[2];
- unsigned short reserved2[4];
- unsigned short queue_depth;
- unsigned short SATA_capabilities;
- unsigned short reserved3;
- unsigned short SATA_features_supported;
- unsigned short SATA_features_enabled;
- unsigned short major_version;
- unsigned short minor_version;
- unsigned short cmd_set0;
- unsigned short cmd_set1;
- unsigned short cmd_feature_sets_supported2;
- unsigned short cmd_feature_sets_supported3;
- unsigned short cmd_feature_sets_supported4;
- unsigned short cmd_feature_sets_supported5;
- unsigned short ultra_DMA_modes;
- unsigned short time_required_erase_cmd;
- unsigned short time_required_enhanced_cmd;
- unsigned short current_AAM_level_value;
- unsigned short master_password_identifier;
- unsigned short hardware_reset_result;
- unsigned short current_AAM_value;
- unsigned short stream_min_request_size;
- unsigned short streaming_transger_time_DMA;
- unsigned short streamimg_access_latency_DMA_PIO;
- unsigned short streaming_performance_granularity[2];
- unsigned short lba48sectors[4];
- unsigned short streaming_transfer_time_PIO;
- unsigned short reserved4;
- unsigned short physical_logical_sector_size;
- unsigned short inter_seek_delay;
- unsigned short world_wide_name[4];
- unsigned short reserved5[4];
- unsigned short reserved6;
- unsigned short words_per_logical_sector[2];
- unsigned short cmd_feature_supported;
- unsigned short cmd_feature_supported_enabled;
- unsigned short reserved7[6];
- unsigned short obsolete7;
- unsigned short security_status;
- unsigned short vendor_specific[31];
- unsigned short CFA_power_mode;
- unsigned short reserved8[7];
- unsigned short dev_from_factor;
- unsigned short reserved9[7];
- unsigned short current_media_serial_number[30];
- unsigned short SCT_cmd_transport;
- unsigned short reserved10[2];
- unsigned short alignment_logical_blocks_within_a_physical_block;
- unsigned short write_read_verify_sector_count_mode_3[2];
- unsigned short write_read_verify_sector_count_mode_2[2];
- unsigned short NV_cache_capabilities;
- unsigned short NV_cache_size[2];
- unsigned short nominal_media_rotation_rate;
- unsigned short reserved11;
- unsigned short NV_cache_options;
- unsigned short write_read_verify_feature_set_current_mode;
- unsigned short reserved12;
- unsigned short transport_major_version_number;
- unsigned short transport_minor_version_number;
- unsigned short reserved13[10];
- unsigned short min_blocks_per_cmd;
- unsigned short max_blocks_per_cmd;
- unsigned short reserved14[19];
- unsigned short integrity_word;
-} __attribute__((packed));
-
-struct ide_channel {
- uint8_t channel_num;
- unsigned short base;
- char irq_num;
- struct _device_extension_s *device;
- char selected_drive;
- uint32_t bmr;
-};
-
-typedef struct _device_extension_s {
- char flag;
- char drive_num;
- char type;
- struct pci_device *device;
- struct ide_channel *channel;
- struct ide_identify_info *info;
- int int_flag;
- unsigned short capabilities;
- unsigned short signature;
- unsigned int command_sets;
- unsigned int size;
- wait_queue_manager_t *wqm;
- struct physicalRegionDescriptor *PRD;
- int index_r, index_w;
-} device_extension_t;
-
-static status_t ide_enter(driver_t *drv_obj);
-static status_t ide_exit(driver_t *drv_obj);
-status_t ide_read(struct _device_s *dev, uint8_t *buf, uint32_t offset, size_t size);
-status_t ide_write(struct _device_s *dev, uint8_t *buf, uint32_t offset, size_t size);
-void ide0_handler(device_t *devobj, int irq);
-void ide1_handler(device_t *devobj, int irq);
-void ide_reset_driver(struct ide_channel *channel);
-void ide_select_device(device_extension_t *devext, char mode, unsigned char head);
-int ide_pulling(struct ide_channel *channel, unsigned int advanced_check);
-int ide_wait(device_extension_t *devext);
-void ide_select_addressing_mode(device_extension_t *devext, unsigned int lba, unsigned char *mode,
- unsigned char *head, unsigned char *data);
-void ide_select_sector(device_extension_t *devext, unsigned char mode, unsigned char *lba,
- unsigned int count);
-void ide_select_cmd(unsigned char rw, unsigned char mode, unsigned char *cmd);
-int AtaTypeTransfer(device_extension_t *devext, unsigned char rw, unsigned int lba, unsigned int count,
- void *buf);
-int PioDataTransfer(device_extension_t *devext, unsigned char rw, unsigned char mode, unsigned char *buf,
- unsigned short count);
-
-uint8_t disk_count;
-struct ide_channel channels[2];
-
-driver_func_t ide_driver = {
- .driver_enter = ide_enter,
- .driver_exit = ide_exit,
- .driver_open = NULL,
- .driver_close = NULL,
- .driver_read = ide_read,
- .driver_write = ide_write,
- .driver_devctl = NULL,
-};
-
-#define IDE_CLASSCODE 0x01
-#define IDE_SUBCLASS 0x01
-
-#define DRV_NAME "General HardDisk Driver(IDE)"
-#define DEV_NAME "hd"
-
-int ide_read_identity_info(device_extension_t *devext, struct ide_channel *channel) {
- devext->info = kmalloc(sizeof(struct ide_identify_info));
- if (devext->info == NULL) {
- printk("kmalloc for ide device info falied!\n");
- return -1;
- }
-
- ide_reset_driver(devext->channel);
- ide_select_device(devext, 0, 0);
-
- // while (!(io_in8(ATA_REG_STATUS(channel)) & ATA_STATUS_READY)) __asm__("nop\n\t");
- IDE_SEND_CMD(channel, ATA_CMD_IDENTIFY); // 获取硬盘识别信息
-
- ide_wait(devext);
- uint32_t status = io_in8(ATA_REG_STATUS(channel));
- printk("[IDE]Channel%d: Status %#02X ", channel->channel_num, status);
- status = io_in8(IDE_BM_REG_STATUS(channel));
- printk("%#02X ", status);
- char err = ide_pulling(channel, 1);
- if (err) {
- printk("error! %d\n", err);
- return -1;
- }
- printk("\n");
- port_insw(ATA_REG_DATA(devext->channel), (unsigned int)devext->info, sizeof(struct ide_identify_info));
- return 0;
-}
-
-static status_t ide_enter(driver_t *drv_obj) {
- struct ide_channel *channel;
- int i = 0, j = 0;
- device_t *devobj;
- device_extension_t *devext;
-
- struct pci_device *device = pci_get_device_ByClass(IDE_CLASSCODE, IDE_SUBCLASS);
- if (device == NULL) { return NODEV; }
-
- // 使用兼容模式(如支持)
- if (device->prog_if & 0x01) {
- if (device->prog_if & 0x02) {
- pci_write8(device->bus, device->dev, device->function, PCI_REG_PROGIF, device->prog_if | 0x01);
- device->prog_if = pci_read8(device->bus, device->dev, device->function, PCI_REG_PROGIF);
- } else {
- return UNSUPPORT;
- }
- }
- if (device->prog_if & 0x04) {
- if (device->prog_if & 0x08) {
- pci_write8(device->bus, device->dev, device->function, PCI_REG_PROGIF, device->prog_if | 0x04);
- device->prog_if = pci_read8(device->bus, device->dev, device->function, PCI_REG_PROGIF);
- } else {
- return UNSUPPORT;
- }
- }
-#ifdef IDE_DMA_MODE
- if (!(device->prog_if & 0x80)) // 是否支持DMA
- {
- return UNSUPPORT;
- }
-#endif
-
- channels[0].base = ATA_PRIMARY_PORT;
- channels[0].channel_num = 0;
- channels[0].irq_num = IDE0_IRQ;
- channels[1].base = ATA_SECONDARY_PORT;
- channels[1].channel_num = 1;
- channels[1].irq_num = IDE1_IRQ;
- channels[0].selected_drive = channels[1].selected_drive = 0;
- channels[0].bmr = device->bar[4].base_addr;
- channels[1].bmr = channels[0].bmr;
-
- pci_enable_bus_mastering(device);
- pci_enable_io_space(device);
-
- while (i < IDE_MAX_CHANNEL_NUM) {
- channel = &channels[i];
-
- while (j < IDE_MAX_DEV_PER_CNL) {
- char devname[3] = {0};
- sprintf(devname, "%s%d", DEV_NAME, i * 2 + j);
- device_create(drv_obj, sizeof(device_extension_t), devname, DEV_STORAGE, &devobj);
- devext = devobj->device_extension;
- if (devext == NULL) {
- device_delete(devobj);
- goto next;
- }
- channel->device = devext;
-
- if (i == 0) {
- device_register_irq(devobj, IDE0_IRQ, ide0_handler);
- } else if (i == 1) {
- device_register_irq(devobj, IDE1_IRQ, ide1_handler);
- }
-
- devext->device = device;
- devext->channel = channel;
- devext->drive_num = j;
- devext->type = IDE_ATA;
- devext->int_flag = 0;
-
- int ret = ide_read_identity_info(devext, channel);
- if (ret != 0) {
- device_delete(devobj);
- goto next;
- }
-
- devext->wqm = create_wait_queue();
- wait_queue_init(devext->wqm);
-
- devext->PRD = kmalloc(sizeof(struct physicalRegionDescriptor) * 64);
- io_out32(IDE_BM_REG_PRDT_ADDR(channel), vir2phy((uint32_t)devext->PRD));
- io_out8(IDE_BM_REG_STATUS(channel), 1 << (j + 5));
-
- devext->command_sets = (int)((devext->info->cmd_set1 << 16) + devext->info->cmd_set0);
-
- if (devext->command_sets & (1 << 26)) {
- devext->size = ((unsigned int)devext->info->lba48sectors[1] << 16) +
- (unsigned int)devext->info->lba48sectors[0];
- } else {
- devext->size = ((unsigned int)devext->info->lba28sectors[1] << 16) +
- (unsigned int)devext->info->lba28sectors[0];
- }
- devext->size /= 2;
-
- devext->capabilities = devext->info->capabilities0;
- devext->signature = devext->info->general_config;
- devext->flag = 1;
- next:
- j++;
- }
- j = 0;
- i++;
- }
- return SUCCUESS;
-}
-
-static status_t ide_exit(driver_t *drv_obj) {
- device_t *devobj, *next;
- device_extension_t *devext;
- // device_extension_t *ext;
- list_for_each_owner_safe (devobj, next, &drv_obj->device_list, list) {
- devext = devobj->device_extension;
- kfree(devext->info);
- device_delete(devobj);
- }
- string_del(&drv_obj->name);
- return SUCCUESS;
-}
-
-status_t ide_read(struct _device_s *dev, uint8_t *buf, uint32_t offset, size_t size) {
- device_extension_t *devext = dev->device_extension;
- wait_queue_add(devext->wqm, 0);
- if (devext->wqm->list_head.next->next != &devext->wqm->list_head) { thread_block(TASK_BLOCKED); }
- int length = DIV_ROUND_UP(size, SECTOR_SIZE);
- char *tmp_buffer = kmalloc(length * SECTOR_SIZE);
- AtaTypeTransfer(devext, IDE_READ, offset, length, tmp_buffer);
- memcpy(buf, tmp_buffer, size);
- kfree(tmp_buffer);
- wait_queue_wakeup(devext->wqm);
- return SUCCUESS;
-}
-
-status_t ide_write(struct _device_s *dev, uint8_t *buf, uint32_t offset, size_t size) {
- device_extension_t *devext = dev->device_extension;
- wait_queue_add(devext->wqm, 0);
- if (devext->wqm->list_head.next->next != &devext->wqm->list_head) { thread_block(TASK_BLOCKED); }
- int length = DIV_ROUND_UP(size, SECTOR_SIZE);
- uint8_t *tmp_buffer;
- if (size % SECTOR_SIZE == 0) {
- tmp_buffer = (uint8_t *)kmalloc(length * SECTOR_SIZE);
- AtaTypeTransfer(devext, IDE_READ, offset + length - 1, 1, tmp_buffer);
- memcpy(tmp_buffer, buf, size);
- } else {
- tmp_buffer = buf;
- AtaTypeTransfer(devext, IDE_READ, offset, length, tmp_buffer);
- }
- AtaTypeTransfer(devext, IDE_WRITE, offset, length, tmp_buffer);
- wait_queue_wakeup(devext->wqm);
- return SUCCUESS;
-}
-
-void ide_write_sector(device_extension_t *devext, uint32_t lba, char *buf) {
- AtaTypeTransfer(devext, IDE_WRITE, lba, 1, buf);
-}
-
-void ide0_handler(device_t *devobj, int irq) {
-}
-
-void ide1_handler(device_t *devobj, int irq) {
-}
-
-void ide_reset_driver(struct ide_channel *channel) {
- char ctrl = io_in8(ATA_REG_CTL(channel));
- io_out8(ATA_REG_CTL(channel), ctrl | (1 << 2));
-
- // 等待重置
- int i;
- for (i = 0; i < 50; i++) {
- io_in8(ATA_REG_ALT_STATUS(channel));
- }
- io_out8(ATA_REG_CTL(channel), ctrl);
-}
-
-void ide_select_device(device_extension_t *devext, char mode, unsigned char head) {
- io_out8(ATA_REG_DEVICE(devext->channel), (0xa0 | 0x40 | devext->drive_num << 4 | head));
- devext->channel->selected_drive = devext->drive_num;
-}
-
-int ide_pulling(struct ide_channel *channel, unsigned int advanced_check) {
- int i;
- for (i = 0; i < 4; i++) {
- io_in8(ATA_REG_ALT_STATUS(channel));
- }
- i = 10000;
- while ((io_in8(ATA_REG_STATUS(channel)) & ATA_STATUS_BUSY) && i--)
- ;
-
- if (advanced_check) {
- unsigned char state = io_in8(ATA_REG_STATUS(channel));
-
- if (state & ATA_STATUS_ERR) { return 2; }
-
- if (state & ATA_STATUS_DF) { return 1; }
-
- if ((state & ATA_STATUS_DRQ) == 0) { return 3; }
- }
-
- return 0;
-}
-
-int ide_wait(device_extension_t *devext) {
- struct ide_channel *channel = devext->channel;
- while (io_in8(ATA_REG_STATUS(channel)) & ATA_STATUS_BUSY)
- ;
- return 0;
-}
-
-void ide_select_addressing_mode(device_extension_t *devext, unsigned int lba, unsigned char *mode,
- unsigned char *head, unsigned char *data) {
- unsigned short cyl;
- unsigned char sector;
- if (lba >= 0x10000000 && devext->capabilities & 0x200) {
- *mode = 2;
- data[0] = lba & 0xff;
- data[1] = (lba >> 8) & 0xff;
- data[2] = (lba >> 16) & 0xff;
- data[3] = (lba >> 24) & 0xff;
- data[4] = 0;
- data[5] = 0;
- *head = 0;
- } else if (devext->capabilities & 0x200) {
- *mode = 1;
- data[0] = lba & 0xff;
- data[1] = (lba >> 8) & 0xff;
- data[2] = (lba >> 16) & 0xff;
- data[3] = 0;
- data[4] = 0;
- data[5] = 0;
- *head = (lba >> 24) & 0x0f;
- } else {
- *mode = 0;
- sector = (lba % 63) + 1;
- cyl = (lba + 1 - sector) / (16 * 63);
- data[0] = sector;
- data[1] = (cyl >> 0) & 0xFF;
- data[2] = (cyl >> 8) & 0xFF;
- data[3] = 0;
- data[4] = 0;
- data[5] = 0;
- *head = (lba + 1 - sector) % (16 * 63) / (63);
- }
-}
-
-void ide_select_sector(device_extension_t *devext, unsigned char mode, unsigned char *lba,
- unsigned int count) {
- struct ide_channel *channel = devext->channel;
-
- /* 如果是LBA48就要写入24高端字节 */
- if (mode == 2) {
- io_out8(ATA_REG_FEATURE(channel), 0); // PIO mode.
-
- /* 写入要读写的扇区数*/
- io_out8(ATA_REG_SECTOR_CNT(channel), 0);
-
- /* 写入lba地址24~47位(即扇区号) */
- io_out8(ATA_REG_SECTOR_LOW(channel), lba[3]);
- io_out8(ATA_REG_SECTOR_MID(channel), lba[4]);
- io_out8(ATA_REG_SECTOR_HIGH(channel), lba[5]);
- }
-
- io_out8(ATA_REG_FEATURE(channel), 0); // PIO mode.
-
- /* 写入要读写的扇区数*/
- io_out8(ATA_REG_SECTOR_CNT(channel), count);
-
- /* 写入lba地址0~23位(即扇区号) */
- io_out8(ATA_REG_SECTOR_LOW(channel), lba[0]);
- io_out8(ATA_REG_SECTOR_MID(channel), lba[1]);
- io_out8(ATA_REG_SECTOR_HIGH(channel), lba[2]);
-}
-
-void ide_select_cmd(unsigned char rw, unsigned char mode, unsigned char *cmd) {
-#ifdef IDE_DMA_MODE
- if (mode == 0 && rw == IDE_READ) *cmd = ATA_CMD_READ_DMA;
- if (mode == 1 && rw == IDE_READ) *cmd = ATA_CMD_READ_DMA;
- if (mode == 2 && rw == IDE_READ) *cmd = ATA_CMD_READ_DMA_EXT;
- if (mode == 0 && rw == IDE_WRITE) *cmd = ATA_CMD_WRITE_DMA;
- if (mode == 1 && rw == IDE_WRITE) *cmd = ATA_CMD_WRITE_DMA;
- if (mode == 2 && rw == IDE_WRITE) *cmd = ATA_CMD_WRITE_DMA_EXT;
-#else
- if (mode == 0 && rw == IDE_READ) *cmd = ATA_CMD_READ_PIO;
- if (mode == 1 && rw == IDE_READ) *cmd = ATA_CMD_READ_PIO;
- if (mode == 2 && rw == IDE_READ) *cmd = ATA_CMD_READ_PIO_EXT;
- if (mode == 0 && rw == IDE_WRITE) *cmd = ATA_CMD_WRITE_PIO;
- if (mode == 1 && rw == IDE_WRITE) *cmd = ATA_CMD_WRITE_PIO;
- if (mode == 2 && rw == IDE_WRITE) *cmd = ATA_CMD_WRITE_PIO_EXT;
-#endif
-}
-
-int PioDataTransfer(device_extension_t *devext, unsigned char rw, unsigned char mode, unsigned char *buf,
- unsigned short count) {
- short i;
- unsigned char error;
- if (rw == IDE_READ) {
- for (i = 0; i < count; i++) {
- /* 醒来后开始执行下面代码*/
- if ((error = ide_wait(devext))) { // 若失败
- /* 重置磁盘驱动并返回 */
- ide_reset_driver(devext->channel);
- return error;
- }
- port_insw(ATA_REG_DATA(devext->channel), (unsigned int)buf, 256);
- buf += SECTOR_SIZE;
- }
- } else {
- for (i = 0; i < count; i++) {
- /* 等待硬盘控制器请求数据 */
- if ((error = ide_wait(devext))) { // 若失败
- /* 重置磁盘驱动并返回 */
- ide_reset_driver(devext->channel);
- return error;
- }
- /* 把数据写入端口,完成1个扇区后会产生一次中断 */
- port_outsw(ATA_REG_DATA(devext->channel), (unsigned int)buf, 256);
- buf += SECTOR_SIZE;
- // printk("write success! ");
- }
- /* 刷新写缓冲区 */
- io_out8(ATA_REG_CMD(devext->channel), mode > 1 ? ATA_CMD_CACHE_FLUSH_EXT : ATA_CMD_CACHE_FLUSH);
- ide_pulling(devext->channel, 0);
- }
- return 0;
-}
-
-int AtaTypeTransfer(device_extension_t *devext, unsigned char rw, unsigned int lba, unsigned int count,
- void *buf) {
-
- unsigned char mode; /* 0: CHS, 1:LBA28, 2: LBA48 */
- unsigned char dma; /* 0: No DMA, 1: DMA */
- unsigned char cmd;
- unsigned char *_buf = (unsigned char *)buf;
-
- unsigned char lbaIO[6]; /* 由于最大是48位,所以这里数组的长度为6 */
-
- struct ide_channel *channel = devext->channel;
-
- unsigned char head, err;
-
- /* 要去操作的扇区数 */
- unsigned int todo;
- /* 已经完成的扇区数 */
- unsigned int done = 0;
-
- while (done < count) {
- /* 获取要去操作的扇区数
- 由于一次最大只能操作256个扇区,这里用256作为分界
- */
- if ((done + 256) <= count) {
- todo = 256;
- } else {
- todo = count - done;
- }
-
- /* 选择传输模式(PIO或DMA) */
-#ifdef IDE_DMA_MODE
- int size;
- dma = 1; // 默认使用DMA模式
- i = 0;
- while (i < 64 && todo > 0) {
- size = (todo * SECTOR_SIZE) % 65536;
- devext->PRD[i].base_addr = vir2phy((uint32_t)_buf);
- devext->PRD[i].count = size;
- _buf += size;
- todo -= size / SECTOR_SIZE;
- done += size / SECTOR_SIZE;
- i++;
- }
- io_out8(IDE_BM_REG_CMD(channel), 0); // 停止传输
- if (rw == IDE_READ) {
- io_out8(IDE_BM_REG_CMD(channel), 0x08); // 读取模式
- } else {
- io_out8(IDE_BM_REG_CMD(channel), 0x00); // 写入模式
- }
- uint32_t status = io_in8(IDE_BM_REG_STATUS(channel));
- io_out8(IDE_BM_REG_STATUS(channel), status | 0x06);
-#else
- dma = 0;
-#endif
-
- /* 选择寻址模式 */
- // (I) Select one from LBA28, LBA48 or CHS;
- ide_select_addressing_mode(devext, lba + done, &mode, &head, lbaIO);
-
- /* 等待驱动不繁忙 */
- // (III) Wait if the drive is busy;
- while (io_in8(ATA_REG_STATUS(channel)) & ATA_STATUS_BUSY)
- ;
- /* 从控制器中选择设备 */
- ide_select_device(devext, mode, head);
-
- /* 填写参数,扇区和扇区数 */
- ide_select_sector(devext, mode, lbaIO, count);
-
- /* 等待磁盘控制器处于准备状态 */
- while (!(io_in8(ATA_REG_STATUS(channel)) & ATA_STATUS_READY))
- ;
-
- /* 选择并发送命令 */
- ide_select_cmd(rw, mode, &cmd);
-
- /* 等待磁盘控制器处于准备状态 */
- while (!(io_in8(ATA_REG_STATUS(channel)) & ATA_STATUS_READY))
- ;
-
- /* 发送命令 */
- IDE_SEND_CMD(channel, cmd);
-
- /* 根据不同的模式传输数据 */
- if (dma) { /* DMA模式 */
- int tmp = io_in8(IDE_BM_REG_CMD(channel));
- io_out8(IDE_BM_REG_CMD(channel), tmp | 0x01);
- while (!(io_in8(IDE_BM_REG_STATUS(channel)) & 0x04))
- ;
- io_out8(IDE_BM_REG_STATUS(channel), 0x04);
- tmp = io_in8(IDE_BM_REG_STATUS(channel));
- io_out8(IDE_BM_REG_CMD(channel), tmp & 0xfe);
- } else {
- /* PIO模式数据传输 */
- if ((err = PioDataTransfer(devext, rw, mode, _buf, todo))) { return err; }
- _buf += todo * SECTOR_SIZE;
- done += todo;
- }
- }
-
- return 0;
-}
-
-static __init void ide_driver_entry(void) {
- if (driver_create(ide_driver, DRV_NAME) < 0) {
- printk(COLOR_RED "[driver] %s driver create failed!\n", __func__);
- }
-}
-
-driver_initcall(ide_driver_entry);
diff --git a/src/arch/x86/drivers/input/8042/8042.c b/src/arch/x86/drivers/input/8042/8042.c
new file mode 100644
index 0000000..93f94c1
--- /dev/null
+++ b/src/arch/x86/drivers/input/8042/8042.c
@@ -0,0 +1,295 @@
+/**
+ * @file 8042.c
+ * @author Ryan Wang (ryan1202@foxmail.com)
+ * @brief 8042控制器的驱动
+ * @version 0.1
+ * @date 2021-06
+ */
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+extern Driver core_driver;
+
+bool usb_legacy_support_disabled = true;
+
+DriverResult i8042_init(void *_device);
+DriverResult i8042_start(void *_device);
+DriverResult i8042_destroy(void *_device);
+
+DeviceOps i8042_device_ops = {
+ .init = i8042_init,
+ .start = i8042_start,
+ .stop = NULL,
+ .destroy = i8042_destroy,
+};
+
+DeviceDriver i8042_device_driver;
+PhysicalDevice *i8042_device;
+
+void i8042_irq_handler(void *arg) {
+ do {
+ i8042_read_data();
+ } while (i8042_get_status(I8042_STAT_OUTBUF));
+}
+
+int i8042_get_status(uint8_t type) {
+ int data = io_in_byte(I8042_PORT_STAT);
+ return data & type;
+}
+
+void i8042_wait_ctr_send_ready(void) {
+ for (;;) {
+ if ((io_in_byte(I8042_PORT_STAT) & I8042_STAT_INBUF) ==
+ 0) { // 输入缓存区为空
+ return;
+ }
+ }
+}
+
+void i8042_send_cmd(uint8_t command) {
+ io_out_byte(I8042_PORT_CMD, command);
+ i8042_wait_ctr_send_ready();
+}
+
+uint8_t i8042_read_data(void) {
+ return io_in_byte(I8042_PORT_DATA);
+}
+
+void i8042_write_data(uint8_t data) {
+ io_out_byte(I8042_PORT_DATA, data);
+}
+
+void i8042_disable_interrupt(int port) {
+ I8042Device *i8042 = i8042_device->private_data;
+ uint8_t cfg;
+ disable_device_irq(i8042->irq[port]);
+ i8042_send_cmd(I8042_CMD_READ);
+ cfg = i8042_read_data();
+ if (port == 0) {
+ cfg &= ~I8042_CFG_INT1;
+ } else if (port == 1) {
+ cfg &= ~I8042_CFG_INT2;
+ }
+ i8042_send_cmd(I8042_CMD_WRITE);
+ i8042_write_data(cfg);
+}
+
+void i8042_enable_interrupt(int port) {
+ I8042Device *i8042 = i8042_device->private_data;
+ uint8_t cfg;
+ disable_device_irq(i8042->irq[port]);
+ i8042_send_cmd(I8042_CMD_READ);
+ cfg = i8042_read_data();
+ if (port == 0) {
+ cfg |= I8042_CFG_INT1;
+ } else if (port == 1) {
+ cfg |= I8042_CFG_INT2;
+ }
+ i8042_send_cmd(I8042_CMD_WRITE);
+ i8042_write_data(cfg);
+ enable_device_irq(i8042->irq[port]);
+}
+
+void i8042_clear_buffer(void) {
+ while (i8042_get_status(I8042_STAT_OUTBUF)) {
+ io_in_byte(I8042_PORT_DATA);
+ }
+}
+
+DriverResult i8042_init(void *_device) {
+ if (!usb_legacy_support_disabled) return DRIVER_ERROR_WAITING;
+
+ PhysicalDevice *device = (PhysicalDevice *)_device;
+ I8042Device *i8042 = device->private_data;
+
+ // 1.禁用设备
+ i8042_send_cmd(I8042_CMD_DISABLE_P1); // 禁用第一个PS/2端口
+ i8042_send_cmd(I8042_CMD_DISABLE_P2); // 禁用第二个PS/2端口(如果有)
+
+ // 2.配置控制器
+ i8042_send_cmd(I8042_CMD_WRITE);
+ i8042_write_data(
+ I8042_CFG_TRANS1 | I8042_CFG_SYS_FLAG | I8042_CFG_INT2 |
+ I8042_CFG_INT1);
+
+ // 3.控制器自检
+ i8042_send_cmd(I8042_CMD_TEST_CTL);
+ if (i8042_read_data() != 0x55) { return DRIVER_ERROR_OTHER; }
+
+ // 4.检测是否为双通道
+ i8042_send_cmd(I8042_CMD_ENABLE_P2);
+ i8042->is_dual_channel = (i8042_read_data() & I8042_CFG_CLK2) == 0;
+ if (i8042->is_dual_channel) { // 存在第二个通道则禁用第二个通道
+ i8042_send_cmd(I8042_CMD_DISABLE_P2);
+
+ i8042_send_cmd(I8042_CMD_READ);
+ uint8_t tmp = i8042_read_data();
+
+ i8042_send_cmd(I8042_CMD_WRITE);
+ i8042_write_data((tmp & ~I8042_CFG_INT2) | I8042_CFG_CLK2);
+ }
+
+ // 5.接口测试
+ i8042_send_cmd(I8042_CMD_TEST_P1);
+ if (i8042_read_data() != 0x00) {
+ printk("[i8042]PS/2 Port 1 test failed!\n");
+ i8042->is_p1_avail = false;
+ } else {
+ i8042->is_p1_avail = true;
+ register_device_irq(
+ &i8042->irq[0], i8042_device, NULL, ps2_irqs[0], i8042_irq_handler,
+ IRQ_MODE_SHARED);
+ }
+ if (i8042->is_dual_channel) {
+ i8042_send_cmd(I8042_CMD_TEST_P2);
+ if (i8042_read_data() != 0x00) {
+ printk("[i8042]PS/2 Port 2 test failed!\n");
+ i8042->is_p2_avail = false;
+ } else {
+ i8042->is_p2_avail = true;
+ register_device_irq(
+ &i8042->irq[1], i8042_device, NULL, ps2_irqs[1],
+ i8042_irq_handler, IRQ_MODE_SHARED);
+ }
+ }
+
+ return DRIVER_OK;
+}
+
+DriverResult i8042_start(void *_device) {
+ PhysicalDevice *physical_device = (PhysicalDevice *)_device;
+ I8042Device *i8042 = physical_device->private_data;
+ if (i8042->is_p1_avail) {
+ // 6.启用端口
+ i8042_send_cmd(I8042_CMD_ENABLE_P1);
+ // 7.重置设备
+ i8042_write_data(I8042_CMD_RESET_DEV);
+
+ while (!i8042_get_status(I8042_STAT_OUTBUF))
+ ;
+ if (i8042_read_data() != 0xfa) {
+ printk("[i8042]PS/2 Port1 Device reset failed!\n");
+ i8042->is_p1_avail = false;
+ goto enable2;
+ }
+ while (!i8042_get_status(I8042_STAT_OUTBUF))
+ ;
+ if (i8042_read_data() != 0xaa) {
+ printk("[i8042]PS/2 Port1 Device self-test failed!\n");
+ i8042->is_p1_avail = false;
+ goto enable2;
+ }
+
+ if (i8042_get_status(I8042_STAT_OUTBUF)) {
+ i8042->p1_dev_type = i8042_read_data();
+
+ if (i8042->p1_dev_type == 0xfc) {
+ printk("[i8042]PS/2 Port1 Device enable failed!\n");
+ i8042->is_p1_avail = false;
+ goto enable2;
+ }
+ } else { // AT键盘没有设备类型的响应
+ i8042->p1_dev_type = 0xff;
+ }
+ }
+enable2:
+ if (i8042->is_p2_avail) {
+ // 6.启用端口
+ i8042_send_cmd(I8042_CMD_ENABLE_P2);
+
+ // 7.重置设备
+ i8042_send_cmd(I8042_CMD_SEND_TO_P2);
+ i8042_write_data(I8042_CMD_RESET_DEV);
+
+ while (!i8042_get_status(I8042_STAT_OUTBUF))
+ ;
+ if (i8042_read_data() != 0xfa) {
+ printk("[i8042]PS/2 Port2 Device reset failed!\n");
+ i8042->is_p2_avail = false;
+ goto next;
+ }
+
+ while (!i8042_get_status(I8042_STAT_OUTBUF))
+ ;
+ if (i8042_read_data() != 0xaa) {
+ printk("[i8042]PS/2 Port2 Device self-test failed!\n");
+ i8042->is_p2_avail = false;
+ goto next;
+ }
+
+ if (i8042_get_status(I8042_STAT_OUTBUF)) {
+ i8042->p2_dev_type = i8042_read_data();
+ if (i8042->p2_dev_type != 0xfa) {
+ printk("[i8042]PS/2 Port2 Device enable failed!\n");
+ i8042->is_p2_avail = false;
+ goto next;
+ }
+ } else { // AT键盘没有设备类型的响应
+ i8042->p2_dev_type = 0xff;
+ }
+ }
+next:
+
+ int available[2] = {i8042->is_p1_avail, i8042->is_p2_avail};
+ int types[2] = {i8042->p1_dev_type, i8042->p2_dev_type};
+ for (int i = 0; i < 2; i++) {
+ if (!available[i]) {
+ printk("[i8042]PS/2 Port %d is not available.\n", i + 1);
+ continue;
+ }
+
+ printk("[i8042]PS/2 Port %d is available.Type: ", i + 1);
+ switch (types[i]) {
+ case 0x00:
+ printk("Standard PS/2 Mouse");
+ ps2_mouse_register(physical_device, i);
+ break;
+ case 0x03:
+ printk("Mouse with scroll wheel");
+ break;
+ case 0xff: {
+ printk("AT Keyboard");
+ ps2_keyboard_register(physical_device, i);
+ break;
+ }
+ default:
+ printk("Unknown Device (0x%x)", types[i]);
+ break;
+ }
+ printk("\n");
+
+ i8042_enable_interrupt(i);
+ enable_device_irq(i8042->irq[i]);
+ }
+
+ return DRIVER_OK;
+}
+
+DriverResult i8042_destroy(void *_device) {
+ PhysicalDevice *device = (PhysicalDevice *)_device;
+ kfree(device->private_data);
+ return DRIVER_OK;
+}
+
+static __init void i8042_driver_entry(void) {
+ register_device_driver(&core_driver, &i8042_device_driver);
+
+ ObjectAttr attr = device_object_attr;
+ create_physical_device(&i8042_device, platform_bus, &attr);
+ register_physical_device(i8042_device, &i8042_device_ops);
+
+ I8042Device *i8042 = kmalloc(sizeof(I8042Device));
+ i8042_device->private_data = i8042;
+}
+
+driver_initcall(i8042_driver_entry);
\ No newline at end of file
diff --git a/src/arch/x86/drivers/input/8042/Makefile b/src/arch/x86/drivers/input/8042/Makefile
new file mode 100644
index 0000000..24062da
--- /dev/null
+++ b/src/arch/x86/drivers/input/8042/Makefile
@@ -0,0 +1,3 @@
+SRC += 8042.c
+SRC += keyboard.c
+SRC += mouse.c
\ No newline at end of file
diff --git a/src/arch/x86/drivers/input/8042/config.toml b/src/arch/x86/drivers/input/8042/config.toml
new file mode 100644
index 0000000..701acd0
--- /dev/null
+++ b/src/arch/x86/drivers/input/8042/config.toml
@@ -0,0 +1 @@
+c = ["8042.c", "keyboard.c", "mouse.c"]
diff --git a/src/arch/x86/drivers/input/8042/keyboard.c b/src/arch/x86/drivers/input/8042/keyboard.c
new file mode 100644
index 0000000..0295526
--- /dev/null
+++ b/src/arch/x86/drivers/input/8042/keyboard.c
@@ -0,0 +1,382 @@
+/**
+ * @file keyboard.c
+ * @author Ryan Wang (ryan1202@foxmail.com)
+ * @brief PS/2键盘驱动
+ * @version 0.1
+ * @date 2021-06
+ */
+#include "driver/input/input_dm.h"
+#include "kernel/device.h"
+#include "kernel/driver_interface.h"
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+DriverResult ps2_keyboard_start(void *_device);
+
+DeviceOps ps2_keyboard_device_ops = {
+ .init = NULL,
+ .start = ps2_keyboard_start,
+ .stop = NULL,
+ .destroy = NULL,
+};
+
+#define SCANCODE_1_MAX 0xd8
+#define SCANCODE_2_MAX 0x83
+
+// clang-format off
+
+static uint8_t scancodes1_usage_id[108] =
+{
+ 0,
+ KEY_ESC, KEY_1, KEY_2, KEY_3, KEY_4, KEY_5, KEY_6, KEY_7, KEY_8, KEY_9, KEY_0, KEY_MINUS, KEY_EQUAL, KEY_BACKSPACE,
+ KEY_TAB, KEY_Q, KEY_W, KEY_E, KEY_R, KEY_T, KEY_Y, KEY_U, KEY_I, KEY_O, KEY_P, KEY_LEFTBRACE, KEY_RIGHTBRACE, KEY_ENTER,
+ KEY_LEFTCTRL, KEY_A, KEY_S, KEY_D, KEY_F, KEY_G, KEY_H, KEY_J, KEY_K, KEY_L, KEY_SEMICOLON, KEY_APOSTROPHE, KEY_GRAVE,
+ KEY_LEFTSHIFT, KEY_BACKSLASH, KEY_Z, KEY_X, KEY_C, KEY_V, KEY_B, KEY_N, KEY_M, KEY_COMMA, KEY_DOT, KEY_SLASH, KEY_RIGHTSHIFT,
+ KEY_KEYPAD_ASTERISK, KEY_LEFTALT, KEY_SPACE, KEY_CAPSLOCK,
+ KEY_F1, KEY_F2, KEY_F3, KEY_F4, KEY_F5, KEY_F6, KEY_F7, KEY_F8, KEY_F9, KEY_F10, KEY_NUMLOCK, KEY_SCROLLLOCK,
+ KEY_KEYPAD_7, KEY_KEYPAD_8, KEY_KEYPAD_9, KEY_KEYPAD_MINUS,
+ KEY_KEYPAD_4, KEY_KEYPAD_5, KEY_KEYPAD_6, KEY_KEYPAD_PLUS,
+ KEY_KEYPAD_1, KEY_KEYPAD_2, KEY_KEYPAD_3,
+ KEY_KEYPAD_0, KEY_KEYPAD_DOT, 0, 0, 0,
+ KEY_F11, KEY_F12, 0, 0, 0, 0
+};
+
+// 从0xE0,0x10开始, 使用最高8位区分Page(0: Keyboard/Keypad Page, 1: Consumer Page, 2: General Desktop Page)
+static uint16_t scancodes1_ext_usage_id[0x5e] = {
+ [0x00] = 0x1000 | KEY_CP_PREVIOUS_TRACK,[0x09] = 0x1000 | KEY_CP_NEXT_TRACK,
+ [0x12] = 0x1000 | KEY_CP_PLAY_PAUSE, [0x14] = 0x1000 | KEY_CP_STOP_EJECT,
+
+ [0x0c] = KEY_KEYPAD_ENTER, [0x25] = KEY_KEYPAD_SLASH,
+ [0x11] = 0x1000 | KEY_CP_AL_CALC, [0x22] = 0x1000 | KEY_CP_AL_INTERNET_BROWSER,
+
+ [0x10] = KEY_CP_MUTE, [0x1e] = KEY_CP_VOLUME_DECREMENT, [0x20] = KEY_CP_VOLUME_INCREMENT,
+
+ [0x42] = KEY_INSERT, [0x37] = KEY_HOME, [0x39] = KEY_PAGEUP,
+ [0x43] = KEY_DELETE, [0x3f] = KEY_END, [0x41] = KEY_PAGEDOWN,
+
+ [0x38] = KEY_UP,
+ [0x3b] = KEY_LEFT, [0x3d] = KEY_RIGHT, [0x40] = KEY_DOWN,
+
+
+ [0x0d] = KEY_RIGHTCTRL, [0x28] = KEY_RIGHTALT,
+ [0x4b] = KEY_LEFTGUI, [0x4c] = KEY_RIGHTGUI,
+ [0x4d] = KEY_APPLICATION,
+ [0x4e] = 0x2000 | KEY_GDP_SYSTEM_POWER_DOWN,
+ [0x4f] = 0x2000 | KEY_GDP_SYSTEM_SLEEP, [0x53] = 0x2000 | KEY_GDP_SYSTEM_WAKEUP,
+ [0x55] = 0x1000 | KEY_CP_AL_RESEARCH_SEARCH_BROWSER,
+ [0x56] = 0x1000 | KEY_CP_AC_BOOKMARKS,
+ [0x57] = 0x1000 | KEY_CP_AC_REFRESH, [0x58] = 0x1000 | KEY_CP_AC_STOP,
+ [0x59] = 0x1000 | KEY_CP_AC_FORWARD, [0x5a] = 0x1000 | KEY_CP_AC_BACK,
+ [0x5b] = 0x1000 | KEY_CP_AL_FILE_BROWSER, [0x5c] = 0x1000 | KEY_CP_AL_EMAIL_READER,
+ [0x5d] = 0x1000 | KEY_CP_AL_CONSUMER_CONTROL_CONFIGURATION,
+};
+
+// printscreen insert
+static uint8_t scancodes2_usage_id[0x84] =
+{
+ 0, KEY_F9, 0,
+ KEY_F5, KEY_F3, KEY_F1, KEY_F2, KEY_F12, 0,
+ KEY_F10, KEY_F8, KEY_F6, KEY_F4, KEY_TAB, KEY_GRAVE, 0, 0,
+ KEY_LEFTALT, KEY_LEFTSHIFT, 0,
+ KEY_LEFTCTRL, KEY_Q, KEY_1, 0, 0, 0,
+ KEY_Z, KEY_S, KEY_A, KEY_W, KEY_2, 0, 0,
+ KEY_C, KEY_X, KEY_D, KEY_E, KEY_4, KEY_3, 0, 0,
+ KEY_SPACE, KEY_V, KEY_F, KEY_T, KEY_R, KEY_5, 0, 0,
+ KEY_N, KEY_B, KEY_H, KEY_G, KEY_Y, KEY_6, 0, 0, 0,
+ KEY_M, KEY_J, KEY_U, KEY_7, KEY_8, 0, 0,
+ KEY_COMMA, KEY_K, KEY_I, KEY_O, KEY_0, KEY_9, 0, 0,
+ KEY_DOT, KEY_SLASH, KEY_L, KEY_SEMICOLON, KEY_P, KEY_MINUS, 0, 0, 0,
+
+ KEY_APOSTROPHE, 0,
+ KEY_LEFTBRACE, KEY_EQUAL, 0, 0,
+ KEY_CAPSLOCK, KEY_RIGHTSHIFT, KEY_ENTER, KEY_RIGHTBRACE, 0,
+ KEY_BACKSLASH, 0, 0, 0, 0, 0, 0, 0, 0,
+ KEY_BACKSPACE, 0, 0,
+ KEY_KEYPAD_1, 0,
+ KEY_KEYPAD_4, KEY_KEYPAD_7, 0, 0, 0,
+ KEY_KEYPAD_0, KEY_KEYPAD_DOT,
+ KEY_KEYPAD_2, KEY_KEYPAD_5, KEY_KEYPAD_6, KEY_KEYPAD_8,
+ KEY_ESC, KEY_NUMLOCK, KEY_F11, KEY_KEYPAD_PLUS,
+ KEY_KEYPAD_3, KEY_KEYPAD_MINUS, KEY_KEYPAD_ASTERISK, KEY_KEYPAD_9, KEY_SCROLLLOCK, 0,0,0,0,
+ KEY_F7,
+};
+
+static uint16_t scancodes2_ext_usage_id[0x6e] = {
+ [0x05] = 0x1000 | KEY_CP_PREVIOUS_TRACK, [0x3d] = 0x1000 | KEY_CP_NEXT_TRACK,
+
+ [0x2a] = 0x1000 | KEY_CP_AC_HOME,
+ [0x08] = 0x1000 | KEY_CP_AC_BOOKMARKS,
+ [0x10] = 0x1000 | KEY_CP_AC_REFRESH,
+ [0x28] = 0x1000 | KEY_CP_AC_BACK, [0x20] = 0x1000 | KEY_CP_AC_FORWARD,
+
+ [0x0f] = KEY_LEFTGUI, [0x17] = KEY_RIGHTGUI,
+ [0x01] = KEY_RIGHTALT, [0x04] = KEY_RIGHTCTRL,
+ [0x4a] = KEY_ENTER, [0x3a] = KEY_KEYPAD_SLASH,
+
+ [0x11] = 0x1000 | KEY_CP_VOLUME_DECREMENT,
+ [0x13] = 0x1000 | KEY_CP_MUTE,
+
+ [0x22] = 0x1000 | KEY_CP_VOLUME_INCREMENT,
+ [0x24] = 0x1000 | KEY_CP_PLAY_PAUSE,
+ [0x2b] = 0x1000 | KEY_CP_STOP,
+
+ [0x00] = 0x1000 | KEY_CP_AL_RESEARCH_SEARCH_BROWSER,
+ [0x30] = 0x1000 | KEY_CP_AL_FILE_BROWSER, [0x38] = 0x1000 | KEY_CP_AL_EMAIL_READER,
+ [0x40] = 0x1000 | KEY_CP_AL_CONSUMER_CONTROL_CONFIGURATION,
+
+ [0x27] = 0x2000 | KEY_GDP_SYSTEM_POWER_DOWN,
+ [0x2f] = 0x2000 | KEY_GDP_SYSTEM_SLEEP, [0x4e] = 0x2000 | KEY_GDP_SYSTEM_WAKEUP,
+
+
+ [0x60] = KEY_INSERT, [0x5c] = KEY_HOME, [0x6d] = KEY_PAGEUP,
+ [0x61] = KEY_DELETE, [0x59] = KEY_END, [0x6a] = KEY_PAGEDOWN,
+ [0x65] = KEY_UP,
+ [0x5b] = KEY_LEFT, [0x62] = KEY_DOWN, [0x64] = KEY_RIGHT,
+
+};
+
+// clang-format on
+
+#define KEYBOARD_CAPSLOCK 0x04
+#define KEYBOARD_NUMLOCK 0x02
+#define KEYBOARD_SCROLLLOCK 0x01
+typedef struct {
+ int port;
+ uint8_t scancode_num;
+
+ uint8_t *scancode;
+ uint8_t scancode_max;
+ uint16_t *scancode_ext;
+
+ uint8_t extended_mode; // 0: none, 1: 0xe0, 2: 0xe1
+ uint8_t release; // scancode 2专用,0: none, 1: 0xf0
+
+ uint8_t locks;
+} Ps2Keyboard;
+
+void scancode_handle(Ps2Keyboard *kbd, uint8_t keycode);
+void keyboard_setleds(Ps2Keyboard *kbd);
+
+void keyboard_irq_handler(void *arg) {
+ Ps2Keyboard *kbd = (Ps2Keyboard *)arg;
+ uint16_t data;
+ data = i8042_read_data();
+ scancode_handle(kbd, data);
+}
+
+uint16_t scancode_handle_ext_1(Ps2Keyboard *kbd, uint8_t keycode) {
+ uint16_t data = kbd->scancode_ext[(keycode & 0x7f) - 0x10];
+ if (kbd->scancode_num == 1) {
+ // print screen pressed: 0xE0 0x2A 0xE0 0x37
+ // print screen released: 0xE0 0xB7 0xE0 0xAA
+
+ // 0xE0字节会被scancode_handle设备为扩展码自动跳过,通过第二个字节判断是pressed还是released,
+ // 第四个字节判断是否为print screen
+ if (keycode == 0x2a) {
+ kbd->release = false;
+ return 0;
+ } else if (keycode == 0xb7) {
+ kbd->release = true;
+ return 0;
+ }
+ if (keycode == 0x37 || keycode == 0xaa) { return KEY_PRINTSCREEN; }
+ } else if (kbd->scancode_num == 2) {
+ // print screen pressed: 0xE0 0x12 0xE0 0x7C
+ // print screen released: 0xE0 0xF0 0x7C 0xE0 0xF0 0x12
+
+ // 由于需要判断结束字节,需要结合release状态(是否遇到过0xF0)判断
+ if (kbd->release == false && keycode == 0x7C) {
+ return KEY_PRINTSCREEN;
+ }
+ if (kbd->release == true && keycode == 0x12) { return KEY_PRINTSCREEN; }
+ }
+ return data;
+}
+
+uint16_t scancode_handle_ext_2(Ps2Keyboard *kbd, uint8_t keycode) {
+ // pause只有pressed
+ if (kbd->scancode_num == 1) {
+ // pause pressed: 0xe1 0x1d 0x45 0xe1 0x9d 0xc5
+ // scancode 1
+ // 0xe1开头的扩展按键只有pause,最后一个字节没有冲突直接通过最后一个字节判断
+ if (keycode == 0xc5) {
+ kbd->release = false;
+ return KEY_PAUSE;
+ }
+ } else if (kbd->scancode_num == 2) {
+ // pause pressed: 0xe1 0x14 0x77 0xe1 0xf0 0x14 0xf0 0x77
+
+ // 0xf0字节会被scancode_handle设备为释放码,所以需要通过最后一个字节判断
+ // 又由于序列中包含两个0x77,而前一个0x77前面没有0xf0,所以要结合release状态(是否遇到过0xf0)判断
+ if (keycode == 0x77 && kbd->release == true) {
+ kbd->release = false;
+ return KEY_PAUSE;
+ }
+ }
+ return 0;
+}
+
+void scancode_handle(Ps2Keyboard *kbd, uint8_t keycode) {
+ bool press = true;
+ uint16_t data = kbd->scancode[keycode];
+ if (keycode == 0xe0) {
+ kbd->extended_mode = 1;
+ return;
+ } else if (keycode == 0xe1) {
+ kbd->extended_mode = 2;
+ return;
+ } else if (kbd->scancode_num == 2 && keycode == 0xf0) {
+ kbd->release = 1;
+ return;
+ } else if (keycode > kbd->scancode_max) {
+ return;
+ } else {
+ if (kbd->scancode_num == 1 && data & 0x80) press = false;
+ }
+
+ if (kbd->extended_mode == 1) {
+ data = scancode_handle_ext_1(kbd, keycode);
+ if (data == 0) return; // 还没处理完
+ } else if (kbd->extended_mode == 2) {
+ data = scancode_handle_ext_2(kbd, keycode);
+ if (data == 0) return; // 还没处理完
+ }
+
+ press = (kbd->release == 1) ? false : press;
+ uint8_t old_locks = kbd->locks;
+ if (data == KEY_CAPSLOCK) { kbd->locks ^= KEYBOARD_CAPSLOCK; }
+ if (data == KEY_NUMLOCK) { kbd->locks ^= KEYBOARD_NUMLOCK; }
+ if (data == KEY_SCROLLLOCK) { kbd->locks ^= KEYBOARD_SCROLLLOCK; }
+ if (old_locks != kbd->locks) { keyboard_setleds(kbd); }
+ if (data != 0) {
+ uint8_t tmp = data >> 12;
+ if (tmp == 0) {
+ new_key_event(
+ INPUT_KEY_EVENT_KEYBOARD_BASE + data & 0xfff, press,
+ INPUT_KEY_PAGE_KEYBOARD_KEYPAD);
+ } else if (tmp == 1) {
+ new_key_event(data & 0xfff, press, INPUT_KEY_PAGE_CONSUMER);
+ } else if (tmp == 2) {
+ new_key_event(data & 0xfff, press, INPUT_KEY_PAGE_GENERAL_DESKTOP);
+ }
+ }
+ if (kbd->extended_mode) kbd->extended_mode = 0;
+ if (kbd->release) kbd->release = 0;
+}
+
+void keyboard_setleds(Ps2Keyboard *kbd) {
+ i8042_wait_ctr_send_ready();
+ i8042_write_data(I8042_KBD_CMD_SET_LEDS);
+ i8042_wait_ctr_send_ready();
+ io_in_byte(I8042_PORT_DATA);
+ i8042_wait_ctr_send_ready();
+ i8042_write_data(kbd->locks & 0x07);
+ i8042_wait_ctr_send_ready();
+ io_in_byte(I8042_PORT_DATA);
+}
+
+DriverResult ps2_keyboard_start(void *_device) {
+ LogicalDevice *device = _device;
+ Ps2Keyboard *kbd = device->private_data;
+
+ i8042_disable_interrupt(kbd->port);
+ // 获取scancode集
+ i8042_wait_ctr_send_ready();
+ i8042_write_data(I8042_KBD_CMD_GET_SET_SCANCODE_SET);
+ i8042_wait_ctr_send_ready();
+ if (i8042_read_data() != 0xfa) {
+ printk(
+ "[i8042]PS/2 Port%d Device get scancode set failed!\n",
+ kbd->port + 1);
+ return DRIVER_ERROR_OTHER;
+ }
+ i8042_wait_ctr_send_ready();
+ i8042_write_data(0);
+ i8042_wait_ctr_send_ready();
+ if (i8042_read_data() != 0xfa) {
+ printk(
+ "[i8042]PS/2 Port%d Device get scancode set failed!\n",
+ kbd->port + 1);
+ return DRIVER_ERROR_OTHER;
+ }
+ int num = i8042_read_data();
+ if (num == 0x43) {
+ kbd->scancode = scancodes1_usage_id;
+ kbd->scancode_max = SCANCODE_1_MAX;
+ kbd->scancode_ext = scancodes1_ext_usage_id;
+ kbd->scancode_num = 1;
+ } else if (num == 0x41) {
+ kbd->scancode = scancodes2_usage_id;
+ kbd->scancode_max = SCANCODE_2_MAX;
+ kbd->scancode_ext = scancodes2_ext_usage_id;
+ kbd->scancode_num = 2;
+ } else {
+ i8042_wait_ctr_send_ready();
+ i8042_write_data(I8042_KBD_CMD_GET_SET_SCANCODE_SET);
+ i8042_wait_ctr_send_ready();
+ if (i8042_read_data() != 0xfa) {
+ printk(
+ "[i8042]PS/2 Port%d Device set scancode set failed!\n",
+ kbd->port + 1);
+ return DRIVER_ERROR_OTHER;
+ }
+ i8042_wait_ctr_send_ready();
+ i8042_write_data(1);
+ i8042_wait_ctr_send_ready();
+ if (i8042_read_data() != 0xfa) {
+ printk(
+ "[i8042]PS/2 Port%d Device set scancode set failed!\n",
+ kbd->port + 1);
+ return DRIVER_ERROR_OTHER;
+ }
+ kbd->scancode = scancodes1_usage_id;
+ kbd->scancode_max = SCANCODE_1_MAX;
+ kbd->scancode_ext = scancodes1_ext_usage_id;
+ kbd->scancode_num = 1;
+ }
+ kbd->release = 0;
+ kbd->extended_mode = 0;
+ // 关闭编码转换
+ i8042_wait_ctr_send_ready();
+ i8042_send_cmd(I8042_CMD_READ);
+ i8042_wait_ctr_send_ready();
+ uint8_t cfg = i8042_read_data();
+ cfg &= ~I8042_CFG_TRANS1;
+ i8042_send_cmd(I8042_CMD_WRITE);
+ i8042_wait_ctr_send_ready();
+ i8042_write_data(cfg);
+
+ I8042Device *i8042 = i8042_device->private_data;
+ // 手动修改irq的处理函数和参数
+ i8042->irq[kbd->port]->handler = keyboard_irq_handler;
+ i8042->irq[kbd->port]->arg = kbd;
+
+ i8042_wait_ctr_send_ready();
+ i8042_write_data(I8042_KBD_CMD_ENABLE_SCANNING);
+ i8042_read_data();
+
+ i8042_enable_interrupt(kbd->port);
+
+ return DRIVER_OK;
+}
+
+void ps2_keyboard_register(PhysicalDevice *physical_device, int port) {
+ InputDevice *in;
+ create_input_device(
+ &in, INPUT_TYPE_KEYBOARD, &ps2_keyboard_device_ops, physical_device,
+ &i8042_device_driver);
+ Ps2Keyboard *kbd = kmalloc(sizeof(Ps2Keyboard));
+ kbd->port = port;
+ in->device->private_data = kbd;
+ kbd->locks = 0;
+}
\ No newline at end of file
diff --git a/src/arch/x86/drivers/input/8042/mouse.c b/src/arch/x86/drivers/input/8042/mouse.c
new file mode 100644
index 0000000..54d869a
--- /dev/null
+++ b/src/arch/x86/drivers/input/8042/mouse.c
@@ -0,0 +1,153 @@
+/**
+ * @file mouse.c
+ * @author Ryan Wang (ryan1202@foxmail.com)
+ * @brief PS/2鼠标驱动
+ * @version 0.1
+ * @date 2021-06
+ */
+#include "driver/input/key_events.h"
+#include "kernel/device.h"
+#include
+#include