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 +#include +#include +#include +#include +#include +#include +#include +#include + +#define MOUSE_Y_OVERFLOW 0x80 +#define MOUSE_X_OVERFLOW 0x40 +#define MOUSE_Y_SIGN 0x20 +#define MOUSE_X_SIGN 0x10 +#define MOUSE_MIDDLE_BTN 0x04 +#define MOUSE_RIGHT_BTN 0x02 +#define MOUSE_LEFT_BTN 0x01 + +struct fifo mouse_fifo; + +DriverResult ps2_mouse_start(void *_device); + +typedef struct { + int port; + + int state; + + int byte0, x, y; + + // 记录左中右键状态来决定是否发送事件 + int btn; +} Ps2Mouse; + +DeviceOps ps2_mouse_device_ops = { + .init = NULL, + .start = ps2_mouse_start, + .stop = NULL, + .destroy = NULL, +}; + +void mouse_handler(void *arg) { + Ps2Mouse *mouse = (Ps2Mouse *)arg; + uint8_t data = i8042_read_data(); + switch (mouse->state) { + case 0: + if ((data & 0x08) != 0x08) { return; } + mouse->byte0 = data; + mouse->state = 1; + break; + case 1: + mouse->x = data; + mouse->state = 2; + break; + case 2: + mouse->y = data; + mouse->state = 0; + break; + default: + mouse->state = 0; + return; + } + if (mouse->state == 1) { // 原先是0 + bool old_left = !!(mouse->btn & MOUSE_LEFT_BTN); + bool old_mid = !!(mouse->btn & MOUSE_MIDDLE_BTN); + bool old_right = !!(mouse->btn & MOUSE_RIGHT_BTN); + bool left = !!(data & MOUSE_LEFT_BTN); + bool mid = !!(data & MOUSE_MIDDLE_BTN); + bool right = !!(data & MOUSE_RIGHT_BTN); + if (mouse->btn != + (data & (MOUSE_LEFT_BTN | MOUSE_MIDDLE_BTN | MOUSE_RIGHT_BTN))) { + // 按键状态变化 + if (left ^ old_left) { + // 左键状态变化 + new_key_event( + INPUT_KEY_EVENT_MOUSE_BASE + KEY_MOUSE_LEFT, left, + INPUT_KEY_PAGE_KEYBOARD_KEYPAD); + } + if (mid ^ old_mid) { + // 中键状态变化 + new_key_event( + INPUT_KEY_EVENT_MOUSE_BASE + KEY_MOUSE_MIDDLE, mid, + INPUT_KEY_PAGE_KEYBOARD_KEYPAD); + } + if (right ^ old_right) { + // 右键状态变化 + new_key_event( + INPUT_KEY_EVENT_MOUSE_BASE + KEY_MOUSE_RIGHT, right, + INPUT_KEY_PAGE_KEYBOARD_KEYPAD); + } + mouse->btn = + data & (MOUSE_LEFT_BTN | MOUSE_MIDDLE_BTN | MOUSE_RIGHT_BTN); + } + } + if (mouse->state == 0) { + if (mouse->x != 0 || mouse->y != 0) { + int16_t dx = (mouse->byte0 & MOUSE_X_SIGN) + ? (0xff00 | (uint16_t)mouse->x) + : (uint16_t)mouse->x; + int16_t dy = (mouse->byte0 & MOUSE_Y_SIGN) + ? (0xff00 | (uint16_t)mouse->y) + : (uint16_t)mouse->y; + new_pointer_event(dx, -dy, POINTER_TYPE_MOVE); + } + mouse->byte0 = mouse->x = mouse->y = 0; + } +} + +DriverResult ps2_mouse_start(void *_device) { + LogicalDevice *logical_device = (LogicalDevice *)_device; + Ps2Mouse *mouse = (Ps2Mouse *)logical_device->private_data; + + i8042_disable_interrupt(mouse->port); + + i8042_wait_ctr_send_ready(); + i8042_send_cmd(I8042_CMD_SEND_TO_P2); + i8042_wait_ctr_send_ready(); + i8042_write_data(I8042_KBD_CMD_ENABLE_SCANNING); + i8042_wait_ctr_send_ready(); + if (i8042_read_data() != 0xfa) { + printk("[i8042]PS/2 Port2 Device enable failed!\n"); + return DRIVER_ERROR_OTHER; + } + + // 手动修改irq的处理函数和参数 + I8042Device *i8042 = i8042_device->private_data; + i8042->irq[mouse->port]->handler = mouse_handler; + i8042->irq[mouse->port]->arg = mouse; + + mouse->state = 0; + i8042_enable_interrupt(mouse->port); + + return DRIVER_OK; +} + +void ps2_mouse_register(PhysicalDevice *physical_device, int port) { + InputDevice *in; + create_input_device( + &in, INPUT_TYPE_MOUSE, &ps2_mouse_device_ops, physical_device, + &i8042_device_driver); + Ps2Mouse *mouse = kmalloc(sizeof(Ps2Mouse)); + mouse->port = port; + in->device->private_data = mouse; +} \ No newline at end of file diff --git a/src/arch/x86/drivers/input/Makefile b/src/arch/x86/drivers/input/Makefile new file mode 100644 index 0000000..ac6c8ad --- /dev/null +++ b/src/arch/x86/drivers/input/Makefile @@ -0,0 +1 @@ +SRC += 8042/ \ No newline at end of file diff --git a/src/arch/x86/drivers/input/config.toml b/src/arch/x86/drivers/input/config.toml new file mode 100644 index 0000000..76ef4f5 --- /dev/null +++ b/src/arch/x86/drivers/input/config.toml @@ -0,0 +1 @@ +dir = ["8042/"] diff --git a/src/arch/x86/drivers/interrupt/8259a.c b/src/arch/x86/drivers/interrupt/8259a.c new file mode 100644 index 0000000..26d3903 --- /dev/null +++ b/src/arch/x86/drivers/interrupt/8259a.c @@ -0,0 +1,135 @@ +/** + * @file 8259a.c + * @author Ryan Wang (ryan1202@foxmail.com) + * @brief PIC驱动 + * @version 1.1 + * @date 2022-07-31 + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +DriverResult i8259a_init(void *device); +int pic_redirect_irq(InterruptDevice *device, int irq); +DriverResult pic_enable_irq(InterruptDevice *device, int irq); +DriverResult pic_disable_irq(InterruptDevice *device, int irq); +void pic_eoi(InterruptDevice *device, int irq); + +extern Driver core_driver; + +DeviceOps i8259a_device_ops = { + .init = i8259a_init, + .start = NULL, + .stop = NULL, + .destroy = NULL, +}; +DeviceOps pic_device_ops = { + .init = NULL, + .start = NULL, + .stop = NULL, + .destroy = NULL, +}; +InterruptDeviceOps pic_interrupt_ops = { + .enable_irq = pic_enable_irq, + .disable_irq = pic_disable_irq, + .eoi = pic_eoi, + .redirect_irq = pic_redirect_irq, +}; + +DeviceDriver pic_device_driver; +PhysicalDevice *i8259a_device; +InterruptDevice *pic_device; +InterruptDevice pic_interrupt_device = { + .ops = &pic_interrupt_ops, + .priority = 0, +}; + +DriverResult register_pic(void) { + ObjectAttr attr = device_object_attr; + + if (use_apic) return DRIVER_OK; + + DRIVER_RESULT_PASS( + register_device_driver(&core_driver, &pic_device_driver)); + + DRIVER_RESULT_PASS( + create_physical_device(&i8259a_device, platform_bus, &attr)); + + DRIVER_RESULT_PASS(create_interrupt_device( + &pic_device, &pic_device_ops, i8259a_device, &pic_device_driver, + &pic_interrupt_ops, 0)); + + register_physical_device(i8259a_device, &i8259a_device_ops); + return DRIVER_OK; +} + +void mask_8259a(void) { + io_out_byte(PIC0_IMR, 0xff); + io_out_byte(PIC1_IMR, 0xff); +} + +DriverResult i8259a_init(void *device) { + io_out_byte(PIC0_IMR, 0xff); // 屏蔽主PIC的所有中断 + io_out_byte(PIC1_IMR, 0xff); // 屏蔽从PIC的所有中断 + + io_out_byte(PIC0_ICW1, 0x11); // 级联,边沿触发 + io_out_byte(PIC0_ICW2, 0x20); // 起始中断向量号位0x20(0x00~0x1f为内部中断) + io_out_byte(PIC0_ICW3, 1 << 2); // IRQ2用于连接从PIC + // 全嵌套模式,非缓冲模式,手动结束中断,x86处理器 + io_out_byte(PIC0_ICW4, 0x01); + + io_out_byte(PIC1_ICW1, 0x11); // 级联,边沿触发 + io_out_byte(PIC1_ICW2, 0x28); // 起始中断向量号位0x28 + io_out_byte(PIC1_ICW3, 0x02); // 连接到主PIC的IRQ2 + // 全嵌套模式,非缓冲模式,手动结束中断,x86处理器 + io_out_byte(PIC1_ICW4, 0x01); + + io_out_byte(PIC0_IMR, 0xfb); // 开启IRQ2(从PIC)中断 + io_out_byte(PIC1_IMR, 0xff); // 屏蔽从PIC的所有中断 + return DRIVER_OK; +} + +int pic_redirect_irq(InterruptDevice *device, int irq) { + return irq; +} + +DriverResult pic_enable_irq(InterruptDevice *device, int irq) { + uint8_t data; + if (irq < 8) { + data = io_in8(PIC0_IMR); + io_out8(PIC0_IMR, BIN_DIS(data, BIT(irq))); + } else { + data = io_in8(PIC1_IMR); + io_out8(PIC1_IMR, BIN_DIS(data, BIT(irq % 8))); + } + return DRIVER_OK; +} + +DriverResult pic_disable_irq(InterruptDevice *device, int irq) { + uint8_t data; + if (irq < 8) { + data = io_in8(PIC0_IMR); + io_out8(PIC0_IMR, BIN_EN(data, BIT(irq))); + } else { + data = io_in8(PIC1_IMR); + io_out8(PIC1_IMR, BIN_EN(data, BIT(irq % 8))); + } + return DRIVER_OK; +} + +void pic_eoi(InterruptDevice *device, int irq) { + if (irq >= 8) { io_out8(PIC1_OCW1, PIC_EOI); } + io_out8(PIC0_OCW1, PIC_EOI); +} diff --git a/src/arch/x86/drivers/interrupt/Makefile b/src/arch/x86/drivers/interrupt/Makefile new file mode 100644 index 0000000..65abe54 --- /dev/null +++ b/src/arch/x86/drivers/interrupt/Makefile @@ -0,0 +1,2 @@ +SRC += 8259a.c +SRC += apic.c \ No newline at end of file diff --git a/src/arch/x86/drivers/interrupt/apic.c b/src/arch/x86/drivers/interrupt/apic.c new file mode 100644 index 0000000..079d18a --- /dev/null +++ b/src/arch/x86/drivers/interrupt/apic.c @@ -0,0 +1,375 @@ +/** + * @file apic.c + * @author Ryan Wang (ryan1202@foxmail.com) + * @brief APIC驱动(参考xv6) + * @version 0.1 + * @date 2025-09 + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +DriverResult apic_init(void *device); +DriverResult apic_start(void *device); +DriverResult apic_stop(void *device); +DriverResult apic_driver_init(struct DeviceDriver *driver); +int apic_redirect_irq(InterruptDevice *device, int irq); +DriverResult apic_enable_irq(InterruptDevice *device, int irq); +DriverResult apic_disable_irq(InterruptDevice *device, int irq); +DriverResult apic_timer_init(void *device); +DriverResult apic_timer_start(void *device); +DriverResult apic_timer_stop(void *device); +void apic_eoi(InterruptDevice *device, int irq); +TimerResult apic_timer_set_frequency( + TimerDevice *timer_device, uint32_t frequency); +void apic_timer_irq_handler(void *device); + +extern Driver core_driver; + +typedef struct ApicInfo { + enum { + APIC_TYPE_XAPIC, + APIC_TYPE_X2APIC, + } apic_type; + uint32_t apic_base; + uint32_t apic_base_high; // 仅在使用x2APIC有用 + uint32_t apic_id; + uint32_t apic_id_high; // 仅在使用x2APIC有用 + uint8_t version; + uint8_t max_lvt_entry; + uint32_t *lapic_mmio; + struct ioapic *ioapic; + DeviceIrq *device_irq; +} ApicInfo; +ApicInfo apic_info; + +volatile struct ioapic { + uint32_t reg; + uint32_t pad[3]; + uint32_t data; +}; + +bool use_apic; + +uint32_t lapic_write(int index, int value) { + apic_info.lapic_mmio[index / 4] = value; + return apic_info.lapic_mmio[APIC_ID / 4]; +} + +uint32_t lapic_read(int index) { + return apic_info.lapic_mmio[index / 4]; +} + +DeviceOps apic_device_ops = { + .init = apic_init, + .start = apic_start, + .stop = apic_stop, + .destroy = NULL, +}; +DeviceOps apic_interrupt_device_ops = { + .init = NULL, + .start = NULL, + .stop = NULL, + .destroy = NULL, +}; +DeviceOps apic_timer_device_ops = { + .init = apic_timer_init, + .start = apic_timer_start, + .stop = apic_timer_stop, + .destroy = NULL, +}; +InterruptDeviceOps apic_interrupt_ops = { + .enable_irq = apic_enable_irq, + .disable_irq = apic_disable_irq, + .eoi = apic_eoi, + .redirect_irq = apic_redirect_irq, +}; +TimerOps apic_timer_ops = { + .set_frequency = apic_timer_set_frequency, +}; + +DeviceDriver apic_device_driver; +PhysicalDevice *apic_device; +InterruptDevice *apic_interrupt_device; +TimerDevice *apic_timer_device; + +uint32_t io_apic_read(uint32_t reg) { + apic_info.ioapic->reg = reg; + return apic_info.ioapic->data; +} + +void io_apic_write(uint32_t reg, uint32_t data) { + apic_info.ioapic->reg = reg; + apic_info.ioapic->data = data; +} + +DriverResult register_apic(void) { + register_device_driver(&core_driver, &apic_device_driver); + + apic_driver_init(&apic_device_driver); + if (!use_apic) return DRIVER_ERROR_NOT_EXIST; + + ObjectAttr attr = device_object_attr; + DRIVER_RESULT_PASS( + create_physical_device(&apic_device, platform_bus, &attr)); + register_physical_device(apic_device, &apic_device_ops); + + DRIVER_RESULT_PASS(create_interrupt_device( + &apic_interrupt_device, &apic_interrupt_device_ops, apic_device, + &apic_device_driver, &apic_interrupt_ops, 1)); + return create_timer_device( + &apic_timer_device, &apic_timer_ops, &apic_timer_device_ops, + apic_device, &apic_device_driver); +} + +void x2apic_init(struct DeviceDriver *driver) { + apic_info.apic_type = APIC_TYPE_X2APIC; + // 还未实现x2apic支持,这里只是简单的初始化 + uint32_t low, high; + read_msr(APIC_BASE_MSR, &low, &high); + + apic_info.apic_base = 0xfee00000; + apic_info.apic_base_high = low >> 12; + + uint32_t tmp; + DRV_RESULT_PRINT_CALL( + driver_remap_memory(&core_driver, apic_info.apic_base, 0x3ff, &tmp)); + apic_info.lapic_mmio = (uint32_t *)tmp; + DRV_RESULT_PRINT_CALL( + driver_remap_memory(&core_driver, 0xfec00000, 0xfff00, &tmp)); + apic_info.ioapic = (struct ioapic *)tmp; + + read_msr(X2APIC_ID_MSR, &apic_info.apic_id, &apic_info.apic_id_high); + apic_info.version = + (lapic_read(APIC_Ver) & 0xff) | ((lapic_read(APIC_Ver) >> 16) & 0xff); +} + +void xapic_init(struct DeviceDriver *driver) { + apic_info.apic_type = APIC_TYPE_XAPIC; + apic_info.apic_base = 0xfee00000; + + DRV_RESULT_PRINT_CALL(driver_remap_memory( + &core_driver, apic_info.apic_base, 0x3ff, + (uint32_t *)&apic_info.lapic_mmio)); + DRV_RESULT_PRINT_CALL(driver_remap_memory( + &core_driver, 0xfec00000, 0xfff00, (uint32_t *)&apic_info.ioapic)); + + apic_info.apic_id = lapic_read(APIC_ID) >> 24; + apic_info.version = (lapic_read(APIC_Ver) & 0xff); + apic_info.max_lvt_entry = (lapic_read(APIC_Ver) >> 16) & 0xff; +} + +DriverResult apic_driver_init(struct DeviceDriver *driver) { + /** + * 所有文档都说要先屏蔽8259a的中断,直到我无数次触发#DF才知道为什么... + * 防止apic完成初始化前触发中断无法正确处理导致异常 + */ + use_apic = true; + if (cpu_check_feature(CPUID_FEAT_X2APIC)) { + mask_8259a(); + x2apic_init(driver); + } else if (cpu_check_feature(CPUID_FEAT_APIC)) { + mask_8259a(); + xapic_init(driver); + } else { + use_apic = false; + return DRIVER_ERROR_NOT_EXIST; + } + return DRIVER_OK; +} + +void enable_apic_with_msr(void) { + // TODO: 完善xAPIC和x2APIC支持 + uint32_t low, high; + read_msr(APIC_BASE_MSR, &low, &high); + write_msr(APIC_BASE_MSR, BIN_EN(low, BIT(APIC_GLOBAL_ENABLE_BIT)), high); +} + +void disable_apic_with_msr(void) { + // TODO: 完善xAPIC和x2APIC支持 + uint32_t low, high; + read_msr(APIC_BASE_MSR, &low, &high); + write_msr(APIC_BASE_MSR, BIN_DIS(low, BIT(APIC_GLOBAL_ENABLE_BIT)), high); +} + +void enable_apic_with_sivr(void) { + uint32_t data = lapic_read(APIC_SIVR); + lapic_write(APIC_SIVR, BIN_EN(data, BIT(APIC_SOFTWARE_ENABLE_BIT))); +} + +void disable_apic_with_sivr(void) { + uint32_t data = lapic_read(APIC_SIVR); + lapic_write(APIC_SIVR, BIN_DIS(data, BIT(APIC_SOFTWARE_ENABLE_BIT))); +} + +void enable_apic(void) { + if (apic_info.apic_type == APIC_TYPE_X2APIC) { + enable_apic_with_msr(); + } else if (apic_info.apic_type == APIC_TYPE_XAPIC) { + enable_apic_with_sivr(); + } +} + +void disable_apic(void) { + if (apic_info.apic_type == APIC_TYPE_X2APIC) { + disable_apic_with_msr(); + } else if (apic_info.apic_type == APIC_TYPE_XAPIC) { + disable_apic_with_sivr(); + } +} + +DriverResult apic_init(void *device) { + DRIVER_RESULT_PASS(apic_driver_init(&apic_device_driver)); + + lapic_write(APIC_LVT_LINT0, BIT(16)); + lapic_write(APIC_LVT_LINT1, BIT(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, APIC_ICR_DELIVERY_MODE_INIT | + APIC_ICR_TRIGGER_MODE_LEVEL | + APIC_ICR_DEST_SHORTHAND_ALL_INCLUDING_SELF); + const int timeout = 100000; + int i; + for (i = 0; + i < timeout && lapic_read(APIC_ICR_LOW) & APIC_ICR_STAT_SEND_PENDING; + i++) + ; + + if (i == timeout) { + print_error_with_position("APIC init timeout\n"); + return DRIVER_ERROR_TIMEOUT; + } + + lapic_write(APIC_TPR, 0); + + for (int i = 0; i < apic_info.max_lvt_entry; i++) { + apic_disable_irq(apic_interrupt_device, 0x20 + i); + } + return DRIVER_OK; +} + +DriverResult apic_timer_calibrate(LogicalDevice *device) { + const int ms = 100; + Timer timer; + timer_init(&timer); + + uint32_t data = lapic_read(APIC_LVT_TIMER); + lapic_write(APIC_LVT_TIMER, BIN_DIS(data, BIT(16))); + + lapic_write(APIC_TIMER_ICT, 0xffffffff); + + delay_ms(&timer, ms); + + lapic_write(APIC_LVT_TIMER, BIN_EN(data, BIT(16))); + + uint32_t apic_timer_count = lapic_read(APIC_TIMER_CCT); + uint32_t delta = (0xffffffff - apic_timer_count); + uint32_t freq = delta * (1000 / ms); + apic_timer_device->source_frequency = freq; + apic_timer_device->min_frequency = DIV_ROUND_UP(freq, 0xffffffff); + apic_timer_device->max_frequency = freq; + apic_timer_device->current_frequency = 0; + apic_timer_device->priority = 2; + return DRIVER_OK; +} + +DriverResult apic_timer_init(void *device) { + lapic_write(APIC_TIMER_DCR, APIC_TIMER_DCR_DIVIDE_BY_1); + lapic_write( + APIC_LVT_TIMER, + APIC_LVT_TIMER_MODE_PERIODIC | (0x20 + LAPIC_TIMER_IRQ)); + + apic_timer_calibrate(device); + return DRIVER_OK; +} + +DriverResult apic_start(void *device) { + enable_apic(); + return DRIVER_OK; +} + +DriverResult apic_timer_start(void *device) { + register_device_irq( + &apic_info.device_irq, apic_device, device, LAPIC_TIMER_IRQ, + apic_timer_irq_handler, IRQ_MODE_EXCLUSIVE); + enable_device_irq(apic_info.device_irq); + uint32_t data = lapic_read(APIC_LVT_TIMER); + lapic_write(APIC_LVT_TIMER, BIN_DIS(data, BIT(16))); + return DRIVER_OK; +} + +DriverResult apic_stop(void *device) { + disable_apic(); + return DRIVER_OK; +} + +DriverResult apic_timer_stop(void *device) { + uint32_t data = lapic_read(APIC_LVT_TIMER); + lapic_write(APIC_LVT_TIMER, BIN_EN(data, BIT(16))); + unregister_device_irq(apic_info.device_irq); + apic_info.device_irq = NULL; + return DRIVER_OK; +} + +int apic_redirect_irq(InterruptDevice *device, int irq) { + if (irq == PIC_PIT_IRQ) { + irq = APIC_PIT_IRQ; + } else if (irq == 2) { + irq = 0; + } + return irq; +} + +DriverResult apic_enable_irq(InterruptDevice *device, int irq) { + io_apic_write(IOAPIC_TBL + irq * 2, BIN_DIS(0x20 + irq, BIT(16))); + io_apic_write(IOAPIC_TBL + irq * 2 + 1, 0); + return DRIVER_OK; +} + +DriverResult apic_disable_irq(InterruptDevice *device, int irq) { + io_apic_write(IOAPIC_TBL + irq * 2, BIN_EN(0x20 + irq, BIT(16))); + io_apic_write(IOAPIC_TBL + irq * 2 + 1, 0); + return DRIVER_OK; +} + +void apic_eoi(InterruptDevice *device, int irq) { + lapic_write(APIC_EOI, 0); +} + +TimerResult apic_timer_set_frequency( + TimerDevice *timer_device, uint32_t frequency) { + uint32_t divisor = + DIV_ROUND_UP(apic_timer_device->source_frequency, frequency); + lapic_write(APIC_TIMER_ICT, divisor); + return TIMER_RESULT_OK; +} + +void apic_timer_irq_handler(void *device) { + timer_irq_handler(device); +} diff --git a/src/arch/x86/drivers/interrupt/config.toml b/src/arch/x86/drivers/interrupt/config.toml new file mode 100644 index 0000000..f84b2c8 --- /dev/null +++ b/src/arch/x86/drivers/interrupt/config.toml @@ -0,0 +1 @@ +c = ["8259a.c", "apic.c"] diff --git a/src/arch/x86/drivers/keyboard.c b/src/arch/x86/drivers/keyboard.c deleted file mode 100644 index d395e47..0000000 --- a/src/arch/x86/drivers/keyboard.c +++ /dev/null @@ -1,181 +0,0 @@ -/** - * @file keyboard.c - * @author Ryan Wang (ryan1202@foxmail.com) - * @brief PS/2键盘驱动 - * @version 0.1 - * @date 2021-06 - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -// clang-format off - -static char scan_codes1[95] = -{ - 0, - 0, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', '\b', - 0, 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', '\n', - 0, 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', '\'', '`', - 0, '\\', 'z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '/', 0, -}; -static char scan_codes1_shift[95] = -{ - 0, - 0, '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_', '+', '\b', - 0, 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '{', '}', '\n', - 0, 'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', '\"', '~', - 0, '|', 'Z', 'X', 'C', 'V', 'B', 'N', 'M', '<', '>', '?', 0, -}; - -static char scan_codes2[0x5d+1] = -{ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '`', 0, 0, 0, 0, - 0, 0, 'q', '1', 0, 0, 0, 'z', 's', 'a', 'w', '2', 0, 0, 'c', 'x', 'd', 'e', '4', - '3', 0, 0, ' ', 'v', 'f', 't', 'r', '5', 0, 0, 'n', 'b', 'h', 'g', 'y', '6', 0, 0, - 0, 'm', 'j', 'u', '7', '8', 0, 0, ',', 'k', 'i', 'o', '0', '9', 0, 0, '.', '/', 'l', - ';', 'p', '-', 0, 0, 0, '\'', 0, '[', '=', 0, 0, 0, 0, 0, ']', 0, '\\' -}; -static char scan_codes2_shift[0x5d+1] = -{ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '~', 0, 0, 0, 0, - 0, 0, 'Q', '!', 0, 0, 0, 'Z', 'S', 'A', 'W', '@', 0, 0, 'C', 'X', 'D', 'E', '$', - '$', 0, 0, 0, 'V', 'F', 'T', 'R', '%', 0, 0, 'N', 'B', 'H', 'G', 'Y', '^', 0, 0, - 0, 'M', 'J', 'U', '&', '*', 0, 0, '<', 'K', 'I', 'O', 'P', '(', 0, 0, '>', '?', 'L', - ':', 'P', '_', 0, 0, 0, '\"', 0, '{', '+', 0, 0, 0, 0, 0, '}', 0, '|' -}; - -// clang-format on - -#define KEYBOARD_IRQ 1 - -#define DRV_NAME "General PS/2 Driver(Keyboard)" -#define DEV_NAME "PS/2 Keyboard" - -typedef struct { - int num_lock, caps_lock, scroll_lock; // 键盘锁 - int left_ctrl, right_ctrl; - int left_shift, right_shift; - int left_alt, right_alt; - int keybuf[512]; - struct fifo keyfifo; -} device_extension_t; - -void keyboard_handler(device_t *devobj, int irq); -static status_t keyboard_enter(driver_t *drv_obj); -static status_t keyboard_exit(driver_t *drv_obj); -char scancode_analysis(device_extension_t *devext, int keycode); -void keyboard_setleds(device_extension_t *devext); - -driver_func_t keyboard_driver = {.driver_enter = keyboard_enter, - .driver_exit = keyboard_exit, - .driver_open = NULL, - .driver_close = NULL, - .driver_read = NULL, - .driver_write = NULL, - .driver_devctl = NULL}; - -static status_t keyboard_enter(driver_t *drv_obj) { - device_t *devobj; - device_extension_t *devext; - - device_create(drv_obj, sizeof(device_extension_t), DEV_NAME, DEV_KEYBOARD, &devobj); - devext = devobj->device_extension; - - fifo_init(&devext->keyfifo, 512, devext->keybuf); - - devext->left_ctrl = 0; - devext->left_shift = 0; - devext->left_alt = 0; - devext->right_ctrl = 0; - devext->right_shift = 0; - devext->right_alt = 0; - - devext->num_lock = 1; - devext->caps_lock = 0; - devext->scroll_lock = 0; - - keyboard_setleds(devext); - - device_register_irq(devobj, KEYBOARD_IRQ, keyboard_handler); - return SUCCUESS; -} - -static status_t keyboard_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) {} - string_del(&drv_obj->name); - return SUCCUESS; -} - -void keyboard_handler(device_t *devobj, int irq) { - device_extension_t *devext = (device_extension_t *)devobj->device_extension; - uint8_t data = i8042_read_data(); - fifo_put(&devext->keyfifo, data); -} - -char scancode_analysis(device_extension_t *devext, int keycode) { - char data = '\0'; - if (keycode <= 0x35 && keycode != 0x2a && keycode != 0x1d) { - if (devext->left_shift == 0 && devext->right_shift == 0) { - data = scan_codes1[keycode]; - } else { - data = scan_codes1_shift[keycode]; - } - } - if (keycode == 0x39) { - data = ' '; - } else if (keycode == 0x1d) { - devext->left_ctrl = 1 - devext->left_ctrl; - } else if (keycode == 0x2a) { - devext->left_shift = 1 - devext->left_shift; - } else if (keycode == 0x36) { - devext->right_shift = 1 - devext->right_shift; - } else if (keycode == 0x38) { - devext->left_alt = 1 - devext->left_alt; - } else if (keycode == 0x3a) { - devext->caps_lock = 1 - devext->caps_lock; - keyboard_setleds(devext); - } else if (keycode == 0x45) { - devext->num_lock = 1 - devext->num_lock; - keyboard_setleds(devext); - } else if (keycode == 0x46) { - devext->scroll_lock = 1 - devext->scroll_lock; - keyboard_setleds(devext); - } - - if (data == 0) { /* code */ - } - return data; -} - -void keyboard_setleds(device_extension_t *devext) { - uint8_t kb_read; - - i8042_wait_ctr_send_ready(); - i8042_write_data(0xed); - do { - kb_read = (uint8_t)io_in8(I8042_PORT_DATA); - } while ((kb_read != 0xfa)); - i8042_wait_ctr_send_ready(); - i8042_write_data(devext->caps_lock << 2 | devext->num_lock << 1 | devext->scroll_lock); - do { - kb_read = (uint8_t)io_in8(I8042_PORT_DATA); - } while ((kb_read != 0xfa)); -} - -static __init void keyboard_driver_entry(void) { - if (driver_create(keyboard_driver, DRV_NAME) < 0) { - printk(COLOR_RED "[driver] %s driver create failed!\n", __func__); - } -} - -driver_initcall(keyboard_driver_entry); \ No newline at end of file diff --git a/src/arch/x86/drivers/mouse.c b/src/arch/x86/drivers/mouse.c deleted file mode 100644 index 9b6d231..0000000 --- a/src/arch/x86/drivers/mouse.c +++ /dev/null @@ -1,84 +0,0 @@ -/** - * @file mouse.c - * @author Ryan Wang (ryan1202@foxmail.com) - * @brief PS/2鼠标驱动 - * @version 0.1 - * @date 2021-06 - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -struct fifo mouse_fifo; - -static status_t mouse_enter(driver_t *drv_obj); -static status_t mouse_exit(driver_t *drv_obj); - -#define MOUSE_IRQ 12 - -driver_func_t mouse_driver = { - .driver_enter = mouse_enter, - .driver_exit = mouse_exit, - .driver_open = NULL, - .driver_close = NULL, - .driver_read = NULL, - .driver_write = NULL, - .driver_devctl = NULL, -}; - -#define DRV_NAME "General PS/2 Driver(Mouse)" -#define DEV_NAME "mouse" - -typedef struct { - int x, y; - int old_x, old_y; - int lbtn, mbtn, rbtn; // 左键 中键 右键 -} device_extension_t; - -void mouse_handler(device_t *devobj, int irq) { - device_extension_t *devext = (device_extension_t *)devobj->device_extension; - uint8_t data = i8042_read_data(); -} - -static status_t mouse_enter(driver_t *drv_obj) { - device_t *devobj; - device_extension_t *devext; - - device_create(drv_obj, sizeof(device_extension_t), DEV_NAME, DEV_MOUSE, &devobj); - devext = devobj->device_extension; - - devext->x = 0; - devext->y = 0; - devext->old_x = 0; - devext->old_y = 0; - devext->lbtn = 0; - devext->mbtn = 0; - devext->rbtn = 0; - - device_register_irq(devobj, MOUSE_IRQ, mouse_handler); - return SUCCUESS; -} - -static status_t mouse_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 mouse_driver_entry(void) { - if (driver_create(mouse_driver, DRV_NAME) < 0) { - printk(COLOR_RED "[driver] %s driver create failed!\n", __func__); - } -} - -driver_initcall(mouse_driver_entry); \ No newline at end of file diff --git a/src/arch/x86/drivers/msr.c b/src/arch/x86/drivers/msr.c index 13af639..b0c7113 100644 --- a/src/arch/x86/drivers/msr.c +++ b/src/arch/x86/drivers/msr.c @@ -7,28 +7,16 @@ */ #include -// char cpuHasMSR(void) -// { -// uint32_t a, d; // eax, edx -// cpuid(1, &a, &d); -// return d & 0x20; -// } - -void cpu_RDMSR(uint32_t msr, uint32_t *lo, uint32_t *hi) -{ - uint32_t l, h; - __asm__ __volatile__("rdmsr \n\t" - : "=a"(l), "=d"(h) - : "c"(msr) - : "memory"); - *lo = l; - *hi = h; +void cpu_RDMSR(uint32_t msr, uint32_t *lo, uint32_t *hi) { + uint32_t l, h; + __asm__ __volatile__("rdmsr \n\t" : "=a"(l), "=d"(h) : "c"(msr) : "memory"); + *lo = l; + *hi = h; } -void cpu_WRMSR(uint32_t msr, uint32_t lo, uint32_t hi) -{ - __asm__ __volatile__("wrmsr \n\t" - : - : "a"(lo), "d"(hi), "c"(msr) - : "memory"); +void cpu_WRMSR(uint32_t msr, uint32_t lo, uint32_t hi) { + __asm__ __volatile__("wrmsr \n\t" + : + : "a"(lo), "d"(hi), "c"(msr) + : "memory"); } \ No newline at end of file diff --git a/src/arch/x86/drivers/network/Makefile b/src/arch/x86/drivers/network/Makefile index 70ea5a5..8b44d87 100644 --- a/src/arch/x86/drivers/network/Makefile +++ b/src/arch/x86/drivers/network/Makefile @@ -1 +1 @@ -SRC += rtl8139.c \ No newline at end of file +SRC += rtl8139/ \ No newline at end of file diff --git a/src/arch/x86/drivers/network/config.toml b/src/arch/x86/drivers/network/config.toml new file mode 100644 index 0000000..ee2eec7 --- /dev/null +++ b/src/arch/x86/drivers/network/config.toml @@ -0,0 +1 @@ +dir = ["rtl8139/"] diff --git a/src/arch/x86/drivers/network/rtl8139.c b/src/arch/x86/drivers/network/rtl8139.c deleted file mode 100644 index ebc6b9a..0000000 --- a/src/arch/x86/drivers/network/rtl8139.c +++ /dev/null @@ -1,351 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#define RTL8139_VENDOR_ID 0x10ec -#define RTL8139_DEVICE_ID 0x8139 - -#define DRV_NAME "Horizon Basic Network Driver" -#define DEV_NAME "RTL8139" - -#define CHIP_INFO_NR 10 -#define TX_DESC_NR 4 - -#define CHIP_HAS_LWAKE 0x01 - -#define IMR_ALL \ - RTL8139_IMR_SERR | RTL8139_IMR_TimeOut | RTL8139_IMR_LenChg | RTL8139_IMR_FOVW | RTL8139_IMR_TER | \ - RTL8139_IMR_TOK | RTL8139_IMR_RER | RTL8139_IMR_ROK -#define RXFTH_NONE RTL8139_RCR_RXFTH(0x07) - -#define RBLEN_64K 0x03 -#define RBLEN_32K 0x02 -#define RBLEN_16K 0x01 -#define RBLEN_8K 0x00 - -#define RECV_BUF_LEN RBLEN_16K -#define RBLEN RTL8139_RCR_RBLEN(RECV_BUF_LEN) - -#define RTL8139_RECV_BUF_SIZE (8192 << RECV_BUF_LEN) + 16 + 1500 - -static status_t rtl8139_enter(driver_t *drv_obj); -static status_t rtl8139_exit(driver_t *drv_obj); -static status_t rtl8139_open(struct _device_s *dev); -static status_t rtl8139_close(struct _device_s *dev); -static status_t rtl8139_write(struct _device_s *dev, uint8_t *buf, uint32_t offset, size_t size); -static status_t rtl8139_read(struct _device_s *dev, uint8_t *buf, uint32_t offset, size_t size); -static status_t rtl8139_ioctl(struct _device_s *dev, uint32_t func_num, uint32_t value); - -driver_func_t rtl8139_driver = { - .driver_enter = rtl8139_enter, - .driver_exit = rtl8139_exit, - .driver_open = rtl8139_open, - .driver_close = rtl8139_close, - .driver_read = rtl8139_read, - .driver_write = rtl8139_write, - .driver_devctl = rtl8139_ioctl, -}; - -struct read_request_s { - uint8_t *buffer; - uint32_t length; -}; - -typedef struct { - struct pci_device *device; - uint32_t io_base; - uint32_t irq; - - uint8_t mac_addr[6]; - struct chip_info *info; - - int8_t tx_idx_w; // 写入到第几个缓冲区了 - int8_t tx_idx_done; // 处理到第几个缓冲区了 - uint32_t tx_flags; // 传输标志 - uint8_t *tx_buffer[TX_DESC_NR]; - uint32_t tx_buffer_phy[TX_DESC_NR]; - - wait_queue_manager_t *wqm; - wait_queue_manager_t *rqm; - - uint16_t rx_offset; - uint8_t *rx_buffer; - uint32_t rx_buffer_phy; - - uint8_t *tmpbuffer; -} device_extension_t; - -struct chip_info { - const char *name; - uint32_t hwverid; - uint32_t flag; -} chips[CHIP_INFO_NR] = { - { "RTL8139", 0b110000000 << 22, 0}, - { "RTL8139A", 0b111000000 << 22, 0}, - { "RTL8139A-G", 0b111010000 << 22, 0}, - { "RTL8139B", 0b111100000 << 22, CHIP_HAS_LWAKE}, - { "RTL8130", 0b111110000 << 22, CHIP_HAS_LWAKE}, - { "RTL8139C", 0b111010000 << 22, CHIP_HAS_LWAKE}, - { "RTL8100", 0b111100010 << 22, CHIP_HAS_LWAKE}, - {"RTL8100B/8139D", 0b111010001 << 22, CHIP_HAS_LWAKE}, - { "RTL8101", 0b111010011 << 22, CHIP_HAS_LWAKE}, -}; - -void rtl8139_handler(device_t *devobj, int irq) { - device_extension_t *devext = (device_extension_t *)devobj->device_extension; - uint16_t status = io_in16(devext->io_base + RTL8139_ISR); - uint16_t length; - int i; - - // printk("[RTL8139]Status:%#0x\t", status); - io_out16(devext->io_base + RTL8139_ISR, - status & ~(RTL8139_ISR_FOVW | RTL8139_ISR_RXOVW | RTL8139_ISR_ROK | RTL8139_ISR_TER)); - if (status & RTL8139_ISR_TOK) { - // if (!wait_queue_empty(devext->wqm)) { wait_queue_wakeup_all(devext->wqm); } - // printk("idx_w:%d idx_done:%d+1\n", devext->tx_idx_w, devext->tx_idx_done); - devext->tx_idx_done = (devext->tx_idx_done + 1) % TX_DESC_NR; - io_out16(devext->io_base + RTL8139_ISR, RTL8139_ISR_TOK); - } - if (status & RTL8139_ISR_ROK) { - uint8_t cmd; - uint32_t rx_status; - do { - i = devext->rx_offset; - rx_status = LE2HOST_DWORD(*(uint32_t *)(devext->rx_buffer + i)); - length = (rx_status >> 16) - 4; - i += 4; - if (length >= sizeof(eth_frame_t) && (rx_status & RTL8139_RX_STAT_ROK)) { - uint8_t *buffer = kmalloc(length); - if (i + length >= RTL8139_RECV_BUF_SIZE) { - memcpy(buffer, devext->rx_buffer + i, RTL8139_RECV_BUF_SIZE - i); - i = RTL8139_RECV_BUF_SIZE - i; - memcpy(buffer + i, devext->rx_buffer + i, length - i); - } else { - memcpy(buffer, devext->rx_buffer + i, length); - } - net_rx_raw_pack(ETH_FRAME, buffer, length); - } else { - printk("[RTL8139]RX Error: status %04x,size %04x, cur %04x\n", rx_status, length + 4, - devext->rx_offset); - } - devext->rx_offset = - (devext->rx_offset + length + 8 + 3) & ~3; // +8:4字节CRC和4字节包头;+3:4字节对齐用 - devext->rx_offset %= RTL8139_RECV_BUF_SIZE; - io_out16(devext->io_base + RTL8139_CAPR, devext->rx_offset - 0x10); - io_out16(devext->io_base + RTL8139_ISR, RTL8139_ISR_ROK); - cmd = io_in8(devext->io_base + RTL8139_CR); - } while (!(cmd & RTL8139_CR_BUFE)); // 缓冲区不为空 - } - // printk("\n"); - return; -} - -static status_t rtl8139_enter(driver_t *drv_obj) { - device_t *devobj; - device_extension_t *devext; - int i; - - device_create(drv_obj, sizeof(device_extension_t), DEV_NAME, DEV_ETH_NET, &devobj); - devext = devobj->device_extension; - - devext->device = pci_get_device_ById(RTL8139_VENDOR_ID, RTL8139_DEVICE_ID); - if (devext->device == NULL) { - printk(COLOR_YELLOW "\n[RTL8139]Cannot find device!\n"); - device_delete(devobj); - return NODEV; - } - - pci_enable_bus_mastering(devext->device); - devext->io_base = pci_device_get_io_addr(devext->device); - devext->irq = devext->device->irqline; - - // 初始化RTL8139 - io_out8(devext->io_base + RTL8139_CONFIG1, 0x00); // 通电 - io_out8(devext->io_base + RTL8139_CR, RTL8139_CR_RST); // 重置 - int f = 1; - for (i = 0; i < 1000; i++) { - if (!(io_in8(devext->io_base + RTL8139_CR) & 0x10)) { - f = 0; - break; - } - } - if (f) { return FAILED; } - - // 判断型号 - uint32_t hwverid = io_in32(devext->io_base + RTL8139_TCR) & 0x7cc00000; - for (i = 0; i < CHIP_INFO_NR; i++) { - if (chips[i].hwverid == hwverid) { - devext->info = &chips[i]; - break; - } - } - - // 读取MAC地址 - for (i = 0; i < 6; i++) { - devext->mac_addr[i] = io_in8(devext->io_base + RTL8139_IDRN(i)); - } - printk("[RTL8139]MAC Address:%02x:%02x:%02x:%02x:%02x:%02x\n", devext->mac_addr[0], devext->mac_addr[1], - devext->mac_addr[2], devext->mac_addr[3], devext->mac_addr[4], devext->mac_addr[5]); - - io_out8(devext->io_base + RTL8139_9346CR, 0xc0); // Unlock - - // 分配接收缓冲区 - devext->rx_offset = 0; - devext->rx_buffer = kmalloc(RTL8139_RECV_BUF_SIZE); - if (devext->rx_buffer == NULL) { return FAILED; } - devext->rx_buffer_phy = vir2phy((uint32_t)devext->rx_buffer); - io_out32(devext->io_base + RTL8139_RBSTART, devext->rx_buffer_phy); - devext->tmpbuffer = kmalloc(ETH_MAX_FRAME_SIZE); - - // 分配发送缓冲区 - for (i = 0; i < TX_DESC_NR; i++) { - devext->tx_buffer[i] = kmalloc(ETH_MAX_FRAME_SIZE); - devext->tx_buffer_phy[i] = vir2phy((uint32_t)devext->tx_buffer[i]); - } - - io_out16(devext->io_base + RTL8139_MPC, 0); - io_out16(devext->io_base + RTL8139_BMCR, 0x3100); - io_out8(devext->io_base + RTL8139_MSR, 0x40); - - io_out32(devext->io_base + RTL8139_RCR, RXFTH_NONE | RBLEN | RTL8139_RCR_MXDMA(0x07) | RTL8139_RCR_AER | - RTL8139_RCR_AR | RTL8139_RCR_WRAP | RTL8139_RCR_AB | - RTL8139_RCR_AM | RTL8139_RCR_APM | RTL8139_RCR_AAP); - io_out32(devext->io_base + RTL8139_TCR, RTL8139_TCR_MXDMA(0x07) | RTL8139_TCR_TXRR(2)); - - io_out32(devext->io_base + RTL8139_MARN(0), 0xffffffff); - io_out32(devext->io_base + RTL8139_MARN(4), 0xffffffff); - - io_out8(devext->io_base + RTL8139_BMCR, 0x00); // Lock - - devext->tx_idx_w = 0; - devext->tx_idx_done = 0; - devext->wqm = create_wait_queue(); - devext->rqm = create_wait_queue(); - wait_queue_init(devext->wqm); - wait_queue_init(devext->rqm); - - io_out8(devext->io_base + RTL8139_CR, RTL8139_CR_RE | RTL8139_CR_TE); // 允许接收和发送 - for (i = 0; i < TX_DESC_NR; i++) { - io_out32(devext->io_base + RTL8139_TSADN(i), devext->tx_buffer_phy[i]); - io_in32(devext->io_base + RTL8139_TSADN(i)); - } - devext->tx_flags = ((256) << 11) & 0x3f0000; - - device_register_irq(devobj, devext->irq, &rtl8139_handler); - - return SUCCUESS; -} - -static status_t rtl8139_open(struct _device_s *dev) { - device_extension_t *devext = (device_extension_t *)dev->device_extension; - io_out32(devext->io_base + RTL8139_MPC, 0); - io_out16(devext->io_base + RTL8139_MULINT, 0); - - // 启用中断 - io_out16(devext->io_base + RTL8139_IMR, IMR_ALL); - - return SUCCUESS; -} - -static status_t rtl8139_read(struct _device_s *dev, uint8_t *buf, uint32_t offset, size_t size) { - device_extension_t *devext = dev->device_extension; - wait_queue_t *rq; - struct read_request_s *rreq; - - // rq = wait_queue_add(devext->rqm, sizeof(struct read_request_s)); - // rreq = (struct read_request_s *)rq->private_data; - // rreq->buffer = buf; - // rreq->length = size; - // thread_block(TASK_BLOCKED); - - return SUCCUESS; -} - -static status_t rtl8139_write(struct _device_s *dev, uint8_t *buf, uint32_t offset, size_t size) { - device_extension_t *devext = dev->device_extension; - wait_queue_t *wq; - uint32_t idx; - - if (size > ETH_MAX_FRAME_SIZE) { return FAILED; } - - // printk(" idx_w:%d idx_done:%d\n", devext->tx_idx_w, devext->tx_idx_done); - // while ((io_in32(devext->io_base + RTL8139_TSDN(devext->tx_idx_w)) & RTL8139_TSR_OWN)) - // ; - while ((devext->tx_idx_w + 1) % TX_DESC_NR == devext->tx_idx_done) {} - idx = devext->tx_idx_w; - devext->tx_idx_w = (devext->tx_idx_w + 1) % TX_DESC_NR; - memcpy(devext->tx_buffer[idx], buf, size); - io_out32(devext->io_base + RTL8139_TSDN(idx), size); - io_in32(devext->io_base + RTL8139_TSDN(idx)); - - return SUCCUESS; -} - -static status_t rtl8139_ioctl(struct _device_s *dev, uint32_t func_num, uint32_t value) { - int i; - - device_extension_t *devext = dev->device_extension; - - switch (func_num) { - case NET_FUNC_GET_MTU: { - uint32_t *p = (uint32_t *)value; - *p = ETH_MTU; - break; - } - case NET_FUNC_GET_MAC_ADDR: { - uint8_t *addr = (uint8_t *)value; - for (i = 0; i < 6; i++) { - addr[i] = devext->mac_addr[i]; - } - break; - } - case NET_FUNC_SET_MAC_ADDR: { - uint8_t *addr = (uint8_t *)value; - for (i = 0; i < 6; i++) { - devext->mac_addr[i] = addr[i]; - } - break; - } - } - return SUCCUESS; -} - -static status_t rtl8139_close(struct _device_s *dev) { - device_extension_t *devext = dev->device_extension; - io_out16(devext->io_base + RTL8139_IMR, 0); - - return SUCCUESS; -} - -static status_t rtl8139_exit(driver_t *drv_obj) { - device_t *devobj, *next; - 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 rtl8139_driver_entry(void) { - if (driver_create(rtl8139_driver, DRV_NAME) < 0) { - printk(COLOR_RED "[driver] %s driver create failed!\n", __func__); - } -} - -driver_initcall(rtl8139_driver_entry); diff --git a/src/arch/x86/drivers/network/rtl8139/Makefile b/src/arch/x86/drivers/network/rtl8139/Makefile new file mode 100644 index 0000000..bf49a87 --- /dev/null +++ b/src/arch/x86/drivers/network/rtl8139/Makefile @@ -0,0 +1 @@ +SRC += rtl8139.c \ No newline at end of file diff --git a/src/arch/x86/drivers/network/rtl8139/config.toml b/src/arch/x86/drivers/network/rtl8139/config.toml new file mode 100644 index 0000000..f532cef --- /dev/null +++ b/src/arch/x86/drivers/network/rtl8139/config.toml @@ -0,0 +1 @@ +c = ["rtl8139.c"] diff --git a/src/arch/x86/drivers/network/rtl8139/rtl8139.c b/src/arch/x86/drivers/network/rtl8139/rtl8139.c new file mode 100644 index 0000000..544a254 --- /dev/null +++ b/src/arch/x86/drivers/network/rtl8139/rtl8139.c @@ -0,0 +1,365 @@ +#include "rtl8139.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +DriverResult rtl8139_init(void *device); +DriverResult rtl8139_start(void *device); +DriverResult rtl8139_pci_probe( + PciDevice *pci_device, PhysicalDevice *physical_device); +TransferResult rtl8139_send(NetworkDevice *device, void *buf, int length); + +PciDriverOps rtl8139_pci_driver_ops = { + .probe = rtl8139_pci_probe, +}; +DeviceOps rtl8139_physical_device_ops = { + .init = NULL, + .start = NULL, + .destroy = NULL, + .stop = NULL, +}; +DeviceOps rtl8139_logical_device_ops = { + .init = rtl8139_init, + .start = rtl8139_start, + .destroy = NULL, + .stop = NULL, +}; +NetworkOps rtl8139_net_device_ops = { + .send = rtl8139_send, +}; + +Driver rtl8139_driver; +DeviceDriver rtl8139_device_driver; +PciDriver rtl8139_pci_driver = { + .driver = &rtl8139_driver, + .device_driver = &rtl8139_device_driver, + .find_type = FIND_BY_VENDORID_DEVICEID, + .vendor_device = {RTL8139_VENDOR_ID, RTL8139_DEVICE_ID}, + .ops = &rtl8139_pci_driver_ops, +}; +NetworkDeviceCapabilities rtl8139_caps = {}; + +void rtl8139_handler(void *_device) { + Rtl8139Device *rtl_device = _device; + + spin_lock(&rtl_device->lock); + int status = io_in_word(rtl_device->io_base + REG_ISR); + + if (status == 0xffff) goto end; + + int _status = 0; + if (status & IMR_TOK) { + rtl_device->tx_done_idx = (rtl_device->tx_done_idx + 1) % TX_DESC_NR; + _status |= IMR_TOK; + } + if (status & IMR_TER) { + print_error("RTL8139", "TX Error\n"); + _status |= IMR_TER; + } + if (status & IMR_ROK) { + pending_softirq(); + _status |= IMR_ROK; + } + if (status & IMR_RER) { + print_error("RTL8139", "RX Error\n"); + _status |= IMR_RER; + } + if (status & IMR_RXOVW) { + print_error("RTL8139", "RX Overflow\n"); + _status |= IMR_RXOVW; + } + if (status & IMR_FOVW) { + print_error("RTL8139", "FIFO Overflow\n"); + _status |= IMR_FOVW; + } + if (status & IMR_PUN_LINKCHG) { + print_warning("RTL8139", "Link Changed"); + _status |= IMR_PUN_LINKCHG; + } + if (status & IMR_LEN_CHG) { + print_warning("RTL8139", "Length Changed"); + _status |= IMR_LEN_CHG; + } + if (status & IMR_TIMEOUT) { + print_error("RTL8139", "TX Timeout\n"); + _status |= IMR_TIMEOUT; + } + if (status & IMR_SERR) { + print_error("RTL8139", "System Error\n"); + _status |= IMR_SERR; + } + io_out_word(rtl_device->io_base + REG_ISR, _status); + +end: + spin_unlock(&rtl_device->lock); +} + +void rtl8139_net_rx_handler(void *data) { + // TODO: SMP防重入 + Rtl8139Device *device = data; + uint8_t cmd = io_in_byte(device->io_base + RTL8139_CR); + uint32_t rx_status; + while (!(cmd & RTL8139_CR_BUFE)) { + int i = device->rx_offset; + rx_status = LE2HOST_DWORD(*(uint32_t *)(device->rx_buffer + i)); + uint16_t length = (rx_status >> 16); + int packet_len = length - 4; + i += 4; + if (packet_len >= ETH_HEADER_SIZE && + (rx_status & RTL8139_RX_STAT_ROK)) { + NetBuffer *net_buffer = net_buffer_create(packet_len); + net_buffer_init(net_buffer, packet_len, 0, packet_len); + void *buffer = net_buffer->ptr; + + if (i + packet_len >= RTL8139_RECV_BUF_SIZE) { + int first_len = RTL8139_RECV_BUF_SIZE - i; + memcpy(buffer, device->rx_buffer + i, first_len); + memcpy( + buffer + first_len, device->rx_buffer + i, + packet_len - first_len); + } else { + memcpy(buffer, device->rx_buffer + i, packet_len); + } + protocol_recv( + device->net_device, net_buffer, NETWORK_TYPE_ETHERNET); + } else { + printk( + "[RTL8139]RX Error: status %#04x,size %#04x, cur %#04x\n", + rx_status, packet_len, device->rx_offset); + } + device->rx_offset = (device->rx_offset + length + 4 + 3) & + ~3; // +8:4字节CRC和4字节包头;+3:4字节对齐用 + device->rx_offset &= RTL8139_RX_READ_POINTER_MASK; + io_out_word(device->io_base + RTL8139_CAPR, device->rx_offset - 0x10); + + cmd = io_in8(device->io_base + RTL8139_CR); + } +} + +PRIVATE int mdio_read(Mii *mii, uint8_t reg_addr) { + Rtl8139Device *device = mii->net_dev->device->private_data; + int reg = rtl8139_mii_reg_map[reg_addr]; + if (reg == 0 || reg_addr > 8) { return 0; } + + return io_in_word(device->io_base + reg); +} + +PRIVATE void mdio_write(Mii *mii, uint8_t reg_addr, uint16_t data) { + Rtl8139Device *device = mii->net_dev->device->private_data; + int reg = rtl8139_mii_reg_map[reg_addr]; + if (reg == 0 || reg_addr > 8) { return; } + + if (reg_addr == 0) { + io_out_byte(device->io_base + REG_9346CR, BIT(7) | BIT(6)); + io_out_word(device->io_base + reg, data); + io_out_byte(device->io_base + REG_9346CR, 0); + } else { + io_out_word(device->io_base + reg, data); + } +} + +TransferResult rtl8139_send(NetworkDevice *device, void *buf, int length) { + Rtl8139Device *rtl_device = device->device->private_data; + if (length > ETH_MAX_FRAME_SIZE) { + print_error("RTL8139", "Too long packet"); + return TRANSFER_ERROR_EXCEED_MAX_SIZE; + } + + int index = rtl_device->tx_write_idx; + memcpy(rtl_device->tx_buffer[index], buf, length); + + int flags = spin_lock_irqsave(&rtl_device->lock); + wmb(); + io_out_dword( + rtl_device->io_base + REG_TSDN(index), rtl_device->tx_flag | length); + rtl_device->tx_write_idx = (index + 1) % TX_DESC_NR; + if (rtl_device->tx_write_idx == rtl_device->tx_done_idx) { + // 缓冲区已满,关闭队列 + net_queue_block(&rtl_device->net_device->tx_queue, NQ_BLOCKER_DRIVER); + } + spin_unlock_irqrestore(&rtl_device->lock, flags); + + return TRANSFER_OK; +} + +DriverResult rtl8139_init(void *_device) { + LogicalDevice *device = _device; + Rtl8139Device *rtl_device = device->private_data; + rtl_device->io_base = rtl_device->pci_device->common.bar[0].base_addr; + rtl_device->io_len = rtl_device->pci_device->common.bar[0].length; + rtl_device->mmio_base = rtl_device->pci_device->common.bar[1].base_addr; + rtl_device->mmio_len = rtl_device->pci_device->common.bar[1].length; + rtl_device->net_device = device->dm_ext; + rtl_device->mii.net_dev = device->dm_ext; + rtl_device->mii.mdio_read = mdio_read; + rtl_device->mii.mdio_write = mdio_write; + timer_init(&rtl_device->timer); + SPINLOCK_INIT(rtl_device->lock); + + NetworkDevice *net = device->dm_ext; + net->mtu = ETH_MTU; + + return DRIVER_OK; +} + +void rtl8139_reset(Rtl8139Device *device) { + io_out_byte(device->io_base + REG_CR, CR_RST); + + uint32_t counter = timer_get_counter() + timer_count_ms(&device->timer, 10); + while (timer_get_counter() < counter && + (io_in_byte(device->io_base + REG_CR) & CR_RST)) { + // 等待重置完成 + } +} + +DriverResult rtl8139_start(void *_device) { + LogicalDevice *device = _device; + Rtl8139Device *rtl_device = device->private_data; + pci_enable_bus_mastering(rtl_device->pci_device); + + if (rtl_device->chipset >= RTL8139B) { + uint8_t config1 = io_in_byte(rtl_device->io_base + REG_CONFIG1); + config1 |= CFG1_PMEN; + // 使CONFIG寄存器可写 + io_out_byte(rtl_device->io_base + REG_9346CR, BIT(7) | BIT(6)); + io_out_byte(rtl_device->io_base + REG_CONFIG1, config1); + // 恢复正常模式 + io_out_byte(rtl_device->io_base + REG_9346CR, 0); + } else { + uint8_t data = io_in_byte(rtl_device->io_base + REG_CONFIG1); + data &= ~(CFG1_SLEEP | CFG1_PWRDN); + io_out_byte(rtl_device->chipset, data); + } + + rtl8139_reset(rtl_device); + + uint8_t mac_addr[6]; + for (int i = 0; i < 6; i++) { + mac_addr[i] = io_in_byte(rtl_device->io_base + REG_IDRN(i)); + } + NetworkDevice *net_device = device->dm_ext; + eth_set_mac_address(net_device->ethernet, mac_addr); + print_info( + "RTL8139", "MAC: %02x:%02x:%02x:%02x:%02x:%02x\n", mac_addr[0], + mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5]); + + net_init_mii(&rtl_device->mii); + + // 启用RX和TX + io_out_byte(rtl_device->io_base + REG_CR, CR_RE | CR_TE); + + // 配置接收缓冲区 + rtl_device->rx_buffer = kernel_alloc_continuous_pages(8 << RECV_BUF_LEN); + rtl_device->rx_buffer_phy = vir2phy((size_t)rtl_device->rx_buffer); + io_out_dword(rtl_device->io_base + REG_RBSTART, rtl_device->rx_buffer_phy); + io_out_dword( + rtl_device->io_base + REG_RCR, RXFTH_NONE | RBLEN | MXDMA | RCR_AER | + RCR_AR | RCR_WRAP | RCR_AB | RCR_AM | + RCR_APM | RCR_AAP); + + // 配置发送缓冲区 + rtl_device->tx_flag = ((256) >> 5) << 16; + io_out_dword(rtl_device->io_base + REG_TCR, MXDMA | TCR_TXRR(2)); + for (int i = 0; i < TX_DESC_NR; i++) { + rtl_device->tx_buffer[i] = kmalloc(ETH_MAX_FRAME_SIZE); + rtl_device->tx_buffer_phy[i] = + vir2phy((size_t)rtl_device->tx_buffer[i]); + io_out_dword( + rtl_device->io_base + REG_TSADN(i), rtl_device->tx_buffer_phy[i]); + } + + // 清空丢包计数器 + io_out_word(rtl_device->io_base + REG_MPC, 0); + + // 允许接收所有多播 + io_out_dword(rtl_device->io_base + REG_MARN(0), 0xffffffff); + io_out_dword(rtl_device->io_base + REG_MARN(4), 0xffffffff); + + // 配置中断 + io_out_word( + rtl_device->io_base + REG_IMR, + IMR_ROK | IMR_RER | IMR_TOK | IMR_TER | IMR_RXOVW | IMR_PUN_LINKCHG | + IMR_FOVW | IMR_LEN_CHG | IMR_TIMEOUT | IMR_SERR); + + register_device_irq( + &rtl_device->irq, device->physical_device, rtl_device, + rtl_device->pci_device->irqline, rtl8139_handler, IRQ_MODE_SHARED); + + rtl_device->net_rx.handler = rtl8139_net_rx_handler; + rtl_device->net_rx.data = rtl_device; + network_softirq_register(&rtl_device->net_rx); + + enable_device_irq(rtl_device->irq); + + return DRIVER_OK; +} + +DriverResult rtl8139_pci_probe( + PciDevice *pci_device, PhysicalDevice *physical_device) { + uint32_t io_base = pci_device->common.bar[0].base_addr; + uint32_t data = io_in_dword(io_base + RTL8139_TCR); + Rtl8139Chipset chipset = RTL_UNKNOWN; + + data &= HWVERID_MASK; + for (int i = 0; i < sizeof(hwrevid) / sizeof(uint32_t) / 2; i++) { + if (data == hwrevid[i][1]) { + chipset = hwrevid[i][0]; + break; + } + } + if (chipset == RTL_UNKNOWN) { return DRIVER_ERROR_UNSUPPORT_DEVICE; } + + Rtl8139Device *rtl_device = kmalloc(sizeof(Rtl8139Device)); + rtl_device->pci_device = pci_device; + rtl_device->chipset = chipset; + + DriverResult result; + NetworkDevice *network_device; + result = create_network_device( + &network_device, NETWORK_TYPE_ETHERNET, rtl8139_caps, + &rtl8139_net_device_ops, &rtl8139_logical_device_ops, physical_device, + &rtl8139_device_driver); + if (result != DRIVER_OK) { + kfree(rtl_device); + return result; + } + register_physical_device(physical_device, &rtl8139_physical_device_ops); + + rtl_device->net_device = network_device; + network_device->device->private_data = rtl_device; + + return DRIVER_OK; +} + +static __init void rtl8139_initcall(void) { + register_driver(&rtl8139_driver); + register_device_driver(&rtl8139_driver, &rtl8139_device_driver); + pci_register_driver(&rtl8139_driver, &rtl8139_pci_driver); +} + +driver_initcall(rtl8139_initcall); \ No newline at end of file diff --git a/src/arch/x86/drivers/network/rtl8139/rtl8139.h b/src/arch/x86/drivers/network/rtl8139/rtl8139.h new file mode 100644 index 0000000..8e9b813 --- /dev/null +++ b/src/arch/x86/drivers/network/rtl8139/rtl8139.h @@ -0,0 +1,178 @@ +#ifndef _RTL8139_H +#define _RTL8139_H + +#include "kernel/driver_interface.h" +#include +#include +#include +#include +#include +#include +#include +#include + +#define RTL8139_VENDOR_ID 0x10ec +#define RTL8139_DEVICE_ID 0x8139 + +#define TX_DESC_NR 4 + +// IDR和MAR寄存器都要按4个字节读写 +#define REG_IDRN(n) (0 + (n)) +#define REG_MARN(n) (8 + (n)) +#define REG_TSDN(n) (0x10 + ((n) << 2)) +#define REG_TSADN(n) (0x20 + ((n) << 2)) +#define REG_RBSTART 0x30 +#define REG_CR 0x37 +#define REG_IMR 0x3c +#define REG_ISR 0x3e +#define REG_TCR 0x40 +#define REG_RCR 0x44 +#define REG_MPC 0x4c +#define REG_9346CR 0x50 +#define REG_CONFIG0 0x51 +#define REG_CONFIG1 0x52 +#define REG_BMCR 0x62 +#define REG_BMSR 0x64 +#define REG_ANAR 0x66 +#define REG_ANLPAR 0x68 +#define REG_ANER 0x6a + +#define CR_BUFE BIT(0) +#define CR_TE BIT(2) +#define CR_RE BIT(3) +#define CR_RST BIT(4) + +#define CFG1_DVRLOAD BIT(5) +#define CFG1_LWACT BIT(4) +#define CFG1_MEMMAP BIT(3) +#define CFG1_IOMAP BIT(2) +#define CFG1_VPD BIT(1) +#define CFG1_PMEN BIT(0) + +#define IMR_ROK BIT(0) +#define IMR_RER BIT(1) +#define IMR_TOK BIT(2) +#define IMR_TER BIT(3) +#define IMR_RXOVW BIT(4) +#define IMR_PUN_LINKCHG BIT(5) +#define IMR_FOVW BIT(6) +#define IMR_LEN_CHG BIT(13) +#define IMR_TIMEOUT BIT(14) +#define IMR_SERR BIT(15) + +/** + * 有资料提到RTL8139和RTL8139A没有CONFIG1寄存器, + * 然而QEMU和Linux代码中都提到了对于这两个芯片存在SLEEP和PWRDN这两位, + * 但我没找到相关文档,只能先写上 + */ +#define CFG1_SLEEP BIT(1) +#define CFG1_PWRDN BIT(0) + +#define RTL8139_HWVERID(a, b, c, d, e, f, g) \ + (a << 30 | b << 29 | c << 28 | d << 27 | e << 26 | f << 23 | g << 22) +#define HWVERID_MASK RTL8139_HWVERID(1, 1, 1, 1, 1, 1, 1) + +#define IMR_ALL \ + RTL8139_IMR_SERR | RTL8139_IMR_TimeOut | RTL8139_IMR_LenChg | \ + RTL8139_IMR_FOVW | RTL8139_IMR_TER | RTL8139_IMR_TOK | \ + RTL8139_IMR_RER | RTL8139_IMR_ROK + +#define RCR_RXFTH(n) ((n & 0x07) << 13) +#define RCR_RBLEN(n) ((n & 0x03) << 11) +#define RCR_MXDMA(n) ((n & 0x07) << 8) +#define RCR_WRAP BIT(7) +#define RCR_AER BIT(5) +#define RCR_AR BIT(4) +#define RCR_AB BIT(3) +#define RCR_AM BIT(2) +#define RCR_APM BIT(1) +#define RCR_AAP BIT(0) + +#define TCR_CRC BIT(16) +#define TCR_TXRR(n) ((n & 0x0f) << 4) +#define TCR_CLRABT BIT(0) + +#define RBLEN_64K 0x03 +#define RBLEN_32K 0x02 +#define RBLEN_16K 0x01 +#define RBLEN_8K 0x00 + +#define MXDMA_16B 0b000 +#define MXDMA_32B 0b001 +#define MXDMA_64B 0b010 +#define MXDMA_128B 0b011 +#define MXDMA_256B 0b100 +#define MXDMA_512B 0b101 +#define MXDMA_1024B 0b110 +#define MXDMA_UNLIMITED 0b111 + +#define MXDMA RCR_MXDMA(MXDMA_1024B) +#define RXFTH_NONE RCR_RXFTH(0x07) +#define RECV_BUF_LEN RBLEN_64K +#define RBLEN RCR_RBLEN(RECV_BUF_LEN) + +#define RTL8139_RECV_BUF_SIZE (8192 << RECV_BUF_LEN) +#define RTL8139_RX_READ_POINTER_MASK (((8192 << RECV_BUF_LEN) - 1) & ~3) + +typedef enum Rtl8139Chipset { + RTL8139 = 0, + RTL8139A, + RTL8139AG, + RTL8139B, + RTL8130, + RTL8139C, + RTL8100, + RTL8139D, + RTL8139CP, + RTL8101, + RTL_UNKNOWN, +} Rtl8139Chipset; + +typedef struct Rtl8139Device { + Timer timer; + PciDevice *pci_device; + NetworkDevice *net_device; + uint32_t io_base, io_len; + uint32_t mmio_base, mmio_len; + Rtl8139Chipset chipset; + Mii mii; + spinlock_t lock; + NetRxHandler net_rx; + DeviceIrq *irq; + + void *rx_buffer; + size_t rx_buffer_phy; + uint32_t rx_offset; + + uint32_t tx_flag; + uint8_t tx_write_idx; + uint8_t tx_done_idx; + void *tx_buffer[TX_DESC_NR]; + size_t tx_buffer_phy[TX_DESC_NR]; +} Rtl8139Device; + +static const int hwrevid[][2] = { + { RTL8139, RTL8139_HWVERID(1, 1, 0, 0, 0, 0, 0)}, + { RTL8139A, RTL8139_HWVERID(1, 1, 1, 0, 0, 0, 0)}, + {RTL8139AG, RTL8139_HWVERID(1, 1, 1, 0, 1, 0, 0)}, + { RTL8139B, RTL8139_HWVERID(1, 1, 1, 1, 0, 0, 0)}, + { RTL8130, RTL8139_HWVERID(1, 1, 1, 1, 0, 0, 0)}, + { RTL8139C, RTL8139_HWVERID(1, 1, 1, 0, 1, 0, 0)}, + {RTL8139CP, RTL8139_HWVERID(1, 1, 1, 0, 1, 1, 0)}, + { RTL8100, RTL8139_HWVERID(1, 1, 1, 1, 0, 1, 0)}, + { RTL8139D, RTL8139_HWVERID(1, 1, 1, 0, 1, 0, 1)}, + { RTL8101, RTL8139_HWVERID(1, 1, 1, 0, 1, 1, 1)}, +}; + +static const int rtl8139_mii_reg_map[] = { + REG_BMCR, // MII_BMCR + REG_BMSR, // MII_BMSR + 0, // MII_PHYID1 + 0, // MII_PHYID2 + REG_ANAR, // MII_ANAR + REG_ANLPAR, // MII_ANLPAR + REG_ANER, // MII_ANER + 0, // MII_ANNPTR +}; + +#endif \ No newline at end of file diff --git a/src/arch/x86/drivers/pci.c b/src/arch/x86/drivers/pci.c deleted file mode 100644 index a27f557..0000000 --- a/src/arch/x86/drivers/pci.c +++ /dev/null @@ -1,241 +0,0 @@ -/** - * @file pci.c - * @author Ryan Wang (ryan1202@foxmail.com) - * @brief - * @version 0.1 - * @date 2020-07 - */ -#include -#include -#include -#include - -struct pci_device pci_devices[PCI_MAX_DEVICE]; - -void init_pci() { - int i, j, k; - - printk("device id\tvendor id\theader " - "type\tclasscode\tsubclass\tprogif\trevision id\n"); - for (i = 0; i < PCI_MAX_DEVICE; i++) { - pci_devices[i].status = PCI_DEVICE_STATUS_INVALID; - } - for (i = 0; i < PCI_MAX_BUS; i++) { - for (j = 0; j < PCI_MAX_DEV; j++) { - for (k = 0; k < PCI_MAX_FUNC; k++) { - pci_scan_device(i, j, k); - } - } - } -} - -PCI_READ(8, uint8_t) -PCI_READ(16, uint16_t) -PCI_READ(32, uint32_t) -PCI_WRITE(8, uint8_t) -PCI_WRITE(16, uint16_t) -PCI_WRITE(32, uint32_t) -PCI_READ_DEVICE(8, uint8_t) -PCI_READ_DEVICE(16, uint16_t) -PCI_READ_DEVICE(32, uint32_t) -PCI_WRITE_DEVICE(8, uint8_t) -PCI_WRITE_DEVICE(16, uint16_t) -PCI_WRITE_DEVICE(32, uint32_t) - -void pci_scan_device(uint8_t bus, uint8_t device, uint8_t function) { - uint32_t value = pci_read32(bus, device, function, 0); - uint16_t vendorID = value & 0xffff; - uint16_t deviceID = value >> 16; - if (vendorID == 0xffff) { return; } - value = pci_read32(bus, device, function, 0x0c); - uint8_t header_type = value >> 16; - value = pci_read32(bus, device, function, 8); - uint32_t classcode = value >> 8; - uint8_t revisionID = value & 0xff; - - struct pci_device *dev = pci_alloc_device(); - if (dev == NULL) { return; } - pci_device_init( - dev, bus, device, function, vendorID, deviceID, classcode, revisionID, - header_type); - - if (header_type == 0x00) { - int bar; - for (bar = 0; bar < PCI_MAX_BAR; bar++) { - value = pci_read32(bus, device, function, PCI_BAR(bar)); - pci_write32(bus, device, function, PCI_BAR(bar), 0xffffffff); - uint32_t len = pci_read32(bus, device, function, PCI_BAR(bar)); - pci_write32(bus, device, function, PCI_BAR(bar), value); - - if (len != 0 && len != 0xffffffff) { - pci_bar_init(&dev->bar[bar], value, len); - } - } - } - - value = pci_read32(bus, device, function, 0x3c) & 0xffff; - if ((value & 0xff) > 0 && (value & 0xff) < 32) { - dev->irqline = value & 0xff; - dev->irqpin = value >> 8; - } - - printk( - "%#06x\t\t%#06x\t\t%#04x\t\t%#04x\t\t%#04x\t\t%#04x\t%#04x\n", deviceID, - vendorID, header_type & (uint8_t)(~0x80), dev->classcode, dev->subclass, - dev->prog_if, revisionID); -} - -struct pci_device *pci_get_device_ById(uint16_t vendorID, uint16_t deviceID) { - int i; - struct pci_device *device; - - for (i = 0; i < PCI_MAX_DEVICE; i++) { - device = &pci_devices[i]; - if (device->vendorID == vendorID && device->deviceID == deviceID) { - return device; - } - } - return NULL; -} - -struct pci_device *pci_get_device_ByClassFull( - uint8_t classcode, uint8_t subclass, uint8_t progif) { - int i; - struct pci_device *device; - - for (i = 0; i < PCI_MAX_DEVICE; i++) { - device = &pci_devices[i]; - if (device->classcode == classcode && device->subclass == subclass && - device->prog_if == progif) { - return device; - } - } - return NULL; -} - -struct pci_device *pci_get_device_ByClass(uint8_t classcode, uint8_t subclass) { - int i; - struct pci_device *device; - - for (i = 0; i < PCI_MAX_DEVICE; i++) { - device = &pci_devices[i]; - if (device->classcode == classcode && device->subclass == subclass) { - return device; - } - } - return NULL; -} - -void pci_enable_bus_mastering(struct pci_device *device) { - uint32_t value = - pci_read32(device->bus, device->dev, device->function, 0x04); - value |= 4; - pci_write32(device->bus, device->dev, device->function, 0x04, value); -} - -void pci_enable_io_space(struct pci_device *device) { - uint32_t value = - pci_read32(device->bus, device->dev, device->function, 0x04); - value |= 1; - pci_write32(device->bus, device->dev, device->function, 0x04, value); -} - -void pci_enable_mem_space(struct pci_device *device) { - uint32_t value = - pci_read32(device->bus, device->dev, device->function, 0x04); - value |= 2; - pci_write32(device->bus, device->dev, device->function, 0x04, value); -} - -uint32_t pci_get_device_connected(void) { - int i; - struct pci_device *device; - for (i = 0; i < PCI_MAX_BAR; i++) { - device = &pci_devices[i]; - if (device->status != PCI_DEVICE_STATUS_USING) { break; } - } - return i; -} - -struct pci_device *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; -} - -int pci_free_device(struct pci_device *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 pci_device_init( - struct pci_device *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) { - int i; - - dev->bus = bus; - dev->dev = device; - dev->function = func; - dev->vendorID = vendorID; - dev->deviceID = deviceID; - dev->classcode = classcode >> 16; - dev->subclass = (classcode & 0xff00) >> 8; - dev->prog_if = classcode & 0xff; - dev->revisionID = revisionID; - dev->multifunction = multifunction; - - for (i = 0; i < PCI_MAX_BAR; i++) { - dev->bar[i].type = PCI_BAR_TYPE_INVALID; - } - dev->irqline = -1; -} - -void pci_bar_init(struct pci_device_bar *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; - } -} - -uint32_t pci_device_get_mem_addr(struct pci_device *dev) { - int i; - - for (i = 0; i < PCI_MAX_BAR; i++) { - if (dev->bar[i].type == PCI_BAR_TYPE_MEM) { - return dev->bar[i].base_addr; - } - } - return -1; -} - -uint32_t pci_device_get_io_addr(struct pci_device *dev) { - int i; - - for (i = 0; i < PCI_MAX_BAR; i++) { - if (dev->bar[i].type == PCI_BAR_TYPE_IO) { - return dev->bar[i].base_addr; - } - } - return -1; -} diff --git a/src/arch/x86/drivers/pit.c b/src/arch/x86/drivers/pit.c deleted file mode 100644 index 780aeb4..0000000 --- a/src/arch/x86/drivers/pit.c +++ /dev/null @@ -1,154 +0,0 @@ -/** - * @file pit.c - * @author Ryan Wang (ryan1202@foxmail.com) - * @brief - * @version 1.0 - * @date 2022-07-31 - */ -#include -#include -#include -#include -#include -#include -#include - -struct timerctl timerctl; - -void init_timer(void) { - int i; - io_out8(PIT_CTRL, 0x34); - io_out8(PIT_CNT0, 0x9c); - io_out8(PIT_CNT0, 0x2e); - - timerctl.count = 0; - timerctl.next = 0xffffffff; // 没有定时器 - timerctl.using = 0; - for (i = 0; i <= MAX_TIMER; i++) { - timerctl.timers0[i].flags = TIMER_FREE; // 释放所有计时器 - } - - if (use_apic) { - put_irq_handler(APIC_PIT_IRQ, timer_handler); - irq_enable(APIC_PIT_IRQ); - } else { - put_irq_handler(PIC_PIT_IRQ, timer_handler); - irq_enable(PIC_PIT_IRQ); - } - return; -} - -void timer_handler(int irq) { - int i; - struct timer *timer; - timerctl.count++; - if (use_apic) { - struct task_s *cur_thread = get_current_thread(); - cur_thread->elapsed_ticks++; - - if (cur_thread->ticks == 0) { - schedule(); - } else { - cur_thread->ticks--; - } - } - if (timerctl.next > timerctl.count) { return; } - timer = timerctl.timers[0]; - for (i = 0; i < timerctl.using; i++) { - if (timer->timeout > timerctl.count) { break; } - timer->flags = TIMER_UNUSED; - fifo_put(timer->fifo, timer->data); - timer = timer->next; - } - timerctl.using -= i; - timerctl.timers[0] = timer; - if (timerctl.using > 0) { - timerctl.next = timerctl.timers[0]->timeout; - } else { - timerctl.next = 0xffffffff; - } - return; -} - -struct timer *timer_alloc(void) { - int i; - for (i = 0; i < MAX_TIMER; i++) { - if (timerctl.timers0[i].flags == 0) { - timerctl.timers0[i].flags = TIMER_UNUSED; - return &timerctl.timers0[i]; - } - } - return 0; -} - -void timer_free(struct timer *timer) { - if (timer->flags == TIMER_USING) { timerctl.using --; } - timer->flags = TIMER_FREE; - return; -} - -void timer_init(struct timer *timer, struct fifo *fifo, int data) { - timer->fifo = fifo; - timer->data = data; - return; -} - -void timer_settime(struct timer *timer, unsigned int timeout) { - int e; - struct timer *t, *s; - timer->timeout = timeout + timerctl.count; - timer->flags = TIMER_USING; - e = io_load_eflags(); - io_cli(); - timerctl.using ++; - if (timerctl.using == 1) { - timerctl.timers[0] = timer; - timer->next = 0; - timerctl.next = timer->timeout; - io_store_eflags(e); - return; - } - t = timerctl.timers[0]; - if (timer->timeout <= t->timeout) { - timerctl.timers[0] = timer; - timer->next = t; - timerctl.next = timer->timeout; - io_store_eflags(e); - return; - } - for (;;) { - s = t; - t = t->next; - if (t == 0) { break; } - if (timer->timeout <= t->timeout) { - s->next = timer; - timer->next = t; - io_store_eflags(e); - return; - } - } - s->next = timer; - timer->next = 0; - io_store_eflags(e); - return; -} - -/** - * @brief 等待 - * - * @param time 时间(单位:10毫秒) - */ -void delay(int time) { - struct timer *timer; - struct fifo fifo; - char buf[1]; - timer = timer_alloc(); - fifo_init(&fifo, 1, (int *)buf); - timer_init(timer, &fifo, 0); - timer_settime(timer, time); - while (!fifo_status(&fifo)) - ; - fifo_get(&fifo); - timer_free(timer); - return; -} diff --git a/src/arch/x86/drivers/serial.c b/src/arch/x86/drivers/serial.c new file mode 100644 index 0000000..4732b9f --- /dev/null +++ b/src/arch/x86/drivers/serial.c @@ -0,0 +1,247 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern Driver core_driver; + +DriverResult serial_init(void *device); +DriverResult serial_start(void *device); +DriverResult serial_self_test(SerialDevice *serial_device); +void serial_set_baud_rate( + SerialDevice *serial_device, SerialBaudRate baud_rate); +void serial_set_recv_mode( + SerialDevice *serial_device, SerialReceiveMode recv_mode); +void serial_set_recv_mode( + SerialDevice *serial_device, SerialReceiveMode recv_mode); +void serial_console_backend_put_string( + void *context, const char *string, int length); + +DeviceOps serial_device_ops = { + .init = serial_init, + .start = serial_start, + .stop = NULL, + .destroy = NULL, +}; +SerialOps serial_serial_ops = { + .self_test = serial_self_test, + .set_baud_rate = serial_set_baud_rate, + .set_recv_mode = serial_set_recv_mode, +}; + +DeviceDriver serial_device_driver; + +const uint16_t serial_ports[] = { + SERIAL_COM1_BASE, + SERIAL_COM2_BASE, + SERIAL_COM3_BASE, + SERIAL_COM4_BASE, +}; +const int serial_irqs[] = { + SERIAL_COM1_IRQ, + SERIAL_COM2_IRQ, + SERIAL_COM3_IRQ, + SERIAL_COM4_IRQ, +}; + +string_t name = STRING_INIT("Serial"); + +void serial_console_backend_put_string( + void *context, const char *string, int length) { + Serial *serial = context; + if (serial->device->state != DEVICE_STATE_ACTIVE) return; + + for (int i = 0; i < length; i++) { + // 等待直到可以发送数据 + while (!( + io_in_byte(serial->base_port + SERIAL_UART_REG_LINE_STATUS) & 0x20)) + ; + io_out_byte(serial->base_port + SERIAL_UART_REG_DATA, string[i]); + } +} + +void serial_irq_handler(void *arg) { + LogicalDevice *device = arg; + SerialDevice *serial_device = device->dm_ext; + Serial *serial = device->private_data; + uint16_t base_port = serial->base_port; + uint8_t status = + io_in_byte(base_port + SERIAL_UART_REG_INTERRUPT_IDENTIFICATION); + + // 判断中断类型 + if (!(status & 0x01)) { + // 接收数据可用 + while (io_in_byte(base_port + SERIAL_UART_REG_LINE_STATUS) & 0x01) { + uint8_t data = io_in_byte(base_port + SERIAL_UART_REG_DATA); + // 处理接收到的数据(例如存入缓冲区) + if (data == 127) data = '\b'; + if (data == '\r') data = '\n'; + if (serial_device->receive != NULL) { + if (data == '\b') { + serial_device->receive('\b'); + serial_device->receive(' '); + serial_device->receive('\b'); + } else serial_device->receive(data); + } + } + } + if (status & 0x02) { + // 发送缓冲区空 + // 可以发送更多数据 + } + if (status & 0x04) { + // 接收线路状态改变 + } + if (status & 0x08) { + // 接收数据超时 + } + if (status & 0x10) { + // 接收FIFO达到触发点 + } +} + +bool serial_probe(int base_port) { + io_out_byte(base_port + SERIAL_UART_REG_SCRATCH, SERIAL_TEST_MAGIC_1); + uint8_t val = io_in_byte(base_port + SERIAL_UART_REG_SCRATCH); + if (val != SERIAL_TEST_MAGIC_1) return false; + io_out_byte(base_port + SERIAL_UART_REG_SCRATCH, SERIAL_TEST_MAGIC_2); + val = io_in_byte(base_port + SERIAL_UART_REG_SCRATCH); + return val == SERIAL_TEST_MAGIC_2; +} + +DriverResult serial_self_test(SerialDevice *serial_device) { + Serial *serial = serial_device->device->private_data; + uint16_t base_port = serial->base_port; + uint8_t val = io_in_byte(base_port + SERIAL_UART_REG_LINE_STATUS); + + // 禁用中断 + io_out_byte(base_port + SERIAL_UART_REG_INTERRUPT_ENABLE, 0x00); + + io_out_byte(base_port + SERIAL_UART_REG_MODEM_CONTROL, 0x1E); + // 测试发送和接收 + io_out_byte(base_port + SERIAL_UART_REG_DATA, 0x5A); + if (io_in_byte(base_port + SERIAL_UART_REG_DATA) != 0x5A) + return DRIVER_ERROR_OTHER; + + io_out_byte(base_port + SERIAL_UART_REG_MODEM_CONTROL, 0x0F); + io_out_byte(base_port + SERIAL_UART_REG_INTERRUPT_ENABLE, val); + + return DRIVER_OK; +} + +void serial_set_baud_rate( + SerialDevice *serial_device, SerialBaudRate baud_rate) { + Serial *serial = serial_device->device->private_data; + uint16_t base_port = serial->base_port; + + uint16_t divisor = SERIAL_RATE_DIVISION; + switch (baud_rate) { + case SERIAL_BAUD_115200: + divisor = SERIAL_RATE_115200_DIVISION; + break; + case SERIAL_BAUD_57600: + divisor = SERIAL_RATE_57600_DIVISION; + break; + case SERIAL_BAUD_38400: + divisor = SERIAL_RATE_38400_DIVISION; + break; + case SERIAL_BAUD_19200: + divisor = SERIAL_RATE_19200_DIVISION; + break; + case SERIAL_BAUD_9600: + divisor = SERIAL_RATE_9600_DIVISION; + break; + } + + // 启用 DLAB + io_out_byte(base_port + SERIAL_UART_REG_LINE_CONTROL, 0x80); + // 设置波特率 + io_out_byte(base_port + SERIAL_UART_REG_DIVISOR_LATCH_LOW, divisor & 0xff); + io_out_byte(base_port + SERIAL_UART_REG_DIVISOR_LATCH_HIGH, divisor >> 8); + // 禁用 DLAB + io_out_byte(base_port + SERIAL_UART_REG_LINE_CONTROL, 0x03); +} + +void serial_set_recv_mode( + SerialDevice *serial_device, SerialReceiveMode recv_mode) { + Serial *serial = serial_device->device->private_data; + uint16_t base_port = serial->base_port; + if (recv_mode == SERIAL_RECV_MODE_HIGH_THROUGHPUT) { + // 启用 FIFO,清空接收和发送 FIFO,设置触发点为 14 字节 + io_out_byte(base_port + SERIAL_UART_REG_FIFO_CONTROL, 0xC7); + } else { + // 启用 FIFO,清空接收和发送 FIFO,设置触发点为 1 字节 + io_out_byte(base_port + SERIAL_UART_REG_FIFO_CONTROL, 0x81); + } +} + +DriverResult serial_init(void *_device) { + LogicalDevice *device = _device; + Serial *serial = device->private_data; + uint16_t base_port = serial->base_port; + + // 禁用中断 + io_out_byte(base_port + SERIAL_UART_REG_INTERRUPT_ENABLE, 0x00); + // 8 位数据位,无奇偶校验,1 位停止位,禁用 DLAB + io_out_byte(base_port + SERIAL_UART_REG_LINE_CONTROL, 0x03); + // 启用 FIFO,清空接收和发送 FIFO,设置触发点为 8 字节 + io_out_byte(base_port + SERIAL_UART_REG_FIFO_CONTROL, 0x87); + // 设置 RTS 和 DSR + io_out_byte(base_port + SERIAL_UART_REG_MODEM_CONTROL, 0x0B); + + register_device_irq( + &serial->irq, device->physical_device, serial->device, serial->irq_num, + serial_irq_handler, IRQ_MODE_SHARED); + + serial->console_backend.init = NULL; + serial->console_backend.put_string = serial_console_backend_put_string; + + return DRIVER_OK; +} + +DriverResult serial_start(void *_device) { + LogicalDevice *device = _device; + Serial *serial = device->private_data; + uint16_t base_port = serial->base_port; + + // 启用接收中断 + io_out_byte(base_port + SERIAL_UART_REG_INTERRUPT_ENABLE, 0x01); + enable_device_irq(serial->irq); + + console_register_backend(&serial->console_backend, serial); + + return DRIVER_OK; +} + +void register_serial() { + register_device_driver(&core_driver, &serial_device_driver); + + DriverResult result; + SerialDevice *serial_device; + LogicalDevice *logical_device; + for (int i = 0; i < sizeof(serial_ports) / sizeof(serial_ports[0]); i++) { + if (serial_probe(serial_ports[i])) { + result = create_serial_device( + &serial_device, &serial_serial_ops, &serial_device_ops, + platform_device, &serial_device_driver); + if (result != DRIVER_OK) continue; + + logical_device = serial_device->device; + Serial *serial = kmalloc(sizeof(Serial)); + serial->base_port = serial_ports[i]; + serial->irq_num = serial_irqs[i]; + serial->device = serial_device->device; + + logical_device->private_data = serial; + } + } +} \ No newline at end of file diff --git a/src/arch/x86/drivers/smbios.c b/src/arch/x86/drivers/smbios.c index 800349e..80119e8 100644 --- a/src/arch/x86/drivers/smbios.c +++ b/src/arch/x86/drivers/smbios.c @@ -31,9 +31,11 @@ void init_smbios(void) { } EntryPoint = (struct SMBIOSEntryPoint *)mem; - struct SMBIOSHeader *header = (struct SMBIOSHeader *)EntryPoint->TableAddress; - mem = (unsigned char *)EntryPoint->TableAddress; - while ((unsigned int)mem < EntryPoint->TableAddress + EntryPoint->TableLength) { + struct SMBIOSHeader *header = + (struct SMBIOSHeader *)EntryPoint->TableAddress; + mem = (unsigned char *)EntryPoint->TableAddress; + while ((unsigned int)mem < + EntryPoint->TableAddress + EntryPoint->TableLength) { smbios_tables[header->Type] = (unsigned int)mem; switch (header->Type) { case 0: @@ -47,15 +49,16 @@ void init_smbios(void) { break; case 4: processor = (struct Processor_info *)mem; - printk(COLOR_AQUA "\nCPU Max Speed: %dMHz\n", processor->MaxSpeed); - printk(COLOR_AQUA "\nCPU Speed: %dMHz\n", processor->CurrentSpeed); + printk(COLOR_CYAN "\nCPU Max Speed: %dMHz\n", processor->MaxSpeed); + printk(COLOR_CYAN "\nCPU Speed: %dMHz\n", processor->CurrentSpeed); break; default: break; } mem += header->Length; - while (mem - (unsigned char *)header < EntryPoint->TableLength - 1 && (mem[0] || mem[1])) + while (mem - (unsigned char *)header < EntryPoint->TableLength - 1 && + (mem[0] || mem[1])) mem++; mem += 2; header = (struct SMBIOSHeader *)mem; diff --git a/src/arch/x86/drivers/sound/Makefile b/src/arch/x86/drivers/sound/Makefile index 5745963..bc8b128 100644 --- a/src/arch/x86/drivers/sound/Makefile +++ b/src/arch/x86/drivers/sound/Makefile @@ -1 +1 @@ -SRC += sb16.c \ No newline at end of file +SRC += sb16/ \ No newline at end of file diff --git a/src/arch/x86/drivers/sound/config.toml b/src/arch/x86/drivers/sound/config.toml new file mode 100644 index 0000000..0ce69d9 --- /dev/null +++ b/src/arch/x86/drivers/sound/config.toml @@ -0,0 +1 @@ +dir = ["sb16/"] diff --git a/src/arch/x86/drivers/sound/sb16.c b/src/arch/x86/drivers/sound/sb16.c deleted file mode 100644 index ffc58a3..0000000 --- a/src/arch/x86/drivers/sound/sb16.c +++ /dev/null @@ -1,229 +0,0 @@ -/** - * @file sb16.c - * @author Ryan Wang (ryan1202@foxmail.com) - * @brief Sound Blaster 16驱动 - * @version 0.1 - * @date 2022-07-22 - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define SB16_DSP_MIXER 0x224 -#define SB16_DSP_MIXER_DATA 0x225 -#define SB16_DSP_RESET 0x226 -#define SB16_DSP_READ 0x22a -#define SB16_DSP_WRITE 0x22c -#define SB16_DSP_READ_STATUS 0x22e -#define SB16_DESP_IACK16 0x22f - -#define SB16_CMD_SET_TIME_CONSTANT 0x40 -#define SB16_CMD_SET_OUTPUT_SAMPLE_RATE 0x41 -#define SB16_CMD_TURN_SPEAKER_ON 0xd1 -#define SB16_CMD_TURN_SPEAKER_OFF 0xd3 -#define SB16_CMD_STOP_PLAY8 0xd0 -#define SB16_CMD_RESUME_PLAY8 0xd4 -#define SB16_CMD_STOP_PLAY16 0xd5 -#define SB16_CMD_RESUME_PLAY16 0xd6 -#define SB16_CMD_GET_DSP_VERSION 0xe1 - -#define SB16_CMD_SET_VOLUME 0x22 -#define SB16_CMD_SET_IRQ 0x80 - -#define SB16_IRQ 0x05 - -static status_t sb16_enter(driver_t *drv_obj); -static status_t sb16_exit(driver_t *drv_obj); -status_t sb16_open(device_t *device); -status_t sb16_close(device_t *device); -status_t sb16_write(device_t *dev, uint8_t *buf, uint32_t offset, size_t size); - -#define DRV_NAME "Sound Blaster 16 Driver" -#define DEV_NAME "sb16" - -#define DMA_MAX 4 -uint32_t data_len[DMA_MAX]; - -driver_func_t sb16_driver = {.driver_enter = sb16_enter, - .driver_exit = sb16_exit, - .driver_open = sb16_open, - .driver_close = sb16_close, - .driver_read = NULL, - .driver_write = sb16_write, - .driver_devctl = NULL}; - -typedef struct { - int major_ver, minor_ver; - int index_r, index_w; - spinlock_t lock; - wait_queue_manager_t *wqm; -} device_extension_t; - -void sb16_request(device_extension_t *devext); -void sb16_dma_config(uint8_t channel, uint32_t addr, uint32_t length); -void dsp_write(uint8_t value); -uint8_t dsp_read(); -status_t dsp_reset(void); -void sb16_set_sample_rate(uint16_t samplerate); - -void sb16_handler(device_t *devobj, int irq) { - device_extension_t *devext = devobj->device_extension; - dsp_write(SB16_CMD_STOP_PLAY16); - io_in8(SB16_DSP_READ_STATUS); - if (devext->major_ver >= 4) { io_in8(SB16_DESP_IACK16); } - devext->index_r = (devext->index_r + 1) % DMA_MAX; - - wait_queue_wakeup(devext->wqm); - - if (devext->index_r != devext->index_w) { sb16_request(devext); } - return; -} - -static status_t sb16_enter(driver_t *drv_obj) { - device_t *devobj; - device_extension_t *devext; - - device_create(drv_obj, sizeof(device_extension_t), DEV_NAME, DEV_SOUND, &devobj); - if (devobj == NULL) { - device_delete(devobj); - return FAILED; - } - devext = devobj->device_extension; - - spinlock_init(&devext->lock); - devext->wqm = create_wait_queue(); - wait_queue_init(devext->wqm); - - devext->index_r = devext->index_w = 0; - memset((void *)0x800000, 0, 0x10000); - memset((void *)0x810000, 0, 0x10000); - memset((void *)0x820000, 0, 0x10000); - memset((void *)0x830000, 0, 0x10000); - - // 复位DSP - if (dsp_reset() != SUCCUESS) { - device_delete(devobj); - return FAILED; - } - - // 获取DSP版本 - dsp_write(SB16_CMD_GET_DSP_VERSION); - devext->major_ver = dsp_read(); - devext->minor_ver = dsp_read(); - printk("[SB16]DSP Version:%d.%d\n", devext->major_ver, devext->minor_ver); - - // 设置采样率 - sb16_set_sample_rate(44100); - - device_register_irq(devobj, SB16_IRQ, sb16_handler); - return SUCCUESS; -} - -void sb16_dma_config(uint8_t channel, uint32_t addr, uint32_t length) { - dma_disable(channel); - dma_ff_reset(channel); - dma_set_mode(channel, 0x58); - dma_set_page(channel, addr >> 16); - dma_set_addr(channel, addr); - dma_set_count(channel, length); - dma_enable(channel); -} - -void dsp_write(uint8_t value) { - while (io_in8(SB16_DSP_WRITE) & 0x80) - ; - io_out8(SB16_DSP_WRITE, value); -} - -uint8_t dsp_read() { - while (!(io_in8(SB16_DSP_READ_STATUS) & 0x80)) - ; - return io_in8(SB16_DSP_READ); -} - -void sb16_set_sample_rate(uint16_t samplerate) { - dsp_write(SB16_CMD_SET_OUTPUT_SAMPLE_RATE); - dsp_write((uint8_t)(samplerate >> 8)); - dsp_write((uint8_t)samplerate); -} - -status_t dsp_reset(void) { - io_out8(SB16_DSP_RESET, 1); - delay(1); - io_out8(SB16_DSP_RESET, 0); - - int data = dsp_read(); - if (data != 0xaa) { - printk(COLOR_RED "[SB16]Reset Failed!\n"); - return FAILED; - } - return SUCCUESS; -} - -status_t sb16_open(device_t *device) { - memset(data_len, 0, DMA_MAX * sizeof(uint32_t)); - return SUCCUESS; -} - -status_t sb16_close(device_t *device) { - return SUCCUESS; -} - -void sb16_request(device_extension_t *devext) { - int length = data_len[devext->index_r]; - if (devext->index_r == devext->index_w) { return; } - - sb16_dma_config(0x05, (uint32_t)(0x800000 + devext->index_r * 0x10000), data_len[devext->index_r]); - uint16_t sample_count = length / sizeof(int16_t) / 2 - 1; - - dsp_write(0xb0); - dsp_write(0x30); - dsp_write((uint8_t)sample_count); - dsp_write((uint8_t)(sample_count >> 8)); -} - -status_t sb16_write(device_t *dev, uint8_t *buf, uint32_t offset, size_t size) { - if (size > 64 * 1024) { return FAILED; } - device_extension_t *devext = dev->device_extension; - while ((devext->index_w + 1) % DMA_MAX == devext->index_r) { - wait_queue_add(devext->wqm, 0); - thread_block(TASK_BLOCKED); - } - uint8_t *dma_mem = (uint8_t *)(0x800000 + devext->index_w * 0x10000); - memcpy(dma_mem, buf, size); - data_len[devext->index_w] = size; - if (devext->index_r == devext->index_w) { - devext->index_w = (devext->index_w + 1) % DMA_MAX; - sb16_request(devext); - } else { - devext->index_w = (devext->index_w + 1) % DMA_MAX; - } - - return SUCCUESS; -} - -static status_t sb16_exit(driver_t *drv_obj) { - device_t *devobj, *next; - 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 sb16_driver_entry(void) { - if (driver_create(sb16_driver, DRV_NAME) < 0) { - printk(COLOR_RED "[driver] %s driver create failed!\n", __func__); - } -} - -driver_initcall(sb16_driver_entry); \ No newline at end of file diff --git a/src/arch/x86/drivers/sound/sb16/Makefile b/src/arch/x86/drivers/sound/sb16/Makefile new file mode 100644 index 0000000..dd6cd79 --- /dev/null +++ b/src/arch/x86/drivers/sound/sb16/Makefile @@ -0,0 +1 @@ +SRC += sb16.c \ No newline at end of file diff --git a/src/arch/x86/drivers/sound/sb16/config.toml b/src/arch/x86/drivers/sound/sb16/config.toml new file mode 100644 index 0000000..4c4ea29 --- /dev/null +++ b/src/arch/x86/drivers/sound/sb16/config.toml @@ -0,0 +1 @@ +c = ["sb16.c"] diff --git a/src/arch/x86/drivers/sound/sb16/sb16.c b/src/arch/x86/drivers/sound/sb16/sb16.c new file mode 100644 index 0000000..a2a300e --- /dev/null +++ b/src/arch/x86/drivers/sound/sb16/sb16.c @@ -0,0 +1,466 @@ +#include "sb16.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +DriverResult sb16_init(void *_device); +DriverResult sb16_start(void *_device); +DriverResult sb16_stop(void *_device); +DriverResult sb16_destroy(void *_device); +DriverResult sb16_probe(IsaDeviceDriver *isa_device_driver); + +DriverResult sb16_pcm_set_default_params(PcmStream *stream); +DriverResult sb16_pcm_set_channel(PcmStream *stream, uint8_t channel); +DriverResult sb16_pcm_set_sample_rate(PcmDevice *pcm, uint32_t sample_rate); +DriverResult sb16_pcm_set_data_type(PcmStream *stream, PcmDataType type); +DriverResult sb16_play_open(SoundDevice *sound_device, PcmStream *stream); +DriverResult sb16_play_prepare( + struct PcmStream *stream, void *addr, size_t size); +DriverResult sb16_play_trigger(PcmStream *stream, PcmTrigger trigger); +size_t sb16_play_position(PcmStream *stream); + +DriverResult sb16_record_open(SoundDevice *sound_device, PcmStream *stream); +DriverResult sb16_record_prepare( + struct PcmStream *stream, void *addr, size_t size); +DriverResult sb16_record_trigger(PcmStream *stream, PcmTrigger trigger); +size_t sb16_record_position(PcmStream *stream); + +DeviceOps sb16_device_ops = { + .init = NULL, + .start = NULL, + .destroy = NULL, + .stop = NULL, +}; +DeviceOps sb16_logical_device_ops = { + .init = sb16_init, + .start = sb16_start, + .destroy = sb16_destroy, + .stop = sb16_stop, +}; +IsaOps sb16_isa_ops = { + .probe = sb16_probe, +}; +SoundOps sb16_sound_device_ops = { + .set_volume = NULL, +}; +PcmOps sb16_pcm_ops = { + .set_sample_rate = sb16_pcm_set_sample_rate, +}; +PcmStreamOps sb16_pcm_play_ops = { + .open = sb16_play_open, + .close = NULL, + .prepare = sb16_play_prepare, + .trigger = sb16_play_trigger, + .position = sb16_play_position, + + .set_default_params = sb16_pcm_set_default_params, + .set_data_type = sb16_pcm_set_data_type, + .set_channel = sb16_pcm_set_channel, +}; +PcmStreamOps sb16_pcm_record_ops = { + .open = sb16_record_open, + .close = NULL, + .prepare = sb16_record_prepare, + .trigger = sb16_record_trigger, + + .set_default_params = sb16_pcm_set_default_params, + .set_data_type = sb16_pcm_set_data_type, + .set_channel = sb16_pcm_set_channel, +}; + +Driver sb_driver; +DeviceDriver sb16_device_driver; +const SoundDeviceCapabilities sb16_capabilities = { + .record = 1, + .play = 1, + .set_volume = 1, + .set_sample_rate = 1, +}; + +static const int sb16_possible_ports[] = {0x220, 0x240, 0x260, 0x280}; +static const int sb16_possible_dmas[] = {5, 6, 7}; +#define DMA_MAX 4 +uint32_t data_len[DMA_MAX]; + +DriverResult sb16_write(Sb16Ports *ports, uint8_t value); + +void sb16_irq_handler(void *arg) { + SoundDevice *sound_device = arg; + Sb16Info *info = sound_device->device->private_data; + PcmDevice *pcm = sound_device->pcm; + PcmStream *current_stream = pcm->current_stream; + + sound_pcm_done(current_stream); + + if (info->major_ver >= 4) { + io_in8(info->ports.iack16); + } else { + io_in8(info->ports.read_status); + } +} + +DriverResult sb16_reset(Sb16Ports *ports) { + Timer timer; + timer_init(&timer); + io_out8(ports->reset, 1); + delay_ms(&timer, 1); + io_out8(ports->reset, 0); + delay_ms(&timer, 1); + for (int i = 0; i < 100000; i++) { + if (io_in8(ports->read_status) & 0x80) { + if (io_in8(ports->read) == 0xaa) { return DRIVER_OK; } + } + } + return DRIVER_ERROR_NOT_EXIST; +} + +DriverResult sb16_write(Sb16Ports *ports, uint8_t value) { + for (int i = 0; i < 100000; i++) { + if ((io_in8(ports->write) & 0x80) == 0) { + io_out8(ports->write, value); + return DRIVER_OK; + } + } + return DRIVER_ERROR_TIMEOUT; +} + +DriverResult sb16_read(Sb16Ports *ports, uint8_t *value) { + for (int i = 0; i < 100000; i++) { + if (io_in8(ports->iack16) & 0x80) { + *value = io_in8(ports->read); + return DRIVER_OK; + } + } + return DRIVER_ERROR_TIMEOUT; +} + +DriverResult sb16_get_version( + Sb16Ports *ports, uint8_t *major_version, uint8_t *minor_version) { + sb16_write(ports, CMD_GET_DSP_VERSION); + + DRIVER_RESULT_PASS(sb16_read(ports, major_version)); + DRIVER_RESULT_PASS(sb16_read(ports, minor_version)); + + return DRIVER_OK; +} + +DriverResult sb16_check(int port, Sb16Info **info) { + Sb16Ports ports; + ports.mixer = port + PORT_MIXER; + ports.mixer_data = port + PORT_MIXER_DATA; + ports.reset = port + PORT_RESET; + ports.read = port + PORT_READ; + ports.write = port + PORT_WRITE; + ports.read_status = port + PORT_READ_STATUS; + ports.iack16 = port + PORT_IACK16; + + uint8_t major, minor; + DRIVER_RESULT_PASS(sb16_reset(&ports)); + DRIVER_RESULT_PASS(sb16_get_version(&ports, &major, &minor)); + print_info("SB16", "DSP found. version:%d.%d\n", major, minor); + + *info = kmalloc(sizeof(Sb16Info)); + (*info)->ports = ports; + (*info)->major_ver = major; + (*info)->minor_ver = minor; + + return DRIVER_OK; +} + +DriverResult sb16_probe(IsaDeviceDriver *isa_device_driver) { + DriverResult result = DRIVER_ERROR_NOT_EXIST; + ObjectAttr attr = device_object_attr; + PhysicalDevice *phy; + SoundDevice *snd; + + for (int i = 0; i < sizeof(sb16_possible_ports) / sizeof(int); i++) { + Sb16Info *info = NULL; + if (sb16_check(sb16_possible_ports[i], &info) == DRIVER_OK) { + result = + create_physical_device(&phy, isa_device_driver->bus, &attr); + if (result != DRIVER_OK) continue; + + result = create_sound_device( + &snd, SOUND_TYPE_PCM, sb16_capabilities, &sb16_sound_device_ops, + &sb16_logical_device_ops, phy, &sb16_device_driver); + if (result != DRIVER_OK) { + delete_physical_device(phy); + continue; + } + PcmDevice *pcm = sound_register_pcm(snd, &sb16_pcm_ops, 128 * 1024); + if (pcm == NULL) { + delete_sound_device(snd); + delete_physical_device(phy); + result = DRIVER_ERROR_OUT_OF_MEMORY; + continue; + } + + DRIVER_RESULT_PASS(pcm_register_stream( + pcm, &pcm->play_stream, &sb16_pcm_play_ops, + &info->stream_info[0])); + DRIVER_RESULT_PASS(pcm_register_stream( + pcm, &pcm->record_stream, &sb16_pcm_record_ops, + &info->stream_info[1])); + DRIVER_RESULT_PASS(pcm_register_dma(pcm, NULL, NULL, &isa_dma_ops)); + + register_physical_device(phy, &sb16_device_ops); + } + } + return result; +} + +DriverResult sb16_init(void *_device) { + LogicalDevice *device = _device; + Sb16Info *info = kmalloc(sizeof(Sb16Info)); + device->private_data = info; + + // io_out8(info->ports.mixer, 0x80 /* 设置IRQ */); + // io_out8(info->ports.mixer_data, 0x02 /* IRQ5 */); + + register_device_irq( + &info->irq, device->physical_device, device->dm_ext, 5, + sb16_irq_handler, IRQ_MODE_SHARED); + + spinlock_init(&info->lock); + + memset(data_len, 0, sizeof(data_len)); + return DRIVER_OK; +} + +DriverResult sb16_start(void *_device) { + LogicalDevice *device = _device; + Sb16Info *info = (Sb16Info *)device->private_data; + enable_device_irq(info->irq); + return DRIVER_OK; +} + +DriverResult sb16_stop(void *_device) { + LogicalDevice *device = _device; + Sb16Info *info = (Sb16Info *)device->private_data; + disable_device_irq(info->irq); + return DRIVER_OK; +} + +DriverResult sb16_destroy(void *_device) { + LogicalDevice *device = _device; + Sb16Info *info = (Sb16Info *)device->private_data; + if (info->irq != NULL) { + unregister_device_irq(info->irq); + info->irq = NULL; + } + int result = kfree(info); + if (result < 0) return DRIVER_ERROR_MEMORY_FREE; + return DRIVER_OK; +} + +DriverResult sb16_set_sample_rate(Sb16Info *info, uint16_t sample_rate) { + sb16_write(&info->ports, CMD_SET_OUTPUT_SAMPLE_RATE); + sb16_write(&info->ports, (uint8_t)(sample_rate >> 8)); + sb16_write(&info->ports, (uint8_t)sample_rate); + return DRIVER_OK; +} + +DriverResult sb16_set_time_constant(Sb16Info *info, uint16_t sample_rate) { + uint16_t time_constant = 65536 - (256000000 / sample_rate); + sb16_write(&info->ports, CMD_SET_TIME_CONSTANT); + sb16_write(&info->ports, (uint8_t)(time_constant >> 8)); + sb16_write(&info->ports, (uint8_t)time_constant); + return DRIVER_OK; +} + +void sb16_setup_dma( + Sb16Info *info, uint8_t channel, uint8_t mode, uint32_t addr, + uint32_t len) { + int flags = dma_lock(); + dma_disable(channel); + dma_ff_reset(channel); + dma_set_mode(channel, mode); + dma_set_addr(channel, addr); + dma_set_count(channel, len); + dma_enable(channel); + dma_unlock(flags); +} + +DriverResult sb16_set_volume(Sb16Info *info, int volume) { + int flags = spin_lock_irqsave(&info->lock); + sb16_write(&info->ports, CMD_SET_OUTPUT_SAMPLE_RATE); + sb16_write(&info->ports, (uint8_t)(volume >> 8)); + sb16_write(&info->ports, (uint8_t)volume); + spin_unlock_irqrestore(&info->lock, flags); + return DRIVER_OK; +} + +DriverResult sb16_pcm_set_default_params(PcmStream *stream) { + stream->data_type = PCM_S16LE; + sb16_pcm_set_data_type(stream, stream->data_type); + stream->hw_mode = PCM_MODE_INTERLEAVED; + stream->user_mode = PCM_MODE_INTERLEAVED; + stream->channel = 2; + stream->pcm->data_bytes = sizeof(uint16_t); + stream->frame_bytes = sizeof(uint16_t) * stream->channel; + stream->period_bytes = 16 * 1024; + stream->frame_per_period = stream->period_bytes / stream->frame_bytes; + stream->start_threshold = 4 * 1024; + stream->stop_threshold = 1 * 1024; + return DRIVER_OK; +} + +DriverResult sb16_pcm_set_data_type(PcmStream *stream, PcmDataType type) { + struct Sb16StreamInfo *info = stream->private_data; + if (type == PCM_U16LE) { + info->data_type &= ~BIT(STEREO_BIT); + } else if (type == PCM_S16LE) { + info->data_type |= BIT(SIGNED_BIT); + } + return DRIVER_OK; +} + +DriverResult sb16_pcm_set_mode(PcmStream *stream, PcmMode mode) { + if (mode == PCM_MODE_INTERLEAVED) stream->hw_mode = mode; + else return DRIVER_ERROR_UNSUPPORT_FEATURE; + return DRIVER_OK; +} + +DriverResult sb16_pcm_set_channel(PcmStream *stream, uint8_t channel) { + struct Sb16StreamInfo *info = stream->private_data; + if (channel == 1) { + info->data_type &= ~BIT(STEREO_BIT); + } else if (channel == 2) { + info->data_type |= BIT(STEREO_BIT); + } + return DRIVER_OK; +} + +DriverResult sb16_pcm_set_sample_rate(PcmDevice *pcm, uint32_t sample_rate) { + return sb16_set_sample_rate( + pcm->sound_device->device->private_data, sample_rate); +} + +DriverResult sb16_play_open(SoundDevice *sound_device, PcmStream *stream) { + Sb16Info *info = (Sb16Info *)sound_device->device->private_data; + info->dma_channel = dma_channel_use( + sound_device->device, (int *)sb16_possible_dmas, + sizeof(sb16_possible_dmas) / sizeof(int)); + + return DRIVER_OK; +} + +DriverResult sb16_play_prepare(PcmStream *stream, void *addr, size_t size) { + Sb16Info *info = (Sb16Info *)stream->sound_device->device->private_data; + struct Sb16StreamInfo *stream_info = stream->private_data; + + sb16_setup_dma( + info, info->dma_channel, + DMA_MODE_SINGLE | DMA_MODE_AUTO | DMA_MODE_WRITE, (uint32_t)addr, size); + + uint16_t sample_count = stream->period_bytes >> 1; + sample_count--; + + int flags = spin_lock_irqsave(&info->lock); + sb16_write( + &info->ports, TRANSFER_16BIT | TRANSFER_PLAY | TRANSFER_AUTOINIT); + sb16_write(&info->ports, stream_info->data_type); + sb16_write(&info->ports, (uint8_t)sample_count); + sb16_write(&info->ports, (uint8_t)(sample_count >> 8)); + sb16_write(&info->ports, CMD_STOP_PLAY16); + spin_unlock_irqrestore(&info->lock, flags); + + return DRIVER_OK; +} + +DriverResult sb16_play_trigger(PcmStream *stream, PcmTrigger trigger) { + Sb16Info *info = (Sb16Info *)stream->sound_device->device->private_data; + switch (trigger) { + case PCM_TRIGGER_START: + case PCM_TRIGGER_RESUME: + sb16_write(&info->ports, CMD_RESUME_PLAY16); + break; + case PCM_TRIGGER_STOP: + case PCM_TRIGGER_PAUSE: + sb16_write(&info->ports, CMD_STOP_PLAY16); + break; + case PCM_TRIGGER_NONE: + return DRIVER_ERROR_OTHER; + } + return DRIVER_OK; +} + +size_t sb16_play_position(PcmStream *stream) { + Sb16Info *info = (Sb16Info *)stream->sound_device->device->private_data; + return dma_pointer(info->dma_channel, stream->pcm->buffer_bytes); +} + +DriverResult sb16_record_open(SoundDevice *sound_device, PcmStream *stream) { + Sb16Info *info = (Sb16Info *)sound_device->device->private_data; + info->dma_channel = dma_channel_use( + sound_device->device, (int *)sb16_possible_dmas, + sizeof(sb16_possible_dmas) / sizeof(int)); + + return DRIVER_OK; +} + +DriverResult sb16_record_prepare(PcmStream *stream, void *addr, size_t size) { + Sb16Info *info = (Sb16Info *)stream->sound_device->device->private_data; + struct Sb16StreamInfo *stream_info = stream->private_data; + + sb16_setup_dma( + info, info->dma_channel, + DMA_MODE_SINGLE | DMA_MODE_AUTO | DMA_MODE_READ, (uint32_t)addr, size); + + uint16_t sample_count = stream->period_bytes >> 1; + sample_count--; + + int flags = spin_lock_irqsave(&info->lock); + sb16_write( + &info->ports, TRANSFER_16BIT | TRANSFER_RECORD | TRANSFER_AUTOINIT); + sb16_write(&info->ports, stream_info->data_type); + sb16_write(&info->ports, (uint8_t)sample_count); + sb16_write(&info->ports, (uint8_t)(sample_count >> 8)); + sb16_write(&info->ports, CMD_STOP_PLAY16); + spin_unlock_irqrestore(&info->lock, flags); + + return DRIVER_OK; +} + +DriverResult sb16_record_trigger(PcmStream *stream, PcmTrigger trigger) { + Sb16Info *info = (Sb16Info *)stream->sound_device->device->private_data; + switch (trigger) { + case PCM_TRIGGER_START: + case PCM_TRIGGER_RESUME: + sb16_write(&info->ports, CMD_RESUME_PLAY16); + break; + case PCM_TRIGGER_STOP: + case PCM_TRIGGER_PAUSE: + sb16_write(&info->ports, CMD_STOP_PLAY16); + break; + case PCM_TRIGGER_NONE: + return DRIVER_ERROR_OTHER; + } + return DRIVER_OK; +} + +static void __init sb16_driver_entry(void) { + register_driver(&sb_driver); + register_device_driver(&sb_driver, &sb16_device_driver); + isa_register_device_driver(&sb16_device_driver, &sb16_isa_ops); +} + +driver_initcall(sb16_driver_entry); \ No newline at end of file diff --git a/src/arch/x86/drivers/sound/sb16/sb16.h b/src/arch/x86/drivers/sound/sb16/sb16.h new file mode 100644 index 0000000..e452ba1 --- /dev/null +++ b/src/arch/x86/drivers/sound/sb16/sb16.h @@ -0,0 +1,65 @@ +#ifndef _SB16_H +#define _SB16_H + +#include "kernel/driver_interface.h" +#include "kernel/spinlock.h" +#include "stdint.h" + +#define PORT_MIXER 0x4 +#define PORT_MIXER_DATA 0x5 +#define PORT_RESET 0x6 +#define PORT_READ 0xa +#define PORT_WRITE 0xc +#define PORT_READ_STATUS 0xe +#define PORT_IACK16 0xf + +#define CMD_SET_TIME_CONSTANT 0x40 +#define CMD_SET_OUTPUT_SAMPLE_RATE 0x41 +#define CMD_TURN_SPEAKER_ON 0xd1 +#define CMD_TURN_SPEAKER_OFF 0xd3 +#define CMD_STOP_PLAY8 0xd0 +#define CMD_RESUME_PLAY8 0xd4 +#define CMD_STOP_PLAY16 0xd5 +#define CMD_RESUME_PLAY16 0xd6 +#define CMD_GET_DSP_VERSION 0xe1 + +#define CMD_SET_VOLUME 0x22 +#define CMD_SET_IRQ 0x80 + +#define TRANSFER_16BIT 0xb0 +#define TRANSFER_8BIT 0xc0 +#define TRANSFER_PLAY 0x00 +#define TRANSFER_RECORD 0x08 +#define TRANSFER_FIFO 0x02 +#define TRANSFER_AUTOINIT 0x04 + +#define STEREO_BIT 5 +#define SIGNED_BIT 4 + +typedef struct Sb16Ports { + int mixer; + int mixer_data; + int reset; + int read; + int write; + int read_status; + int iack16; +} Sb16Ports; + +#define SB16_MAX_DMA_REGION 4 + +typedef struct Sb16Info { + Sb16Ports ports; + uint8_t major_ver; + uint8_t minor_ver; + uint8_t dma_channel; + spinlock_t lock; + + DeviceIrq *irq; + + struct Sb16StreamInfo { + uint8_t data_type; + } stream_info[2]; +} Sb16Info; + +#endif \ No newline at end of file diff --git a/src/arch/x86/drivers/timer/Makefile b/src/arch/x86/drivers/timer/Makefile new file mode 100644 index 0000000..3b044b4 --- /dev/null +++ b/src/arch/x86/drivers/timer/Makefile @@ -0,0 +1 @@ +SRC += pit.c \ No newline at end of file diff --git a/src/arch/x86/drivers/timer/config.toml b/src/arch/x86/drivers/timer/config.toml new file mode 100644 index 0000000..6a7b406 --- /dev/null +++ b/src/arch/x86/drivers/timer/config.toml @@ -0,0 +1 @@ +c = ["pit.c"] diff --git a/src/arch/x86/drivers/timer/pit.c b/src/arch/x86/drivers/timer/pit.c new file mode 100644 index 0000000..072b83e --- /dev/null +++ b/src/arch/x86/drivers/timer/pit.c @@ -0,0 +1,106 @@ +/** + * @file pit.c + * @author Ryan Wang (ryan1202@foxmail.com) + * @brief PIT(Programmable Interval Timer)驱动 + * @date 2022-07-31 + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define PIT_MAX_FREQUENCY 1193180 + +DriverResult pit_init(void *device); +TimerResult pit_set_frequency(TimerDevice *timer_device, uint32_t frequency); +DriverResult pit_start(void *device); +DriverResult pit_stop(void *device); +void pit_irq_handler(void *device); + +extern Driver core_driver; + +DeviceOps i8254_device_ops = { + .init = NULL, + .destroy = NULL, + .start = NULL, + .stop = NULL, +}; +DeviceOps pit_device_ops = { + .init = pit_init, + .destroy = NULL, + .start = pit_start, + .stop = pit_stop, +}; +TimerOps pit_timer_ops = { + .one_shot = NULL, + .set_frequency = pit_set_frequency, +}; + +DeviceDriver pit_device_driver; +PhysicalDevice *i8254_device; +TimerDevice *pit_timer_device; +DeviceIrq *pit_device_irq; + +DriverResult register_pit() { + register_device_driver(&core_driver, &pit_device_driver); + + ObjectAttr attr = device_object_attr; + DRIVER_RESULT_PASS( + create_physical_device(&i8254_device, platform_bus, &attr)); + + DRIVER_RESULT_PASS(create_timer_device( + &pit_timer_device, &pit_timer_ops, &pit_device_ops, i8254_device, + &pit_device_driver)); + + register_physical_device(i8254_device, &i8254_device_ops); + return DRIVER_OK; +} + +DriverResult pit_init(void *device) { + io_out_byte(PIT_CTRL, 0x34); + + pit_timer_device->current_frequency = 0; + pit_timer_device->min_frequency = PIT_MAX_FREQUENCY / (uint16_t)-1; + pit_timer_device->max_frequency = PIT_MAX_FREQUENCY / 1; + pit_timer_device->source_frequency = PIT_MAX_FREQUENCY; + pit_timer_device->priority = 1; + + return register_device_irq( + &pit_device_irq, i8254_device, pit_timer_device->device, PIC_PIT_IRQ, + pit_irq_handler, IRQ_MODE_EXCLUSIVE); +} + +TimerResult pit_set_frequency(TimerDevice *timer_device, uint32_t frequency) { + uint32_t divisor = PIT_MAX_FREQUENCY / frequency; + io_out_byte(PIT_CNT0, (uint8_t)(divisor & 0xff)); + io_out_byte(PIT_CNT0, (uint8_t)((divisor >> 8) & 0xff)); + return TIMER_RESULT_OK; +} + +DriverResult pit_start(void *device) { + DRIVER_RESULT_PASS(enable_device_irq(pit_device_irq)); + return DRIVER_OK; +} + +DriverResult pit_stop(void *device) { + DRIVER_RESULT_PASS(disable_device_irq(pit_device_irq)); + return DRIVER_OK; +} + +void pit_irq_handler(void *device) { + timer_irq_handler(device); +} diff --git a/src/arch/x86/drivers/usb/Makefile b/src/arch/x86/drivers/usb/Makefile index 380d31f..978216b 100644 --- a/src/arch/x86/drivers/usb/Makefile +++ b/src/arch/x86/drivers/usb/Makefile @@ -1,5 +1 @@ -SRC += hcd.c -SRC += func.c -SRC += hub.c -SRC += usb.c -SRC += hci/ \ No newline at end of file +SRC += hcd/ \ No newline at end of file diff --git a/src/arch/x86/drivers/usb/config.toml b/src/arch/x86/drivers/usb/config.toml new file mode 100644 index 0000000..24cb422 --- /dev/null +++ b/src/arch/x86/drivers/usb/config.toml @@ -0,0 +1 @@ +dir = ["hcd/"] diff --git a/src/arch/x86/drivers/usb/func.c b/src/arch/x86/drivers/usb/func.c deleted file mode 100644 index 9cacad5..0000000 --- a/src/arch/x86/drivers/usb/func.c +++ /dev/null @@ -1,227 +0,0 @@ -#include "kernel/list.h" -#include -#include -#include -#include -#include - -struct usb_device_descriptor *usb_get_device_descriptor( - usb_hcd_t *hcd, usb_device_t *device, usb_endpoint_t *ep) { - struct usb_device_descriptor *desc = - kmalloc(sizeof(struct usb_device_descriptor)); - - usb_request_t *usb_req = usb_create_request( - USB_REQ_DEVICE_TO_HOST, USB_REQ_TYPE_STANDARD, USB_REQ_RECIPIENT_DEVICE, - USB_REQ_GET_DESCRIPTOR, USB_DESC_TYPE_DEVICE, 0, 0, - USB_DESC_TYPE_DEVICE_SIZE); - usb_control_transaction_in( - hcd, device, ep, desc, usb_req, USB_DESC_TYPE_DEVICE_SIZE); - return desc; -} - -struct usb_config_descriptor *usb_get_config_descriptor( - usb_hcd_t *hcd, usb_device_t *device, usb_endpoint_t *ep) { - struct usb_config_descriptor *desc = - kmalloc(sizeof(struct usb_config_descriptor)); - - usb_request_t *usb_req = usb_create_request( - USB_REQ_DEVICE_TO_HOST, USB_REQ_TYPE_STANDARD, USB_REQ_RECIPIENT_DEVICE, - USB_REQ_GET_DESCRIPTOR, USB_DESC_TYPE_CONFIG, 0, 0, - USB_DESC_TYPE_CONFIG_SIZE); - usb_control_transaction_in( - hcd, device, ep, desc, usb_req, USB_DESC_TYPE_CONFIG_SIZE); - - uint8_t *buffer = kmalloc(desc->wTotalLength); - usb_req->wLength = desc->wTotalLength; - usb_control_transaction_in( - hcd, device, ep, buffer, usb_req, desc->wTotalLength); - - int length = desc->wTotalLength; - while (length > 0) { - uint8_t type = buffer[1]; - if (type == USB_DESC_TYPE_INTERFACE) { - struct usb_interface_descriptor *interface_desc = - (struct usb_interface_descriptor *)buffer; - usb_interface_t *interface = kmalloc(sizeof(usb_interface_t)); - - interface->interface = interface_desc->bInterfaceNumber; - interface->class = interface_desc->bInterfaceClass; - interface->subclass = interface_desc->bInterfaceSubClass; - interface->protocol = interface_desc->bInterfaceProtocol; - - list_add_tail(&interface->list, &device->interface_lh); - - } else if (type == USB_DESC_TYPE_ENDPOINT) { - struct usb_endpoint_descriptor *endpoint_desc = - (struct usb_endpoint_descriptor *)buffer; - - usb_endpoint_t *ep = usb_create_endpoint( - endpoint_desc->bEndpointAddress & 0x0f, - endpoint_desc->bmAttributes & 0x03, - endpoint_desc->bEndpointAddress >> 7, - endpoint_desc->wMaxPacketSize & 0x07ff); - - list_add_tail(&ep->list, &device->ep_lh); - } - length -= buffer[0]; - buffer += buffer[0]; - } - return desc; -} - -uint8_t usb_get_config( - usb_hcd_t *hcd, usb_device_t *device, usb_endpoint_t *ep) { - uint8_t config; - - usb_request_t *usb_req = usb_create_request( - USB_REQ_DEVICE_TO_HOST, USB_REQ_TYPE_STANDARD, USB_REQ_RECIPIENT_DEVICE, - USB_REQ_GET_CONFIGURATION, 0, 0, 0, 1); - usb_control_transaction_in(hcd, device, ep, &config, usb_req, 1); - - return config; -} - -usb_setup_status_t usb_set_config( - usb_hcd_t *hcd, usb_device_t *device, usb_endpoint_t *ep, uint8_t config) { - - usb_request_t *usb_req = usb_create_request( - USB_REQ_HOST_TO_DEVICE, USB_REQ_TYPE_STANDARD, USB_REQ_RECIPIENT_DEVICE, - USB_REQ_SET_CONFIGURATION, config, 0, 0, 0); - - return usb_control_transaction_out(hcd, device, ep, NULL, usb_req, 0); -} - -struct usb_hub_descriptor *usb_get_hub_descriptor( - usb_hcd_t *hcd, usb_device_t *device, usb_endpoint_t *ep) { - struct usb_hub_descriptor *desc = - kmalloc(sizeof(struct usb_hub_descriptor)); - - usb_request_t *usb_req = usb_create_request( - USB_REQ_DEVICE_TO_HOST, USB_REQ_TYPE_CLASS, USB_REQ_RECIPIENT_DEVICE, - USB_REQ_GET_DESCRIPTOR, USB_DESC_TYPE_HUB, 0, 0, - USB_DESC_TYPE_HUB_SIZE); - usb_control_transaction_in( - hcd, device, ep, desc, usb_req, USB_DESC_TYPE_HUB_SIZE); - return desc; -} - -uint32_t usb_get_hub_status( - usb_hcd_t *hcd, usb_device_t *device, usb_endpoint_t *ep) { - uint32_t stat; - - usb_request_t *usb_req = usb_create_request( - USB_REQ_DEVICE_TO_HOST, USB_REQ_TYPE_STANDARD, USB_REQ_RECIPIENT_DEVICE, - USB_REQ_GET_STATUS, 0, 0, 0, 4); - usb_control_transaction_in(hcd, device, ep, &stat, usb_req, 4); - return stat; -} - -uint32_t usb_get_port_status( - usb_hcd_t *hcd, usb_device_t *device, usb_endpoint_t *ep, uint8_t port) { - uint32_t stat; - - usb_request_t *usb_req = usb_create_request( - USB_REQ_DEVICE_TO_HOST, USB_REQ_TYPE_CLASS, USB_REQ_RECIPIENT_OTHER, - USB_REQ_GET_STATUS, 0, 0, port, REQ_GET_PORT_STATUS_SIZE); - usb_control_transaction_in( - hcd, device, ep, &stat, usb_req, REQ_GET_PORT_STATUS_SIZE); - return stat; -} - -struct usb_string_descriptor *usb_get_string_descriptor( - usb_hcd_t *hcd, usb_device_t *device, uint8_t index, usb_endpoint_t *ep) { - uint8_t buffer[2]; - - usb_request_t *usb_req = usb_create_request( - USB_REQ_DEVICE_TO_HOST, USB_REQ_TYPE_STANDARD, USB_REQ_RECIPIENT_DEVICE, - USB_REQ_GET_DESCRIPTOR, USB_DESC_TYPE_STRING, index, 0x0409, 2); - - usb_control_transaction_in(hcd, device, ep, buffer, usb_req, 2); - - struct usb_string_descriptor *desc = - kmalloc(sizeof(struct usb_string_descriptor) + buffer[0]); - usb_req->wLength = buffer[0]; - usb_control_transaction_in(hcd, device, ep, desc, usb_req, buffer[0]); - - return desc; -} - -usb_setup_status_t usb_set_address( - usb_hcd_t *hcd, usb_device_t *device, usb_endpoint_t *ep, - uint32_t address) { - - usb_request_t *req = usb_create_request( - USB_REQ_HOST_TO_DEVICE, USB_REQ_TYPE_STANDARD, USB_REQ_RECIPIENT_DEVICE, - USB_REQ_SET_ADDRESS, address >> 8, address & 0xff, 0, 0); - - return usb_control_transaction_out(hcd, device, ep, NULL, req, 0); -} - -usb_setup_status_t usb_set_port_feature( - usb_hcd_t *hcd, usb_device_t *device, usb_endpoint_t *ep, uint8_t port, - uint16_t feature) { - - usb_request_t *req = usb_create_request( - USB_REQ_HOST_TO_DEVICE, USB_REQ_TYPE_CLASS, USB_REQ_RECIPIENT_OTHER, - USB_REQ_SET_FEATURE, feature >> 8, feature & 0xff, port, 0); - - return usb_control_transaction_out(hcd, device, ep, NULL, req, 0); -} - -void usb_show_device_descriptor( - usb_hcd_t *hcd, usb_device_t *device, usb_endpoint_t *ep, - struct usb_device_descriptor *desc) { - printk("USB Device Descriptor:\n"); - printk("Length: %d\n", desc->bLength); - printk("DescriptorType: %d\n", desc->bDescriptorType); - printk( - "Support USB Version: %x.%02x\n", desc->bcdUSB >> 8, - desc->bcdUSB & 0xff); - printk("Device Class: %d\n", desc->bDeviceClass); - printk("Device SubClass: %d\n", desc->bDeviceSubClass); - printk("Device Protocol: %d\n", desc->bDeviceProtocol); - printk("Max Packet Size: %d\n", desc->bMaxPacketSize0); - printk("Vendor ID: %d\n", desc->idVendor); - printk("Product ID: %d\n", desc->idProduct); - printk( - "Device Version: %x.%02x\n", desc->bcdDevice >> 8, - desc->bcdDevice & 0xff); - - printk("Manufacturer: "); - struct usb_string_descriptor *str1 = - usb_get_string_descriptor(hcd, device, desc->iManufacturer, ep); - for (int i = 0; i < (str1->bLength - 2) / 2; i++) { - printk("%c", str1->wData[i]); - } - printk("\n"); - - printk("Product: "); - struct usb_string_descriptor *str2 = - usb_get_string_descriptor(hcd, device, desc->iProduct, ep); - for (int i = 0; i < (str2->bLength - 2) / 2; i++) { - printk("%c", str2->wData[i]); - } - printk("\n"); - - printk("Serial Number: "); - struct usb_string_descriptor *str3 = - usb_get_string_descriptor(hcd, device, desc->iSerialNumber, ep); - for (int i = 0; i < (str3->bLength - 2) / 2; i++) { - printk("%c", str3->wData[i]); - } - printk("\n"); - - printk("Number of Configurations: %d\n", desc->bNumConfigurations); -} - -void usb_show_hub_descriptor(struct usb_hub_descriptor *desc) { - printk("USB Hub Descriptor:\n"); - printk("Length: %d\n", desc->bLength); - printk("DescriptorType: %d\n", desc->bDescriptorType); - printk("Number of Ports: %d\n", desc->bNbrPorts); - printk("Characteristics: %d\n", desc->wHubCharacteristics); - printk("Power On To Power Good Time: %d\n", desc->bPwrOn2PwrGood); - printk("Hub Controller Current: %d\n", desc->bHubContrCurrent); - printk("Device Removable: %d\n", desc->DeviceRemovable); - printk("Port Power Control Mask: %d\n", desc->PortPwrCtrlMask); -} diff --git a/src/arch/x86/drivers/usb/hcd.c b/src/arch/x86/drivers/usb/hcd.c deleted file mode 100644 index aea7c18..0000000 --- a/src/arch/x86/drivers/usb/hcd.c +++ /dev/null @@ -1,39 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -LIST_HEAD(hcd_list); - -usb_hcd_t *usb_hcd_register( - device_t *device, char *name, uint32_t port_cnt, - usb_hcd_interface_t *interface) { - usb_hcd_t *hcd = kmalloc(sizeof(usb_hcd_t)); - if (hcd == NULL) return NULL; - - list_add_tail(&hcd->list, &hcd_list); - hcd->device = device; - hcd->device_count = 0; - - hcd->interface = interface; - - string_t *string = kmalloc(sizeof(string_t)); - string_init(string); - string_new(string, name, strlen(name)); - hcd->name = string; - - hcd->ports = kmalloc(sizeof(usb_hcd_port_t) * port_cnt); - - for (int i = 0; i < port_cnt; i++) { - hcd->ports[i].port = i; - hcd->ports[i].hcd = hcd; - hcd->ports[i].connected = 0; - } - - return hcd; -} \ No newline at end of file diff --git a/src/arch/x86/drivers/usb/hcd/Makefile b/src/arch/x86/drivers/usb/hcd/Makefile new file mode 100644 index 0000000..e027c57 --- /dev/null +++ b/src/arch/x86/drivers/usb/hcd/Makefile @@ -0,0 +1,2 @@ +SRC += hcd.c +SRC += uhci/ \ No newline at end of file diff --git a/src/arch/x86/drivers/usb/hcd/config.toml b/src/arch/x86/drivers/usb/hcd/config.toml new file mode 100644 index 0000000..9e30df0 --- /dev/null +++ b/src/arch/x86/drivers/usb/hcd/config.toml @@ -0,0 +1,2 @@ +dir = ["uhci/"] +c = ["hcd.c"] diff --git a/src/arch/x86/drivers/usb/hcd/hcd.c b/src/arch/x86/drivers/usb/hcd/hcd.c new file mode 100644 index 0000000..ad424b3 --- /dev/null +++ b/src/arch/x86/drivers/usb/hcd/hcd.c @@ -0,0 +1,12 @@ +#include +#include +#include + +Driver x86_usb_hcd_driver; + +static __init void usb_hcd_entry(void) { + register_driver(&x86_usb_hcd_driver); + return; +} + +driver_initcall(usb_hcd_entry); \ No newline at end of file diff --git a/src/arch/x86/drivers/usb/hcd/hcd.h b/src/arch/x86/drivers/usb/hcd/hcd.h new file mode 100644 index 0000000..66ff01f --- /dev/null +++ b/src/arch/x86/drivers/usb/hcd/hcd.h @@ -0,0 +1,8 @@ +#ifndef _X86_HCD_H +#define _X86_HCD_H + +#include + +extern Driver x86_usb_hcd_driver; + +#endif \ No newline at end of file diff --git a/src/arch/x86/drivers/usb/hcd/uhci/Makefile b/src/arch/x86/drivers/usb/hcd/uhci/Makefile new file mode 100644 index 0000000..eee8698 --- /dev/null +++ b/src/arch/x86/drivers/usb/hcd/uhci/Makefile @@ -0,0 +1,3 @@ +SRC += packet.c +SRC += skeleton.c +SRC += uhci.c \ No newline at end of file diff --git a/src/arch/x86/drivers/usb/hcd/uhci/config.toml b/src/arch/x86/drivers/usb/hcd/uhci/config.toml new file mode 100644 index 0000000..4d5c41a --- /dev/null +++ b/src/arch/x86/drivers/usb/hcd/uhci/config.toml @@ -0,0 +1 @@ +c = ["packet.c", "skeleton.c", "uhci.c"] diff --git a/src/arch/x86/drivers/usb/hcd/uhci/packet.c b/src/arch/x86/drivers/usb/hcd/uhci/packet.c new file mode 100644 index 0000000..6c2f8ff --- /dev/null +++ b/src/arch/x86/drivers/usb/hcd/uhci/packet.c @@ -0,0 +1,321 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DEFAULT_TD_COUNT 4 + +void *uhci_create_pipeline(UsbDevice *usb_device, UsbEndpoint *endpoint); + +void uhci_add_interrupt_transfer( + UsbHcd *hcd, UsbDevice *device, UsbEndpoint *ep, + struct UsbRequestBlock *urb); +void uhci_interrupt_transfer(UsbHcd *hcd, UsbEndpoint *ep); + +UsbHcdOps uhci_hcd_ops = { + .create_pipeline = uhci_create_pipeline, + .ctrl_transfer_in = uhci_ctrl_transfer_in, + .ctrl_transfer_out = uhci_ctrl_transfer_out, + .add_interrupt_transfer = uhci_add_interrupt_transfer, + .interrupt_transfer = uhci_interrupt_transfer, +}; + +void *uhci_create_pipeline(UsbDevice *usb_device, UsbEndpoint *endpoint) { + UhciPipeline *pipe = kmalloc(sizeof(UhciPipeline)); + pipe->qh.qe_link = UHCI_TERMINATE; + pipe->qh.qh_link = UHCI_TERMINATE; + pipe->qh.endpoint = endpoint; + + uint8_t ep_type = endpoint->desc->bmAttributes & 0x03; + if (ep_type == USB_EP_INTERRUPT) { + pipe->td_count = 2; // 1个正式TD和1个备用TD + + // 向下对齐后最大128 + int type = + aligned_down_log2n(endpoint->desc->bInterval | 1 /* 保证最小为1 */); + uhci_skel_add_qh( + usb_device->hcd->device->private_data, &pipe->qh, type); + } else if (ep_type == USB_EP_CONTROL) { + pipe->td_count = 3; // SETUP, DATA, STATUS 3个阶段 + + uhci_skel_add_qh( + usb_device->hcd->device->private_data, &pipe->qh, ASYNC); + } else { + pipe->td_count = DEFAULT_TD_COUNT; + uhci_skel_add_qh( + usb_device->hcd->device->private_data, &pipe->qh, ASYNC); + } + pipe->td_used = 0; + pipe->pre_alloc_td = kmalloc(sizeof(UhciTd) * pipe->td_count); + list_init(&pipe->pipe_lh); + + for (int i = 0; i < pipe->td_count; i++) { + pipe->pre_alloc_td[i].link = UHCI_TERMINATE; + } + return pipe; +} + +UhciTd *uhci_alloc_td(UhciPipeline *pipe) { + UhciTd *td; + int index = BIT_FFZ_R(pipe->td_used); + if (index >= pipe->td_count) { + td = kmalloc(sizeof(UhciTd)); + } else { + td = &pipe->pre_alloc_td[index]; + pipe->td_used |= (1 << index); + } + return td; +} + +void uhci_free_td(UhciPipeline *pipe, UhciTd *td) { + int index = (td - pipe->pre_alloc_td); + if (index >= 0 && index < pipe->td_count) { + pipe->td_used &= ~(1 << index); + } else { + kfree(td); + } +} + +void uhci_free_all_td(UhciPipeline *pipe) { + UhciTd *td, *next; + list_for_each_owner_safe (td, next, &pipe->pipe_lh, list) { + list_del(&td->list); + uhci_free_td(pipe, td); + } +} + +UhciTd *uhci_send_token_packet( + UsbDevice *device, UsbEndpoint *ep, UhciQh *qh, uint8_t data_toggle, + void *buffer, uint8_t packet_id, int length) { + UsbDevice *usb_device = device; + UhciPipeline *pipe = ep->pipe; + UhciTd *td = uhci_alloc_td(pipe); + memset(td, 0, sizeof(UhciTd)); + + td->packet_id = packet_id; + td->device_addr = usb_device->address & 0x7f; + td->endpoint = ep->desc->bEndpointAddress & 0x0f; + td->data_toggle = data_toggle; + td->max_length = length > 0 ? (length - 1) : 0x7ff; + td->lowspeed_device = (usb_device->speed == USB_SPEED_LOW) ? 1 : 0; + + td->active = 1; + td->actlen = 0; + + td->error_count = 3; + + if (buffer != NULL) td->buf_addr_phy = vir2phy((uint32_t)buffer); + else td->buf_addr_phy = 0; + + if (!list_empty(&pipe->pipe_lh)) { + UhciTd *last_td = list_last_owner(&pipe->pipe_lh, UhciTd, list); + list_add_tail(&td->list, &pipe->pipe_lh); + last_td->link = BIN_DIS(vir2phy((uint32_t)td), UHCI_QH_TD_SELECT); + last_td->link = BIN_EN(last_td->link, UHCI_VERTICAL_FIRST); + last_td->next = td; + } else { + list_add_tail(&td->list, &pipe->pipe_lh); + qh->first_td = td; + } + td->link = UHCI_TERMINATE; + return td; +} + +static inline UhciTd *uhci_setup_transcation( + UsbDevice *device, UsbEndpoint *ep, UhciQh *qh, void *buffer, + uint32_t length) { + return uhci_send_token_packet( + device, ep, qh, 0, buffer, USB_PACKET_ID_SETUP, length); +} + +static inline UhciTd *uhci_in_transcation( + UsbDevice *device, UsbEndpoint *ep, UhciQh *qh, int data_toggle, + void *buffer, uint32_t length) { + return uhci_send_token_packet( + device, ep, qh, data_toggle, buffer, USB_PACKET_ID_IN, length); +} + +static inline UhciTd *uhci_out_transcation( + UsbDevice *device, UsbEndpoint *ep, UhciQh *qh, int data_toggle, + void *buffer, uint32_t length) { + return uhci_send_token_packet( + device, ep, qh, data_toggle, buffer, USB_PACKET_ID_OUT, length); +} + +int uhci_wait_transfer(UhciQh *qh) { + Timer timer; + timer_init(&timer); + UhciTd *td = qh->first_td; + while (td->active) { + if (td->active == 0) { break; } + + delay_ms(&timer, 1); + } + if (!(td->crc_timeout_Error | td->bitstuff_Error | td->databuffer_Error | + td->stalled | td->NAK_received)) + return 0; + + // 发送错误 + uint32_t *raw = (uint32_t *)td; // TD 在内存首地址 + printk( + "TD raw: w0=%08x w1=%08x w2=%08x w3=%08x\n", raw[0], raw[1], raw[2], + raw[3]); + printk( + " decoded: pid=%02x dev=%u ep=%u toggle=%u maxlen=%u active=%u\n", + td->packet_id, td->device_addr, td->endpoint, td->data_toggle, + td->max_length, td->active); + printk("[UHCI]td %#08x(phy %#08x) timeout.\n", td, vir2phy((uint32_t)td)); + return -1; +} + +UsbSetupStatus uhci_ctrl_transfer_in( + UsbHcd *hcd, UsbDevice *device, void *buffer, uint32_t data_length, + UsbControlRequest *usb_req) { + UhciPipeline *pipe = device->ep0->pipe; + UhciQh *qh = &pipe->qh; + qh->qe_link = UHCI_TERMINATE; + qh->qh_link = UHCI_TERMINATE; + uhci_setup_transcation(device, device->ep0, qh, usb_req, 8); + uhci_in_transcation(device, device->ep0, qh, 0, buffer, data_length); + UhciTd *last_td = uhci_out_transcation(device, device->ep0, qh, 1, NULL, 0); + UhciTd *first_td = qh->first_td; + qh->qe_link = BIN_DIS(vir2phy((uint32_t)first_td), UHCI_QH_TD_SELECT); + + if (uhci_wait_transfer(qh) < 0) { + // 超时 + uhci_free_all_td(pipe); + return USB_SETUP_CRC_TIMEOUT_ERR; + } + qh->qe_link = UHCI_TERMINATE; + + UsbSetupStatus result; + + if (last_td->stalled) { + result = USB_SETUP_STALLED; + } else if (last_td->crc_timeout_Error) { + result = USB_SETUP_CRC_TIMEOUT_ERR; + } else if (last_td->bitstuff_Error) { + result = USB_SETUP_BITSTUFF_ERR; + } else if (last_td->databuffer_Error) { + result = USB_SETUP_DATABUFFER_ERR; + } else if (last_td->NAK_received) { + result = USB_SETUP_NAK_RECV; + } else { + result = USB_SETUP_SUCCESS; + } + uhci_free_all_td(pipe); + + return result; +} + +UsbSetupStatus uhci_ctrl_transfer_out( + UsbHcd *hcd, UsbDevice *device, void *buffer, uint32_t data_length, + UsbControlRequest *usb_req) { + UhciPipeline *pipe = device->ep0->pipe; + UhciQh *qh = &pipe->qh; + qh->qe_link = UHCI_TERMINATE; + qh->qh_link = UHCI_TERMINATE; + uhci_setup_transcation(device, device->ep0, qh, usb_req, 8); + if (data_length != 0) { + uhci_out_transcation(device, device->ep0, qh, 0, buffer, data_length); + } + UhciTd *last_td = uhci_in_transcation(device, device->ep0, qh, 1, NULL, 0); + UhciTd *first_td = qh->first_td; + qh->qe_link = BIN_DIS(vir2phy((uint32_t)first_td), UHCI_QH_TD_SELECT); + + if (uhci_wait_transfer(qh) < 0) { + // 超时 + uhci_free_all_td(pipe); + return USB_SETUP_CRC_TIMEOUT_ERR; + } + qh->qe_link = UHCI_TERMINATE; + + UsbSetupStatus result; + + if (last_td->stalled) { + result = USB_SETUP_STALLED; + } else if (last_td->crc_timeout_Error) { + result = USB_SETUP_CRC_TIMEOUT_ERR; + } else if (last_td->bitstuff_Error) { + result = USB_SETUP_BITSTUFF_ERR; + } else if (last_td->databuffer_Error) { + result = USB_SETUP_DATABUFFER_ERR; + } else if (last_td->NAK_received) { + result = USB_SETUP_NAK_RECV; + } else { + result = USB_SETUP_SUCCESS; + } + uhci_free_all_td(pipe); + + return result; +} + +void uhci_add_interrupt_transfer( + UsbHcd *hcd, UsbDevice *device, UsbEndpoint *ep, UsbRequestBlock *urb) { + UhciPipeline *pipe = ep->pipe; + UhciQh *qh = &pipe->qh; + UhciTd *td, *_td; + qh->qe_link = UHCI_TERMINATE; + if (ep->desc->bEndpointAddress >> 7 == USB_EP_IN) { + td = uhci_in_transcation( + device, ep, qh, ep->data_toggle, urb->buffer, + ep->desc->wMaxPacketSize); + _td = uhci_in_transcation( + device, ep, qh, ep->data_toggle ^ 1, urb->buffer, + ep->desc->wMaxPacketSize); + } else { + td = uhci_out_transcation( + device, ep, qh, ep->data_toggle, urb->buffer, + ep->desc->wMaxPacketSize); + _td = uhci_out_transcation( + device, ep, qh, ep->data_toggle ^ 1, urb->buffer, + ep->desc->wMaxPacketSize); + } + + UhciTd *first_td = qh->first_td; + qh->qe_link = BIN_DIS(vir2phy((uint32_t)first_td), UHCI_QH_TD_SELECT); + td->urb = urb; + _td->urb = urb; + td->interrupt_on_complete = 1; // 传输完成后中断通知 + _td->interrupt_on_complete = 0; + wmb(); +} + +void uhci_interrupt_transfer(UsbHcd *hcd, UsbEndpoint *ep) { + UhciPipeline *pipe = ep->pipe; + + UhciTd *first_td = pipe->qh.first_td; + UhciTd *next = first_td->next; + + ep->data_toggle ^= 1; + + first_td->data_toggle = ep->data_toggle; + first_td->stalled = 0; + first_td->crc_timeout_Error = 0; + first_td->bitstuff_Error = 0; + first_td->NAK_received = 0; + first_td->databuffer_Error = 0; + + first_td->active = 1; + first_td->actlen = 0; + first_td->interrupt_on_complete = 1; + + next->data_toggle = ep->data_toggle ^ 1; + next->active = 1; + + // 2. 挂回 QH + pipe->qh.qe_link = BIN_DIS(vir2phy((uint32_t)first_td), UHCI_QH_TD_SELECT); +} diff --git a/src/arch/x86/drivers/usb/hcd/uhci/skeleton.c b/src/arch/x86/drivers/usb/hcd/uhci/skeleton.c new file mode 100644 index 0000000..11d52ec --- /dev/null +++ b/src/arch/x86/drivers/usb/hcd/uhci/skeleton.c @@ -0,0 +1,102 @@ +#include +#include +#include +#include +#include + +void uhci_skel_init(Uhci *uhci) { + int i; + UhciQh *qhs; + + uhci->skel = kmalloc(sizeof(UhciSkel)); + qhs = uhci->skel->qh; + + memset32(uhci->fl.frames_vir, 1, 1024); + + uint32_t phy = vir2phy((uint32_t)&qhs[TIME_1MS]); + qhs[TIME_1MS].next = &qhs[ASYNC]; + qhs[TIME_1MS].qh_link = + BIN_EN(vir2phy((uint32_t)qhs[TIME_1MS].next), UHCI_QH_TD_SELECT); + qhs[TIME_1MS].qe_link = UHCI_TERMINATE; + for (i = 1; i < 8; i++) { + qhs[i].next = &qhs[TIME_1MS]; + qhs[i].qh_link = BIN_EN(phy, UHCI_QH_TD_SELECT); + qhs[i].qe_link = UHCI_TERMINATE; + } + qhs[ASYNC].next = &qhs[TERM]; + qhs[ASYNC].qh_link = + BIN_EN(vir2phy((uint32_t)qhs[ASYNC].next), UHCI_QH_TD_SELECT); + qhs[ASYNC].qe_link = UHCI_TERMINATE; + + // 构建结束的QH和TD + + UhciTd *term_td = (UhciTd *)kmalloc(sizeof(UhciTd)); + memset(term_td, 0, sizeof(UhciTd)); + + term_td->max_length = 0x7ff; + term_td->device_addr = 0x7f; + term_td->packet_id = USB_PACKET_ID_IN; + term_td->link = vir2phy((uint32_t)term_td); + + qhs[TERM].qh_link = UHCI_TERMINATE; + qhs[TERM].qe_link = term_td->link; + qhs[TERM].first_td = term_td; + + i = 0; + while (i < 1024) { + int irq = 1 + BIT_FFS_R(i + FRAMELIST_SIZE); + if (irq > 7) irq = 0; + + uhci->fl.frames_vir[i] = + BIN_EN(vir2phy((uint32_t)&qhs[irq]), UHCI_QH_TD_SELECT); + i++; + } +} + +void uhci_skel_add_qh(Uhci *uhci, UhciQh *qh, UhciSkelType type) { + UhciQh *first_qh = uhci->skel->qh[type].first_qh; + if (qh->enqueued) return; // 已经被添加 + if (first_qh != NULL) { + qh->qh_link = uhci->skel->qh[type].qe_link; + qh->next = first_qh; + uhci->skel->qh[type].first_qh = qh; + uhci->skel->qh[type].qe_link = + BIN_EN(vir2phy((uint32_t)qh), UHCI_QH_TD_SELECT); + } else { + qh->qh_link = UHCI_TERMINATE; + uhci->skel->qh[type].qe_link = + BIN_EN(vir2phy((uint32_t)qh), UHCI_QH_TD_SELECT); + } + qh->enqueued = 1; + uhci->skel->qh[type].first_qh = qh; +} + +void uhci_skel_del_qh(Uhci *uhci, UhciQh *qh, UhciSkelType type) { + UhciQh *_qh, *prev = NULL; + UhciQh *ptr = uhci->skel->qh[type].first_qh; + while (ptr != NULL) { + _qh = ptr; + if (_qh == qh) { + // Found the QH to delete + if (prev != NULL) { + prev->next = qh->next; + prev->qh_link = qh->qh_link; + } else if (qh->next != NULL) { + uhci->skel->qh[type].first_qh = qh->next; + uhci->skel->qh[type].qe_link = + BIN_EN(vir2phy((uint32_t)qh->next), UHCI_QH_TD_SELECT); + } else { + uhci->skel->qh[type].qe_link = UHCI_TERMINATE; + } + _qh->qh_link = UHCI_TERMINATE; + _qh->next = 0; + break; + } + prev = _qh; + ptr = _qh->next; + } + qh->qe_link = UHCI_TERMINATE; + if (qh->first_td != NULL) uhci_free_all_td((UhciPipeline *)qh); + qh->first_td = NULL; + qh->enqueued = 0; +} \ No newline at end of file diff --git a/src/arch/x86/drivers/usb/hcd/uhci/uhci.c b/src/arch/x86/drivers/usb/hcd/uhci/uhci.c new file mode 100644 index 0000000..daf9c74 --- /dev/null +++ b/src/arch/x86/drivers/usb/hcd/uhci/uhci.c @@ -0,0 +1,431 @@ +/** + * @file uhci.c + * @author Ryan Wang (Ryan1202@foxmail.com) + * @brief UHCI驱动程序 + * @version 0.1 + * @date 2022-09-10 + * + * 目前仅仅只是初始化了UHCI而已,其他涉及USB协议的东西都还没做 + * + */ +#include "../hcd.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern bool usb_legacy_support_disabled; + +#define UHCI_CLASSID 0x0c +#define UHCI_SUBCLASSID 0x03 +#define UHCI_PROGIF 0x00 + +#define DRV_NAME "Universal Serial Bus(USB) Driver" +#define DEV_NAME "UHCI" +#define DEV_FULL_NAME "Universal Host Controller Interface(UHCI)" + +extern UsbHcdOps uhci_hcd_ops; + +uint32_t uhci_get_hub_status(UsbHub *hub); +uint32_t uhci_get_port_status(UsbHub *hub, uint8_t port); +UsbSetupStatus uhci_clear_port_feature( + UsbHub *hub, uint8_t port, uint16_t feature); +UsbSetupStatus uhci_set_port_feature( + UsbHub *hub, uint8_t port, uint16_t feature); +void uhci_register(Driver *driver); +DriverResult uhci_init(void *_device); +DriverResult uhci_start(void *_device); +DriverResult uhci_pci_probe( + PciDevice *pci_device, PhysicalDevice *physical_device); +void uhci_port_reset(Uhci *uhci, int port); +void uhci_port_init(UsbHub *hub, UsbHcd *hcd, int port); + +PciDriverOps uhci_pci_driver_ops = { + .probe = uhci_pci_probe, +}; +DeviceOps uhci_logical_device_ops = { + .init = NULL, + .start = NULL, + .destroy = NULL, + .stop = NULL, +}; +DeviceOps uhci_device_ops = { + .init = uhci_init, + .start = uhci_start, + .destroy = NULL, + .stop = NULL, +}; +UsbHubOps uhci_root_hub_ops = { + .init = NULL, + .clear_port_feature = uhci_clear_port_feature, + .set_port_feature = uhci_set_port_feature, + .get_hub_status = uhci_get_hub_status, + .get_port_status = uhci_get_port_status, +}; + +DeviceDriver uhci_device_driver; +PciDriver uhci_pci_driver = { + .driver = &usb_driver, + .device_driver = &uhci_device_driver, + .find_type = FIND_BY_CLASSCODE_SUBCLASS_PROGIF, + .class_subclass_progif = {UHCI_CLASSID, UHCI_SUBCLASSID, UHCI_PROGIF}, + .ops = &uhci_pci_driver_ops, +}; + +void uhci_handler(void *arg) { + Uhci *uhci = arg; + UhciQh *qhs = uhci->skel->qh, *qh; + + // 清除UHCI状态寄存器 + uint16_t status = io_in_word(uhci->io_base + UHCI_REG_STS); + if (status == 0) return; + if (status & UHCI_STAT_INTERRUPT) { + io_out_word(uhci->io_base + UHCI_REG_STS, UHCI_STAT_INTERRUPT); + } + if (status & UHCI_STAT_ERROR_INT) { + print_error("UHCI", "Error Interrupt"); + io_out_word(uhci->io_base + UHCI_REG_STS, UHCI_STAT_ERROR_INT); + } + if (status & UHCI_STAT_RESUME_DETECT) { + print_error("UHCI", "Resume Detect"); + io_out_word(uhci->io_base + UHCI_REG_STS, UHCI_STAT_RESUME_DETECT); + } + if (status & UHCI_STAT_HOST_SYSTEM_ERROR) { + print_error("UHCI", "Host System Error"); + io_out_word(uhci->io_base + UHCI_REG_STS, UHCI_STAT_HOST_SYSTEM_ERROR); + } + if (status & UHCI_STAT_HC_PROCESS_ERROR) { + print_error("UHCI", "HC Process Error"); + io_out_word(uhci->io_base + UHCI_REG_STS, UHCI_STAT_HC_PROCESS_ERROR); + } + if (status & UHCI_STAT_HC_HALTED) { + print_error("UHCI", "HC Halted"); + io_out_word(uhci->io_base + UHCI_REG_STS, UHCI_STAT_HC_HALTED); + } + + for (int i = 0; i < UHCI_SKEL_QH_COUNT; i++) { + if (qhs[i].qe_link == UHCI_TERMINATE) continue; + if (!(qhs[i].qe_link & UHCI_QH_TD_SELECT)) continue; + // 每一个Endpoint都有一个对应的QH,这个QH下只有TD + qh = (UhciQh *)qhs[i].first_qh; + if (qh->endpoint == NULL) continue; + while (qh != NULL && qh->first_td != NULL) { + UhciTd *td = (UhciTd *)qh->first_td; + qh = qh->next; + while (td != NULL) { + if (td->active || !td->interrupt_on_complete) { + td = td->next; + continue; + } + // 传输完成 + td->interrupt_on_complete = 0; + if (td->urb != NULL) { + td->urb->actual_len += td->actlen; + td->urb->status = + td->stalled ? USB_STATUS_STALL + : (td->crc_timeout_Error | td->bitstuff_Error | + td->databuffer_Error) + ? USB_STATUS_ERR + : td->NAK_received ? USB_STATUS_NAK + : USB_STATUS_ACK; + list_add_tail(&td->urb->list, &urb_lh); + pending_softirq(); + } + td = td->next; + } + } + } +} + +UsbSetupStatus uhci_clear_port_feature( + UsbHub *hub, uint8_t port, uint16_t feature) { + UsbHcd *hcd = hub->hcd; + Uhci *uhci = (Uhci *)hcd->device->private_data; + uint32_t io_port = uhci->io_base + UHCI_PORTSC1 + port * 2; + uint16_t value = io_in_word(io_port); + switch (feature) { + case HUB_FEAT_PORT_ENABLE: + io_out_word(io_port, BIN_DIS(value, UHCI_PORT_SC_ENABLE)); + break; + case HUB_FEAT_C_PORT_CONNECTION: + io_out_word(io_port, BIN_EN(value, UHCI_PORT_SC_CONN_CHG)); + break; + case HUB_FEAT_C_PORT_ENABLE: + io_out_word(io_port, BIN_EN(value, UHCI_PORT_SC_EN_CHG)); + break; + case HUB_FEAT_C_PORT_RESET: + io_out_word(io_port, BIN_DIS(value, UHCI_PORT_SC_RESET)); + break; + default: + return USB_SETUP_STALLED; + } + return USB_SETUP_SUCCESS; +} + +uint32_t uhci_get_hub_status(UsbHub *hub) { + return 0b00; +} + +uint32_t uhci_get_port_status(UsbHub *hub, uint8_t port) { + UsbHcd *hcd = hub->hcd; + Uhci *uhci = (Uhci *)hcd->device->private_data; + uint32_t io_port = uhci->io_base + UHCI_PORTSC1 + port * 2; + uint16_t uhci_port_status = io_in_word(io_port); + uint16_t usb_port_status; + + usb_port_status = (uhci_port_status & UHCI_PORT_SC_CONNECTED) | + (uhci_port_status & UHCI_PORT_SC_ENABLE) >> 1 | + (uhci_port_status & UHCI_PORT_SC_SUSPEND) >> 10 | + (uhci_port_status & UHCI_PORT_SC_RESET) >> 5 | + USB_PORT_STAT_POWER | + (uhci_port_status & UHCI_PORT_SC_LOWSPEED); + return usb_port_status; +} + +UsbSetupStatus uhci_set_port_feature( + UsbHub *hub, uint8_t port, uint16_t feature) { + UsbHcd *hcd = hub->hcd; + Uhci *uhci = (Uhci *)hcd->device->private_data; + uint32_t io_port = uhci->io_base + UHCI_PORTSC1 + port * 2; + uint16_t value = io_in_word(io_port); + switch (feature) { + case HUB_FEAT_PORT_RESET: + uhci_port_reset(uhci, port); + break; + case HUB_FEAT_PORT_SUSPEND: + io_out_word(io_port, BIN_EN(value, UHCI_PORT_SC_SUSPEND)); + break; + case HUB_FEAT_PORT_POWER: + break; + default: + return USB_SETUP_STALLED; + } + return USB_SETUP_SUCCESS; +} + +void uhci_reset(Uhci *uhci) { + // io_out16(uhci->io_base+UHCI_REG_USBINTR, 0); //禁用UHCI的所有中断 + io_out_word( + uhci->io_base + UHCI_REG_CMD, UHCI_CMD_GLBRESET | UHCI_CMD_HCRESET); + delay_ms(&uhci->timer, 10); + io_out_word(uhci->io_base + UHCI_REG_CMD, 0); + + for (int i = 2; i < uhci->port_cnt; i++) // 逐个检测是否有效 + { + uint16_t value = io_in_word(UHCI_PORTSC1 + i * 2); + if (((value & 0x80) == 0) || value == 0xffff) { + uhci->port_cnt = i; + break; + } + } +} + +void uhci_port_reset(Uhci *uhci, int port) { + // 重置 + uint32_t io_port = uhci->io_base + UHCI_PORTSC1 + port * 2; + + uint16_t value = io_in_word(io_port); + io_out_word(io_port, BIN_EN(value, UHCI_PORT_SC_RESET)); + + delay_ms(&uhci->timer, 10); + + value = io_in_word(io_port); + io_out_word(io_port, BIN_DIS(value, UHCI_PORT_SC_RESET)); + do { + value = io_in_word(io_port); + } while (BIN_IS_EN(value, UHCI_PORT_SC_RESET)); + + delay_ms(&uhci->timer, 10); + + if (value & UHCI_PORT_SC_CONNECTED) { + io_out_word(io_port, BIN_EN(value, UHCI_PORT_SC_ENABLE)); + } + // 使能 + value = io_in_word(io_port); + io_out_word( + io_port, BIN_EN(value, UHCI_PORT_SC_CONN_CHG | UHCI_PORT_SC_EN_CHG)); + io_in_word(io_port); + + delay_ms(&uhci->timer, 10); +} + +void uhci_port_init(UsbHub *hub, UsbHcd *hcd, int port) { + Uhci *uhci = (Uhci *)hcd->device->private_data; + uint32_t io_port = uhci->io_base + UHCI_PORTSC1 + port * 2; + UsbHcdPort *hcd_port = &hcd->ports[port]; + + // 获取端口信息 + uint32_t port_status = io_in_word(io_port); + + // 重置端口,注册设备 + if (BIN_IS_EN(port_status, UHCI_PORT_SC_CONNECTED)) { + UsbDeviceSpeed speed = BIN_IS_EN(port_status, UHCI_PORT_SC_LOWSPEED) + ? USB_SPEED_LOW + : USB_SPEED_FULL; + printk("[UHCI]port %d connected.\n", port); + + uhci_port_reset(uhci, port); + + usb_probe_device(hcd, hub, speed); + } + + // 输出端口信息 + port_status = io_in_word(io_port); + hcd_port->connected = BIN_IS_EN(port_status, UHCI_PORT_SC_CONNECTED); + hcd_port->enable = BIN_IS_EN(port_status, UHCI_PORT_SC_ENABLE); + hcd_port->suspend = BIN_IS_EN(port_status, UHCI_PORT_SC_SUSPEND); + + printk( + "[UHCI]suspend: %d, enable: %d, connected: %d,", hcd_port->suspend, + hcd_port->enable, hcd_port->connected); + printk( + "speed: %s\n", BIN_IS_EN(port_status, UHCI_PORT_SC_LOWSPEED) + ? "LowSpeed" + : "FullSpeed"); +} + +DriverResult uhci_init(void *_device) { + PhysicalDevice *device = _device; + Uhci *uhci = device->private_data; + + timer_init(&uhci->timer); + uhci_reset(uhci); + uint16_t intr = io_in_word(uhci->io_base + UHCI_REG_USBINTR); + intr |= UHCI_INTR_SPI | UHCI_INTR_IOC | UHCI_INTR_RESUME | UHCI_INTR_CRC; + io_out_word(uhci->io_base + UHCI_REG_USBINTR, intr); + + return DRIVER_OK; +} + +void uhci_probe_thread(void *arg) { + Uhci *uhci = (Uhci *)arg; + + UsbHub *hub = kmalloc(sizeof(UsbHub)); + hub->usb_device = NULL; + hub->hcd = uhci->hcd; + hub->ops = &uhci_root_hub_ops; + + struct UsbHubDescriptor *desc = kmalloc(sizeof(struct UsbHubDescriptor)); + hub->desc = desc; + desc->bLength = 9; + desc->bDescriptorType = USB_DESC_TYPE_HUB; + desc->bNbrPorts = uhci->port_cnt; + desc->wHubCharacteristics = HOST2LE_WORD(0x0009); // 无电源开关,单独供电 + desc->bPwrOn2PwrGood = 0; + desc->bHubContrCurrent = 0; + memset(&desc->DeviceRemovable, 0xff, 8); // 都是可移除的 + memset(&desc->PortPwrCtrlMask, 0xff, 8); // 都是电源控制的 + + for (int i = 0; i < uhci->port_cnt; i++) { + uhci_port_init(hub, uhci->hcd, i); + } +} + +void uhci_probe(Uhci *uhci) { + // 通过独立线程初始化,避免usb初始化长时间的等待导致系统阻塞 + thread_start( + "UHCI Probe", THREAD_DEFAULT_PRIO, uhci_probe_thread, uhci, NULL); +} + +DriverResult uhci_start(void *_device) { + PhysicalDevice *device = _device; + Uhci *uhci = device->private_data; + uhci->fl.frames_vir = (uint32_t *)kernel_alloc_pages(1); + uhci->fl.frames_phy = (uint32_t *)vir2phy((uint32_t)uhci->fl.frames_vir); + uhci_skel_init(uhci); + + pci_device_write16(uhci->device, UHCI_PCI_REG_LEGSUP, 0x2000); + pci_enable_bus_mastering(uhci->device); + + usb_legacy_support_disabled = true; + + io_out_word(uhci->io_base + UHCI_FRNUM, 0); + io_out_dword(uhci->io_base + UHCI_FRBASEADD, (uint32_t)uhci->fl.frames_phy); + + uint16_t cmd = io_in_word(uhci->io_base + UHCI_REG_CMD); + io_out_word(uhci->io_base + UHCI_REG_CMD, cmd | UHCI_CMD_RUN); + + uhci_probe(uhci); + + register_device_irq( + &uhci->irq, device, uhci, uhci->device->irqline, uhci_handler, + IRQ_MODE_SHARED); + + enable_device_irq(uhci->irq); + + return DRIVER_OK; +} + +DriverResult uhci_pci_probe( + PciDevice *pci_device, PhysicalDevice *physical_device) { + uint32_t io_base = pci_device->common.bar[4].base_addr & 0xfffffff0; + if (io_base == 0) { return DRIVER_ERROR_UNSUPPORT_DEVICE; } + + uint8_t port_cnt = (pci_device->common.bar[4].length - UHCI_PORTSC1) / 2; + + uint16_t status; + for (int i = 0; i < port_cnt; i++) { + status = io_in_word(io_base + UHCI_PORTSC1 + i * 2); + if ((status & 0x80) == 0 || status == 0xffff) { + port_cnt = i; + break; + } + } + + DriverResult result; + + Uhci *uhci = kmalloc(sizeof(Uhci)); + uhci->device = pci_device; + uhci->io_base = io_base; + uhci->port_cnt = port_cnt; + + result = usb_create_hcd( + &uhci->hcd, port_cnt, &uhci_hcd_ops, &uhci_logical_device_ops, + physical_device, &uhci_device_driver); + if (result != DRIVER_OK) { + kfree(uhci); + return result; + } + + usb_legacy_support_disabled = false; // 发现USB控制器,让8042驱动等待 + + LogicalDevice *logical_device = uhci->hcd->device; + logical_device->private_data = uhci; + physical_device->private_data = uhci; + + register_physical_device(physical_device, &uhci_device_ops); + + return DRIVER_OK; +} + +static __init void uhci_driver_entry(void) { + register_device_driver(&x86_usb_hcd_driver, &uhci_device_driver); + pci_register_driver(&x86_usb_hcd_driver, &uhci_pci_driver); +} + +driver_initcall(uhci_driver_entry); \ No newline at end of file diff --git a/src/arch/x86/drivers/usb/hci/Makefile b/src/arch/x86/drivers/usb/hci/Makefile deleted file mode 100644 index 01d0702..0000000 --- a/src/arch/x86/drivers/usb/hci/Makefile +++ /dev/null @@ -1,2 +0,0 @@ -SRC += uhci/ -SRC += uhci.c \ No newline at end of file diff --git a/src/arch/x86/drivers/usb/hci/uhci.c b/src/arch/x86/drivers/usb/hci/uhci.c deleted file mode 100644 index cf598df..0000000 --- a/src/arch/x86/drivers/usb/hci/uhci.c +++ /dev/null @@ -1,207 +0,0 @@ -/** - * @file uhci.c - * @author Ryan Wang (Ryan1202@foxmail.com) - * @brief UHCI驱动程序 - * @version 0.1 - * @date 2022-09-10 - * - * 目前仅仅只是初始化了UHCI而已,其他涉及USB协议的东西都还没做 - * - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define UHCI_CLASSID 0x0c -#define UHCI_SUBCLASSID 0x03 -#define UHCI_PROGIF 0x00 - -#define DRV_NAME "Universal Serial Bus(USB) Driver" -#define DEV_NAME "Universal Host Controller Interface(UHCI)" - -static status_t uhci_enter(driver_t *drv_obj); -static status_t uhci_exit(driver_t *drv_obj); - -extern usb_hcd_interface_t uhci_interface; - -driver_func_t uhci_driver = { - .driver_enter = uhci_enter, - .driver_exit = uhci_exit, - .driver_open = NULL, - .driver_close = NULL, - .driver_read = NULL, - .driver_write = NULL, - .driver_devctl = NULL}; - -void uhci_port_reset(uhci_t *devext, int port); -void uhci_port_init(usb_hcd_t *hcd, int port); - -void uhci_handler(int irq) { - return; -} - -void uhci_print_status(uhci_t *devext) { - uint16_t status = io_in16(devext->io_base + UHCI_REG_STS); - printk("\n[UHCI]Status:\n"); - if (status & 0x20) { printk("[UHCI]HCHalted.\n"); } - if (status & 0x10) { printk("[UHCI]HC Process Error.\n"); } - if (status & 0x08) { printk("[UHCI]Host System Error.\n"); } - if (status & 0x04) { printk("[UHCI]Resume Detect.\n"); } - printk("[UHCI]Error Int:%d\n", status & 0x02); - printk("[UHCI]Interrupt:%d\n", status & 0x01); -} - -void uhci_reset(uhci_t *devext) { - int i; - - // io_out16(devext->io_base+UHCI_REG_USBINTR, 0); //禁用UHCI的所有中断 - io_out16(devext->io_base + UHCI_REG_CMD, UHCI_CMD_GLBRESET); - delay(50 / 10); // 至少50ms - io_out16(devext->io_base + UHCI_REG_CMD, 0); - - devext->port_cnt = - (devext->device->bar[4].length - UHCI_PORTSC1) / 2; // 有多少接口 - for (i = 2; i < devext->port_cnt; i++) // 逐个检测是否有效 - { - uint16_t value = io_in16(UHCI_PORTSC1 + i * 2); - if (((value & 0x80) == 0) || value == 0xffff) { - devext->port_cnt = i; - break; - } - } -} - -static status_t uhci_enter(driver_t *drv_obj) { - device_t *devobj; - uhci_t *devext; - - device_create(drv_obj, sizeof(uhci_t), DEV_NAME, DEV_USB, &devobj); - devext = devobj->device_extension; - - devext->device = - pci_get_device_ByClassFull(UHCI_CLASSID, UHCI_SUBCLASSID, UHCI_PROGIF); - if (devext->device == NULL) { - printk(COLOR_YELLOW "\n[UHCI]Cannot find UHCI controller!\n"); - device_delete(devobj); - return NODEV; - } - printk("UHCI\n"); - - devext->io_base = devext->device->bar[4].base_addr & 0xfffffff0; - - pci_enable_bus_mastering(devext->device); - pci_enable_io_space(devext->device); - - uhci_reset(devext); - uint16_t intr = io_in16(devext->io_base + UHCI_REG_USBINTR); - io_out16( - devext->io_base + UHCI_REG_USBINTR, - intr | UHCI_INTR_SPI | UHCI_INTR_IOC | UHCI_INTR_RESUME | - UHCI_INTR_CRC); - devext->fl.frames_vir = (uint32_t *)kernel_alloc_pages(1); - devext->fl.frames_phy = - (uint32_t *)vir2phy((uint32_t)devext->fl.frames_vir); - uhci_skel_init(devext); - - io_out16(devext->io_base + UHCI_FRNUM, 0); - io_out32(devext->io_base + UHCI_FRBASEADD, (uint32_t)devext->fl.frames_phy); - - uint16_t cmd = io_in16(devext->io_base + UHCI_REG_CMD); - io_out16(devext->io_base + UHCI_REG_CMD, cmd | UHCI_CMD_RUN); - - usb_hcd_t *hcd = - usb_hcd_register(devobj, DEV_NAME, devext->port_cnt, &uhci_interface); - - int i; - for (i = 0; i < devext->port_cnt; i++) { - uhci_port_init(hcd, i); - } - - return SUCCUESS; -} - -void uhci_port_reset(uhci_t *devext, int port) { - // 重置 - uint32_t io_port = devext->io_base + UHCI_PORTSC1 + port * 2; - - io_out16(io_port, UHCI_PORT_SC_RESET); - delay(50 / 10); - uint32_t value = io_in16(io_port); - io_out16(io_port, BIN_DIS(value, UHCI_PORT_SC_RESET)); - do { - value = io_in16(io_port); - } while (BIN_IS_EN(value, UHCI_PORT_SC_RESET)); - delay(10 / 10); - - // 使能 - io_out16( - io_port, - UHCI_PORT_SC_CONN_CHG | UHCI_PORT_SC_EN_CHG | UHCI_PORT_SC_ENABLE); - io_in16(io_port); - delay(10 / 10); -} - -void uhci_port_init(usb_hcd_t *hcd, int port) { - uhci_t *devext = (uhci_t *)hcd->device->device_extension; - uint32_t io_port = devext->io_base + UHCI_PORTSC1 + port * 2; - usb_hcd_port_t *hcd_port = &hcd->ports[port]; - - // 获取端口信息 - uint32_t port_status = io_in16(io_port); - - // 重置端口,注册设备 - if (BIN_IS_EN(port_status, UHCI_PORT_SC_CONNECTED)) { - usb_device_t *usb_device = usb_create_device( - BIN_IS_EN(port_status, UHCI_PORT_SC_LOWSPEED) ? USB_SPEED_LOW - : USB_SPEED_FULL, - 0); - - uhci_port_reset(devext, port); - - usb_init_device(hcd, usb_device); - } - - // 输出端口信息 - port_status = io_in16(io_port); - hcd_port->connected = BIN_IS_EN(port_status, UHCI_PORT_SC_CONNECTED); - hcd_port->enable = BIN_IS_EN(port_status, UHCI_PORT_SC_ENABLE); - hcd_port->suspend = BIN_IS_EN(port_status, UHCI_PORT_SC_SUSPEND); - - printk("[UHCI]port %d reset. status: %04x\n", port, port_status); - printk( - "[UHCI]suspend: %d, enable: %d, connected: %d,", hcd_port->suspend, - hcd_port->enable, hcd_port->connected); - printk( - "speed: %s\n", BIN_IS_EN(port_status, UHCI_PORT_SC_LOWSPEED) - ? "LowSpeed" - : "FullSpeed"); -} - -static status_t uhci_exit(driver_t *drv_obj) { - device_t *devobj, *next; - 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 uhci_driver_entry(void) { - if (driver_create(uhci_driver, DRV_NAME) < 0) { - printk(COLOR_RED "[driver] %s driver create failed!\n", __func__); - } -} - -driver_initcall(uhci_driver_entry); \ No newline at end of file diff --git a/src/arch/x86/drivers/usb/hci/uhci/Makefile b/src/arch/x86/drivers/usb/hci/uhci/Makefile deleted file mode 100644 index 85f66dc..0000000 --- a/src/arch/x86/drivers/usb/hci/uhci/Makefile +++ /dev/null @@ -1,2 +0,0 @@ -SRC += packet.c -SRC += skeleton.c \ No newline at end of file diff --git a/src/arch/x86/drivers/usb/hci/uhci/packet.c b/src/arch/x86/drivers/usb/hci/uhci/packet.c deleted file mode 100644 index b07eb23..0000000 --- a/src/arch/x86/drivers/usb/hci/uhci/packet.c +++ /dev/null @@ -1,154 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -usb_hcd_interface_t uhci_interface = { - .control_transaction_in = uhci_control_transaction_in, - .control_transaction_out = uhci_control_transaction_out, -}; - -void uhci_send_token_packet( - usb_transfer_t *transfer, uhci_qh_t *qh, uint8_t data_toggle, void *buffer, - uint8_t packet_id, int length) { - usb_device_t *usb_device = transfer->device; - uhci_td_t *td = kmalloc(sizeof(uhci_td_t)); - - td->packet_id = packet_id; - td->device_addr = usb_device->address & 0x7f; - td->endpoint = transfer->ep->endpoint & 0x0f; - td->data_toggle = data_toggle; - td->max_length = length - 1; - - td->active = 1; - td->actlen = 0; - - td->td_addr_phy = vir2phy((uint32_t)td); - - if (buffer != NULL) { td->buf_addr_phy = vir2phy((uint32_t)buffer); } - - td->prev_ptr = qh->last_ptr; - uhci_td_t *last_td = (uhci_td_t *)qh->last_ptr; - if (last_td != NULL) { - last_td->link = BIN_EN( - BIN_DIS(td->td_addr_phy, UHCI_QH_TD_SELECT), UHCI_VERTICAL_FIRST); - } else { - qh->qe_link = BIN_DIS(td->td_addr_phy, UHCI_QH_TD_SELECT); - } - td->link = UHCI_TERMINATE; - - qh->last_ptr = (uint32_t)td; -} - -int uhci_setup_packet( - usb_device_t *device, usb_transfer_t *transfer, uhci_qh_t *qh, void *buffer, - uint32_t length) { - uhci_send_token_packet( - transfer, qh, 0, buffer, USB_PACKET_ID_SETUP, length); - return 0; -} - -int uhci_in_packet( - usb_device_t *device, usb_transfer_t *transfer, uhci_qh_t *qh, void *buffer, - uint32_t length) { - uhci_send_token_packet(transfer, qh, 1, buffer, USB_PACKET_ID_IN, length); - return 0; -} - -int uhci_out_packet( - usb_device_t *device, usb_transfer_t *transfer, uhci_qh_t *qh, void *buffer, - uint32_t length) { - uhci_send_token_packet(transfer, qh, 1, buffer, USB_PACKET_ID_OUT, length); - return 0; -} - -int uhci_wait_transfer(uhci_qh_t *qh) { - int timeout = 150; - uhci_td_t *td = (uhci_td_t *)qh->last_ptr; - while (timeout > 0) { - if (td->active == 0) { return 1; } - - delay(10 / 10); - timeout--; - } - printk("[UHCI]td %#08x(phy %#08x) timeout.", td, td->td_addr_phy); - return -1; -} - -usb_setup_status_t uhci_control_transaction_in( - usb_hcd_t *hcd, usb_device_t *device, usb_transfer_t *transfer, - void *buffer, uint32_t data_length, usb_request_t *usb_req) { - uhci_qh_t *qh = kmalloc(sizeof(uhci_qh_t)); - qh->qh_addr_phy = vir2phy((uint32_t)qh); - qh->qe_link = UHCI_TERMINATE; - qh->qh_link = UHCI_TERMINATE; - uhci_setup_packet(device, transfer, qh, usb_req, 8); - uhci_in_packet(device, transfer, qh, buffer, data_length); - uhci_out_packet(device, transfer, qh, NULL, 0x800); - - uhci_skel_add_qh(hcd->device->device_extension, qh, LOW_SPEED); - uhci_wait_transfer(qh); - - uhci_td_t *last_td = (uhci_td_t *)qh->last_ptr; - usb_setup_status_t result; - - if (last_td->stalled) { - result = USB_SETUP_STALLED; - } else if (last_td->crc_timeout_Error) { - result = USB_SETUP_CRC_TIMEOUT_ERR; - } else if (last_td->bitstuff_Error) { - result = USB_SETUP_BITSTUFF_ERR; - } else if (last_td->databuffer_Error) { - result = USB_SETUP_DATABUFFER_ERR; - } else if (last_td->NAK_received) { - result = USB_SETUP_NAK_RECV; - } else { - result = USB_SETUP_SUCCESS; - } - uhci_skel_del_qh(hcd->device->device_extension, qh, LOW_SPEED); - - return result; -} - -usb_setup_status_t uhci_control_transaction_out( - usb_hcd_t *hcd, usb_device_t *device, usb_transfer_t *transfer, - void *buffer, uint32_t data_length, usb_request_t *usb_req) { - uhci_qh_t *qh = kmalloc(sizeof(uhci_qh_t)); - qh->qh_addr_phy = vir2phy((uint32_t)qh); - qh->qe_link = UHCI_TERMINATE; - qh->qh_link = UHCI_TERMINATE; - uhci_setup_packet(device, transfer, qh, usb_req, 8); - if (data_length != 0) { - uhci_out_packet(device, transfer, qh, buffer, data_length); - } - uhci_in_packet(device, transfer, qh, NULL, 0x800); - - uhci_skel_add_qh(hcd->device->device_extension, qh, LOW_SPEED); - uhci_wait_transfer(qh); - - uhci_td_t *last_td = (uhci_td_t *)qh->last_ptr; - usb_setup_status_t result; - - if (last_td->stalled) { - result = USB_SETUP_STALLED; - } else if (last_td->crc_timeout_Error) { - result = USB_SETUP_CRC_TIMEOUT_ERR; - } else if (last_td->bitstuff_Error) { - result = USB_SETUP_BITSTUFF_ERR; - } else if (last_td->databuffer_Error) { - result = USB_SETUP_DATABUFFER_ERR; - } else if (last_td->NAK_received) { - result = USB_SETUP_NAK_RECV; - } else { - result = USB_SETUP_SUCCESS; - } - uhci_skel_del_qh(hcd->device->device_extension, qh, LOW_SPEED); - - return result; -} diff --git a/src/arch/x86/drivers/usb/hci/uhci/skeleton.c b/src/arch/x86/drivers/usb/hci/uhci/skeleton.c deleted file mode 100644 index 0933721..0000000 --- a/src/arch/x86/drivers/usb/hci/uhci/skeleton.c +++ /dev/null @@ -1,100 +0,0 @@ -#include "stdint.h" -#include -#include -#include - -void uhci_skel_init(uhci_t *devext) { - int i; - - struct uhci_qh *qhs; - - devext->skel = kmalloc(sizeof(struct uhci_skel)); - qhs = devext->skel->qh; - - memset32(devext->fl.frames_vir, 1, 1024); - - qhs[TIME_1MS].qh_addr_phy = vir2phy((uint32_t)&qhs[TIME_1MS]); - qhs[TIME_1MS].next_ptr = (uint32_t)&qhs[LOW_SPEED]; - qhs[TIME_1MS].qh_link = - BIN_EN(vir2phy(qhs[TIME_1MS].next_ptr), UHCI_QH_TD_SELECT); - qhs[TIME_1MS].qe_link = UHCI_TERMINATE; - for (i = 1; i < 8; i++) { - qhs[i].qh_addr_phy = vir2phy((uint32_t)&qhs[i]); - qhs[i].next_ptr = (uint32_t)&qhs[TIME_1MS]; - qhs[i].qh_link = BIN_EN(qhs[TIME_1MS].qh_addr_phy, UHCI_QH_TD_SELECT); - qhs[i].qe_link = UHCI_TERMINATE; - } - qhs[LOW_SPEED].qh_addr_phy = vir2phy((uint32_t)&qhs[LOW_SPEED]); - qhs[LOW_SPEED].next_ptr = (uint32_t)&qhs[TERM]; - qhs[LOW_SPEED].qh_link = - BIN_EN(vir2phy(qhs[LOW_SPEED].next_ptr), UHCI_QH_TD_SELECT); - qhs[LOW_SPEED].qe_link = UHCI_TERMINATE; - - // 构建结束的QH和TD - - uhci_td_t *term_td = (uhci_td_t *)kmalloc(sizeof(uhci_td_t)); - memset(term_td, 0, sizeof(uhci_td_t)); - - term_td->max_length = 0x7ff; - term_td->device_addr = 0x7f; - term_td->packet_id = USB_PACKET_ID_IN; - term_td->td_addr_phy = vir2phy((uint32_t)term_td); - term_td->link = term_td->td_addr_phy; - - qhs[TERM].qh_link = UHCI_TERMINATE; - qhs[TERM].qe_link = term_td->td_addr_phy; - - i = 0; - while (i < 1024) { - int irq = 1 + BIT_FFS_R(i + FRAMELIST_SIZE); - if (irq > 7) irq = 7; - - devext->fl.frames_vir[i] = - BIN_EN(vir2phy((uint32_t)&qhs[irq]), UHCI_QH_TD_SELECT); - i++; - } -} - -void uhci_skel_add_qh(uhci_t *devext, uhci_qh_t *qh, enum uhci_skel_type type) { - uhci_qh_t *last_qh = ((uhci_qh_t *)devext->skel->qh[type].last_ptr); - if (last_qh != NULL) { - qh->qh_link = last_qh->qh_link; - last_qh->next_ptr = (uint32_t)qh; - last_qh->qh_link = BIN_EN(qh->qh_addr_phy, UHCI_QH_TD_SELECT); - qh->prev_ptr = (uint32_t)last_qh; - } else { - devext->skel->qh[type].qe_link = - BIN_EN(qh->qh_addr_phy, UHCI_QH_TD_SELECT); - qh->qh_link = UHCI_TERMINATE; - } - devext->skel->qh[type].last_ptr = (uint32_t)qh; -} - -void uhci_skel_del_qh(uhci_t *devext, uhci_qh_t *qh, enum uhci_skel_type type) { - if (qh->prev_ptr != 0) { - if (qh->next_ptr != 0) { - uhci_qh_t *next_qh = (uhci_qh_t *)qh->next_ptr; - uhci_qh_t *prev_qh = (uhci_qh_t *)qh->prev_ptr; - prev_qh->next_ptr = qh->next_ptr; - next_qh->prev_ptr = qh->prev_ptr; - } - } else { - if (qh->next_ptr != 0) { - uhci_qh_t *next_qh = (uhci_qh_t *)qh->next_ptr; - next_qh->prev_ptr = 0; - devext->skel->qh[type].qe_link = qh->qh_link; - } else { - devext->skel->qh[type].qe_link = UHCI_TERMINATE; - devext->skel->qh[type].last_ptr = 0; - } - } - - uhci_td_t *td = (uhci_td_t *)qh->last_ptr; - uhci_td_t *tmp; - while (td) { - tmp = (uhci_td_t *)td->prev_ptr; - kfree((void *)td); - td = tmp; - } - kfree(qh); -} \ No newline at end of file diff --git a/src/arch/x86/drivers/usb/hub.c b/src/arch/x86/drivers/usb/hub.c deleted file mode 100644 index 2439f75..0000000 --- a/src/arch/x86/drivers/usb/hub.c +++ /dev/null @@ -1,39 +0,0 @@ -#include "bits.h" -#include "drivers/usb/uhci.h" -#include -#include -#include -#include -#include -#include - -void usb_init_hub(usb_hcd_t *hcd, usb_device_t *device) { - usb_endpoint_t ep = usb_default_ep; - hcd->device_count++; - usb_set_address(hcd, device, &ep, hcd->device_count); - delay(2); - device->address = hcd->device_count; - struct usb_hub_descriptor *desc = usb_get_hub_descriptor(hcd, device, &ep); - usb_show_hub_descriptor(desc); - - uint32_t status = usb_get_hub_status(hcd, device, &ep); - - int i; - for (i = 1; i <= desc->bNbrPorts; i++) { - - usb_set_port_feature(hcd, device, &ep, i, HUB_FEAT_PORT_POWER); - delay(50 / 10); - usb_set_port_feature(hcd, device, &ep, i, HUB_FEAT_PORT_RESET); - delay(200 / 10); - - status = usb_get_port_status(hcd, device, &ep, i); - if (BIN_IS_EN(status, USB_PORT_STAT_CONNECTION)) { - usb_device_t *dev = usb_create_device( - (BIN_IS_EN(status, USB_PORT_STAT_LOW_SPEED) ? USB_SPEED_LOW - : USB_SPEED_FULL), - 0); - usb_init_device(hcd, dev); - delay(100 / 10); - } - } -} \ No newline at end of file diff --git a/src/arch/x86/drivers/usb/usb.c b/src/arch/x86/drivers/usb/usb.c deleted file mode 100644 index 8a83180..0000000 --- a/src/arch/x86/drivers/usb/usb.c +++ /dev/null @@ -1,96 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include - -usb_device_t *usb_create_device(usb_device_speed_t speed, uint8_t address) { - usb_device_t *device = (usb_device_t *)kmalloc(sizeof(usb_device_t)); - device->desc = kmalloc(sizeof(struct usb_device_descriptor)); - device->speed = speed; - device->address = address; - return device; -} - -int usb_destroy_device(usb_device_t *device) { - return kfree(device); -} - -usb_request_t *usb_create_request( - uint8_t direction, uint8_t type, uint8_t recipient, uint8_t request_id, - uint8_t value_hi, uint8_t value_lo, uint16_t index, uint16_t length) { - usb_request_t *request = (usb_request_t *)kmalloc(sizeof(usb_request_t)); - request->bmRequestType = direction << 7 | type << 5 | recipient; - request->bRequest = request_id; - request->wValue = HOST2LE_WORD(value_hi << 8 | value_lo); - request->wIndex = HOST2LE_WORD(index); - request->wLength = HOST2LE_WORD(length); - return request; -} - -usb_endpoint_t usb_default_ep = { - .endpoint = 0, - .transfer_type = USB_EP_CONTROL, - .direction = USB_EP_OUT, - .max_packet_size = 64, -}; - -usb_endpoint_t *usb_create_endpoint( - uint8_t endpoint, enum ep_transfer_type transfer_type, - enum ep_direction direction, uint16_t max_packet_size) { - usb_endpoint_t *ep = (usb_endpoint_t *)kmalloc(sizeof(usb_endpoint_t)); - ep->endpoint = endpoint; - ep->transfer_type = transfer_type; - ep->direction = direction; - ep->max_packet_size = max_packet_size; - return ep; -} - -usb_transfer_t *usb_create_transfer( - usb_device_t *device, usb_endpoint_t *endpoint) { - usb_transfer_t *transfer = - (usb_transfer_t *)kmalloc(sizeof(usb_transfer_t)); - transfer->device = device; - transfer->ep = endpoint; - return transfer; -} - -int usb_init_device(usb_hcd_t *hcd, usb_device_t *device) { - usb_endpoint_t ep = usb_default_ep; - struct usb_device_descriptor *desc = - usb_get_device_descriptor(hcd, device, &ep); - usb_show_device_descriptor(hcd, device, &ep, desc); - hcd->device_count++; - usb_set_address(hcd, device, &ep, hcd->device_count); - delay(2); - - device->address = hcd->device_count; - usb_get_config_descriptor(hcd, device, &ep); - usb_set_config(hcd, device, &ep, 1); - - if (desc->bDeviceClass == USB_CLASS_HUB) { usb_init_hub(hcd, device); } - return 0; -} - -usb_setup_status_t usb_control_transaction_in( - usb_hcd_t *hcd, usb_device_t *device, usb_endpoint_t *ep, void *buffer, - usb_request_t *usb_req, uint32_t length) { - - usb_transfer_t *transfer = usb_create_transfer(device, ep); - - return hcd->interface->control_transaction_in( - hcd, device, transfer, buffer, length, usb_req); -} - -usb_setup_status_t usb_control_transaction_out( - usb_hcd_t *hcd, usb_device_t *device, usb_endpoint_t *ep, void *buffer, - usb_request_t *usb_req, uint32_t length) { - - usb_transfer_t *transfer = usb_create_transfer(device, ep); - - return hcd->interface->control_transaction_out( - hcd, device, transfer, buffer, length, usb_req); -} \ No newline at end of file diff --git a/src/arch/x86/drivers/video.c b/src/arch/x86/drivers/video.c deleted file mode 100644 index 70324da..0000000 --- a/src/arch/x86/drivers/video.c +++ /dev/null @@ -1,222 +0,0 @@ -/** - * @file video.c - * @author Ryan Wang (ryan1202@foxmail.com) - * @brief - * @version 0.6 - * @date 2020-10 - */ -#include -#include -#include -#include -#include - -struct VideoInfo video_info; - -/** - * VIDEO_INFO_ADDR处存着loader保存的显示模式信息 - * VIDEO_INFO_ADDR+0 X分辨率 - * VIDEO_INFO_ADDR+2 Y分辨率 - * VIDEO_INFO_ADDR+4 颜色位数 - * VIDEO_INFO_ADDR+6 显存物理地址 - * VIDEO_INFO_ADDR+10 显示模式的INFO_BLOCK - * - * 2024.11.25: VIDEO_INFO_ADDR已废弃,直接在平台初始化阶段赋值video_info - */ - -#define SEG_ADDR2LINEAR_ADDR(addr) \ - ((unsigned int *)(((unsigned int)(addr) >> 12) & 0xffff0) + \ - ((unsigned int)(addr) & 0xffff)) - -void init_video() { - // 因为VRAM地址在启用分页后发生了变化,所以要重新设置 - video_info.vram = (uint8_t *)VRAM_VIR_ADDR; - - printk( - "Display mode: %d*%d %dbit\n", video_info.width, video_info.height, - video_info.BitsPerPixel); - - video_info.vbe_mode_info->OemStringPtr = - SEG_ADDR2LINEAR_ADDR(video_info.vbe_mode_info->OemStringPtr); - video_info.vbe_mode_info->VideoModePtr = - SEG_ADDR2LINEAR_ADDR(video_info.vbe_mode_info->VideoModePtr); - video_info.vbe_mode_info->OemVendorNamePtr = - SEG_ADDR2LINEAR_ADDR(video_info.vbe_mode_info->OemVendorNamePtr); - video_info.vbe_mode_info->OemProduceRevPtr = - SEG_ADDR2LINEAR_ADDR(video_info.vbe_mode_info->OemProduceRevPtr); - video_info.vbe_mode_info->OemProductNamePtr = - SEG_ADDR2LINEAR_ADDR(video_info.vbe_mode_info->OemProductNamePtr); - - // 如果是256色模式则设置调色板 - if (video_info.BitsPerPixel == 8) { - unsigned char table[216 * 3], *p; - int i, j, k, eflags; - for (i = 0; i < 6; i++) { - for (j = 0; j < 6; j++) { - for (k = 0; k < 6; k++) { - table[(k + j * 6 + i * 36) * 3 + 0] = k * 51; - table[(k + j * 6 + i * 36) * 3 + 1] = j * 51; - table[(k + j * 6 + i * 36) * 3 + 2] = i * 51; - } - } - } - eflags = io_load_eflags(); - io_cli(); - io_out8(0x3c8, 0); - p = table; - for (i = 0; i < 216; i++) { - io_out8(0x3c9, p[0] / 4); - io_out8(0x3c9, p[1] / 4); - io_out8(0x3c9, p[2] / 4); - p += 3; - } - io_store_eflags(eflags); - } -} - -/** - * @brief 显示VBE相关信息 - * - */ -void show_vbeinfo() { - int i; - - printk("VBE Version:%x\n", video_info.vbe_mode_info->VbeVersion); - printk("OEMString:%s\n", video_info.vbe_mode_info->OemStringPtr); - - printk("VBE Capabilities:\n"); - printk( - " %s\n", - (video_info.vbe_mode_info->Capabilities & 0x01 - ? "DAC width is switchable to 8 bits per primary color" - : "DAC is fixed width, with 6 bits per primary color")); - printk( - " %s\n", (video_info.vbe_mode_info->Capabilities & 0x02 - ? "Controller is not VGA compatible" - : "Controller is VGA compatible")); - printk( - " %s\n", - (video_info.vbe_mode_info->Capabilities & 0x04 - ? "When programming large blocks of information to the RAMDAC" - : "Normal RAMDAC operation")); - printk( - " %s\n", - (video_info.vbe_mode_info->Capabilities & 0x08 - ? "Hardware stereoscopic signaling supported by controller" - : "No hardware stereoscopic signaling support")); - printk( - " %s\n", (video_info.vbe_mode_info->Capabilities & 0x10 - ? "Stereo signaling supported via VESA EVC" - : "Stereo signaling supported via external VESA " - "stereo connector")); - - printk("VideoMode:\n"); - for (i = 0; - ((unsigned short *)video_info.vbe_mode_info->VideoModePtr)[i] >= 0x100; - i++) { - printk( - "%x ", - ((unsigned short *)video_info.vbe_mode_info->VideoModePtr)[i]); - } - printk("\n"); - - printk("VBE totalMemory:%dKB\n", video_info.vbe_mode_info->TotalMemory); - printk("OEM SoftwareRev:%#x\n", video_info.vbe_mode_info->OemSoftwareRev); - printk("OEM VendorName:%s\n", video_info.vbe_mode_info->OemVendorNamePtr); - printk("OEM ProductName:%s\n", video_info.vbe_mode_info->OemProductNamePtr); - printk("OEM ProduceRev:%s\n", video_info.vbe_mode_info->OemProduceRevPtr); -} - -/** - * @brief 写像素 - * - * @param x x坐标 - * @param y y坐标 - * @param color 颜色 - */ -void write_pixel(int x, int y, unsigned int color) { - unsigned char r, g, b; - r = (unsigned char)(color >> 16); - g = (unsigned char)(color >> 8); - b = (unsigned char)color; - unsigned char *vram = - (unsigned char *)(video_info.vram + (y * video_info.width + x) * - (video_info.BitsPerPixel / 8)); - if (video_info.BitsPerPixel == 32) { - vram[0] = color & 0xff; - vram[1] = (color >> 8) & 0xff; - vram[2] = (color >> 16) & 0xff; - } else if (video_info.BitsPerPixel == 24) { - vram[0] = color & 0xff; - vram[1] = (color >> 8) & 0xff; - vram[2] = (color >> 16) & 0xff; - } else if (video_info.BitsPerPixel == 16) { - vram[0] = ((g * 63 / 255) & 0x7) << 5 | (b * 31 / 255); - vram[1] = (r * 31 / 255) << 3 | ((g * 63 / 255) & 0x38) >> 3; - } else if (video_info.BitsPerPixel == 8) { - vram[0] = (r / 51) + (g / 51) * 6 + (b / 51) * 36; - } -} - -/** - * @brief 画矩形 - * - * @param x x坐标 - * @param y y坐标 - * @param width 宽度 - * @param height 高度 - * @param color 颜色 - */ -void draw_rect(int x, int y, int width, int height, int color) { - /*wide-video wide*/ - int x0, y0; - for (y0 = 0; y0 < height; y0++) { - for (x0 = 0; x0 < width; x0++) { - write_pixel(x + x0, y + y0, color); - } - } -} - -/** - * @brief 打印字符 - * - * @param x x坐标 - * @param y y坐标 - * @param ascii 字符数据(16*8点阵字体) - * @param color 颜色 - */ -void print_word(int x, int y, unsigned char *ascii, unsigned int color) { - int i; - char d; - for (i = 0; i < 16; i++) { - // vram = (unsigned char *)(video_info.vram + ((y+i)*video_info.width + - // x)*(video_info.BitsPerPixel/8)); - d = ascii[i]; - if (d & 0x80) { write_pixel(x + 0, y + i, color); } - if (d & 0x40) { write_pixel(x + 1, y + i, color); } - if (d & 0x20) { write_pixel(x + 2, y + i, color); } - if (d & 0x10) { write_pixel(x + 3, y + i, color); } - if (d & 0x08) { write_pixel(x + 4, y + i, color); } - if (d & 0x04) { write_pixel(x + 5, y + i, color); } - if (d & 0x02) { write_pixel(x + 6, y + i, color); } - if (d & 0x01) { write_pixel(x + 7, y + i, color); } - } -} - -/** - * @brief 打印字符串 - * - * @param x x坐标 - * @param y y坐标 - * @param color 颜色 - * @param font 字体 - * @param string 字符串 - */ -void print_string( - int x, int y, unsigned int color, unsigned char *font, char *string) { - while (*string != 0) { - print_word(x, y, font + (*string) * 16, color); - string++; - x += 9; - } -} \ No newline at end of file diff --git a/src/arch/x86/i686-none.json b/src/arch/x86/i686-none.json new file mode 100644 index 0000000..1355057 --- /dev/null +++ b/src/arch/x86/i686-none.json @@ -0,0 +1,33 @@ +{ + "arch": "x86", + "code-model": "kernel", + "cpu": "i686", + "crt-objects-fallback": "false", + "data-layout": "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-i128:128-f64:32:64-f80:32-n8:16:32-S128", + "disable-redzone": true, + "features": "-mmx,-sse,-sse2,-sse3,-ssse3,-sse4.1,-sse4.2,-avx,-avx2,+soft-float", + "linker": "rust-lld", + "linker-flavor": "gnu-lld", + "llvm-target": "i686-unknown-none-elf", + "max-atomic-width": 32, + "metadata": { + "description": "Freestanding/bare-metal x86 softfloat", + "host_tools": false, + "std": false, + "tier": 2 + }, + "panic-strategy": "abort", + "plt-by-default": false, + "position-independent-executables": true, + "relro-level": "full", + "rustc-abi": "x86-softfloat", + "stack-probes": { + "kind": "inline" + }, + "static-position-independent-executables": true, + "supported-sanitizers": [ + "kcfi", + "kernel-address" + ], + "target-pointer-width": 32 +} \ No newline at end of file diff --git a/src/arch/x86/include/bios_emu/bios_emu.h b/src/arch/x86/include/bios_emu/bios_emu.h new file mode 100644 index 0000000..079b2d1 --- /dev/null +++ b/src/arch/x86/include/bios_emu/bios_emu.h @@ -0,0 +1,13 @@ +#ifndef _BIOS_EMU_H +#define _BIOS_EMU_H + +#include +#include + +extern BiosEmuEnvironment bios_emu_env; + +void bios_emu_init(void); +BiosEmuExceptions emu_run(BiosEmuEnvironment *env); +BiosEmuExceptions emu_interrupt(int vector); + +#endif \ No newline at end of file diff --git a/src/arch/x86/include/bios_emu/environment.h b/src/arch/x86/include/bios_emu/environment.h new file mode 100644 index 0000000..a191425 --- /dev/null +++ b/src/arch/x86/include/bios_emu/environment.h @@ -0,0 +1,68 @@ +#ifndef _BIOS_EMU_ENVIRONMENT_H +#define _BIOS_EMU_ENVIRONMENT_H + +#include + +#define DEF_GENERIC_REG(name) \ + union { \ + struct { \ + uint8_t name##l; \ + uint8_t name##h; \ + }; \ + uint16_t name##x; \ + uint32_t e##name##x; \ + }; +#define DEF_OTHER_REG(name) \ + union { \ + uint16_t name; \ + uint32_t e##name; \ + }; + +typedef struct BiosEmuEnvironment { + // The CPU state + struct { + DEF_GENERIC_REG(a); + DEF_GENERIC_REG(b); + DEF_GENERIC_REG(c); + DEF_GENERIC_REG(d); + DEF_OTHER_REG(si); + DEF_OTHER_REG(di); + DEF_OTHER_REG(bp); + DEF_OTHER_REG(sp); + DEF_OTHER_REG(flags); + DEF_OTHER_REG(ip); + uint32_t cs, ds, es, fs, gs, ss; + } regs; + + void *cur_ip; + uint32_t stack_bottom; + struct { + uint16_t offset; + uint16_t segment; + } *ivt; + struct { + uint8_t repeat : 1; + uint8_t rep_e_ne : 1; // 0:repne/repnz, 1:repe/repz + uint8_t stack_size : 1; // 0:16bit, 1:32bit + uint8_t operand_size : 1; // 0:16bit, 1:32bit + uint8_t default_operand_size : 1; + uint8_t address_size : 1; // 0:16bit, 1:32bit + uint8_t default_address_size : 1; + } flags; + uint32_t *default_ss; + + // 寄存器地址查找表 + // 0:al, 1:cl, 2:dl, 3:bl, 4:ah, 5:ch, 6:dh, 7:bh + uint8_t *reg_lut_r8[8]; + // 0:ax, 1:cx, 2:dx, 3:bx, 4:sp, 5:bp, 6:si, 7:di + uint16_t *reg_lut_r16[8]; + // 0:eax, 1:ecx, 2:edx, 3:ebx, 4:esp, 5:ebp, 6:esi, 7:edi + uint32_t *reg_lut_r32[8]; + + enum { + IntDone, + } stop_condition; + size_t int_entry_stack; // 进入中断时的栈指针 +} BiosEmuEnvironment; + +#endif \ No newline at end of file diff --git a/src/arch/x86/include/bios_emu/exceptions.h b/src/arch/x86/include/bios_emu/exceptions.h new file mode 100644 index 0000000..382c45c --- /dev/null +++ b/src/arch/x86/include/bios_emu/exceptions.h @@ -0,0 +1,32 @@ +#ifndef _BIOS_EMU_EXCEPTIONS +#define _BIOS_EMU_EXCEPTIONS + +typedef enum BiosEmuExceptions { + // x86支持的异常,下划线开头的异常是实模式不支持的 + DivideError, + DebugException, + NMIInterrupt, + Breakpoint, + Overflow, + BOUNDRangeExceeded, + InvalidOpcode, + DeviceNotAvailable, + DoubleFault, + _Reserved1, + _InvalidTSS, + _SegmentNotPresent, + StackFault, + GeneralProtection, + _PageFault, + _Reserved2, + FloatPointError, + _AlignmentCheck, + MachineCheck, + + // 下面是自定义的 + NoException, + EventInterruptDone, + EventHalted, +} BiosEmuExceptions; + +#endif \ No newline at end of file diff --git a/src/arch/x86/include/drivers/8042.h b/src/arch/x86/include/drivers/8042.h index 6ecd6a0..fae8522 100644 --- a/src/arch/x86/include/drivers/8042.h +++ b/src/arch/x86/include/drivers/8042.h @@ -1,6 +1,8 @@ #ifndef _8042_H #define _8042_H +#include +#include #include #define I8042_PORT_DATA 0x60 @@ -22,6 +24,12 @@ #define I8042_CMD_SEND_TO_P2 0xd4 #define I8042_CMD_RESET_DEV 0xff +#define I8042_KBD_CMD_SET_LEDS 0xed +#define I8042_KBD_CMD_GET_SET_SCANCODE_SET 0xf0 +#define I8042_KBD_CMD_IDENTIFY 0xf2 +#define I8042_KBD_CMD_ENABLE_SCANNING 0xf4 +#define I8042_KBD_CMD_DISABLE_SCANNING 0xf5 + // 配置 #define I8042_CFG_INT1 0x01 #define I8042_CFG_INT2 0x02 @@ -38,10 +46,31 @@ #define I8042_STAT_TIMEOUT_ERR 0x40 #define I8042_STAT_PARITY_ERR 0x80 -int i8042_get_status(uint8_t type); // 获取控制器状态 -void i8042_wait_ctr_send_ready(void); // 等待输入缓存区为空 -void i8042_send_cmd(int command); // 发送控制字节 -int i8042_read_data(void); // 读取数据 -void i8042_write_data(int data); // 写数据 +typedef struct { + uint8_t is_dual_channel; + uint8_t is_p1_avail; + uint8_t is_p2_avail; + uint8_t p1_dev_type; + uint8_t p2_dev_type; + + DeviceIrq *irq[2]; +} I8042Device; + +extern DeviceDriver i8042_device_driver; +extern PhysicalDevice *i8042_device; + +static const int ps2_irqs[2] = {1, 12}; + +int i8042_get_status(uint8_t type); // 获取控制器状态 +void i8042_wait_ctr_send_ready(void); // 等待输入缓存区为空 +void i8042_send_cmd(uint8_t command); // 发送控制字节 +uint8_t i8042_read_data(void); // 读取数据 +void i8042_write_data(uint8_t data); // 写数据 +void i8042_disable_interrupt(int port); +void i8042_enable_interrupt(int port); +void i8042_clear_buffer(void); // 清空缓冲区 + +void ps2_keyboard_register(PhysicalDevice *physical_device, int port); +void ps2_mouse_register(PhysicalDevice *physical_device, int port); #endif \ No newline at end of file diff --git a/src/arch/x86/include/drivers/8259a.h b/src/arch/x86/include/drivers/8259a.h index 02531de..45a5418 100644 --- a/src/arch/x86/include/drivers/8259a.h +++ b/src/arch/x86/include/drivers/8259a.h @@ -1,6 +1,8 @@ #ifndef _8259A_H #define _8259A_H +#include + #define PIC0_ICW1 0x20 #define PIC0_OCW1 0x20 #define PIC0_IMR 0x21 @@ -16,9 +18,9 @@ #define PIC_EOI 0x20 -void mask_8259a(void); -void init_8259a(void); -void pic_enable_irq(int irq); -void pic_eoi(int irq); +extern struct PhysicalDevice *i8259a_device; + +void mask_8259a(void); +DriverResult register_pic(void); #endif \ No newline at end of file diff --git a/src/arch/x86/include/drivers/apic.h b/src/arch/x86/include/drivers/apic.h index 4f8e308..1ecc925 100644 --- a/src/arch/x86/include/drivers/apic.h +++ b/src/arch/x86/include/drivers/apic.h @@ -1,7 +1,10 @@ #ifndef APIC_H #define APIC_H -#define APIC_ID 0x20 +#include +#include + +#define APIC_ID 0x20 #define APIC_Ver 0x30 #define APIC_TPR 0x80 #define APIC_APR 0x90 @@ -19,7 +22,7 @@ #define APIC_INT_DISABLE 0x00010000 -#define APIC_ESR 0x280 +#define APIC_ESR 0x280 #define APIC_LVT_CMCI 0x2f0 #define APIC_ICR_LOW 0x300 #define APIC_ICR_HIGH 0x310 @@ -34,12 +37,64 @@ #define APIC_TIMER_CCT 0x390 #define APIC_TIMER_DCR 0x3E0 +#define APIC_BASE_MSR 0x1b +#define X2APIC_ID_MSR 0x802 + +// Interrupt Command Register +#define APIC_ICR_DELIVERY_MODE_FIXED (0b000 << 8) +#define APIC_ICR_DELIVERY_MODE_LOW_PRIO (0b001 << 8) +#define APIC_ICR_DELIVERY_MODE_SMI (0b010 << 8) +#define APIC_ICR_DELIVERY_MODE_NMI (0b100 << 8) +#define APIC_ICR_DELIVERY_MODE_INIT (0b101 << 8) +#define APIC_ICR_DELIVERY_MODE_STARTUP (0b110 << 8) + +#define APIC_ICR_DEST_MODE_BIT 11 +#define APIC_ICR_DEST_MODE_PHYSICAL (0 << APIC_ICR_DEST_MODE_BIT) +#define APIC_ICR_DEST_MODE_LOGICAL (1 << APIC_ICR_DEST_MODE_BIT) + +#define APIC_ICR_STAT_BIT 12 +#define APIC_ICR_STAT_IDLE (0 << APIC_ICR_STAT_BIT) +#define APIC_ICR_STAT_SEND_PENDING (1 << APIC_ICR_STAT_BIT) + +#define APIC_ICR_LEVEL_BIT 14 +#define APIC_ICR_LEVEL_DEASSERT (0 << APIC_ICR_LEVEL_BIT) +#define APIC_ICR_LEVEL_ASSERT (1 << APIC_ICR_LEVEL_BIT) + +#define APIC_ICR_TRIGGER_MODE_BIT 15 +#define APIC_ICR_TRIGGER_MODE_EDGE (0 << APIC_ICR_TRIGGER_MODE_BIT) +#define APIC_ICR_TRIGGER_MODE_LEVEL (1 << APIC_ICR_TRIGGER_MODE_BIT) + +#define APIC_ICR_DEST_SHORTHAND_NO_SHORTHAND (0b00 << 18) +#define APIC_ICR_DEST_SHORTHAND_SELF (0b01 << 18) +#define APIC_ICR_DEST_SHORTHAND_ALL_INCLUDING_SELF (0b10 << 18) +#define APIC_ICR_DEST_SHORTHAND_ALL_EXCLUDING_SELF (0b11 << 18) + +// Divide Configuration Register +#define APIC_TIMER_DCR_DIVIDE_BY_2 0b0000 +#define APIC_TIMER_DCR_DIVIDE_BY_4 0b0001 +#define APIC_TIMER_DCR_DIVIDE_BY_8 0b0010 +#define APIC_TIMER_DCR_DIVIDE_BY_16 0b0011 +#define APIC_TIMER_DCR_DIVIDE_BY_32 0b1000 +#define APIC_TIMER_DCR_DIVIDE_BY_64 0b1001 +#define APIC_TIMER_DCR_DIVIDE_BY_128 0b1010 +#define APIC_TIMER_DCR_DIVIDE_BY_1 0b1011 + +// Timer LVT +#define APIC_LVT_TIMER_MODE_ONESHOT (0b00 << 17) +#define APIC_LVT_TIMER_MODE_PERIODIC (0b001 << 17) +#define APIC_LVT_TIMER_MODE_TSC_DEADLINE (0b010 << 17) + +// MSR +#define APIC_GLOBAL_ENABLE_BIT 11 +// SVIR +#define APIC_SOFTWARE_ENABLE_BIT 8 + #define LAPIC_TIMER_IRQ 0 -void init_apic(void); -void apic_enable_irq(int irq); -void apic_eoi(void); +extern struct PhysicalDevice *apic_device; +extern struct TimerDevice *apic_timer_device; +extern bool use_apic; -extern char use_apic; +DriverResult register_apic(void); #endif diff --git a/src/arch/x86/include/drivers/bus/isa/dma.h b/src/arch/x86/include/drivers/bus/isa/dma.h new file mode 100644 index 0000000..323e883 --- /dev/null +++ b/src/arch/x86/include/drivers/bus/isa/dma.h @@ -0,0 +1,94 @@ +#ifndef _ISA_DMA_H +#define _ISA_DMA_H + +#include "kernel/device.h" +#include "stdint.h" + +#define DMA0 0x00 +#define DMA1 0xc0 + +#define DMA_ADDR0 0x00 +#define DMA_CNT0 0x01 +#define DMA_ADDR1 0x02 +#define DMA_CNT1 0x03 +#define DMA_ADDR2 0x04 +#define DMA_CNT2 0x05 +#define DMA_ADDR3 0x06 +#define DMA_CNT3 0x07 +#define DMA_ADDR4 0xc0 +#define DMA_CNT4 0xc2 +#define DMA_ADDR5 0xc4 +#define DMA_CNT5 0xc6 +#define DMA_ADDR6 0xc8 +#define DMA_CNT6 0xca +#define DMA_ADDR7 0xcc +#define DMA_CNT7 0xce + +// DMA寄存器 +#define DMA1_REG_STAT 0x08 // 状态寄存器 +#define DMA1_REG_CMD 0x08 // 命令寄存器 +#define DMA1_REG_REQ 0x09 // 请求寄存器 +#define DMA1_REG_MASK 0x0a // 屏蔽寄存器 +#define DMA1_REG_MODE 0x0b // 模式寄存器 +#define DMA1_REG_FF_RESET 0x0c // 触发器复位寄存器 +#define DMA1_REG_TEMP 0x0d // 暂存寄存器 +#define DMA1_REG_RESET 0x0d // 主DMA复位寄存器 +#define DMA1_REG_MASK_RESET 0x0e // 复位屏蔽寄存器 +#define DMA1_REG_ALL_MASK 0x0f // 多通道屏蔽寄存器 + +#define DMA2_REG_STAT 0xd0 // 状态寄存器 +#define DMA2_REG_CMD 0xd0 // 命令寄存器 +#define DMA2_REG_REQ 0xd2 // 请求寄存器 +#define DMA2_REG_MASK 0xd4 // 屏蔽寄存器 +#define DMA2_REG_MODE 0xd6 // 模式寄存器 +#define DMA2_REG_FF_RESET 0xd8 // 触发器复位寄存器 +#define DMA2_REG_TEMP 0xda // 暂存寄存器 +#define DMA2_REG_RESET 0xda // DMA复位寄存器 +#define DMA2_REG_MASK_RESET 0xdc // 复位屏蔽寄存器 +#define DMA2_REG_ALL_MASK 0xde // 多通道屏蔽寄存器 + +// 屏蔽寄存器 +#define DMA_MASK_ON 0x04 + +// DMA页寄存器 +#define DMA_PAGE0 0x87 +#define DMA_PAGE1 0x83 +#define DMA_PAGE2 0x81 +#define DMA_PAGE3 0x82 +#define DMA_PAGE5 0x8b +#define DMA_PAGE6 0x89 +#define DMA_PAGE7 0x8a + +#define DMA_MODE_READ 0x04 +#define DMA_MODE_WRITE 0x08 +#define DMA_MODE_AUTO 0x10 +#define DMA_MODE_SINGLE 0x40 +#define DMA_MODE_BLOCK 0x80 + +#define DMA_MAX_REGION_COUNT 16 +#define DMA_REGION_SIZE 64 * 1024 + +#include "kernel/dma.h" +#include "kernel/driver.h" + +extern DmaOps isa_dma_ops; + +void dma_init(); +void *dma_alloc_region(Dma *dma, uint32_t size); +DriverResult dma_free_region(Dma *dma, void *ptr, uint32_t size); + +int dma_channel_use(struct LogicalDevice *device, int *possible_ch, int len); +void dma_channel_unuse(struct LogicalDevice *device, uint8_t channel); + +int dma_lock(); +void dma_unlock(int flags); + +void dma_enable(unsigned int channel); +void dma_disable(unsigned int channel); +void dma_ff_reset(unsigned int channel); +void dma_set_mode(unsigned int channel, char mode); +void dma_set_addr(unsigned int channel, unsigned int addr); +void dma_set_count(unsigned int channel, unsigned int count); +uint32_t dma_pointer(int channel, unsigned int size); + +#endif \ No newline at end of file diff --git a/src/arch/x86/include/drivers/bus/isa/isa.h b/src/arch/x86/include/drivers/bus/isa/isa.h new file mode 100644 index 0000000..e02c3d2 --- /dev/null +++ b/src/arch/x86/include/drivers/bus/isa/isa.h @@ -0,0 +1,26 @@ +#ifndef _ISA_H +#define _ISA_H + +#include "kernel/bus_driver.h" +#include "kernel/device_driver.h" +#include "kernel/driver.h" +#include "kernel/list.h" + +struct IsaDeviceDriver; +typedef struct IsaOps { + DriverResult (*probe)(struct IsaDeviceDriver *isa_device_driver); +} IsaOps; + +typedef struct IsaDeviceDriver { + list_t list; + DeviceDriver *device_driver; + IsaOps *ops; + + BusDriver *bus_driver; + Bus *bus; +} IsaDeviceDriver; + +DriverResult isa_register_device_driver( + DeviceDriver *device_driver, IsaOps *ops); + +#endif \ No newline at end of file diff --git a/src/arch/x86/include/drivers/bus/pci/pci.h b/src/arch/x86/include/drivers/bus/pci/pci.h new file mode 100644 index 0000000..9688b51 --- /dev/null +++ b/src/arch/x86/include/drivers/bus/pci/pci.h @@ -0,0 +1,253 @@ +#ifndef _PCI_H +#define _PCI_H + +#include "kernel/device.h" +#include "kernel/driver_interface.h" +#include "stdint.h" + +#define PCI_CONFIG_ADDR 0xcf8 +#define PCI_CONFIG_DATA 0xcfc + +#define PCI_REG_DEVICEID 0x00 +#define PCI_REG_VENDORID 0x02 +#define PCI_REG_STATUS 0x04 +#define PCI_REG_COMMAND 0x06 +#define PCI_REG_CLASSCODE 0x08 +#define PCI_REG_SUBCLASS 0x09 +#define PCI_REG_PROGIF 0x0a +#define PCI_REG_REVISIONID 0x0b +#define PCI_REG_BIST 0x0c +#define PCI_REG_HEADERTYPE 0x0d +#define PCI_REG_LTIMER 0x0e +#define PCI_REG_CLSIZE 0x0f + +#define PCI_BAR_BASE 0x10 +#define PCI_BAR(x) PCI_BAR_BASE + x * 4 +#define PCI_BAR_MEM_MASK ~0x0f +#define PCI_BAR_IO_MASK ~0x03 + +#define PCI_MAX_BAR 6 +#define PCI_MAX_BUS 256 +#define PCI_MAX_DEV 32 +#define PCI_MAX_FUNC 8 +#define PCI_MAX_DEVICE 256 + +#define PCI_SEL_REG(bus, device, function, offset) \ + { \ + uint32_t addr_reg; \ + addr_reg = (1 << 31) | (bus << 16) | (device << 11) | (func << 8) | \ + (offset & 0xfc); \ + io_out_dword(PCI_CONFIG_ADDR, addr_reg); \ + } + +#define DEF_PCI_RW(size) \ + uint##size##_t pci_read##size( \ + uint8_t bus, uint8_t device, uint8_t func, uint8_t offset) { \ + PCI_SEL_REG(bus, device, func, offset); \ + return io_in##size(PCI_CONFIG_DATA); \ + } \ + void pci_write##size( \ + uint8_t bus, uint8_t device, uint8_t func, uint8_t offset, \ + uint##size##_t value) { \ + PCI_SEL_REG(bus, device, func, offset); \ + io_out##size(PCI_CONFIG_DATA, value); \ + } + +#define DEF_PCI_RW_DEVICE(size) \ + uint##size##_t pci_device_read##size(PciDevice *device, uint8_t offset) { \ + return pci_read##size( \ + device->bus_num, device->dev_num, device->function_num, offset); \ + } \ + void pci_device_write##size( \ + PciDevice *device, uint8_t offset, uint##size##_t value) { \ + pci_write##size( \ + device->bus_num, device->dev_num, device->function_num, offset, \ + value); \ + } + +#define PCI_DEVICE_STATUS_INVALID 0 +#define PCI_DEVICE_STATUS_UNUSED 1 +#define PCI_DEVICE_STATUS_USING 2 +#define PCI_BAR_TYPE_INVALID 0 +#define PCI_BAR_TYPE_MEM 1 +#define PCI_BAR_TYPE_IO 2 + +uint8_t pci_read8(uint8_t bus, uint8_t device, uint8_t func, uint8_t offset); +uint16_t pci_read16(uint8_t bus, uint8_t device, uint8_t func, uint8_t offset); +uint32_t pci_read32(uint8_t bus, uint8_t device, uint8_t func, uint8_t offset); +void pci_write8( + uint8_t bus, uint8_t device, uint8_t func, uint8_t offset, uint8_t value); +void pci_write16( + uint8_t bus, uint8_t device, uint8_t func, uint8_t offset, uint16_t value); +void pci_write32( + uint8_t bus, uint8_t device, uint8_t func, uint8_t offset, uint32_t value); + +void init_pci(); + +uint32_t pci_get_device_connected(void); + +#include "kernel/bus_driver.h" +#include "kernel/driver.h" + +typedef struct PciDeviceBar { + uint32_t type; + uint32_t base_addr; + uint32_t length; +} PciDeviceBar; + +typedef struct PciDevice { + Bus *bus; + PhysicalDevice *device; + + struct PciDriver *pci_driver; + + char status; + + uint8_t bus_num; + uint8_t dev_num; + uint8_t function_num; + + uint16_t vendor_id; + uint16_t device_id; + uint8_t classcode; + uint8_t subclass; + uint8_t prog_if; + uint8_t revision_id; + uint8_t bist; + uint8_t multifunction; + uint8_t header_type; + uint8_t latency_timer; + uint8_t cache_line_size; + uint8_t irqline; + uint8_t irqpin; + + union { + struct { + PciDeviceBar bar[PCI_MAX_BAR]; + + uint32_t cardbus_cis_pointer; + uint16_t subsystem_id; + uint16_t subsystem_vendor_id; + uint32_t expension_rom_base_address; + uint8_t capabilities_pointer; + uint8_t max_latency; + uint8_t min_grant; + } common; + struct { + PciDeviceBar bar[2]; + + uint8_t secondary_latency_timer; + uint8_t secondary_bus_number; + uint8_t subordinate_bus_number; + uint8_t primary_bus_number; + uint16_t secondary_status; + + uint16_t io_base_upper; + uint16_t io_base; + uint16_t io_limit_upper; + uint16_t io_limit; + + uint16_t memory_limit; + uint16_t memory_base; + + uint32_t prefetchable_limit_upper; + uint16_t prefetchable_memory_limit; + uint32_t prefetchable_base_upper; + uint16_t prefetchable_memory_base; + + uint8_t capabilities_pointer; + uint32_t expension_rom_base_address; + uint16_t bridge_control; + } pci2pci_bridge; + struct { + uint32_t cardbus_socket_base_address; + uint16 secondary_status; + uint8_t capabilities_offset; + uint8_t cardbus_latency_timer; + uint8_t subordiante_bus_number; + uint8_t cardbus_bus_number; + uint8_t pci_bus_number; + uint32_t memory_base0; + uint32_t memory_limit0; + uint32_t memory_base1; + uint32_t memory_limit1; + uint32_t io_base0; + uint32_t io_limit0; + uint32_t io_base1; + uint32_t io_limit1; + uint16_t bridge_control; + uint16_t subsystem_vendor_id; + uint16_t subsystem_device_id; + uint32_t legacy_base_address; + } pci2cardbus_bridge; + }; +} PciDevice; + +typedef struct PciDriverOps { + DriverResult (*probe)( + struct PciDevice *pci_device, PhysicalDevice *physical_device); +} PciDriverOps; + +typedef struct PciDriver { + list_t pci_driver_list; + + Driver *driver; + DeviceDriver *device_driver; + + enum { + FIND_BY_CLASSCODE_SUBCLASS, + FIND_BY_CLASSCODE_SUBCLASS_PROGIF, + FIND_BY_VENDORID_DEVICEID, + } find_type; + + union { + struct { + uint16_t vendor_id; + uint16_t device_id; + } vendor_device; + struct { + uint8_t classcode; + uint8_t subclass; + } class_subclass; + struct { + uint8_t classcode; + uint8_t subclass; + uint8_t progif; + } class_subclass_progif; + }; + PciDevice *pci_device; + + PciDriverOps *ops; +} PciDriver; + +extern list_t pci_driver_lh; +extern Driver pci_driver; + +DriverResult pci_set_driver(PciDriver *pci_driver, PciDevice *pci_device); +PciDevice *pci_alloc_device(void); +int pci_free_device(PciDevice *dev); +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); +void get_pci_bar_info(PciDeviceBar *bar, uint32_t addr, uint32_t len); +DriverResult pci_scan_device( + Bus *bus, uint8_t bus_num, uint8_t device_num, uint8_t function_num, + PciDevice **out_pci_device); + +uint8_t pci_device_read8(PciDevice *device, uint8_t offset); +uint16_t pci_device_read16(PciDevice *device, uint8_t offset); +uint32_t pci_device_read32(PciDevice *device, uint8_t offset); +void pci_device_write8(PciDevice *device, uint8_t offset, uint8_t value); +void pci_device_write16(PciDevice *device, uint8_t offset, uint16_t value); +void pci_device_write32(PciDevice *device, uint8_t offset, uint32_t value); + +DriverResult pci_register_driver(Driver *driver, PciDriver *new_pci_driver); +uint32_t pci_device_get_mem_addr(PciDevice *pci_device); +void pci_enable_mem_space(PciDevice *pci_device); +void pci_enable_io_space(PciDevice *pci_device); +void pci_enable_bus_mastering(PciDevice *pci_device); +uint32_t pci_device_get_io_addr(PciDevice *pci_device); + +#endif \ No newline at end of file diff --git a/src/arch/x86/include/drivers/cmos.h b/src/arch/x86/include/drivers/cmos.h index 6cffc5e..6ef4407 100644 --- a/src/arch/x86/include/drivers/cmos.h +++ b/src/arch/x86/include/drivers/cmos.h @@ -1,50 +1,40 @@ #ifndef _CMOS_H #define _CMOS_H +#include +#include +#include #include #define CMOS_REGS 0x70 #define CMOS_DATA 0x71 // CMOS寄存器 -#define CMOS_SECONDS 0x00 -#define CMOS_MINUTES 0x02 -#define CMOS_HOURS 0x04 -#define CMOS_WEEKDAY 0x06 +#define CMOS_SECONDS 0x00 +#define CMOS_MINUTES 0x02 +#define CMOS_HOURS 0x04 +#define CMOS_WEEKDAY 0x06 #define CMOS_DAY_OF_MONTH 0x07 -#define CMOS_MONTH 0x08 -#define CMOS_YEAR 0x09 -#define CMOS_STATUS_A 0x0a -#define CMOS_STATUS_B 0x0b +#define CMOS_MONTH 0x08 +#define CMOS_YEAR 0x09 +#define CMOS_STATUS_A 0x0a +#define CMOS_STATUS_B 0x0b #define CMOS_FLOPPY_TYPE 0x10 -#define CMOS_EQP 0x14 -#define CMOS_CENTURY 0x32 +#define CMOS_EQP 0x14 +#define CMOS_CENTURY 0x32 -#define CMOS_READ(reg) ({ \ - io_out8(CMOS_REGS, reg); \ - io_in8(CMOS_DATA); \ -}) +#define CMOS_READ(reg) \ + ({ \ + io_out8(CMOS_REGS, reg); \ + io_in8(CMOS_DATA); \ + }) #define BCD2BIN(bcd) ((bcd >> 4) * 10 + (bcd & 0x0f)) +#define BIN2BCD(bin) (((bin / 10) << 4) + (bin % 10)) -struct time { - int year, month, day; - int hour, minute, second; -}; - -static inline void cmos_get_time(struct time *time) -{ - io_cli(); - do { - time->year = CMOS_READ(CMOS_YEAR) + CMOS_READ(CMOS_CENTURY) * 0x100; - time->month = CMOS_READ(CMOS_MONTH); - time->day = CMOS_READ(CMOS_DAY_OF_MONTH); - time->hour = CMOS_READ(CMOS_HOURS); - time->minute = CMOS_READ(CMOS_MINUTES); - time->second = CMOS_READ(CMOS_SECONDS); - } while (time->second != CMOS_READ(CMOS_SECONDS)); - io_out8(CMOS_REGS, 0x00); - io_sti(); -} +extern PhysicalDevice *cmos_device; +extern TimeDevice *rtc_time_device; + +DriverResult register_cmos(void); #endif \ No newline at end of file diff --git a/src/arch/x86/include/drivers/dma.h b/src/arch/x86/include/drivers/dma.h deleted file mode 100644 index ba591a8..0000000 --- a/src/arch/x86/include/drivers/dma.h +++ /dev/null @@ -1,70 +0,0 @@ -#ifndef _DMA_H -#define _DMA_H - -#define DMA0 0x00 -#define DMA1 0xc0 - -#define DMA_ADDR0 0x00 -#define DMA_CNT0 0x01 -#define DMA_ADDR1 0x02 -#define DMA_CNT1 0x03 -#define DMA_ADDR2 0x04 -#define DMA_CNT2 0x05 -#define DMA_ADDR3 0x06 -#define DMA_CNT3 0x07 -#define DMA_ADDR4 0xc0 -#define DMA_CNT4 0xc2 -#define DMA_ADDR5 0xc4 -#define DMA_CNT5 0xc6 -#define DMA_ADDR6 0xc8 -#define DMA_CNT6 0xca -#define DMA_ADDR7 0xcc -#define DMA_CNT7 0xce - -// DMA寄存器 -#define DMA1_REG_STAT 0x08 // 状态寄存器 -#define DMA1_REG_CMD 0x08 // 命令寄存器 -#define DMA1_REG_REQ 0x09 // 请求寄存器 -#define DMA1_REG_MASK 0x0a // 屏蔽寄存器 -#define DMA1_REG_MODE 0x0b // 模式寄存器 -#define DMA1_REG_FF_RESET 0x0c // 触发器复位寄存器 -#define DMA1_REG_TEMP 0x0d // 暂存寄存器 -#define DMA1_REG_RESET 0x0d // 主DMA复位寄存器 -#define DMA1_REG_MASK_RESET 0x0e // 复位屏蔽寄存器 -#define DMA1_REG_ALL_MASK 0x0f // 多通道屏蔽寄存器 - -#define DMA2_REG_STAT 0xd0 // 状态寄存器 -#define DMA2_REG_CMD 0xd0 // 命令寄存器 -#define DMA2_REG_REQ 0xd2 // 请求寄存器 -#define DMA2_REG_MASK 0xd4 // 屏蔽寄存器 -#define DMA2_REG_MODE 0xd6 // 模式寄存器 -#define DMA2_REG_FF_RESET 0xd8 // 触发器复位寄存器 -#define DMA2_REG_TEMP 0xda // 暂存寄存器 -#define DMA2_REG_RESET 0xda // DMA复位寄存器 -#define DMA2_REG_MASK_RESET 0xdc // 复位屏蔽寄存器 -#define DMA2_REG_ALL_MASK 0xde // 多通道屏蔽寄存器 - -// 屏蔽寄存器 -#define DMA_MASK_ON 0x04 - -// DMA页寄存器 -#define DMA_PAGE0 0x87 -#define DMA_PAGE1 0x83 -#define DMA_PAGE2 0x81 -#define DMA_PAGE3 0x82 -#define DMA_PAGE5 0x8b -#define DMA_PAGE6 0x89 -#define DMA_PAGE7 0x8a - -#define DMA_MODE_READ 0x06 -#define DMA_MODE_WRITE 0x0a - -void dma_enable(unsigned int channel); -void dma_disable(unsigned int channel); -void dma_ff_reset(unsigned int channel); -void dma_set_mode(unsigned int channel, char mode); -void dma_set_page(unsigned int channel, char page); -void dma_set_addr(unsigned int channel, unsigned int addr); -void dma_set_count(unsigned int channel, unsigned int count); - -#endif \ No newline at end of file diff --git a/src/arch/x86/include/drivers/pci.h b/src/arch/x86/include/drivers/pci.h deleted file mode 100644 index 5119e4c..0000000 --- a/src/arch/x86/include/drivers/pci.h +++ /dev/null @@ -1,123 +0,0 @@ -#ifndef _PCI_H -#define _PCI_H - -#include - -#define PCI_CONFIG_ADDR 0xcf8 -#define PCI_CONFIG_DATA 0xcfc - -#define PCI_REG_DEVICEID 0x00 -#define PCI_REG_VENDORID 0x02 -#define PCI_REG_STATUS 0x04 -#define PCI_REG_COMMAND 0x06 -#define PCI_REG_CLASSCODE 0x08 -#define PCI_REG_SUBCLASS 0x09 -#define PCI_REG_PROGIF 0x0a -#define PCI_REG_REVISIONID 0x0b -#define PCI_REG_BIST 0x0c -#define PCI_REG_HEADERTYPE 0x0d -#define PCI_REG_LTIMER 0x0e -#define PCI_REG_CLSIZE 0x0f - -#define PCI_BAR_BASE 0x10 -#define PCI_BAR(x) PCI_BAR_BASE + x * 4 -#define PCI_BAR_MEM_MASK ~0x0f -#define PCI_BAR_IO_MASK ~0x03 - -#define PCI_MAX_BAR 6 -#define PCI_MAX_BUS 256 -#define PCI_MAX_DEV 32 -#define PCI_MAX_FUNC 8 -#define PCI_MAX_DEVICE 256 - -#define PCI_SEL_REG(bus, device, function, offset) \ - { \ - uint32_t addr_reg; \ - addr_reg = (1 << 31) | (bus << 16) | (device << 11) | (func << 8) | (offset & 0xfc); \ - io_out32(PCI_CONFIG_ADDR, addr_reg); \ - } - -#define PCI_READ(size, type) \ - type pci_read##size(uint8_t bus, uint8_t device, uint8_t func, uint8_t offset) { \ - PCI_SEL_REG(bus, device, func, offset); \ - return io_in##size(PCI_CONFIG_DATA); \ - } -#define PCI_WRITE(size, type) \ - void pci_write##size(uint8_t bus, uint8_t device, uint8_t func, uint8_t offset, type value) { \ - PCI_SEL_REG(bus, device, func, offset); \ - io_out##size(PCI_CONFIG_DATA, value); \ - } - -#define PCI_READ_DEVICE(size, type) \ - type pci_device_read##size(struct pci_device *dev, uint8_t offset) { \ - return pci_read##size(dev->bus, dev->dev, dev->function, offset); \ - } -#define PCI_WRITE_DEVICE(size, type) \ - void pci_device_write##size(struct pci_device *dev, uint8_t offset, type value) { \ - pci_write##size(dev->bus, dev->dev, dev->function, offset, value); \ - } - -struct pci_device_bar { - uint32_t type; - uint32_t base_addr; - uint32_t length; -}; - -#define PCI_DEVICE_STATUS_INVALID 0 -#define PCI_DEVICE_STATUS_USING 1 -#define PCI_BAR_TYPE_INVALID 0 -#define PCI_BAR_TYPE_MEM 1 -#define PCI_BAR_TYPE_IO 2 - -struct pci_device { - char status; - - uint8_t bus; - uint8_t dev; - uint8_t function; - - uint16_t vendorID; - uint16_t deviceID; - uint8_t classcode; - uint8_t subclass; - uint8_t prog_if; - uint8_t revisionID; - uint8_t multifunction; - uint8_t irqline; - uint8_t irqpin; - - struct pci_device_bar bar[PCI_MAX_BAR]; -}; - -uint8_t pci_read8(uint8_t bus, uint8_t device, uint8_t func, uint8_t offset); -uint16_t pci_read16(uint8_t bus, uint8_t device, uint8_t func, uint8_t offset); -uint32_t pci_read32(uint8_t bus, uint8_t device, uint8_t func, uint8_t offset); -void pci_write8(uint8_t bus, uint8_t device, uint8_t func, uint8_t offset, uint8_t value); -void pci_write16(uint8_t bus, uint8_t device, uint8_t func, uint8_t offset, uint16_t value); -void pci_write32(uint8_t bus, uint8_t device, uint8_t func, uint8_t offset, uint32_t value); - -uint8_t pci_device_read8(struct pci_device *dev, uint8_t offset); -uint16_t pci_device_read16(struct pci_device *dev, uint8_t offset); -uint32_t pci_device_read32(struct pci_device *dev, uint8_t offset); -void pci_device_write8(struct pci_device *dev, uint8_t offset, uint8_t value); -void pci_device_write16(struct pci_device *dev, uint8_t offset, uint16_t value); -void pci_device_write32(struct pci_device *dev, uint8_t offset, uint32_t value); - -void init_pci(); -void pci_scan_device(uint8_t bus, uint8_t device, uint8_t function); -struct pci_device *pci_get_device_ById(uint16_t vendorID, uint16_t deviceID); -struct pci_device *pci_get_device_ByClass(uint8_t classcode, uint8_t subclass); -struct pci_device *pci_get_device_ByClassFull(uint8_t classcode, uint8_t subclass, uint8_t progif); -void pci_enable_bus_mastering(struct pci_device *device); -void pci_enable_io_space(struct pci_device *device); -void pci_enable_mem_space(struct pci_device *device); -uint32_t pci_get_device_connected(void); -struct pci_device *pci_alloc_device(void); -int pci_free_device(struct pci_device *dev); -void pci_device_init(struct pci_device *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); -void pci_bar_init(struct pci_device_bar *bar, uint32_t addr, uint32_t len); -uint32_t pci_device_get_mem_addr(struct pci_device *dev); -uint32_t pci_device_get_io_addr(struct pci_device *dev); - -#endif \ No newline at end of file diff --git a/src/arch/x86/include/drivers/pit.h b/src/arch/x86/include/drivers/pit.h index cab64d7..751c0d6 100644 --- a/src/arch/x86/include/drivers/pit.h +++ b/src/arch/x86/include/drivers/pit.h @@ -1,39 +1,21 @@ #ifndef _PIT_H #define _PIT_H +#include "kernel/driver.h" #define PIT_CTRL 0x43 #define PIT_CNT0 0x40 -#define PIC_PIT_IRQ 0 // 使用PIC时PIT的IRQ为1 +#define PIC_PIT_IRQ 0 // 使用PIC时PIT的IRQ为1 #define APIC_PIT_IRQ 2 // 使用APIC时PIT的IRQ为2 #define MAX_TIMER 2048 -#define TIMER_FREE 0 +#define TIMER_FREE 0 #define TIMER_UNUSED 1 -#define TIMER_USING 2 +#define TIMER_USING 2 -struct timer { - struct timer *next; - unsigned int timeout, flags; - struct fifo *fifo; - int data; -}; - -struct timerctl { - unsigned int count, next, using; - struct timer *timers[MAX_TIMER]; - struct timer timers0[MAX_TIMER]; -}; - -extern struct timerctl timerctl; - -void init_timer(void); -void timer_handler(int irq); -struct timer *timer_alloc(void); -void timer_free(struct timer *timer); -void timer_init(struct timer *timer, struct fifo *fifo, int data); -void timer_settime(struct timer *timer, unsigned int timeout); -void delay(int time); +DriverResult register_pit(); +extern struct PhysicalDevice *i8254_device; +extern struct TimerDevice *pit_timer_device; #endif \ No newline at end of file diff --git a/src/arch/x86/include/drivers/serial.h b/src/arch/x86/include/drivers/serial.h new file mode 100644 index 0000000..4447bc2 --- /dev/null +++ b/src/arch/x86/include/drivers/serial.h @@ -0,0 +1,56 @@ +#ifndef _SERIAL_H +#define _SERIAL_H + +#include "kernel/driver_interface.h" +#include +#include +#include +#include +#include +#include + +#define SERIAL_COM1_BASE 0x3F8 +#define SERIAL_COM2_BASE 0x2F8 +#define SERIAL_COM3_BASE 0x3E8 +#define SERIAL_COM4_BASE 0x2E8 + +#define SERIAL_RATE_115200_DIVISION 1 +#define SERIAL_RATE_57600_DIVISION 2 +#define SERIAL_RATE_38400_DIVISION 3 +#define SERIAL_RATE_19200_DIVISION 6 +#define SERIAL_RATE_9600_DIVISION 12 + +#define SERIAL_RATE_DIVISION SERIAL_RATE_115200_DIVISION + +#define SERIAL_COM1_IRQ 4 +#define SERIAL_COM2_IRQ 3 +#define SERIAL_COM3_IRQ 4 +#define SERIAL_COM4_IRQ 3 + +#define SERIAL_UART_REG_DATA 0 +#define SERIAL_UART_REG_DIVISOR_LATCH_LOW 0 +#define SERIAL_UART_REG_INTERRUPT_ENABLE 1 +#define SERIAL_UART_REG_DIVISOR_LATCH_HIGH 1 +#define SERIAL_UART_REG_INTERRUPT_IDENTIFICATION 2 +#define SERIAL_UART_REG_FIFO_CONTROL 2 +#define SERIAL_UART_REG_LINE_CONTROL 3 +#define SERIAL_UART_REG_MODEM_CONTROL 4 +#define SERIAL_UART_REG_LINE_STATUS 5 +#define SERIAL_UART_REG_MODEM_STATUS 6 +#define SERIAL_UART_REG_SCRATCH 7 + +#define SERIAL_TEST_MAGIC_1 0x55 +#define SERIAL_TEST_MAGIC_2 0xAA + +typedef struct { + LogicalDevice *device; + uint16_t base_port; + uint8_t irq_num; + DeviceIrq *irq; + + ConsoleBackend console_backend; +} Serial; + +void register_serial(); + +#endif \ No newline at end of file diff --git a/src/arch/x86/include/drivers/usb/func.h b/src/arch/x86/include/drivers/usb/func.h deleted file mode 100644 index 07218cf..0000000 --- a/src/arch/x86/include/drivers/usb/func.h +++ /dev/null @@ -1,41 +0,0 @@ -#ifndef _USB_FUNC_H -#define _USB_FUNC_H - -#include - -#define REQ_GET_PORT_STATUS_SIZE 4 - -struct usb_device_descriptor *usb_get_device_descriptor( - usb_hcd_t *hcd, usb_device_t *device, usb_endpoint_t *ep); -struct usb_config_descriptor *usb_get_config_descriptor( - usb_hcd_t *hcd, usb_device_t *device, usb_endpoint_t *ep); - -uint8_t usb_get_config( - usb_hcd_t *hcd, usb_device_t *device, usb_endpoint_t *ep); -usb_setup_status_t usb_set_config( - usb_hcd_t *hcd, usb_device_t *device, usb_endpoint_t *ep, uint8_t config); - -struct usb_hub_descriptor *usb_get_hub_descriptor( - usb_hcd_t *hcd, usb_device_t *device, usb_endpoint_t *ep); - -usb_setup_status_t usb_set_address( - usb_hcd_t *hcd, usb_device_t *device, usb_endpoint_t *ep, uint32_t address); - -usb_setup_status_t usb_set_port_feature( - usb_hcd_t *hcd, usb_device_t *device, usb_endpoint_t *ep, uint8_t port, - uint16_t feature); - -uint32_t usb_get_hub_status( - usb_hcd_t *hcd, usb_device_t *device, usb_endpoint_t *ep); -uint32_t usb_get_port_status( - usb_hcd_t *hcd, usb_device_t *device, usb_endpoint_t *ep, uint8_t port); - -struct usb_string_descriptor *usb_get_string_descriptor( - usb_hcd_t *hcd, usb_device_t *device, uint8_t index, usb_endpoint_t *ep); - -void usb_show_device_descriptor( - usb_hcd_t *hcd, usb_device_t *device, usb_endpoint_t *ep, - struct usb_device_descriptor *desc); -void usb_show_hub_descriptor(struct usb_hub_descriptor *desc); - -#endif \ No newline at end of file diff --git a/src/arch/x86/include/drivers/usb/hcd.h b/src/arch/x86/include/drivers/usb/hcd.h deleted file mode 100644 index baed3ff..0000000 --- a/src/arch/x86/include/drivers/usb/hcd.h +++ /dev/null @@ -1,51 +0,0 @@ -#ifndef HCD_H -#define HCD_H - -#include -#include -#include -#include - -struct usb_device; -struct usb_transfer; -struct usb_request; - -typedef struct usb_hcd_port { - uint32_t port; - struct usb_hcd *hcd; - - uint8_t suspend; - uint8_t enable; - uint8_t connected; -} usb_hcd_port_t; - -typedef struct usb_hcd_interface { - enum usb_setup_status (*control_transaction_in)( - struct usb_hcd *hcd, struct usb_device *device, - struct usb_transfer *transfer, void *buffer, uint32_t data_length, - struct usb_request *usb_req); - enum usb_setup_status (*control_transaction_out)( - struct usb_hcd *hcd, struct usb_device *device, - struct usb_transfer *transfer, void *buffer, uint32_t data_length, - struct usb_request *usb_req); -} usb_hcd_interface_t; - -typedef struct usb_hcd { - list_t list; - usb_hcd_port_t *ports; - - usb_hcd_interface_t *interface; - - string_t *name; - device_t *device; - - uint8_t device_count; - - list_t usb_devices; -} usb_hcd_t; - -usb_hcd_t *usb_hcd_register( - device_t *device, char *name, uint32_t port_cnt, - usb_hcd_interface_t *interface); - -#endif // HCD_H \ No newline at end of file diff --git a/src/arch/x86/include/drivers/usb/hub.h b/src/arch/x86/include/drivers/usb/hub.h deleted file mode 100644 index 4c5e11b..0000000 --- a/src/arch/x86/include/drivers/usb/hub.h +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef _USB_HUB_H -#define _USB_HUB_H - -#include - -#define HUB_FEAT_C_LOCAL_POWER 0 -#define HUB_FEAT_C_OVER_CURRENT 1 - -#define HUB_FEAT_PORT_CONNECTION 0 -#define HUB_FEAT_PORT_ENABLE 1 -#define HUB_FEAT_PORT_SUSPEND 2 -#define HUB_FEAT_PORT_OVER_CURRENT 3 -#define HUB_FEAT_PORT_RESET 4 -#define HUB_FEAT_PORT_POWER 8 -#define HUB_FEAT_PORT_LOW_SPEED 9 - -#define HUB_FEAT_C_PORT_CONNECTION 16 -#define HUB_FEAT_C_PORT_ENABLE 17 -#define HUB_FEAT_C_PORT_SUSPEND 18 -#define HUB_FEAT_C_PORT_OVER_CURRENT 19 -#define HUB_FEAT_C_PORT_RESET 20 - -#define HUB_FEAT_PORT_TEST 21 -#define HUB_FEAT_PORT_INDICATOR 22 - -void usb_init_hub(usb_hcd_t *hcd, usb_device_t *device); - -#endif \ No newline at end of file diff --git a/src/arch/x86/include/drivers/usb/uhci.h b/src/arch/x86/include/drivers/usb/uhci.h index 5bf5f77..2fd8faf 100644 --- a/src/arch/x86/include/drivers/usb/uhci.h +++ b/src/arch/x86/include/drivers/usb/uhci.h @@ -2,8 +2,14 @@ #define _UHCI_H #include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include #include #define FRAMELIST_SIZE 1024 @@ -17,6 +23,8 @@ #define UHCI_PORTSC1 0x10 #define UHCI_PORTSC2 0x12 +#define UHCI_PCI_REG_LEGSUP 0xc0 + #define UHCI_CMD_RUN 0x01 #define UHCI_CMD_HCRESET 0x02 #define UHCI_CMD_GLBRESET 0x04 @@ -40,6 +48,13 @@ #define UHCI_PORT_SC_CONN_CHG BIT(1) #define UHCI_PORT_SC_CONNECTED BIT(0) +#define UHCI_STAT_HC_HALTED BIT(5) +#define UHCI_STAT_HC_PROCESS_ERROR BIT(4) +#define UHCI_STAT_HOST_SYSTEM_ERROR BIT(3) +#define UHCI_STAT_RESUME_DETECT BIT(2) +#define UHCI_STAT_ERROR_INT BIT(1) +#define UHCI_STAT_INTERRUPT BIT(0) + #define UHCI_STAT_SPEED BIT(29) #define UHCI_STAT_ERROR_LIMIT_BIT 27 #define UHCI_STAT_LSD BIT(26) @@ -64,24 +79,28 @@ #define UHCI_QH_TD_SELECT BIT(1) // 1:QH, 0:TD #define UHCI_TERMINATE BIT(0) -struct uhci_frame_list { +#define UHCI_SKEL_QH_COUNT 11 + +typedef struct UhciFrameList { uint32_t *frames_vir; uint32_t *frames_phy; -}; +} UhciFrameList; -typedef struct uhci_qh { +typedef struct UhciQh { // 硬件用 - uint32_t qh_link; - uint32_t qe_link; + uint32_t qh_link; + uint32_t qe_link; // 软件用 - uint32_t qh_addr_phy; - uint32_t prev_ptr; - uint32_t last_ptr; - uint32_t next_ptr; - uint32_t align[2]; // 用于对齐16字节 -} uhci_qh_t; - -typedef struct uhci_td { + uint8_t enqueued : 1; + struct UhciQh *next; + union { + struct UhciQh *first_qh; + struct UhciTd *first_td; + }; + UsbEndpoint *endpoint; +} __attribute__((packed, aligned(16))) UhciQh; + +typedef struct UhciTd { uint32_t link; // TD control and status @@ -113,25 +132,40 @@ typedef struct uhci_td { uint32_t buf_addr_phy; // software use - uint32_t prev_ptr; - uint32_t td_addr_phy; - uint32_t software_use[2]; -} __attribute__((packed)) uhci_td_t; + list_t list; + struct UhciTd *next; + UsbRequestBlock *urb; +} __attribute__((packed, aligned(16))) UhciTd; + +typedef struct UhciSched { + UhciQh qh; -struct uhci_skel { - struct uhci_qh qh[11]; // 1ms, 2ms, 4ms, 8ms, 16ms, 32ms, 64ms, 128ms -}; + uint8_t td_count; + uint8_t td_used; // bitmap + UhciTd *pre_alloc_td; // 预分配的TD + + list_t pipe_lh; +} UhciPipeline; + +typedef struct UhciSkel { + struct UhciQh + qh[UHCI_SKEL_QH_COUNT]; // 1ms, 2ms, 4ms, 8ms, 16ms, 32ms, 64ms, 128ms +} UhciSkel; typedef struct { - struct pci_device *device; - uint32_t io_base; - struct uhci_frame_list fl; - uint8_t port_cnt; + PciDevice *device; + uint32_t io_base; + UhciFrameList fl; + uint8_t port_cnt; + Timer timer; - struct uhci_skel *skel; -} uhci_t; + UhciSkel *skel; + UsbHcd *hcd; -enum uhci_skel_type { + DeviceIrq *irq; +} Uhci; + +typedef enum UhciSkelType { TIME_1MS = 0, TIME_2MS, TIME_4MS, @@ -140,21 +174,22 @@ enum uhci_skel_type { TIME_32MS, TIME_64MS, TIME_128MS, - LOW_SPEED, - FULL_SPEED, + ASYNC, TERM, -}; +} UhciSkelType; + +void uhci_skel_init(Uhci *uhci); -void uhci_skel_init(uhci_t *devext); +void uhci_skel_add_qh(Uhci *uhci, UhciQh *qh, UhciSkelType type); +void uhci_skel_del_qh(Uhci *uhci, UhciQh *qh, UhciSkelType type); -void uhci_skel_add_qh(uhci_t *devext, uhci_qh_t *qh, enum uhci_skel_type type); -void uhci_skel_del_qh(uhci_t *devext, uhci_qh_t *qh, enum uhci_skel_type type); +void uhci_free_all_td(UhciPipeline *pipe); -usb_setup_status_t uhci_control_transaction_in( - usb_hcd_t *hcd, usb_device_t *device, usb_transfer_t *transfer, - void *buffer, uint32_t data_length, usb_request_t *usb_req); -usb_setup_status_t uhci_control_transaction_out( - usb_hcd_t *hcd, usb_device_t *device, usb_transfer_t *transfer, - void *buffer, uint32_t data_length, usb_request_t *usb_req); +UsbSetupStatus uhci_ctrl_transfer_in( + UsbHcd *hcd, UsbDevice *device, void *buffer, uint32_t data_length, + UsbControlRequest *usb_req); +UsbSetupStatus uhci_ctrl_transfer_out( + UsbHcd *hcd, UsbDevice *device, void *buffer, uint32_t data_length, + UsbControlRequest *usb_req); #endif \ No newline at end of file diff --git a/src/arch/x86/include/drivers/usb/usb.h b/src/arch/x86/include/drivers/usb/usb.h deleted file mode 100644 index 3013d0d..0000000 --- a/src/arch/x86/include/drivers/usb/usb.h +++ /dev/null @@ -1,235 +0,0 @@ -#ifndef _USB_H -#define _USB_H - -#include -#include -#include -#include - -#define USB_REQ_HOST_TO_DEVICE 0 -#define USB_REQ_DEVICE_TO_HOST 1 - -#define USB_REQ_TYPE_STANDARD 0 -#define USB_REQ_TYPE_CLASS 1 -#define USB_REQ_TYPE_VENDOR 2 - -#define USB_REQ_RECIPIENT_DEVICE 0x00 -#define USB_REQ_RECIPIENT_INTERFACE 0x01 -#define USB_REQ_RECIPIENT_ENDPOINT 0x02 -#define USB_REQ_RECIPIENT_OTHER 0x03 - -#define USB_REQ_GET_STATUS 0x00 -#define USB_REQ_CLEAR_FEATURE 0x01 -#define USB_REQ_SET_FEATURE 0x03 -#define USB_REQ_SET_ADDRESS 0x05 -#define USB_REQ_GET_DESCRIPTOR 0x06 -#define USB_REQ_SET_DESCRIPTOR 0x07 -#define USB_REQ_GET_CONFIGURATION 0x08 -#define USB_REQ_SET_CONFIGURATION 0x09 -#define USB_REQ_GET_INTERFACE 0x0a -#define USB_REQ_SYNC_FRAME 0x0c - -#define USB_DESC_TYPE_DEVICE 0x01 -#define USB_DESC_TYPE_CONFIG 0x02 -#define USB_DESC_TYPE_STRING 0x03 -#define USB_DESC_TYPE_INTERFACE 0x04 -#define USB_DESC_TYPE_ENDPOINT 0x05 -#define USB_DESC_TYPE_DEVICE_QUALIFIER 0x06 -#define USB_DESC_TYPE_OTHER_SPEED_CONFIG 0x07 -#define USB_DESC_TYPE_INTERFACE_POWER 0x08 - -#define USB_DESC_TYPE_DEVICE_SIZE 18 -#define USB_DESC_TYPE_CONFIG_SIZE 9 -#define USB_DESC_TYPE_HUB_SIZE 9 - -#define USB_DESC_TYPE_HUB 0x29 - -#define USB_PACKET_ID_IN 0x69 -#define USB_PACKET_ID_OUT 0xe1 -#define USB_PACKET_ID_SETUP 0x2d -#define USB_PACKET_ID_ACK 0xd2 -#define USB_PACKET_ID_NAK 0xa1 -#define USB_PACKET_ID_STALL 0x54 -#define USB_PACKET_ID_NYET 0x96 - -#define USB_CLASS_AUDIO 0x01 -#define USB_CLASS_COMM 0x02 -#define USB_CLASS_HID 0x03 -#define USB_CLASS_MASS 0x08 -#define USB_CLASS_HUB 0x09 - -#define USB_PORT_STAT_CONNECTION BIT(0) -#define USB_PORT_STAT_ENABLE BIT(1) -#define USB_PORT_STAT_SUSPEND BIT(2) -#define USB_PORT_STAT_OVER_CURRENT BIT(3) -#define USB_PORT_STAT_RESET BIT(4) -#define USB_PORT_STAT_POWER BIT(8) -#define USB_PORT_STAT_LOW_SPEED BIT(9) -#define USB_PORT_STAT_HIGH_SPEED BIT(10) -#define USB_PORT_STAT_TEST BIT(11) -#define USB_PORT_STAT_INDICATOR BIT(12) - -struct usb_device_descriptor { - uint8_t bLength; - uint8_t bDescriptorType; - uint16_t bcdUSB; - uint8_t bDeviceClass; - uint8_t bDeviceSubClass; - uint8_t bDeviceProtocol; - uint8_t bMaxPacketSize0; - uint16_t idVendor; - uint16_t idProduct; - uint16_t bcdDevice; - uint8_t iManufacturer; - uint8_t iProduct; - uint8_t iSerialNumber; - uint8_t bNumConfigurations; -} __attribute__((packed)); - -struct usb_config_descriptor { - uint8_t bLength; - uint8_t bDescriptorType; - uint16_t wTotalLength; - uint8_t bNumInterfaces; - uint8_t bConfigurationValue; - uint8_t iConfiguration; - uint8_t bmAttributes; - uint8_t bMaxPower; -} __attribute__((packed)); - -struct usb_interface_descriptor { - uint8_t bLength; - uint8_t bDescriptorType; - uint8_t bInterfaceNumber; - uint8_t bAlternateSetting; - uint8_t bNumEndpoints; - uint8_t bInterfaceClass; - uint8_t bInterfaceSubClass; - uint8_t bInterfaceProtocol; - uint8_t iInterface; -} __attribute__((packed)); - -struct usb_endpoint_descriptor { - uint8_t bLength; - uint8_t bDescriptorType; - uint8_t bEndpointAddress; - uint8_t bmAttributes; - uint16_t wMaxPacketSize; - uint8_t bInterval; -} __attribute__((packed)); - -struct usb_string_descriptor { - uint8_t bLength; - uint8_t bDescriptorType; - uint16_t wData[]; -} __attribute__((packed)); - -struct usb_hub_descriptor { - uint8_t bLength; - uint8_t bDescriptorType; - uint8_t bNbrPorts; - uint16_t wHubCharacteristics; - uint8_t bPwrOn2PwrGood; - uint8_t bHubContrCurrent; - uint8_t DeviceRemovable; - uint8_t PortPwrCtrlMask; -} __attribute__((packed)); - -typedef enum usb_device_speed { - USB_SPEED_LOW, - USB_SPEED_FULL, - USB_SPEED_HIGH, -} usb_device_speed_t; - -typedef struct usb_device { - list_t list; - uint8_t address; - - list_t ep_lh; - list_t interface_lh; - - struct usb_device_descriptor *desc; - usb_device_speed_t speed; -} usb_device_t; - -typedef struct usb_endpoint { - list_t list; - - uint8_t endpoint; - enum ep_transfer_type { - USB_EP_CONTROL, - USB_EP_ISOCHRONOUS, - USB_EP_BULK, - USB_EP_INTERRUPT, - } transfer_type; - enum ep_direction { - USB_EP_OUT, - USB_EP_IN, - } direction; - uint16_t max_packet_size; -} usb_endpoint_t; - -typedef struct usb_interface { - list_t list; - - uint8_t interface; - uint8_t class; - uint8_t subclass; - uint8_t protocol; -} usb_interface_t; - -typedef struct usb_transfer { - usb_device_t *device; - usb_endpoint_t *ep; -} usb_transfer_t; - -typedef enum usb_status { - USB_STATUS_ACK, - USB_STATUS_NAK, - USB_STATUS_STALL, - USB_STATUS_NYET, - USB_STATUS_ERR, -} usb_status_t; - -typedef enum usb_setup_status { - USB_SETUP_SUCCESS, - USB_SETUP_NAK_RECV, - USB_SETUP_STALLED, - USB_SETUP_CRC_TIMEOUT_ERR, - USB_SETUP_BITSTUFF_ERR, - USB_SETUP_DATABUFFER_ERR, -} usb_setup_status_t; - -typedef struct usb_request { - uint8_t bmRequestType; - uint8_t bRequest; - uint16_t wValue; - uint16_t wIndex; - uint16_t wLength; -} usb_request_t; - -extern usb_endpoint_t usb_default_ep; - -usb_device_t *usb_create_device(usb_device_speed_t speed, uint8_t address); -int usb_destroy_device(usb_device_t *device); - -usb_request_t *usb_create_request( - uint8_t direction, uint8_t type, uint8_t recipient, uint8_t request_id, - uint8_t value_hi, uint8_t value_lo, uint16_t index, uint16_t length); -usb_endpoint_t *usb_create_endpoint( - uint8_t endpoint, enum ep_transfer_type transfer_type, - enum ep_direction direction, uint16_t max_packet_size); - -usb_transfer_t *usb_create_transfer( - usb_device_t *device, usb_endpoint_t *endpoint); - -int usb_init_device(usb_hcd_t *hcd, usb_device_t *device); - -usb_setup_status_t usb_control_transaction_in( - usb_hcd_t *hcd, usb_device_t *device, usb_endpoint_t *ep, void *buffer, - usb_request_t *usb_req, uint32_t length); -usb_setup_status_t usb_control_transaction_out( - usb_hcd_t *hcd, usb_device_t *device, usb_endpoint_t *ep, void *buffer, - usb_request_t *usb_req, uint32_t length); - -#endif \ No newline at end of file diff --git a/src/arch/x86/include/drivers/vesa_display.h b/src/arch/x86/include/drivers/vesa_display.h new file mode 100644 index 0000000..41d336e --- /dev/null +++ b/src/arch/x86/include/drivers/vesa_display.h @@ -0,0 +1,46 @@ +#ifndef _VESA_DISPLAY_H +#define _VESA_DISPLAY_H + +#include "kernel/driver.h" +struct VbeModeInfoBlock { + unsigned char VbeSignature[4]; + unsigned short VbeVersion; + unsigned int *OemStringPtr; + unsigned int Capabilities; + unsigned int *VideoModePtr; + unsigned short TotalMemory; + unsigned short OemSoftwareRev; + unsigned int *OemVendorNamePtr; + unsigned int *OemProductNamePtr; + unsigned int *OemProduceRevPtr; + unsigned char Reserved[222]; + unsigned char OemData; +} __attribute__((packed)); + +struct VbeControlInfoBlock { + unsigned char VbeSignature[4]; + unsigned short VbeVersion; + unsigned int OemStringPtr; + unsigned char Capabilities[4]; + unsigned int VideoModePtr; + unsigned short TotalMemory; + unsigned short OemSoftwareRev; + unsigned int OemVendorNamePtr; + unsigned int OemProductNamePtr; + unsigned int OemProduceRevPtr; + unsigned char OemData[256]; +}; + +struct VesaDisplayInfo { + unsigned short width, height; + unsigned short BitsPerPixel; + unsigned char *vram; + struct VbeModeInfoBlock *vbe_mode_info; + struct VbeControlInfoBlock *vbe_conrtol_info; +}; + +extern struct LogicalDevice vesa_display_device; + +DriverResult register_vesa_display(void); + +#endif \ No newline at end of file diff --git a/src/arch/x86/include/drivers/video.h b/src/arch/x86/include/drivers/video.h index 6ebb33f..963c3b9 100644 --- a/src/arch/x86/include/drivers/video.h +++ b/src/arch/x86/include/drivers/video.h @@ -50,18 +50,9 @@ struct VideoInfo { extern struct VideoInfo video_info; -// 写像素 -void write_pixel(int x, int y, unsigned int color); // 获取显示模式信息 void init_video(void); // 输出VBE信息 void show_vbeinfo(void); -// 输出字符 -void print_word(int x, int y, unsigned char *ascii, unsigned int color); -// 输出字符串 -void print_string( - int x, int y, unsigned int color, unsigned char *font, char *string); - -void draw_rect(int x, int y, int width, int height, int color); #endif \ No newline at end of file diff --git a/src/arch/x86/include/kernel/cpu.h b/src/arch/x86/include/kernel/cpu.h new file mode 100644 index 0000000..3c9a136 --- /dev/null +++ b/src/arch/x86/include/kernel/cpu.h @@ -0,0 +1,6 @@ +#ifndef _CPU_H +#define _CPU_H + +#define DEF_PER_CPU(type, name) type name __attribute__((section(".percpu"))); + +#endif \ No newline at end of file diff --git a/src/arch/x86/include/kernel/descriptor.h b/src/arch/x86/include/kernel/descriptor.h index 84606eb..4d06c14 100644 --- a/src/arch/x86/include/kernel/descriptor.h +++ b/src/arch/x86/include/kernel/descriptor.h @@ -74,6 +74,5 @@ void set_segment_descriptor( struct segment_descriptor *sd, unsigned int limit, int base, int ar); void set_gate_descriptor( struct gate_descriptor *gd, int offset, int selector, int ar); -void irq_enable(int irq); #endif \ No newline at end of file diff --git a/src/arch/x86/include/kernel/feature.h b/src/arch/x86/include/kernel/feature.h new file mode 100644 index 0000000..6fabf23 --- /dev/null +++ b/src/arch/x86/include/kernel/feature.h @@ -0,0 +1,71 @@ +#ifndef _FEATURE_H +#define _FEATURE_H + +enum x86_cpu_features { + CPUID_FEAT_SSE3 = 0, + CPUID_FEAT_PCLMUL = 1, + CPUID_FEAT_DTES64 = 2, + CPUID_FEAT_MONITOR = 3, + CPUID_FEAT_DS_CPL = 4, + CPUID_FEAT_VMX = 5, + CPUID_FEAT_SMX = 6, + CPUID_FEAT_EST = 7, + CPUID_FEAT_TM2 = 8, + CPUID_FEAT_SSSE3 = 9, + CPUID_FEAT_CID = 10, + CPUID_FEAT_FMA = 12, + CPUID_FEAT_CX16 = 13, + CPUID_FEAT_XTPR = 14, + CPUID_FEAT_PDCM = 15, + CPUID_FEAT_PCID = 17, + CPUID_FEAT_DCA = 18, + CPUID_FEAT_SSE4_1 = 19, + CPUID_FEAT_SSE4_2 = 20, + CPUID_FEAT_X2APIC = 21, + CPUID_FEAT_MOVBE = 22, + CPUID_FEAT_POPCNT = 23, + CPUID_FEAT_TSC_DEADLINE = 24, + CPUID_FEAT_AES = 25, + CPUID_FEAT_XSAVE = 26, + CPUID_FEAT_OSXSAVE = 27, + CPUID_FEAT_AVX = 28, + CPUID_FEAT_F16C = 29, + CPUID_FEAT_RDRAND = 30, + CPUID_FEAT_HYPERVISOR = 31, + + CPUID_FEAT_FPU = 32 + 0, + CPUID_FEAT_VME = 32 + 1, + CPUID_FEAT_DE = 32 + 2, + CPUID_FEAT_PSE = 32 + 3, + CPUID_FEAT_TSC = 32 + 4, + CPUID_FEAT_MSR = 32 + 5, + CPUID_FEAT_PAE = 32 + 6, + CPUID_FEAT_MCE = 32 + 7, + CPUID_FEAT_CX8 = 32 + 8, + CPUID_FEAT_APIC = 32 + 9, + CPUID_FEAT_SEP = 32 + 11, + CPUID_FEAT_MTRR = 32 + 12, + CPUID_FEAT_PGE = 32 + 13, + CPUID_FEAT_MCA = 32 + 14, + CPUID_FEAT_CMOV = 32 + 15, + CPUID_FEAT_PAT = 32 + 16, + CPUID_FEAT_PSE36 = 32 + 17, + CPUID_FEAT_PSN = 32 + 18, + CPUID_FEAT_CLFLUSH = 32 + 19, + CPUID_FEAT_DS = 32 + 21, + CPUID_FEAT_ACPI = 32 + 22, + CPUID_FEAT_MMX = 32 + 23, + CPUID_FEAT_FXSR = 32 + 24, + CPUID_FEAT_SSE = 32 + 25, + CPUID_FEAT_SSE2 = 32 + 26, + CPUID_FEAT_SS = 32 + 27, + CPUID_FEAT_HTT = 32 + 28, + CPUID_FEAT_TM = 32 + 29, + CPUID_FEAT_PBE = 32 + 31 +}; + +void read_features(void); +int cpu_check_feature(enum x86_cpu_features feature); +void print_features(); + +#endif \ No newline at end of file diff --git a/src/arch/x86/include/kernel/func.h b/src/arch/x86/include/kernel/func.h index a7e7c35..3f53aaf 100644 --- a/src/arch/x86/include/kernel/func.h +++ b/src/arch/x86/include/kernel/func.h @@ -1,6 +1,7 @@ #ifndef _FUNC_H #define _FUNC_H +#include #define CR0_PE 0x01 #define CR0_MP 0x02 #define CR0_EM 0x04 @@ -26,16 +27,39 @@ void io_sti(void); void io_hlt(void); void io_stihlt(void); -static inline void get_cpuid(unsigned int Mop, unsigned int Sop, unsigned int *a, unsigned int *b, - unsigned int *c, unsigned int *d) { - __asm__ __volatile__("cpuid \n\t" : "=a"(*a), "=b"(*b), "=c"(*c), "=d"(*d) : "0"(Mop), "2"(Sop)); +static inline void get_cpuid( + unsigned int Mop, unsigned int Sop, unsigned int *a, unsigned int *b, + unsigned int *c, unsigned int *d) { + __asm__ __volatile__("cpuid \n\t" + : "=a"(*a), "=b"(*b), "=c"(*c), "=d"(*d) + : "0"(Mop), "2"(Sop)); } static inline void ltr(unsigned short sel) { __asm__ __volatile__("ltr %0" ::"r"(sel)); } +static inline void io_stream_in8( + unsigned int port, unsigned int buffer, unsigned int nr) { + __asm__ __volatile__("cld;\n\t \ + rep;\n\t \ + insb;\n\t \ + mfence;" ::"d"(port), + "D"(buffer), "c"(nr) + : "memory"); +} -static inline void port_insw(unsigned int port, unsigned int buffer, unsigned int nr) { +static inline void io_stream_out8( + unsigned int port, unsigned int buffer, unsigned int nr) { + __asm__ __volatile__("cld;\n\t \ + rep;\n\t \ + outsb;\n\t \ + mfence;\n\t" ::"d"(port), + "S"(buffer), "c"(nr) + : "memory"); +} + +static inline void io_stream_in16( + unsigned int port, unsigned int buffer, unsigned int nr) { __asm__ __volatile__("cld;\n\t \ rep;\n\t \ insw;\n\t \ @@ -44,7 +68,8 @@ static inline void port_insw(unsigned int port, unsigned int buffer, unsigned in : "memory"); } -static inline void port_outsw(unsigned int port, unsigned int buffer, unsigned int nr) { +static inline void io_stream_out16( + unsigned int port, unsigned int buffer, unsigned int nr) { __asm__ __volatile__("cld;\n\t \ rep;\n\t \ outsw;\n\t \ @@ -53,6 +78,26 @@ static inline void port_outsw(unsigned int port, unsigned int buffer, unsigned i : "memory"); } +static inline void io_stream_in32( + unsigned int port, unsigned int buffer, unsigned int nr) { + __asm__ __volatile__("cld;\n\t \ + rep;\n\t \ + insl;\n\t \ + mfence;\n\t" ::"d"(port), + "S"(buffer), "c"(nr) + : "memory"); +} + +static inline void io_stream_out32( + unsigned int port, unsigned int buffer, unsigned int nr) { + __asm__ __volatile__("cld;\n\t \ + rep;\n\t \ + outsl;\n\t \ + mfence;\n\t" ::"d"(port), + "S"(buffer), "c"(nr) + : "memory"); +} + static inline unsigned int bsr(unsigned int x) { unsigned int index; __asm__ __volatile__("bsrl %1, %0" : "=r"(index) : "r"(x)); @@ -65,6 +110,12 @@ static inline unsigned int bsf(unsigned int x) { return index; } +static inline uint64_t read_tsc(void) { + unsigned int low, high; + __asm__ __volatile__("rdtsc" : "=a"(low), "=d"(high)); + return ((uint64_t)high << 32) | low; +} + #define GET_REG(reg, var) __asm__ __volatile__("mov %%" reg ", %0" : "=g"(var)); int read_cr3(); @@ -81,6 +132,8 @@ void load_idtr(int limit, int addr); int io_load_eflags(void); void io_store_eflags(int eflags); +int save_eflags_cli(void); + void exception_entry0(void); void exception_entry1(void); void exception_entry2(void); diff --git a/src/arch/x86/include/kernel/page.h b/src/arch/x86/include/kernel/page.h index 6561928..9038875 100644 --- a/src/arch/x86/include/kernel/page.h +++ b/src/arch/x86/include/kernel/page.h @@ -6,47 +6,50 @@ #define PDT_PHY_ADDR 0x201000 // 页目录表物理地址 -#define TBL_PHY_ADDR 0x202000 +#define TBL_PHY_ADDR 0x202000 #define VRAM_PT_PHY_ADDR 0x203000 #define DMA_PT_PHY_ADDR1 0x204000 #define DMA_PT_PHY_ADDR2 0x205000 #define PAGE_SIZE 1024 * 4 // 页大小 -#define SIGN_P 0x01 // 存在 +#define SIGN_P 0x01 // 存在 #define SIGN_RW 0x02 // 读写 -#define SIGN_US 0x04 // 普通/超级用户 +#define SIGN_US 0x04 // 普通/超级用户 #define SIGN_USER 0x04 // 用户内存 #define SIGN_SYS 0x00 // 系统内存 -#define SIGN_PWT 0x08 // 页级写穿 -#define SIGN_PCD 0x10 // 页级高速缓存 -#define SIGN_A 0x20 // 访问 -#define SIGN_D 0x40 // 脏页 -#define SIGN_PAT 0x80 // 页表属性 -#define SIGN_G 0x100 // 全局 +#define SIGN_PWT 0x08 // 页级写穿 +#define SIGN_PCD 0x10 // 页级高速缓存 +#define SIGN_A 0x20 // 访问 +#define SIGN_D 0x40 // 脏页 +#define SIGN_PAT 0x80 // 页表属性 +#define SIGN_G 0x100 // 全局 #define SIGN_AVL 0x200 // 软件可用 -void setup_page(void); -uint32_t *pte_ptr(uint32_t vaddr); -uint32_t *pde_ptr(uint32_t vaddr); -uint32_t vir2phy(uint32_t vaddr); -void *remap(uint32_t paddr, size_t size); -void unmap(uint32_t vaddr, size_t size); -int alloc_vir_page(void); -int free_vir_page(int vir_addr); -void *kernel_alloc_pages(int pages); -void kernel_free_page(int vaddr, int pages); -void fill_vir_page_table(uint32_t vaddr, uint8_t sign); -void clean_vir_page_table(uint32_t vaddr); -uint32_t alloc_mem_page(void); -uint32_t free_mem_page(int address); -void *thread_get_page(struct task_s *thread, uint32_t vaddr); -uint32_t thread_alloc_vir_page(struct task_s *thread); -uint32_t thread_free_vir_page(struct task_s *thread, uint32_t addr); -void *thread_alloc_page(struct task_s *thread, int pages); -void thread_free_page(struct task_s *thread, uint32_t vaddr, int pages); -int thread_use_page(struct task_s *thread, uint32_t vaddr, uint32_t addr, int pages); +void setup_page(void); +uint32_t *pte_ptr(uint32_t vaddr); +uint32_t *pde_ptr(uint32_t vaddr); +uint32_t vir2phy(uint32_t vaddr); +MemoryResult remap(uint32_t in_paddr, size_t in_size, uint32_t *out_vaddr); +void unmap(uint32_t vaddr, size_t size); +int alloc_vir_pages(int count); +int free_vir_page(int vir_addr); +void *kernel_alloc_pages(int pages); +void *kernel_alloc_continuous_pages(int pages); +void kernel_free_page(int vaddr, int pages); +void fill_vir_page_table(uint32_t vaddr, uint32_t paddr, uint8_t sign); +void clean_vir_page_table(uint32_t vaddr); +uint32_t alloc_mem_page(void); +uint32_t alloc_mem_pages(int pages); +uint32_t free_mem_page(int address); +void *thread_get_page(struct task_s *thread, uint32_t vaddr); +uint32_t thread_alloc_vir_page(struct task_s *thread); +uint32_t thread_free_vir_page(struct task_s *thread, uint32_t addr); +void *thread_alloc_page(struct task_s *thread, int pages); +void thread_free_page(struct task_s *thread, uint32_t vaddr, int pages); +MemoryResult thread_use_page( + struct task_s *thread, uint32_t vaddr, uint32_t addr, int pages); #endif \ No newline at end of file diff --git a/src/arch/x86/include/kernel/thread.h b/src/arch/x86/include/kernel/thread.h index 233d60c..0481ff1 100644 --- a/src/arch/x86/include/kernel/thread.h +++ b/src/arch/x86/include/kernel/thread.h @@ -1,86 +1,160 @@ #ifndef THREAD_H #define THREAD_H +#include "kernel/spinlock.h" #include #include +#include #include typedef void thread_func(void *); typedef enum { - TASK_RUNNING, - TASK_READY, - TASK_BLOCKED, - TASK_WAITING, - TASK_HANGING, - TASK_DIED + TASK_RUNNING, + TASK_READY, + TASK_INTERRUPTIBLE, + TASK_UNINTERRUPTIBLE, + TASK_DIED } task_status_t; struct intr_stack { - uint32_t vec_no; - uint32_t edi; - uint32_t esi; - uint32_t ebp; - uint32_t esp_dummy; - uint32_t ebx; - uint32_t edx; - uint32_t ecx; - uint32_t eax; - uint32_t gs; - uint32_t fs; - uint32_t es; - uint32_t ds; - - uint32_t err_code; - void (*eip)(void); - uint32_t cs; - uint32_t eflags; - void *esp; - uint32_t ss; + uint32_t vec_no; + uint32_t edi; + uint32_t esi; + uint32_t ebp; + uint32_t esp_dummy; + uint32_t ebx; + uint32_t edx; + uint32_t ecx; + uint32_t eax; + uint32_t gs; + uint32_t fs; + uint32_t es; + uint32_t ds; + + uint32_t err_code; + void (*eip)(void); + uint32_t cs; + uint32_t eflags; + void *esp; + uint32_t ss; }; struct thread_stack { - uint32_t ebp; - uint32_t ebx; - uint32_t edi; - uint32_t esi; + uint32_t ebp; + uint32_t ebx; + uint32_t edi; + uint32_t esi; - void (*eip)(thread_func *func, void *func_arg); + void (*eip)(thread_func *func, void *func_arg); - void(*unused_retaddr); - thread_func *function; - void *func_arg; + void(*unused_retaddr); + thread_func *function; + void *func_arg; }; struct task_s { - uint32_t *kstack; - - uint32_t pid; - char name[32]; - task_status_t status; - uint8_t priority; - uint8_t ticks; - uint32_t elapsed_ticks; - uint32_t *pgdir; - uint32_t stack_magic; - - struct mmap vir_page_mmap; - struct memory_manage *memory_manage; - - list_t general_tag; - list_t all_list_tag; + uint32_t *kstack; + + uint32_t pid; + char name[32]; + task_status_t status; + spinlock_t status_lock; + uint8_t priority; + uint8_t ticks; + uint32_t elapsed_ticks; + uint32_t *pgdir; + uint32_t stack_magic; + size_t subject_id; + + struct { + uint8_t need_resched : 1; // 是否需要调度 + } flags; + + struct lock child_lock; // 保护子线程计数器的锁 + int child_count; // 当前活跃的子线程数 + struct semaphore child_sem; // 子线程完成信号量(初始为0) + struct task_s *parent; + + struct mmap vir_page_mmap; + struct memory_manage *memory_manage; + + list_t wait_queue_tag; + list_t general_tag; + list_t all_list_tag; }; +extern uint32_t preempt_count; +extern list_t thread_all; +extern spinlock_t thread_ready_lock; + +extern struct task_s *current_task; + #define THREAD_DEFAULT_PRIO 100 +#define PREEMPT_COUNT_MASK 0xff0000 +#define HARDIRQ_COUNT_MASK 0xff00 +#define SOFTIRQ_COUNT_MASK 0xff +#define PREEMPT_COUNT_SHIFT 16 +#define HARDIRQ_COUNT_SHIFT 8 +#define SOFTIRQ_COUNT_SHIFT 0 + +#define softirq_count() \ + ((preempt_count & SOFTIRQ_COUNT_MASK) >> SOFTIRQ_COUNT_SHIFT) +#define hardirq_count() \ + ((preempt_count & HARDIRQ_COUNT_MASK) >> HARDIRQ_COUNT_SHIFT) +#define preempt_count() \ + ((preempt_count & PREEMPT_COUNT_MASK) >> PREEMPT_COUNT_SHIFT) + +#define in_softirq() ((preempt_count & SOFTIRQ_COUNT_MASK) != 0) +#define in_hardirq() ((preempt_count & HARDIRQ_COUNT_MASK) != 0) +#define can_preempt() \ + ((preempt_count & (PREEMPT_COUNT_MASK | HARDIRQ_COUNT_MASK)) == 0) + +static inline bool need_resched(void) { + return current_task != NULL && current_task->flags.need_resched; +} + +static inline void hardirq_enter(void) { + preempt_count += 1 << HARDIRQ_COUNT_SHIFT; +} + +static inline void hardirq_exit(void) { + preempt_count -= 1 << HARDIRQ_COUNT_SHIFT; +} + +static inline void softirq_enter(void) { + preempt_count += 1 << SOFTIRQ_COUNT_SHIFT; +} + +static inline void softirq_exit(void) { + preempt_count -= 1 << SOFTIRQ_COUNT_SHIFT; +} + +static inline void disable_preempt(void) { + preempt_count += 1 << PREEMPT_COUNT_SHIFT; +} + +static inline void enable_preempt(void) { + preempt_count -= 1 << PREEMPT_COUNT_SHIFT; +} + struct task_s *get_current_thread(); -void init_thread(struct task_s *pthread, char *name, int priority); -void thread_create(struct task_s *pthread, thread_func *function, void *func_arg); -struct task_s *thread_start(char *name, int priority, thread_func function, void *func_arg); -void thread_block(task_status_t status); -void thread_unblock(struct task_s *pthread); -void init_task(void); -void schedule(void); -void init_thread_memory_manage(struct task_s *thread); +size_t get_current_subject_id(); +void init_thread( + struct task_s *pthread, void *stack_page, char *name, int priority); +void thread_create( + struct task_s *pthread, thread_func *function, void *func_arg); +struct task_s *thread_start( + char *name, int priority, thread_func function, void *func_arg, + struct task_s *parent); +void thread_exit(void); +void thread_set_status(task_status_t status); +void thread_wait(); +void thread_unblock(struct task_s *pthread); +void init_task(void); +void schedule(void); +void init_thread_memory_manage(struct task_s *thread); +void thread_wait_children(struct task_s *parent); #endif \ No newline at end of file diff --git a/src/arch/x86/include/kernel/x86_barrier.h b/src/arch/x86/include/kernel/x86_barrier.h new file mode 100644 index 0000000..73ab979 --- /dev/null +++ b/src/arch/x86/include/kernel/x86_barrier.h @@ -0,0 +1,15 @@ +#ifndef _X86_BARRIER_H +#define _X86_BARRIER_H + +#if ARCH_X86 == 32 +#define memory_barrier() \ + __asm__ __volatile__("lock; addl $0,0(%%esp)" ::: "memory") +#define read_memory_barrier() memory_barrier() +#define write_memory_barrier() memory_barrier() +#else +#define memory_barrier() __asm__ __volatile__("mfence" ::: "memory") +#define read_memory_barrier() __asm__ __volatile__("lfence" ::: "memory") +#define write_memory_barrier() __asm__ __volatile__("sfence" ::: "memory") +#endif + +#endif \ No newline at end of file diff --git a/src/arch/x86/kernel.lds b/src/arch/x86/kernel.lds index 31c36f8..e3dd9d7 100644 --- a/src/arch/x86/kernel.lds +++ b/src/arch/x86/kernel.lds @@ -1,6 +1,6 @@ OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386") OUTPUT_ARCH(i386) -ENTRY(_start) +ENTRY(_start) /* start is at boot/xxx/xxx.S */ PHDRS { @@ -16,12 +16,17 @@ SECTIONS { */ . = 0x00100000; + .multiboot2_header ALIGN(8) : { + KEEP(*(.multiboot2_header)) + } : text + /* code segment */ - .text ALIGN(4) : { + .text : { + . = ALIGN(4); /* 4 bytes align */ *(.text) *(.init.text) *(.exit.text) - } :text + } : text .initcall ALIGN(8) : { @@ -29,7 +34,7 @@ SECTIONS { KEEP(*(.initcall_0.text)) KEEP(*(.initcall_1.text)) PROVIDE(__initcall_end = .); - } :text + } : text .exitcall ALIGN(8) : { @@ -37,34 +42,26 @@ SECTIONS { KEEP(*(.exitcall_0.text)) KEEP(*(.exitcall_1.text)) PROVIDE(__exitcall_end = .); - } :text + } : text + + .percpu ALIGN(64) : + { + . = ALIGN(64); + PROVIDE(__percpu_start = .); + *(.percpu) + . = ALIGN(64); + PROVIDE(__percpu_end = .); + } : data /* data segment */ - .data ALIGN(4) : { + .data : { + . = ALIGN(4); /* 4 bytes align */ *(.data) - } :data + } : data /* bss segement */ - .bss ALIGN(4) : { + .bss : { + . = ALIGN(4); /* 4 bytes align */ *(.bss) - } :data - - . = ALIGN(4); - _end_of_file = .; /* 标记文件结尾 */ - - . = ALIGN(4); - /DISCARD/ : { - *(.note*) - *(.comment) - } - .debug_aranges 0 (NOLOAD) : { *(.debug_aranges) } - .debug_info 0 (NOLOAD) : { *(.debug_info) } - .debug_abbrev 0 (NOLOAD) : { *(.debug_abbrev) } - .debug_line 0 (NOLOAD) : { *(.debug_line) } - .debug_str 0 (NOLOAD) : { *(.debug_str) } - .debug_addr 0 (NOLOAD) : { *(.debug_addr) } - .debug_line_str 0 (NOLOAD) : { *(.debug_line_str) } - .debug_rnglists 0 (NOLOAD) : { *(.debug_rnglists) } - .debug_str_offsets 0 (NOLOAD) : { *(.debug_str_offsets) } - .debug_loclists 0 (NOLOAD) : { *(.debug_loclists) } + } : data } \ No newline at end of file diff --git a/src/arch/x86/kernel/Makefile b/src/arch/x86/kernel/Makefile index d3bf441..fd4bc87 100644 --- a/src/arch/x86/kernel/Makefile +++ b/src/arch/x86/kernel/Makefile @@ -2,4 +2,5 @@ SRC += start.asm SRC += func.asm SRC += descriptor.c SRC += page.c -SRC += platform.c \ No newline at end of file +SRC += platform.c +SRC += feature.c \ No newline at end of file diff --git a/src/arch/x86/kernel/config.toml b/src/arch/x86/kernel/config.toml new file mode 100644 index 0000000..d440512 --- /dev/null +++ b/src/arch/x86/kernel/config.toml @@ -0,0 +1,2 @@ +c = ["descriptor.c", "feature.c", "page.c", "platform.c"] +asm = ["func.asm", "start.asm"] diff --git a/src/arch/x86/kernel/descriptor.c b/src/arch/x86/kernel/descriptor.c index 30a0594..4062cdd 100644 --- a/src/arch/x86/kernel/descriptor.c +++ b/src/arch/x86/kernel/descriptor.c @@ -5,14 +5,18 @@ * @version 1.2 * @date 2022-07-31 */ +#include #include #include #include #include #include #include +#include #include #include +#include +#include #include #include @@ -328,7 +332,9 @@ void exception_handler( } else { printk(COLOR_RED " TI: selector in gdt.\n"); } - printk(COLOR_RED " Selector: idx %d\n", (error_code & 0xfff8) >> 3); + printk( + COLOR_RED " Selector: idx %d\n" COLOR_RESET, + (error_code & 0xfff8) >> 3); } io_hlt(); @@ -336,28 +342,32 @@ void exception_handler( ; } -void do_irq(int irq) { - if (use_apic) { - apic_eoi(); - } else { - pic_eoi(irq); +void irq_return(void) { + if (need_resched() && preempt_count() == 0) { + get_current_thread()->flags.need_resched = 0; + schedule(); } +} + +void do_irq(int irq) { + disable_interrupt(); + hardirq_enter(); device_irq_handler(irq); irq_table[irq](irq); -} -void default_irq_handler(int irq) { - if (use_apic) { - apic_eoi(); - } else { - pic_eoi(irq); - } + interrupt_eoi(irq); + hardirq_exit(); + enable_interrupt(); + + do_softirq(); + + irq_return(); } -void irq_enable(int irq) { - if (use_apic) { - apic_enable_irq(irq); - } else { - pic_enable_irq(irq); - } +void default_irq_handler(int irq) { + // if (use_apic) { + // apic_eoi(); + // } else { + // pic_eoi(irq); + // } } diff --git a/src/arch/x86/kernel/feature.c b/src/arch/x86/kernel/feature.c new file mode 100644 index 0000000..993c854 --- /dev/null +++ b/src/arch/x86/kernel/feature.c @@ -0,0 +1,91 @@ +#include +#include +#include +#include +#include + +char vendor_id[13] = {0}; +char model_name[49] = {0}; +static uint32_t max_basic_func_num; +static uint8_t cpu_family, cpu_model, cpu_stepping_id; +static uint8_t processor_type, brand_index; +static uint8_t default_apic_id, max_logical_processor_per_package; +static uint16_t cache_line_size; +static uint32_t feature_flags[2]; + +const char feature_names[64][16] = { + "SSE3", "PCLMUL", "DTES64", "MONITOR", "DS-CPL", + "VMX", "SMX", "EST", "TM2", "SSSE3", + "CID", "", "FMA", "CX16", "XTPR", + "PDCM", "", "PCID", "DCA", "SSE4.1", + "SSE4.2", "x2APIC", "MOVBE", "POPCNT", "TSC-DEADLINE", + "AES", "XSAVE", "OSXSAVE", "AVX", "F16C", + "RDRAND", "HYPERVISOR", + + "FPU", "VME", "DE", "PSE", "TSC", + "MSR", "PAE", "MCE", "CX8", "APIC", + "", "SEP", "MTRR", "PGE", "MCA", + "CMOV", "PAT", "PSE36", "PSN", "CLFLUSH", + "", "DS", "ACPI", "MMX", "FXSR", + "SSE", "SSE2", "SS", "HTT", "TM", + "", "PBE", +}; + +void read_features(void) { + uint32_t a, b, c, d; + get_cpuid( + 0, 0, &max_basic_func_num, (uint32_t *)&vendor_id[0], + (uint32_t *)&vendor_id[8], (uint32_t *)&vendor_id[4]); + get_cpuid(1, 0, &a, &b, &c, &d); + cpu_family = (a >> 8) & 0x0f + (a >> 20) & 0xff; + cpu_model = ((a >> 4) & 0x0f) | (((a >> 16) & 0x0f) << 4); + cpu_stepping_id = a & 0x0f; + processor_type = (a >> 12) & 0x03; + + default_apic_id = b >> 24; + max_logical_processor_per_package = (b >> 16) & 0xff; + cache_line_size = ((b >> 8) & 0xff) * 8; + brand_index = b & 0xff; + + feature_flags[0] = c; + feature_flags[1] = d; + + get_cpuid( + 0x80000002, 0, (uint32_t *)&model_name[0], (uint32_t *)&model_name[4], + (uint32_t *)&model_name[8], (uint32_t *)&model_name[12]); + get_cpuid( + 0x80000003, 0, (uint32_t *)&model_name[16], (uint32_t *)&model_name[20], + (uint32_t *)&model_name[24], (uint32_t *)&model_name[28]); + get_cpuid( + 0x80000003, 0, (uint32_t *)&model_name[32], (uint32_t *)&model_name[36], + (uint32_t *)&model_name[40], (uint32_t *)&model_name[44]); +} + +int cpu_check_feature(enum x86_cpu_features feature) { + if (feature >= 32) { + return !!(feature_flags[1] & BIT(feature % 32)); + } else { + return !!(feature_flags[0] & BIT(feature)); + } +} + +void print_features() { + printk("CPU Infomations:\n"); + printk("Vendor: %s,", vendor_id); + printk("Model: %s\n", model_name); + printk("Family: %d,", cpu_family); + printk("Model: %d,", cpu_model); + printk("Stepping ID: %d\n", cpu_stepping_id); + printk("Processor Type: %d,", processor_type); + printk("Default APIC ID: %d\n", default_apic_id); + printk( + "Max Logical Processor Per Package: %d\n", + max_logical_processor_per_package); + printk("Cache Line Size: %dBytes\n", cache_line_size); + printk("Brand Index: %d\n", brand_index); + printk("Features: "); + for (int i = 0; i < 64; i++) { + if (cpu_check_feature(i)) { printk("%s, ", feature_names[i]); } + } + printk("\n"); +} diff --git a/src/arch/x86/kernel/func.asm b/src/arch/x86/kernel/func.asm index a8c3c71..dd68f54 100644 --- a/src/arch/x86/kernel/func.asm +++ b/src/arch/x86/kernel/func.asm @@ -1,6 +1,6 @@ global io_in8, io_out8, io_in16, io_out16, io_in32, io_out32 global io_read, io_write - global io_cli, io_sti, io_hlt, io_stihlt + global io_cli, io_sti, io_hlt, io_stihlt, save_eflags_cli global read_cr3, write_cr3, read_cr2, read_cr0, write_cr0, enable_paging global load_gdtr, load_idtr global io_load_eflags, io_store_eflags @@ -11,7 +11,7 @@ global stack_exception global general_protection global page_fault - global IRQ_timer, IRQ_pit, IRQ_keyboard, + global IRQ_timer, IRQ_pit, IRQ_keyboard global thread_intr_exit global switch_to @@ -85,16 +85,16 @@ EXCEPTION_ENTRY 8,ERROR_CODE EXCEPTION_ENTRY 9,NO_ERROR_CODE EXCEPTION_ENTRY 10,ERROR_CODE EXCEPTION_ENTRY 11,ERROR_CODE -EXCEPTION_ENTRY 12,NO_ERROR_CODE +EXCEPTION_ENTRY 12,ERROR_CODE EXCEPTION_ENTRY 13,ERROR_CODE EXCEPTION_ENTRY 14,ERROR_CODE EXCEPTION_ENTRY 15,NO_ERROR_CODE -EXCEPTION_ENTRY 16,ERROR_CODE +EXCEPTION_ENTRY 16,NO_ERROR_CODE EXCEPTION_ENTRY 17,ERROR_CODE EXCEPTION_ENTRY 18,NO_ERROR_CODE -EXCEPTION_ENTRY 19,ERROR_CODE -EXCEPTION_ENTRY 20,ERROR_CODE -EXCEPTION_ENTRY 21,NO_ERROR_CODE +EXCEPTION_ENTRY 19,NO_ERROR_CODE +EXCEPTION_ENTRY 20,NO_ERROR_CODE +EXCEPTION_ENTRY 21,ERROR_CODE EXCEPTION_ENTRY 22,NO_ERROR_CODE EXCEPTION_ENTRY 23,ERROR_CODE EXCEPTION_ENTRY 24,ERROR_CODE @@ -122,7 +122,7 @@ INTERRUPT_ENTRY 13 INTERRUPT_ENTRY 14 INTERRUPT_ENTRY 15 -INTERRUPT_ENTRY 0, +INTERRUPT_ENTRY 0 io_in8: ;int io_in8(int port); mov edx,[esp+4] @@ -255,6 +255,12 @@ io_store_eflags: ; void io_store_eflags(int eflags); popfd ; pop eflags ret +save_eflags_cli: ; int save_eflags_cli(void); + pushfd + cli + pop eax + ret + global syscall_handler syscall_handler: push 0 diff --git a/src/arch/x86/kernel/page.c b/src/arch/x86/kernel/page.c index fc9f057..e8f82a5 100644 --- a/src/arch/x86/kernel/page.c +++ b/src/arch/x86/kernel/page.c @@ -5,7 +5,7 @@ * @version 1.2 * @date 2022-07-15 */ -#include +#include #include #include #include @@ -15,12 +15,16 @@ #include #include +extern struct VesaDisplayInfo vesa_display_info; + void setup_page(void) { uint32_t *pdt = (uint32_t *)PDT_PHY_ADDR; memset((void *)PDT_PHY_ADDR, 0, PAGE_SIZE); // 清空数据 + // 0x00000000 - 0x003fffff pdt[0] = (TBL_PHY_ADDR | SIGN_RW | SIGN_SYS | SIGN_P); // 第0个页(前4MB内存):GDT、BIOS、内核主程序 + // 0xffc00000 - 0xffffffff pdt[1023] = (PDT_PHY_ADDR | SIGN_RW | SIGN_SYS | SIGN_P); // 第1023个页(最后4MB内存):页表 @@ -34,26 +38,21 @@ void setup_page(void) { pt[i] = addr; addr += PAGE_SIZE; } + pt[0] &= ~SIGN_P; // 0x00000000不可用 - pdt[1] = (DMA_PT_PHY_ADDR1 | SIGN_RW | SIGN_SYS | SIGN_P); + // 0x00800000 - 0x00bfffff pdt[2] = (DMA_PT_PHY_ADDR2 | SIGN_RW | SIGN_SYS | SIGN_P); - pt = (uint32_t *)DMA_PT_PHY_ADDR1; - addr = (0x400000 | SIGN_RW | SIGN_SYS | SIGN_P); - for (i = 0; i < 1024; i++) { - pt[i] = addr; - addr += PAGE_SIZE; - } - pt = (uint32_t *)DMA_PT_PHY_ADDR2; - addr = (0x800000 | SIGN_RW | SIGN_SYS | SIGN_P); + pt = (uint32_t *)DMA_PT_PHY_ADDR2; + addr = (0x800000 | SIGN_RW | SIGN_SYS | SIGN_P); for (i = 0; i < 1024; i++) { pt[i] = addr; addr += PAGE_SIZE; } // VRAM - uint32_t vram_addr = (uint32_t)video_info.vram; - uint32_t size = - video_info.width * video_info.height * (video_info.BitsPerPixel / 8); + uint32_t vram_addr = (uint32_t)vesa_display_info.vram; + uint32_t size = vesa_display_info.width * vesa_display_info.height * + (vesa_display_info.BitsPerPixel / 8); for (i = 1; i <= DIV_ROUND_UP(size, PAGE_SIZE * 1024); i++) { pdt[i] = ((VRAM_PT_PHY_ADDR + (i - 1) * PAGE_SIZE) | SIGN_RW | SIGN_SYS | @@ -178,40 +177,30 @@ int __unmap(uint32_t vaddr, size_t size) { * * @param paddr 物理地址 * @param size 大小 - * @return void* 虚拟地址 + * @param uint32_t* 虚拟地址 */ -void *remap(uint32_t paddr, size_t size) { +MemoryResult remap(uint32_t in_paddr, size_t in_size, uint32_t *out_vaddr) { - if (!paddr || !size) { return NULL; } - uint32_t i, j, *pdt, *pt; - for (i = 0; i < 1024; i++) { - pdt = (uint32_t *)0xfffff000; - if (pdt[i]) { - for (j = 0; j < 1024; j++) { - pt = (uint32_t *)(0xffc00000 + i * 0x1000); - if (pt[j] == ((paddr + size - 1) & 0x003ff000)) { - return (void *)(i * 0x40000 + j * 0x1000 + - (paddr & 0x0fff)); - } - } - } - } + if (!in_paddr || !in_size) { return MEMORY_RESULT_INVALID_INPUT; } - uint32_t vaddr = alloc_vaddr(size); - if (vaddr == 0) { - printk("alloc virtual addr for IO remap failed!\n"); - return NULL; + if (in_paddr + in_size < 0x400000) { + // 低4MB内存默认已经映射,直接返回 + return in_paddr; } + uint32_t vaddr; + MEMORY_RESULT_DELIVER_CALL(alloc_vaddr, in_size, &vaddr); + int old_status = io_load_eflags(); io_cli(); - - __remap(paddr, vaddr, size); + __remap(in_paddr, vaddr, in_size); + io_store_eflags(old_status); io_sti(); uint32_t ret = vaddr & 0xfffff000; - ret |= (paddr & 0x0fff); - return (void *)ret; + ret |= (in_paddr & 0x0fff); + *out_vaddr = ret; + return MEMORY_RESULT_OK; } /** @@ -231,12 +220,14 @@ void unmap(uint32_t vaddr, size_t size) { * * @return int 虚拟页地址 */ -int alloc_vir_page(void) { +int alloc_vir_pages(int count) { int idx; int vir_addr; - idx = mmap_search(&vir_page_mmap, 1); + idx = mmap_search(&vir_page_mmap, count); if (idx != -1) { - mmap_set(&vir_page_mmap, idx, 1); + for (int i = 0; i < count; i++) { + mmap_set(&vir_page_mmap, idx + i, 1); + } } else { return -1; } @@ -274,30 +265,50 @@ void *kernel_alloc_pages(int pages) { int old_status = io_load_eflags(); io_cli(); - vir_page_addr = alloc_vir_page(); // 分配一个虚拟地址的页 - + vir_page_addr = alloc_vir_pages(pages); // 分配一个虚拟地址的页 + if (vir_page_addr < 0) return NULL; fill_vir_page_table( - vir_page_addr, + vir_page_addr, alloc_mem_page(), SIGN_SYS); // 把页添加到当前页目录表系统中,使他可以被使用 - if (pages == 1) { // 如果只有一个页 - memset((void *)vir_page_addr, 0, PAGE_SIZE); + vir_page_addr_more = vir_page_addr + PAGE_SIZE; // 分配一个虚拟地址的页 + for (i = 1; i < pages; i++) { + fill_vir_page_table( + vir_page_addr_more, alloc_mem_page(), + SIGN_SYS); // 把页添加到当前页目录表系统中,使他可以被使用 + vir_page_addr_more += PAGE_SIZE; + } - io_store_eflags(old_status); - return (void *)vir_page_addr; - } else if (pages > 1) { - for (i = 1; i < pages; i++) { - vir_page_addr_more = alloc_vir_page(); // 分配一个虚拟地址的页 - fill_vir_page_table( - vir_page_addr_more, - SIGN_SYS); // 把页添加到当前页目录表系统中,使他可以被使用 - } - memset((void *)vir_page_addr, 0, PAGE_SIZE * pages); - io_store_eflags(old_status); + memset((void *)vir_page_addr, 0, PAGE_SIZE * pages); + io_store_eflags(old_status); - return (void *)vir_page_addr; + return (void *)vir_page_addr; +} + +/** + * @brief 分配物理地址连续的页 + * + * @param pages 页数 + * @return void* 起始地址 + */ +void *kernel_alloc_continuous_pages(int pages) { + size_t vir_page_addr = 0; + + int old_status = io_load_eflags(); + io_cli(); + + vir_page_addr = alloc_vir_pages(pages); + + size_t paddr = alloc_mem_pages(pages); + for (int i = 0; i < pages; i++) { + fill_vir_page_table( + vir_page_addr + i * PAGE_SIZE, paddr + i * PAGE_SIZE, + SIGN_SYS); // 把页添加到当前页目录表系统中,使他可以被使用 } - return NULL; + if (!paddr) return NULL; + io_store_eflags(old_status); + + return (void *)vir_page_addr; } /** @@ -337,7 +348,7 @@ void kernel_free_page(int vaddr, int pages) { * @param vaddr 虚拟内存地址 * @param sign 是用户内存还是系统内存(SIGN_SYS:系统内存,SIGN_USER:用户内存) */ -void fill_vir_page_table(uint32_t vaddr, uint8_t sign) { +void fill_vir_page_table(uint32_t vaddr, uint32_t paddr, uint8_t sign) { uint32_t *pde, *pte; pde = pde_ptr(vaddr); if (((*pde) & 0x00000001) != 0x00000001) { // 不存在页表 @@ -345,12 +356,10 @@ void fill_vir_page_table(uint32_t vaddr, uint8_t sign) { pt |= SIGN_RW | SIGN_P | (sign & SIGN_US); *pde = pt; // 填写页目录项为页表的地址 } - pte = pte_ptr(vaddr); - if (((*pte) & 0x00000001) != 0x00000001) { // 不存在页表项 - uint32_t page = alloc_mem_page(); // 分配页地址 - page |= SIGN_RW | SIGN_P | (sign & SIGN_US); - *pte = page; // 填写页表项为页的地址 - } + pte = pte_ptr(vaddr); + uint32_t page = paddr; + page |= SIGN_RW | SIGN_P | (sign & SIGN_US); + *pte = page; // 填写页表项为页的地址 } /** @@ -387,6 +396,24 @@ uint32_t alloc_mem_page(void) { return mem_addr; } +uint32_t alloc_mem_pages(int pages) { + int addr = 0; + int idx; + int mem_addr; + idx = mmap_search(&phy_page_mmap, pages); + if (idx != -1) { + for (int i = 0; i < pages; i++) { + mmap_set(&phy_page_mmap, idx + i, 1); + } + } else { + return (int)NULL; + } + mem_addr = idx * 0x1000 + PHY_MEM_BASE_ADDR; + + return mem_addr; + return addr; +} + /** * @brief 释放一个物理页 * @@ -419,7 +446,7 @@ void *thread_get_page(struct task_s *thread, uint32_t vaddr) { mmap_set(&thread->vir_page_mmap, idx, 1); - fill_vir_page_table(vaddr, SIGN_USER); + fill_vir_page_table(vaddr, alloc_mem_page(), SIGN_USER); return (void *)vaddr; } @@ -472,7 +499,7 @@ void *thread_alloc_page(struct task_s *thread, int pages) { vir_page_addr = thread_alloc_vir_page(thread); // 分配一个虚拟地址的页 fill_vir_page_table( - vir_page_addr, + vir_page_addr, alloc_mem_page(), SIGN_USER); // 把页添加到当前页目录表系统中,使他可以被使用 if (pages == 1) { // 如果只有一个页 @@ -483,7 +510,7 @@ void *thread_alloc_page(struct task_s *thread, int pages) { vir_page_addr_more = thread_alloc_vir_page(thread); // 分配一个虚拟地址的页 fill_vir_page_table( - vir_page_addr_more, + vir_page_addr_more, alloc_mem_page(), SIGN_USER); // 把页添加到当前页目录表系统中,使他可以被使用 } memset((void *)vir_page_addr, 0, PAGE_SIZE * pages); @@ -524,15 +551,15 @@ void thread_free_page(struct task_s *thread, uint32_t vaddr, int pages) { * @param addr 内存的物理地址 * @param pages 载入内存的大小(单位:页) * - * @return 成功则返回0,失败则返回NULL + * @return MemoryResult */ -int thread_use_page( +MemoryResult thread_use_page( struct task_s *thread, uint32_t vaddr, uint32_t addr, int pages) { int i = 0; int idx = (vaddr - USER_VIR_MEM_BASE_ADDR) / PAGE_SIZE; while (i < pages) { - if (thread->vir_page_mmap.bits[idx / 8] & (1 << (idx % 8))) { - return -1; + if (mmap_get(&thread->vir_page_mmap, idx)) { + return MEMORY_RESULT_MEMORY_IS_USED; } mmap_set(&thread->vir_page_mmap, idx, 1); @@ -547,16 +574,19 @@ int thread_use_page( *pde = pt | SIGN_P | SIGN_RW | SIGN_USER; // 填写页目录项为页表的地址 } - pt = (uint32_t)remap(pt & 0xfffff000, PAGE_SIZE); + + MEMORY_RESULT_DELIVER_CALL(remap, pt & 0xfffff000, PAGE_SIZE, &pt); + pte = (uint32_t *)(pt + ((vaddr & 0x003ff000) >> 12) * 4); - if (((*pte) & 0x00000001) != 0x00000001) { // 不存在页表项 + if (((*pte) & 0x00000001) != 0x00000001) { // 不存在页表项 *pte = addr | SIGN_P | SIGN_RW | SIGN_USER; // 填写页表项为页的地址 addr += PAGE_SIZE; } + unmap(pt, PAGE_SIZE); idx++; i++; } - return 0; + return MEMORY_RESULT_OK; } diff --git a/src/arch/x86/kernel/platform.c b/src/arch/x86/kernel/platform.c index ff6bf69..6b6ca7e 100644 --- a/src/arch/x86/kernel/platform.c +++ b/src/arch/x86/kernel/platform.c @@ -1,14 +1,117 @@ +#include +#include +#include +#include +#include #include +#include +#include #include +#include +#include #include +#include #include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include -void platform_init() { +BusOps platform_bus_ops = { + .scan_bus = NULL, + .probe_device = NULL, +}; +DeviceOps platform_device_ops = { + .init = NULL, + .start = NULL, + .stop = NULL, + .destroy = NULL, +}; + +Driver platform_driver; +BusDriver platform_bus_driver = { + .name = STRING_INIT("Platform"), +}; +Bus *platform_bus; + +DeviceDriver platform_device_driver; +PhysicalDevice *platform_device; + +// 完成一些平台必要的准备工作 +void platform_early_init() { + // 初始化段描述符和中断描述符 init_descriptor(); - init_video(); +} + +DriverResult platform_init() { + DriverResult result; + + // 因为platform_bus是虚拟的,所以不需要注册device + ObjectAttr attr = driver_object_attr; + register_driver(&platform_driver); + register_bus_driver( + &platform_driver, BUS_TYPE_PLATFORM, &platform_bus_driver, &attr); + register_device_driver(&platform_driver, &platform_device_driver); + + result = create_bus(&platform_bus, &platform_bus_driver, &platform_bus_ops); + if (result != DRIVER_OK) { return result; } + + result = create_physical_device(&platform_device, platform_bus, &attr); + if (result != DRIVER_OK) { return result; } + register_physical_device(platform_device, &platform_device_ops); + + read_features(); + + bios_emu_init(); + + register_serial(); + result = register_vesa_display(); + result = register_apic(); + result = register_pic(); + result = register_pit(); + result = register_cmos(); + + dma_init(); + + if (cpu_check_feature(CPUID_FEAT_TSC)) rand_seed((uint32_t)read_tsc()); + + return DRIVER_OK; +} + +void serial_receive(uint8_t data) { + printk("%c", data); +} + +void platform_start_devices() { + init_and_start_physical_device(i8254_device); + init_and_start_physical_device(cmos_device); + + Object *serial_object; + framebuffer_start_all(); init_console(); - init_memory(); - init_apic(); - init_timer(); + interrupt_dm_start(); // 启动由interrupt_dm选择的中断控制器 + + ObjectResult result; + result = open_object_by_path("\\Device\\Serial0", &serial_object); + if (result == OBJECT_OK) { + serial_device_open(serial_object, SERIAL_BAUD_115200, serial_receive); + } + + print_features(); + DRV_RESULT_PRINT_CALL( + init_and_start_logical_device(pit_timer_device->device)); + // if (use_apic) + // DRV_RESULT_PRINT_CALL( + // init_and_start_logical_device(apic_timer_device->device)); + DRV_RESULT_PRINT_CALL( + init_and_start_logical_device(rtc_time_device->device)); + + // platform_bus_driver.subdriver.state = SUBDRIVER_STATE_READY; } \ No newline at end of file diff --git a/src/arch/x86/multiboot2/config.toml b/src/arch/x86/multiboot2/config.toml new file mode 100644 index 0000000..fecbc06 --- /dev/null +++ b/src/arch/x86/multiboot2/config.toml @@ -0,0 +1,2 @@ +c = ["multiboot2.c"] +asm = ["multiboot2.asm"] diff --git a/src/arch/x86/multiboot2/multiboot2.c b/src/arch/x86/multiboot2/multiboot2.c index 9ab1ec6..a5868c8 100644 --- a/src/arch/x86/multiboot2/multiboot2.c +++ b/src/arch/x86/multiboot2/multiboot2.c @@ -1,21 +1,15 @@ #include "multiboot2.h" -#include +#include #include #include #include #include #include +extern struct VesaDisplayInfo vesa_display_info; + void multiboot2_loader(uint32_t eax, uint32_t ebx) { if (eax != 0x36d76289) { - // 尝试输出 - video_info.vram = (uint8_t *)0xe0000000; - video_info.width = 1024; - video_info.height = 768; - video_info.BitsPerPixel = 32; - print_string( - 0, 0, 0xffffff, font16, - "Not booted by a multiboot2-compliant bootloader."); while (true) ; } @@ -30,19 +24,19 @@ void multiboot2_loader(uint32_t eax, uint32_t ebx) { uint32_t size = *(p + 1); switch (type) { case MBIT_FRAMEBUFER_INFO: { - struct framebuffer_tag *fb = (struct framebuffer_tag *)p; - video_info.vram = (uint8_t *)fb->framebuffer_addr[0]; - video_info.width = fb->framebuffer_width; - video_info.height = fb->framebuffer_height; - video_info.BitsPerPixel = fb->framebuffer_bpp; + struct framebuffer_tag *fb = (struct framebuffer_tag *)p; + vesa_display_info.vram = (uint8_t *)fb->framebuffer_addr[0]; + vesa_display_info.width = fb->framebuffer_width; + vesa_display_info.height = fb->framebuffer_height; + vesa_display_info.BitsPerPixel = fb->framebuffer_bpp; break; } case MBIT_VBE_INFO: { struct vbe_info_tag *vbe = (struct vbe_info_tag *)p; - video_info.vbe_mode_info = - (struct vbe_mode_info_block *)vbe->vbe_mode_info; - video_info.vbe_conrtol_info = - (struct vbe_control_info_block *)vbe->vbe_control_info; + vesa_display_info.vbe_mode_info = + (struct VbeModeInfoBlock *)vbe->vbe_mode_info; + vesa_display_info.vbe_conrtol_info = + (struct VbeControlInfoBlock *)vbe->vbe_control_info; break; } case MBIT_MEM_MAP: { @@ -70,5 +64,4 @@ void multiboot2_loader(uint32_t eax, uint32_t ebx) { size >>= 2; p += size; } - print_string(0, 0, 0xc0c0c0, font16, "Starting up by multiboot2 success!"); } \ No newline at end of file diff --git a/src/config.toml b/src/config.toml new file mode 100644 index 0000000..561fa3d --- /dev/null +++ b/src/config.toml @@ -0,0 +1,15 @@ +dir = ["driver/", "drivers/", "fs/", "kernel/", "lib/", "objects/"] +includes = ["include/", "../include/"] +output = "kernel.elf" + +[arch.x86] +dir = ["arch/x86"] +lds = "arch/x86/kernel.lds" +includes = ["arch/x86/include"] +macro = { ARCH_X86 = "32" } + +[arch.x86_64] +dir = ["arch/x86"] +lds = "arch/x86/kernel.lds" +includes = ["arch/x86/include"] +macro = { ARCH_X86 = "64" } diff --git a/src/driver/Makefile b/src/driver/Makefile new file mode 100644 index 0000000..6fc8baa --- /dev/null +++ b/src/driver/Makefile @@ -0,0 +1,10 @@ +SRC += storage/ +SRC += sound/ +SRC += timer/ +SRC += network/ +SRC += input/ +SRC += serial/ +SRC += framebuffer/ +SRC += interrupt/ +SRC += bus_dm.c +SRC += time_dm.c \ No newline at end of file diff --git a/src/driver/bus_dm.c b/src/driver/bus_dm.c new file mode 100644 index 0000000..edca79f --- /dev/null +++ b/src/driver/bus_dm.c @@ -0,0 +1,23 @@ +#include +#include +#include +#include +#include +#include +#include + +DeviceManagerOps bus_controller_dm_ops = { + .dm_load = NULL, + .dm_unload = NULL, + + .init_device_hook = NULL, + .start_device_hook = NULL, + .stop_device_hook = NULL, + .destroy_device_hook = NULL, +}; + +DeviceManager bus_controller_dm = { + .type = DEVICE_TYPE_BUS_CONTROLLER, + .ops = &bus_controller_dm_ops, + .private_data = NULL, +}; diff --git a/src/driver/config.toml b/src/driver/config.toml new file mode 100644 index 0000000..e9bfe6c --- /dev/null +++ b/src/driver/config.toml @@ -0,0 +1,11 @@ +dir = [ + "framebuffer/", + "input/", + "interrupt/", + "network/", + "serial/", + "sound/", + "storage/", + "timer/", +] +c = ["bus_dm.c", "time_dm.c"] diff --git a/src/driver/framebuffer/Makefile b/src/driver/framebuffer/Makefile new file mode 100644 index 0000000..7a3df55 --- /dev/null +++ b/src/driver/framebuffer/Makefile @@ -0,0 +1,3 @@ +SRC += framebuffer_dm.c +SRC += framebuffer.c +SRC += console_backend.c \ No newline at end of file diff --git a/src/driver/framebuffer/config.toml b/src/driver/framebuffer/config.toml new file mode 100644 index 0000000..8ae3d15 --- /dev/null +++ b/src/driver/framebuffer/config.toml @@ -0,0 +1 @@ +c = ["console_backend.c", "framebuffer_dm.c", "framebuffer.c"] diff --git a/src/driver/framebuffer/console_backend.c b/src/driver/framebuffer/console_backend.c new file mode 100644 index 0000000..46868b3 --- /dev/null +++ b/src/driver/framebuffer/console_backend.c @@ -0,0 +1,275 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +void fb_console_backend_update(void *arg); + +void fb_console_backend_init(void *context) { + FrameBufferDevice *fb_device = context; + FrameBufferConsoleBackend *backend = &fb_device->console_backend; + + backend->fb_device = fb_device; + backend->font = font16; + backend->width = fb_device->mode_info.width / 10; + backend->real_height = fb_device->mode_info.height / 16; + backend->height = backend->real_height + 1; // 多出4行用于滚屏 + + backend->buffer_size = backend->width * backend->height; + backend->text_buffer = kmalloc(backend->buffer_size); + backend->current = backend->text_buffer; + backend->last_update = backend->text_buffer; + backend->line_ends = kmalloc(backend->height * sizeof(char *)); + backend->line_widths = kmalloc(backend->height * sizeof(uint16_t)); + for (int i = 0; i < backend->height; i++) { + backend->line_ends[i] = backend->text_buffer; + backend->line_widths[i] = 0; + } + + backend->x = backend->y = 0; + backend->last_update_y = 0; + backend->last_update_x = 0; + + backend->default_fg_color = FB_DEFAULT_FG_COLOR; + backend->default_bg_color = FB_DEFAULT_BG_COLOR; + backend->foreground_color = backend->default_fg_color; + backend->background_color = backend->default_bg_color; + + backend->periodic_task.func = fb_console_backend_update; + backend->periodic_task.arg = backend; + periodic_task_add(&backend->periodic_task); + + spinlock_init(&backend->lock); +} + +void fb_console_backend_scroll(FrameBufferConsoleBackend *backend, int lines) { + FrameBufferDevice *fb_device = backend->fb_device; + + int bpp = fb_device->mode_info.bytes_per_pixel; + int line_length = fb_device->mode_info.width * bpp; + uint8_t *vram = fb_device->framebuffer_address; + uint8_t *src_vram = vram + (lines * 16 * line_length); + uint8_t *dst_vram = vram; + + int width, offset = backend->line_ends[lines - 1] - backend->text_buffer; + width = MAX(backend->line_widths[0], backend->line_widths[lines]); + width *= 10 * bpp; + for (int j = 0; j < 16; j++) { + memcpy(dst_vram, src_vram, width); + src_vram += line_length; + dst_vram += line_length; + } + for (int i = 1; i < backend->real_height - lines; i++) { + width = MAX(backend->line_widths[i], backend->line_widths[i + lines]); + width *= 10 * bpp; + for (int j = 0; j < 16; j++) { + memcpy(dst_vram, src_vram, width); + src_vram += line_length; + dst_vram += line_length; + } + } + for (int i = backend->real_height - lines; i < backend->real_height; i++) { + draw_rect( + fb_device, 0, i * 16, backend->line_widths[i] * 10, 16, + backend->background_color); + } + memcpy( + backend->text_buffer, backend->text_buffer + offset, + backend->buffer_size - offset); + memcpy( + &backend->line_widths[0], &backend->line_widths[lines], + (backend->height - lines) * sizeof(uint16_t)); + for (int i = lines; i < backend->height; i++) { + backend->line_ends[i - lines] = backend->line_ends[i] - offset; + } + for (int i = backend->height - lines; i < backend->height; i++) { + backend->line_ends[i] = backend->text_buffer + backend->buffer_size; + backend->line_widths[i] = 0; + } + backend->y -= lines; + backend->last_update_y -= lines; + backend->current -= offset; + backend->last_update -= offset; +} + +void fb_console_backend_control( + FrameBufferConsoleBackend *backend, char *current) { + const uint32_t color_map1[8] = { + 0x000000, 0xaa0000, 0x00aa00, 0xaa5500, + 0x0000aa, 0xaa00aa, 0x00aaaa, 0xaaaaaa, + }; + const uint32_t color_map2[8] = { + 0x555555, 0xff5555, 0x55ff55, 0xffff55, + 0x5555ff, 0xff55ff, 0x55ffff, 0xffffff, + }; + int param1 = -1, param2 = -1; + + if (*current >= '0' && *current <= '9') { + param1 = *current - '0'; + current++; + } + while (*current >= '0' && *current <= '9') { + param1 = param1 * 10 + (*current - '0'); + current++; + } + + if (*current == ';') { + current++; + if (*current >= '0' && *current <= '9') { + param2 = *current - '0'; + current++; + } + while (*current >= '0' && *current <= '9') { + param2 = param2 * 10 + (*current - '0'); + current++; + } + } + + switch (*current++) { + case 'm': { + if (param1 == -1) { + backend->foreground_color = backend->default_fg_color; + backend->background_color = backend->default_bg_color; + } else if (param1 == 1) { + if (param2 >= 30 && param2 <= 37) { + backend->foreground_color = color_map2[(param2 - 30) & 7]; + } else if (param2 >= 40 && param2 <= 47) { + backend->background_color = color_map2[(param2 - 40) & 7]; + } + } else if (param1 >= 30 && param1 <= 37) { + backend->foreground_color = color_map1[(param1 - 30) & 7]; + } else if (param1 >= 40 && param1 <= 47) { + backend->background_color = color_map1[(param1 - 40) & 7]; + } + } + default: + break; + } + backend->last_update = current; +} + +void fb_console_backend_update(void *arg) { + FrameBufferConsoleBackend *backend = arg; + + int status = spin_try_lock_irqsave(&backend->lock); + if (status == 0) return; + + FrameBufferDevice *fb_device = backend->fb_device; + int bpp = backend->fb_device->mode_info.bytes_per_pixel; + int screen_w = backend->fb_device->mode_info.width; + int line_length = screen_w * bpp; + uint8_t *vram = backend->fb_device->framebuffer_address; + uint8_t *cur_vram = vram + (backend->last_update_y * 16 * screen_w + + backend->last_update_x * 10) * + bpp; + + char *current = backend->last_update; + if (backend->y >= backend->real_height) { + fb_console_backend_scroll( + backend, backend->y - backend->real_height + 1); + cur_vram = vram + (backend->last_update_y * 16 * screen_w + + backend->last_update_x * 10) * + bpp; + current = backend->last_update; + } + while (current < backend->current) { + if (current == backend->line_ends[backend->last_update_y]) { + backend->last_update_y++; + backend->last_update_x = 0; + cur_vram = vram + backend->last_update_y * 16 * line_length; + continue; + } + if (current[0] == '\033') { + if (current[1] == '[') { + current += 2; + fb_console_backend_control(backend, current); + current = backend->last_update; + continue; + } + } + draw_rect( + fb_device, backend->last_update_x * 10, backend->last_update_y * 16, + 10, 16, backend->background_color); + print_word( + fb_device->framebuffer_ops, &fb_device->mode_info, cur_vram, + backend->font + (*current) * 16, backend->foreground_color); + cur_vram += 10 * bpp; + backend->last_update_x++; + current++; + } + if (current == backend->line_ends[backend->last_update_y]) { + backend->last_update_y++; + } + backend->last_update = backend->current; + backend->last_update_y = backend->y; + backend->last_update_x = backend->x; + + spin_unlock_irqrestore(&backend->lock, status); +} + +void fb_console_backend_put_string( + void *context, const char *string, int length) { + FrameBufferDevice *fb_device = context; + FrameBufferConsoleBackend *backend = &fb_device->console_backend; + + spin_lock(&backend->lock); + for (int i = 0; i < length; i++) { + bool new_line = false; + if (string[i] == '\033') { + bool flag = true; + *backend->current++ = string[i++]; + *backend->current++ = string[i++]; + while (flag) { + *backend->current++ = string[i]; + if (string[i] >= 'a' && string[i] <= 'z') flag = false; + if (string[i] >= 'A' && string[i] <= 'Z') flag = false; + i++; + } + i--; + } else if (string[i] == '\n') { + new_line = true; + } else if (string[i] == '\b') { + backend->current--; + + backend->x = MAX(backend->x - 1, 0); + backend->line_widths[backend->y] = + MAX(backend->line_widths[backend->y] - 1, 0); + if (backend->y == backend->last_update_y) { + backend->last_update_x = backend->x; + } + } else if (string[i] == '\t') { + do { + *backend->current++ = ' '; + backend->x++; + backend->line_widths[backend->y]++; + } while (backend->x & 3); + backend->line_widths[backend->y] = + MIN(backend->line_widths[backend->y], backend->width); + if (backend->x >= backend->width) new_line = true; + } else { + *backend->current++ = string[i]; + backend->x++; + backend->line_widths[backend->y]++; + if (backend->x >= backend->width) new_line = true; + } + if (new_line) { + backend->line_ends[backend->y++] = backend->current; + + backend->x = 0; + if (backend->y >= backend->height) { + // 超过最大行数,滚屏 + fb_console_backend_scroll(backend, 1); + } + } + } + spin_unlock(&backend->lock); + if (list_empty(&thread_all)) { fb_console_backend_update(backend); } +} diff --git a/src/driver/framebuffer/framebuffer.c b/src/driver/framebuffer/framebuffer.c new file mode 100644 index 0000000..e2e35c8 --- /dev/null +++ b/src/driver/framebuffer/framebuffer.c @@ -0,0 +1,222 @@ +#include +#include +#include + +extern struct FrameBufferDeviceManager video_dm_ext; +void write_pixel_rgbto8(uint8_t *vram, uint8_t r, uint8_t g, uint8_t b) { + *vram = (r * 6 / 256) + (g * 6 / 256) * 6 + (b * 6 / 256) * 36; +} + +void write_pixel_rgbto16(uint8_t *vram, uint8_t r, uint8_t g, uint8_t b) { + *((uint16_t *)vram) = + (r * 32 / 256) << 11 | ((g * 64 / 256)) << 5 | (b * 32 / 256); +} + +void write_pixel_rgbto24(uint8_t *vram, uint8_t r, uint8_t g, uint8_t b) { + vram[0] = b; + vram[1] = g; + vram[2] = r; +} + +void write_pixel_rgbto32(uint8_t *vram, uint8_t r, uint8_t g, uint8_t b) { + vram[0] = b; + vram[1] = g; + vram[2] = r; + vram[3] = 0; +} + +void write_pixel_raw_8(uint8_t *vram, uint32_t color) { + *vram = color; +} +void write_pixel_raw_16(uint8_t *vram, uint32_t color) { + *((uint16_t *)vram) = color; +} +void write_pixel_raw_24(uint8_t *vram, uint32_t color) { + vram[0] = color & 0xff; + vram[1] = (color >> 8) & 0xff; + vram[2] = (color >> 16) & 0xff; +} +void write_pixel_raw_32(uint8_t *vram, uint32_t color) { + *((uint32_t *)vram) = color; +} + +FramebufferOps fb_ops_8 = { + .write_pixel_raw = write_pixel_raw_8, + .write_pixel_rgb = write_pixel_rgbto8, +}; +FramebufferOps fb_ops_16 = { + .write_pixel_raw = write_pixel_raw_16, + .write_pixel_rgb = write_pixel_rgbto16, +}; +FramebufferOps fb_ops_24 = { + .write_pixel_raw = write_pixel_raw_24, + .write_pixel_rgb = write_pixel_rgbto24, +}; +FramebufferOps fb_ops_32 = { + .write_pixel_raw = write_pixel_raw_32, + .write_pixel_rgb = write_pixel_rgbto32, +}; + +/** + * @brief 写像素 + * + * @param x x坐标 + * @param y y坐标 + * @param color 颜色 + */ +void inline write_pixel( + FrameBufferDevice *fb_device, int x, int y, uint32_t color) { + uint8_t *vram = fb_device->framebuffer_address; + vram += (y * fb_device->mode_info.width + x) * + (fb_device->mode_info.bits_per_pixel / 8); + fb_device->framebuffer_ops->write_pixel_raw(vram, color); +} + +/** + * @brief 写像素 + * + * @param x x坐标 + * @param y y坐标 + * @param r 红色 + * @param g 绿色 + * @param b 蓝色 + */ +void inline write_pixel_rgb( + FrameBufferDevice *fb_device, int x, int y, uint8_t r, uint8_t g, + uint8_t b) { + uint8_t *vram = fb_device->framebuffer_address; + vram += (y * fb_device->mode_info.width + x) * + (fb_device->mode_info.bits_per_pixel / 8); + fb_device->framebuffer_ops->write_pixel_rgb(vram, r, g, b); +} + +/** + * @brief 画矩形 + * + * @param fb_device 显示设备 + * @param x x坐标 + * @param y y坐标 + * @param width 宽度 + * @param height 高度 + * @param color 颜色 + */ +void draw_rect( + FrameBufferDevice *fb_device, int x, int y, int width, int height, + int color) { + int bpp = fb_device->mode_info.bytes_per_pixel; + int x0, y0; + uint8_t *vram = fb_device->framebuffer_address + + (y * fb_device->mode_info.width + x) * bpp; + int delta = (fb_device->mode_info.width - width) * bpp; + for (y0 = 0; y0 < height; y0++) { + for (x0 = 0; x0 < width; x0++) { + fb_device->framebuffer_ops->write_pixel_raw(vram, color); + vram += bpp; + } + vram += delta; + } +} + +/** + * @brief 画矩形 + * + * @param x x坐标 + * @param y y坐标 + * @param width 宽度 + * @param height 高度 + * @param r 红色 + * @param g 绿色 + * @param b 蓝色 + */ +void draw_rect_rgb( + FrameBufferDevice *fb_device, int x, int y, int width, int height, + uint8_t r, uint8_t g, uint8_t b) { + int bpp = fb_device->mode_info.bytes_per_pixel; + int x0, y0; + uint8_t *vram = fb_device->framebuffer_address + + (y * fb_device->mode_info.width + x) * bpp; + int delta = (fb_device->mode_info.width - width) * bpp; + for (y0 = y; y0 < y + height; y0++) { + for (x0 = 0; x0 < width; x0++) { + fb_device->framebuffer_ops->write_pixel_rgb(vram, r, g, b); + vram += bpp; + } + vram += delta; + } +} + +/** + * @brief 打印字符 + * + * @param x x坐标 + * @param y y坐标 + * @param ascii 字符数据(16*8点阵字体) + * @param color 颜色 + */ +void print_word( + FramebufferOps *ops, FrameBufferModeInfo *mode_info, uint8_t *vram, + uint8_t *ascii, int color) { + int i; + char d; + uint8_t bpp = mode_info->bytes_per_pixel; + int delta = (mode_info->width - 8) * bpp; + for (i = 0; i < 16; i++) { + d = ascii[i]; + if (d & 0x80) ops->write_pixel_raw(vram, color); + vram += bpp; + if (d & 0x40) ops->write_pixel_raw(vram, color); + vram += bpp; + if (d & 0x20) ops->write_pixel_raw(vram, color); + vram += bpp; + if (d & 0x10) ops->write_pixel_raw(vram, color); + vram += bpp; + if (d & 0x08) ops->write_pixel_raw(vram, color); + vram += bpp; + if (d & 0x04) ops->write_pixel_raw(vram, color); + vram += bpp; + if (d & 0x02) ops->write_pixel_raw(vram, color); + vram += bpp; + if (d & 0x01) ops->write_pixel_raw(vram, color); + vram += bpp; + vram += delta; + } +} + +/** + * @brief 打印字符 + * + * @param x x坐标 + * @param y y坐标 + * @param ascii 字符数据(16*8点阵字体) + * @param r 红色 + * @param g 绿色 + * @param b 蓝色 + */ +void print_word_rgb( + FramebufferOps *ops, FrameBufferModeInfo *mode_info, uint8_t *vram, + char *ascii, uint8_t r, uint8_t g, uint8_t b) { + int i; + char d; + uint8_t bpp = mode_info->bytes_per_pixel; + int delta = (mode_info->width - 8) * bpp; + for (i = 0; i < 16; i++) { + d = ascii[i]; + if (d & 0x80) { ops->write_pixel_rgb(vram, r, g, b); } + vram += bpp; + if (d & 0x40) { ops->write_pixel_rgb(vram, r, g, b); } + vram += bpp; + if (d & 0x20) { ops->write_pixel_rgb(vram, r, g, b); } + vram += bpp; + if (d & 0x10) { ops->write_pixel_rgb(vram, r, g, b); } + vram += bpp; + if (d & 0x08) { ops->write_pixel_rgb(vram, r, g, b); } + vram += bpp; + if (d & 0x04) { ops->write_pixel_rgb(vram, r, g, b); } + vram += bpp; + if (d & 0x02) { ops->write_pixel_rgb(vram, r, g, b); } + vram += bpp; + if (d & 0x01) { ops->write_pixel_rgb(vram, r, g, b); } + vram += bpp; + vram += delta; + } +} diff --git a/src/driver/framebuffer/framebuffer_dm.c b/src/driver/framebuffer/framebuffer_dm.c new file mode 100644 index 0000000..6ffa5ba --- /dev/null +++ b/src/driver/framebuffer/framebuffer_dm.c @@ -0,0 +1,161 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +DriverResult framebuffer_device_start( + DeviceManager *manager, LogicalDevice *device); + +DeviceManagerOps framebuffer_dm_ops = { + .dm_load = NULL, + .dm_unload = NULL, + + .init_device_hook = NULL, + .start_device_hook = NULL, + .stop_device_hook = NULL, + .destroy_device_hook = NULL, +}; + +FrameBufferDeviceManager framebuffer_dm_ext; + +struct DeviceManager framebuffer_dm = { + .type = DEVICE_TYPE_FRAMEBUFFER, + + .ops = &framebuffer_dm_ops, + + .private_data = &framebuffer_dm_ext, +}; + +DriverResult framebuffer_dm_load(DeviceManager *manager) { + FrameBufferDeviceManager *framebuffer_manager = manager->private_data; + framebuffer_manager->main_display_device = NULL; + framebuffer_dm_ext.new_fb_device_num = 0; + framebuffer_manager->fb_device_count = 0; + + return DRIVER_OK; +} + +DriverResult framebuffer_dm_unload(DeviceManager *manager) { + FrameBufferDeviceManager *framebuffer_manager = manager->private_data; + framebuffer_manager->main_display_device = NULL; + + return DRIVER_OK; +} + +DriverResult create_framebuffer_device( + FrameBufferDevice **fb_device, DeviceOps *ops, + PhysicalDevice *physical_device, DeviceDriver *device_driver) { + DriverResult result; + LogicalDevice *logical_device = NULL; + + result = create_logical_device( + &logical_device, physical_device, device_driver, ops, + DEVICE_TYPE_FRAMEBUFFER); + if (result != DRIVER_OK) return result; + + *fb_device = kmalloc(sizeof(FrameBufferDevice)); + if (*fb_device == NULL) { + delete_logical_device(logical_device); + return DRIVER_ERROR_OUT_OF_MEMORY; + } + FrameBufferDevice *fb = *fb_device; + logical_device->dm_ext = fb; + fb->device = logical_device; + + string_t name; + char _name[] = "FrameBuffer"; + string_new_with_number( + &name, _name, sizeof(_name) - 1, framebuffer_dm_ext.new_fb_device_num); + framebuffer_dm_ext.new_fb_device_num++; + framebuffer_dm_ext.fb_device_count++; + + Object *obj = create_object(&device_object, &name, device_object_attr); + if (obj == NULL) { + kfree(fb); + delete_logical_device(logical_device); + return DRIVER_ERROR_OBJECT; + } + obj->value.device.kind = DEVICE_KIND_LOGICAL; + obj->value.device.logical = logical_device; + logical_device->object = obj; + + list_init(&fb->fb_list_lh); + + ConsoleBackend *backend = &fb->console_backend.backend; + backend->init = fb_console_backend_init; + backend->put_string = fb_console_backend_put_string; + + return DRIVER_OK; +} + +DriverResult delete_framebuffer_device(FrameBufferDevice *framebuffer_device) { + framebuffer_dm_ext.fb_device_count--; + + LogicalDevice *logical_device = framebuffer_device->device; + + list_del(&framebuffer_device->fb_list_lh); + delete_logical_device(logical_device); + int result = kfree(framebuffer_device); + if (result < 0) return DRIVER_ERROR_MEMORY_FREE; + return DRIVER_OK; +} + +DriverResult framebuffer_device_start( + DeviceManager *manager, LogicalDevice *device) { + FrameBufferDevice *fb_device = (FrameBufferDevice *)device->dm_ext; + + init_and_start_logical_device(device); + + if (framebuffer_dm_ext.main_display_device == NULL) { + framebuffer_dm_ext.main_display_device = device; + } + if (fb_device->framebuffer_address == NULL) { return DRIVER_ERROR_OTHER; } + if (fb_device->mode_info.bits_per_pixel == 8) { + fb_device->framebuffer_ops = &fb_ops_8; + } else if (fb_device->mode_info.bits_per_pixel == 16) { + fb_device->framebuffer_ops = &fb_ops_16; + } else if (fb_device->mode_info.bits_per_pixel == 24) { + fb_device->framebuffer_ops = &fb_ops_24; + } else if (fb_device->mode_info.bits_per_pixel == 32) { + fb_device->framebuffer_ops = &fb_ops_32; + } else { + return DRIVER_ERROR_UNSUPPORT_FEATURE; + } + console_register_backend(&fb_device->console_backend.backend, fb_device); + + return DRIVER_OK; +} + +DriverResult framebuffer_start_all() { + LogicalDevice *device; + list_for_each_owner (device, &framebuffer_dm.device_lh, dm_device_list) { + framebuffer_device_start(&framebuffer_dm, device); + } + return DRIVER_OK; +} + +DriverResult framebuffer_get_device( + int in_index, FrameBufferDevice **out_device) { + LogicalDevice *device; + if (in_index == 0) { + *out_device = framebuffer_dm_ext.main_display_device->dm_ext; + return DRIVER_OK; + } + int i = 0; + list_for_each_owner (device, &framebuffer_dm.device_lh, dm_device_list) { + if (device == framebuffer_dm_ext.main_display_device) { continue; } + if (i == in_index) { + *out_device = device->dm_ext; + return DRIVER_OK; + } + i++; + } + return DRIVER_ERROR_NOT_EXIST; +} diff --git a/src/driver/input/Makefile b/src/driver/input/Makefile new file mode 100644 index 0000000..35201cf --- /dev/null +++ b/src/driver/input/Makefile @@ -0,0 +1 @@ +SRC += input_dm.c \ No newline at end of file diff --git a/src/driver/input/config.toml b/src/driver/input/config.toml new file mode 100644 index 0000000..87ad3d6 --- /dev/null +++ b/src/driver/input/config.toml @@ -0,0 +1 @@ +c = ["input_dm.c"] diff --git a/src/driver/input/input_dm.c b/src/driver/input/input_dm.c new file mode 100644 index 0000000..2ea5489 --- /dev/null +++ b/src/driver/input/input_dm.c @@ -0,0 +1,169 @@ +#include "kernel/console.h" +#include "kernel/driver.h" +#include "kernel/spinlock.h" +#include "string.h" +#include +#include +#include +#include +#include +#include +#include +#include + +string_t input_object = STRING_INIT("Input"); + +DriverResult input_dm_load(DeviceManager *manager); +DriverResult input_dm_unload(DeviceManager *manager); + +DeviceManagerOps input_dm_ops = { + .dm_load = input_dm_load, + .dm_unload = NULL, +}; +InputDeviceManager input_dm_ext; +DeviceManager input_dm = { + .type = DEVICE_TYPE_INPUT, + .ops = &input_dm_ops, + .private_data = &input_dm_ext, +}; + +DriverResult input_dm_load(DeviceManager *manager) { + for (int i = 0; i < INPUT_TYPE_MAX; i++) { + input_dm_ext.new_device_num[i] = 0; + input_dm_ext.device_count[i] = 0; + spinlock_init(&input_dm_ext.lock[i]); + } + + input_dm_ext.key_events = + kmalloc(sizeof(KeyEvent) * INPUT_EVENT_QUEUE_SIZE); + input_dm_ext.key_event_w = 0; + input_dm_ext.key_event_r = 0; + input_dm_ext.key_event_full = false; + input_dm_ext.pointer_events = + kmalloc(sizeof(PointerEvent) * INPUT_EVENT_QUEUE_SIZE); + input_dm_ext.pointer_event_w = 0; + input_dm_ext.pointer_event_r = 0; + input_dm_ext.pointer_event_full = false; + return DRIVER_OK; +} + +DriverResult input_dm_unload(DeviceManager *manager) { + kfree(input_dm_ext.key_events); + kfree(input_dm_ext.pointer_events); + return DRIVER_OK; +} + +DriverResult create_input_device( + InputDevice **input_device, InputDeviceType type, DeviceOps *ops, + PhysicalDevice *physical_device, DeviceDriver *device_driver) { + DriverResult result; + LogicalDevice *logical_device = NULL; + + result = create_logical_device( + &logical_device, physical_device, device_driver, ops, + DEVICE_TYPE_INPUT); + if (result != DRIVER_OK) return result; + + *input_device = kmalloc(sizeof(InputDevice)); + if (*input_device == NULL) { + delete_logical_device(logical_device); + return DRIVER_ERROR_OUT_OF_MEMORY; + } + InputDevice *in = *input_device; + logical_device->dm_ext = in; + in->device = logical_device; + in->type = type; + + char name1[] = "Keyboard"; + char name2[] = "Mouse"; + char name3[] = "Input"; + char *_name; + uint8_t len; + string_t name; + uint8_t num; + if (type == INPUT_TYPE_KEYBOARD) { + _name = name1; + len = sizeof(name1) - 1; + } else if (type == INPUT_TYPE_MOUSE) { + _name = name2; + len = sizeof(name2) - 1; + } else { + _name = name3; + len = sizeof(name3) - 1; + } + spin_lock(&input_dm_ext.lock[type]); + num = input_dm_ext.new_device_num[type]++; + input_dm_ext.device_count[type]++; + spin_unlock(&input_dm_ext.lock[type]); + string_new_with_number(&name, _name, len, num); + + Object *obj = create_object(&device_object, &name, device_object_attr); + if (obj == NULL) { + kfree(in); + delete_logical_device(logical_device); + return DRIVER_ERROR_OBJECT; + } + obj->value.device.kind = DEVICE_KIND_LOGICAL; + obj->value.device.logical = logical_device; + logical_device->object = obj; + + if (result != DRIVER_OK) return result; + return DRIVER_OK; +} + +DriverResult delete_input_device(InputDevice *input_device) { + InputDeviceType type = input_device->type; + spin_lock(&input_dm_ext.lock[type]); + if (input_dm_ext.device_count[type] > 0) input_dm_ext.device_count[type]--; + spin_unlock(&input_dm_ext.lock[type]); + + LogicalDevice *logical_device = input_device->device; + + list_del(&logical_device->dm_device_list); + delete_logical_device(logical_device); + int result = kfree(input_device); + if (result < 0) return DRIVER_ERROR_MEMORY_FREE; + return DRIVER_OK; +} + +void new_key_event(uint16_t keycode, uint8_t pressed, uint8_t page) { + if (input_dm_ext.key_event_full) { + // 队列满,丢弃最旧的事件 + input_dm_ext.key_event_r = + (input_dm_ext.key_event_r + 1) % INPUT_EVENT_QUEUE_SIZE; + // 分配新的事件后仍然是满的,所以不更新full标志 + } + KeyEvent *event = &input_dm_ext.key_events[input_dm_ext.key_event_w]; + event->keycode = keycode; + event->pressed = pressed; + event->page = page; + input_dm_ext.key_event_w = + (input_dm_ext.key_event_w + 1) % INPUT_EVENT_QUEUE_SIZE; + + // 如果更新前w在前r在后,更新后相等说明队列满 + if (input_dm_ext.key_event_w == input_dm_ext.key_event_r) { + input_dm_ext.key_event_full = true; + } + return; +} + +void new_pointer_event(int16_t dx, int16_t dy, enum PointerEventType type) { + if (input_dm_ext.pointer_event_full) { + // 队列满,丢弃最旧的事件 + input_dm_ext.pointer_event_r = + (input_dm_ext.pointer_event_r + 1) % INPUT_EVENT_QUEUE_SIZE; + // 分配新的事件后仍然是满的,所以不更新full标志 + } + PointerEvent *event = + &input_dm_ext.pointer_events[input_dm_ext.pointer_event_w]; + event->dx = dx; + event->dy = dy; + event->type = type; + input_dm_ext.pointer_event_w = + (input_dm_ext.pointer_event_w + 1) % INPUT_EVENT_QUEUE_SIZE; + + if (input_dm_ext.pointer_event_w == input_dm_ext.pointer_event_r) { + input_dm_ext.pointer_event_full = true; + } + return; +} diff --git a/src/driver/interrupt/Makefile b/src/driver/interrupt/Makefile new file mode 100644 index 0000000..d3c6cf2 --- /dev/null +++ b/src/driver/interrupt/Makefile @@ -0,0 +1 @@ +SRC += interrupt_dm.c \ No newline at end of file diff --git a/src/driver/interrupt/config.toml b/src/driver/interrupt/config.toml new file mode 100644 index 0000000..fd95a49 --- /dev/null +++ b/src/driver/interrupt/config.toml @@ -0,0 +1 @@ +c = ["interrupt_dm.c"] diff --git a/src/driver/interrupt/interrupt_dm.c b/src/driver/interrupt/interrupt_dm.c new file mode 100644 index 0000000..aaf8a58 --- /dev/null +++ b/src/driver/interrupt/interrupt_dm.c @@ -0,0 +1,191 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +DriverResult interrupt_start(DeviceManager *manager, PhysicalDevice *device); + +DeviceManagerOps interrupt_dm_ops = { + .dm_load = NULL, + .dm_unload = NULL, + + .init_device_hook = NULL, + .start_device_hook = NULL, + .stop_device_hook = NULL, + .destroy_device_hook = NULL, +}; + +typedef struct InterruptDeviceManager { + InterruptDevice *current_device; +} InterruptDeviceManager; + +InterruptDeviceManager interrupt_dm_ext; + +struct DeviceManager interrupt_dm = { + .type = DEVICE_TYPE_INTERRUPT_CONTROLLER, + + .ops = &interrupt_dm_ops, + + .private_data = &interrupt_dm_ext, +}; + +DriverResult interrupt_dm_load(DeviceManager *manager) { + interrupt_dm_ext.current_device = NULL; + + return DRIVER_OK; +} + +/** + * @brief 检查是否提供了必要的接口 + */ +DriverResult check_intterupt_ops(InterruptDeviceOps *int_ops) { + if (!int_ops->disable_irq) { + print_error("Interrupt", "no disable_irq operation\n"); + return DRIVER_ERROR_INCOMPLETABLE_OPS; + } + if (!int_ops->enable_irq) { + print_error("Interrupt", "no enable_irq operation\n"); + return DRIVER_ERROR_INCOMPLETABLE_OPS; + } + if (!int_ops->eoi) { + print_error("Interrupt", "no eoi operation\n"); + return DRIVER_ERROR_INCOMPLETABLE_OPS; + } + if (!int_ops->redirect_irq) { + print_error("Interrupt", "no redirect_irq operation\n"); + return DRIVER_ERROR_INCOMPLETABLE_OPS; + } + return DRIVER_OK; +} + +DriverResult create_interrupt_device( + InterruptDevice **interrupt_device, DeviceOps *ops, + PhysicalDevice *physical_device, DeviceDriver *device_driver, + InterruptDeviceOps *int_ops, int priority) { + DriverResult result; + LogicalDevice *logical_device = NULL; + + DRIVER_RESULT_PASS(check_intterupt_ops(int_ops)); + + result = create_logical_device( + &logical_device, physical_device, device_driver, ops, + DEVICE_TYPE_INTERRUPT_CONTROLLER); + if (result != DRIVER_OK) return result; + + *interrupt_device = kmalloc(sizeof(InterruptDevice)); + if (*interrupt_device == NULL) { + delete_logical_device(logical_device); + return DRIVER_ERROR_OUT_OF_MEMORY; + } + InterruptDevice *int_device = *interrupt_device; + logical_device->dm_ext = int_device; + int_device->device = logical_device; + int_device->ops = int_ops; + int_device->priority = priority; + + InterruptDevice *current_device = interrupt_dm_ext.current_device; + if (current_device) { + if (int_device->priority > current_device->priority) { + if (current_device->device->state == DEVICE_STATE_ACTIVE) { + DEV_OPS_CALL(current_device->device, stop); + } + interrupt_dm_ext.current_device = int_device; + } + } else { + interrupt_dm_ext.current_device = int_device; + } + + return DRIVER_OK; +} + +DriverResult delete_interrupt_device(InterruptDevice *interrupt_device) { + InterruptDeviceManager *manager = &interrupt_dm_ext; + + LogicalDevice *cur; + LogicalDevice *device = interrupt_device->device; + + // 如果是正在使用的设备 + InterruptDevice *new_interrupt_device = NULL; + if (manager->current_device == interrupt_device) { + // 寻找替代的设备 + list_for_each_owner (cur, &interrupt_dm.device_lh, dm_device_list) { + if (cur != device) { + if (new_interrupt_device == NULL) { + new_interrupt_device = cur->dm_ext; + } else { + InterruptDevice *cur_interrupt_device = cur->dm_ext; + if (cur_interrupt_device->priority > + new_interrupt_device->priority) { + new_interrupt_device = cur_interrupt_device; + } + } + } + } + if (new_interrupt_device == NULL) return DRIVER_ERROR_BUSY; + } + if (device->ops->stop && device->state == DEVICE_STATE_ACTIVE) + DRIVER_RESULT_PASS(device->ops->stop(device)); + + LogicalDevice *new_device = new_interrupt_device->device; + + // 恢复运行状态 + if (device->state == DEVICE_STATE_UNINIT) { + init_and_start_logical_device(new_device); + } else if (device->state == DEVICE_STATE_READY) { + start_logical_device(new_device); + } + new_device->state = DEVICE_STATE_ACTIVE; + manager->current_device = new_interrupt_device; + + list_del(&device->dm_device_list); + DRIVER_RESULT_PASS(delete_logical_device(device)); + int result = kfree(interrupt_device); + if (result < 0) return DRIVER_ERROR_MEMORY_FREE; + + return DRIVER_OK; +} + +DriverResult interrupt_dm_start() { + if (interrupt_dm_ext.current_device) { + LogicalDevice *device = interrupt_dm_ext.current_device->device; + if (device->physical_device->state != DEVICE_STATE_READY) { + DRIVER_RESULT_PASS( + init_and_start_physical_device(device->physical_device)); + } + init_and_start_logical_device(device); + return DRIVER_OK; + } + return DRIVER_ERROR_NOT_EXIST; +} + +uint32_t interrupt_redirect_irq(int irq) { + InterruptDevice *interrupt_device = interrupt_dm_ext.current_device; + + return interrupt_device->ops->redirect_irq(interrupt_device, irq); +} + +DriverResult interrupt_enable_irq(int irq) { + InterruptDevice *interrupt_device = interrupt_dm_ext.current_device; + + return interrupt_device->ops->enable_irq(interrupt_device, irq); +} + +DriverResult interrupt_disable_irq(int irq) { + InterruptDevice *interrupt_device = interrupt_dm_ext.current_device; + + return interrupt_device->ops->disable_irq(interrupt_device, irq); +} + +void interrupt_eoi(int irq) { + InterruptDevice *interrupt_device = interrupt_dm_ext.current_device; + + interrupt_device->ops->eoi(interrupt_device, irq); +} diff --git a/src/driver/network/Makefile b/src/driver/network/Makefile new file mode 100644 index 0000000..a92df03 --- /dev/null +++ b/src/driver/network/Makefile @@ -0,0 +1,8 @@ +SRC += network_dm.c +SRC += network.c +SRC += mii.c +SRC += conn.c +SRC += buffer.c +SRC += neighbour.c +SRC += ethernet/ +SRC += protocols/ \ No newline at end of file diff --git a/src/driver/network/buffer.c b/src/driver/network/buffer.c new file mode 100644 index 0000000..1242769 --- /dev/null +++ b/src/driver/network/buffer.c @@ -0,0 +1,76 @@ +#include +#include +#include +#include +#include + +NetBuffer *net_buffer_create(uint16_t size) { + NetBuffer *buffer = kmalloc(sizeof(NetBuffer)); + if (buffer == NULL) { return NULL; } + buffer->ptr = kmalloc(size); + if (buffer->ptr == NULL) { + kfree(buffer); + return NULL; + } + buffer->size = size; + return buffer; +} + +void net_buffer_delete(NetBuffer *buffer) { + if (buffer == NULL) return; + if (buffer->ptr) kfree(buffer->ptr); + kfree(buffer); +} + +void net_buffer_init( + NetBuffer *buffer, uint16_t size, uint16_t head, uint16_t tail) { + buffer->size = size; + + buffer->head = buffer->ptr + head; + buffer->data = buffer->ptr + head; + buffer->tail = buffer->ptr + tail; +} + +void net_buffer_reset(NetBuffer *buffer) { + buffer->head = buffer->data; + buffer->tail = buffer->data; +} + +void net_buffer_clean_data(NetBuffer *buffer) { + buffer->tail = buffer->data; +} + +void net_buffer_header_alloc(NetBuffer *buffer, uint16_t size) { + buffer->head -= size; +} + +void net_buffer_header_free(NetBuffer *buffer, uint16_t size) { + buffer->head += size; +} + +void net_buffer_tail_alloc(NetBuffer *buffer, uint16_t size) { + buffer->tail += size; +} + +void net_buffer_tail_free(NetBuffer *buffer, uint16_t size) { + buffer->tail -= size; +} + +ProtocolResult net_buffer_data_alloc(NetBuffer *buffer, uint16_t size) { + if (buffer->tail + size > buffer->ptr + buffer->size) { + // 如果数据超过了缓冲区的大小,则不进行写入 + return PROTO_ERROR_EXCEED_MAX_SIZE; + } + buffer->tail += size; + return PROTO_OK; +} + +ProtocolResult net_buffer_put(NetBuffer *buffer, uint16_t size) { + if (buffer->tail + size > buffer->ptr + buffer->size) { + // 如果数据超过了缓冲区的大小,则不进行写入 + return PROTO_ERROR_EXCEED_MAX_SIZE; + } + buffer->tail += size; + + return PROTO_OK; +} diff --git a/src/driver/network/config.toml b/src/driver/network/config.toml new file mode 100644 index 0000000..2824976 --- /dev/null +++ b/src/driver/network/config.toml @@ -0,0 +1,2 @@ +dir = ["ethernet/", "protocols/"] +c = ["buffer.c", "conn.c", "mii.c", "neighbour.c", "network_dm.c", "network.c"] diff --git a/src/driver/network/conn.c b/src/driver/network/conn.c new file mode 100644 index 0000000..f9e6a61 --- /dev/null +++ b/src/driver/network/conn.c @@ -0,0 +1,109 @@ +#include "driver/network/ethernet/ethernet.h" +#include "driver/network/protocols/ipv4/ipv4.h" +#include "driver/network/protocols/protocols.h" +#include "kernel/list.h" +#include "kernel/spinlock.h" +#include "kernel/thread.h" +#include "objects/object.h" +#include +#include +#include +#include +#include + +NetworkConnection *net_create_conn(Object *object) { + if (object->attr->type != OBJECT_TYPE_DEVICE) { return NULL; } + NetworkConnection *conn = kmalloc(sizeof(NetworkConnection)); + if (conn == NULL) { return NULL; } + conn->object = object; + conn->handle = object_handle_create(object); + conn->net_device = object->value.device.logical->dm_ext; + conn->state = CONN_STATE_INIT; + + conn->thread = get_current_thread(); + + conn->phy_protocol = PHY_PROTO_NONE; + conn->dl_protocol = DL_PROTO_NONE; + conn->net_protocol = NET_PROTO_NONE; + conn->trans_protocol = TRANS_PROTO_NONE; + conn->tcp.info = NULL; + + spinlock_init(&conn->recv_lock); + list_init(&conn->recv_lh); + return conn; +} + +void net_destroy_conn(NetworkConnection *conn) { + object_handle_delete(conn->handle); + kfree(conn); +} + +ProtocolResult conn_wrap(NetworkConnection *conn, ProtocolLevel level) { + if (conn == NULL) { return PROTO_ERROR_NULL_PTR; } + uint16_t trans_protocol = 0; + uint16_t net_protocol = 0; + uint8_t dst_mac[8] = {0}; + + ProtocolResult result = PROTO_OK; + switch (level) { + case PROTO_LEVEL_TRANSPORT: + case PROTO_LEVEL_NETWORK: + if (trans_protocol == 0) { + switch (conn->trans_protocol) { + case TRANS_PROTO_UDP: + trans_protocol = IP_PROTO_UDP; + break; + case TRANS_PROTO_TCP: + trans_protocol = IP_PROTO_TCP; + break; + default: + break; + } + } + switch (conn->net_protocol) { + case NET_PROTO_IPV4: + result = ipv4_wrap(conn, trans_protocol, CONN_REMOTE_IP(conn), 64); + if (result != PROTO_OK) return result; + result = ipv4_lookup_mac( + conn->net_device, conn->ipv4.conn_info.remote.ip, dst_mac); + break; + default: + return PROTO_ERROR_UNSUPPORT; + } + case PROTO_LEVEL_DATA_LINK: + switch (conn->dl_protocol) { + default: + break; + } + case PROTO_LEVEL_PHYSICAL: + if (net_protocol == 0) { + switch (conn->net_protocol) { + case NET_PROTO_IPV4: + net_protocol = ETH_PROTO_TYPE_IPV4; + break; + default: + return PROTO_ERROR_UNSUPPORT; + } + } + if (net_protocol == 0) { + switch (conn->dl_protocol) { + case DL_PROTO_ARP: + net_protocol = ETH_PROTO_TYPE_ARP; + break; + default: + return PROTO_ERROR_UNSUPPORT; + } + } + switch (conn->phy_protocol) { + case PHY_PROTO_ETHERNET: + result = eth_wrap( + conn->buffer, conn->ethernet.mac, dst_mac, net_protocol); + break; + default: + return PROTO_ERROR_UNSUPPORT; + } + break; + } + + return result; +} diff --git a/src/driver/network/ethernet/Makefile b/src/driver/network/ethernet/Makefile new file mode 100644 index 0000000..c21cbb6 --- /dev/null +++ b/src/driver/network/ethernet/Makefile @@ -0,0 +1 @@ +SRC += ethernet.c \ No newline at end of file diff --git a/src/driver/network/ethernet/config.toml b/src/driver/network/ethernet/config.toml new file mode 100644 index 0000000..280b667 --- /dev/null +++ b/src/driver/network/ethernet/config.toml @@ -0,0 +1 @@ +c = ["ethernet.c"] diff --git a/src/driver/network/ethernet/ethernet.c b/src/driver/network/ethernet/ethernet.c new file mode 100644 index 0000000..073b241 --- /dev/null +++ b/src/driver/network/ethernet/ethernet.c @@ -0,0 +1,111 @@ +/** + * @file ethernet.c + * @author Jiajun Wang (ryan1202@foxmail.com) + * @brief Ethernet II + * + * Reference: + * IEEE 802.3: IEEE Standard for Ethernet + * RFC 894: A Standard for the Transmission of IP Datagrams over Ethernet + * Networks + * + */ +#include "driver/network/protocols/ipv4/ipv4.h" +#include "driver/network/protocols/protocols.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +NetProtocol ethernet_protocol = { + .head_size = 14, + .tail_size = 0, +}; + +const uint8_t eth_broadcast_mac[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +const uint8_t eth_null_mac[6] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + +void eth_set_mac_address(EthernetDevice *device, uint8_t *mac_addr) { + memcpy(device->mac_addr, mac_addr, 6); +} + +void eth_get_mac_address(EthernetDevice *device, uint8_t *mac_addr) { + memcpy(mac_addr, device->mac_addr, 6); +} + +void eth_register(NetworkConnection *conn) { + EthernetDevice *eth_device = conn->net_device->ethernet; + conn->phy_protocol = PHY_PROTO_ETHERNET; + eth_get_mac_address(eth_device, conn->ethernet.mac); + conn->pmtu = ETH_MTU; + NET_BUF_RESV_HEAD(conn, 14); +} + +ProtocolResult eth_wrap( + NetBuffer *buffer, uint8_t *mac_addr, const uint8_t *dst_addr, + uint16_t protocol) { + net_buffer_header_alloc(buffer, 14); + EthernetHeader *header = (EthernetHeader *)buffer->head; + memcpy(header->dst_mac, dst_addr, 6); + memcpy(header->src_mac, mac_addr, 6); + + int content_size = buffer->tail - buffer->head; + if (content_size > ETH_MAX_FRAME_SIZE) return PROTO_ERROR_EXCEED_MAX_SIZE; + if (content_size < ETH_MIN_FRAME_SIZE) { + // 填充最小帧长度 + memset(buffer->tail, 0, ETH_MIN_FRAME_SIZE - content_size); + } + header->protocol_type = HOST2BE_WORD(protocol); + + return PROTO_OK; +} + +ProtocolResult eth_reply(NetworkDevice *device, NetBuffer *buffer) { + EthernetHeader *header = (EthernetHeader *)buffer->head; + uint8_t tmp[ETH_IDENTIFIER_SIZE]; + if (memcmp(header->dst_mac, eth_broadcast_mac, ETH_IDENTIFIER_SIZE) == 0) { + // 广播包不回复 + return PROTO_ERROR_CANNOT_FIND_ROUTE; + } + memcpy(tmp, header->dst_mac, ETH_IDENTIFIER_SIZE); + memcpy(header->dst_mac, header->src_mac, ETH_IDENTIFIER_SIZE); + memcpy(header->src_mac, tmp, ETH_IDENTIFIER_SIZE); + return PROTO_OK; +} + +ProtocolResult eth_recv( + NetworkDevice *device, NetBuffer *net_buffer, ProtocolReplyCallback *stack, + int stack_size) { + EthernetHeader *header = (EthernetHeader *)net_buffer->data; + int size = net_buffer->tail - net_buffer->data; + if (size < ETH_HEADER_SIZE) { return PROTO_ERROR_UNSUPPORT; } + if (size > ETH_MAX_FRAME_SIZE) { return PROTO_ERROR_EXCEED_MAX_SIZE; } + + net_buffer->data += sizeof(EthernetHeader); + + ProtocolResult result = PROTO_OK; + + *stack++ = eth_reply; + stack_size--; + switch (BE2HOST_WORD(header->protocol_type)) { + case ETH_PROTO_TYPE_IPV4: + ipv4_neigh_update( + device, net_buffer, header->src_mac, ETH_IDENTIFIER_SIZE); + result = ipv4_recv(device, net_buffer, stack, stack_size); + break; + case ETH_PROTO_TYPE_ARP: + result = arp_recv(device, net_buffer); + break; + default: + result = PROTO_ERROR_UNSUPPORT; + } + + return result; +} diff --git a/src/driver/network/mii.c b/src/driver/network/mii.c new file mode 100644 index 0000000..cd19f57 --- /dev/null +++ b/src/driver/network/mii.c @@ -0,0 +1,56 @@ +#include "kernel/console.h" +#include "kernel/driver_interface.h" +#include +#include +#include +#include + +bool mii_is_linked(Mii *mii) { + uint32_t data = mii->mdio_read(mii, MII_REG_BMSR); + return !!(data & MII_BMSR_LINK_STATUS); +} + +MiiMediaType mii_check_media_type(uint32_t negotiation) { + MiiMediaType type = MMT_UNKNOWN; + if (negotiation & BIT(5)) type = MMT_10HALF; + if (negotiation & BIT(6)) type = MMT_10FULL; + if (negotiation & BIT(7)) type = MMT_100HALF; + if (negotiation & BIT(8)) type = MMT_100FULL; + if (negotiation & BIT(9)) type = MMT_100T4; + + return type; +} + +/** + * @brief 通过MII接口初始化网卡配置 + * + */ +DriverResult net_init_mii(Mii *mii) { + bool linked = mii_is_linked(mii); + char *device_name = mii->net_dev->device->object->name.text; + + if (!linked) { + print_info("MII", "device %s No link detected\n", device_name); + mii->net_dev->state = NET_STATE_NO_CARRIER; + return DRIVER_OK; + } + print_info("MII", "device %s Link detecteds\n", device_name); + mii->net_dev->state = NET_STATE_RUNNING; + + uint32_t anar = mii->mdio_read(mii, MII_REG_ANAR); // 本地能力 + uint32_t anlpar = mii->mdio_read(mii, MII_REG_ANLPAR); // 对端能力 + uint32_t support = anar & anlpar; // 计算双方都支持的特性 + MiiMediaType media_type = mii_check_media_type(support); + + print_info("MII", "device %s Media type: ", device_name); + int speed = (media_type >> 1) & 0b111; + int duplex = media_type & 1; + if (speed == 0) printk("10Mbps "); + else if (speed == 1) printk("100Mbps "); + if (duplex) printk("Full Duplex"); + else printk("Half Duplex"); + printk("\n"); + + mii->full_duplex = duplex; + return DRIVER_OK; +} \ No newline at end of file diff --git a/src/driver/network/neighbour.c b/src/driver/network/neighbour.c new file mode 100644 index 0000000..34ebbc7 --- /dev/null +++ b/src/driver/network/neighbour.c @@ -0,0 +1,88 @@ +#include "driver/network/network_dm.h" +#include "driver/network/protocols/ipv4/arp.h" +#include "kernel/list.h" +#include "kernel/spinlock.h" +#include +#include +#include +#include + +NeighbourTable neighbour_table; +int neighbour_max_retries = 5; + +void neighbour_init(void) { + for (int i = 0; i < NEIGH_BUCKET_SIZE; i++) { + list_init(&neighbour_table.buckets[i]); + spinlock_init(&neighbour_table.lock[i]); + } +} + +NeighbourEntry *neighbour_entry_create( + NetworkDevice *device, NeighbourKey hash_key, uint8_t *addr, + uint8_t length) { + NeighbourEntry *entry = kmalloc(sizeof(NeighbourEntry) + length); + if (!entry) { return NULL; } + + hash_key %= NEIGH_BUCKET_SIZE; + + spinlock_init(&entry->lock); + entry->key = hash_key; + entry->state = NEIGH_STATE_NONE; + entry->device = device; + entry->hlen = 0; + memset(entry->haddr, 0, sizeof(entry->haddr)); + memcpy(entry->ip_addr, addr, length); + + // list_init(&entry->list); + + switch (device->type) { + case NETWORK_TYPE_ETHERNET: + entry->ops = &arp_proto_ops; + break; + default: + break; + } + + entry->ip_length = length; + memcpy(entry->ip_addr, addr, length); + + NeighbourTable *table = &neighbour_table; + spin_lock(&table->lock[hash_key]); + list_add_tail(&entry->list, &table->buckets[hash_key]); + spin_unlock(&table->lock[hash_key]); + + return entry; +} + +NeighbourEntry *neighbour_table_try_lookup( + NetworkDevice *device, NeighbourKey hash_key, uint8_t *ip_addr, + uint8_t ip_length) { + NeighbourEntry *entry = NULL; + + hash_key %= NEIGH_BUCKET_SIZE; + spin_lock(&neighbour_table.lock[hash_key]); + list_for_each_owner (entry, &neighbour_table.buckets[hash_key], list) { + if (ip_length == entry->ip_length && + memcmp(entry->ip_addr, ip_addr, ip_length) == 0) { + spin_unlock(&neighbour_table.lock[hash_key]); + return entry; + } + } + spin_unlock(&neighbour_table.lock[hash_key]); + + return NULL; +} + +NeighbourEntry *neighbour_table_lookup( + NetworkDevice *device, NeighbourKey hash_key, uint8_t *ip_addr, + uint8_t ip_length) { + NeighbourEntry *entry = + neighbour_table_try_lookup(device, hash_key, ip_addr, ip_length); + if (entry != NULL) return entry; + + entry = neighbour_entry_create(device, hash_key, ip_addr, ip_length); + + entry->ops->request(entry, NULL); + + return entry; +} diff --git a/src/driver/network/network.c b/src/driver/network/network.c new file mode 100644 index 0000000..a0bbeec --- /dev/null +++ b/src/driver/network/network.c @@ -0,0 +1,89 @@ +#include "driver/network/network.h" +#include "driver/network/buffer.h" +#include "driver/network/conn.h" +#include "driver/network/protocols/protocols.h" +#include "kernel/device.h" +#include "kernel/list.h" +#include +#include +#include +#include +#include +#include +#include + +LIST_HEAD(net_rx_lh); + +void net_queue_block(NetworkQueue *queue, int blocker) { + queue->blocker = blocker; +} + +bool net_queue_is_blocked(NetworkQueue *queue, int blocker) { + return (queue->blocker & blocker) == blocker; +} + +TransferResult network_transfer( + struct Object *object, struct ObjectHandle *obj_handle, + TransferDirection direction, uint8_t *buf, size_t size) { + LogicalDevice *device = object->value.device.logical; + NetworkDevice *net_device = device->dm_ext; + if (net_device->ops->send == NULL) { return TRANSFER_ERROR_NOT_SUPPORTED; } + if (net_queue_is_blocked(&net_device->tx_queue, NQ_BLOCKER_DRIVER)) { + return TRANSFER_ERROR_FAILED; + } + return net_device->ops->send(net_device, buf, size); +} + +DriverResult network_softirq_register(NetRxHandler *handler) { + list_add_tail(&handler->list, &net_rx_lh); + return DRIVER_OK; +} + +void network_softirq_handler(void) { + NetRxHandler *handler; + list_for_each_owner (handler, &net_rx_lh, list) { + if (handler->handler) { + handler->handler(handler->data); + } else { + printk("[Network] Rx handler is NULL, skipping.\n"); + } + } +} + +NetBuffer *network_recv(NetworkConnection *conn) { + NetBuffer *net_buffer = NULL; + if (!list_empty(&conn->recv_lh)) { + disable_preempt(); + spin_lock(&conn->recv_lock); + net_buffer = list_first_owner(&conn->recv_lh, NetBuffer, list); + list_del(&net_buffer->list); + spin_unlock(&conn->recv_lock); + enable_preempt(); + } + return net_buffer; +} + +ProtocolResult protocol_recv( + NetworkDevice *device, NetBuffer *net_buffer, NetworkDeviceType type) { + ProtocolReplyCallback callback_stack[NET_CONN_MAX_PROTOCOLS]; + switch (type) { + case NETWORK_TYPE_ETHERNET: + return eth_recv( + device, net_buffer, callback_stack, NET_CONN_MAX_PROTOCOLS); + default: + return PROTO_ERROR_UNSUPPORT; + } +} + +ProtocolResult protocol_reply( + NetworkDevice *device, NetBuffer *net_buffer, ProtocolReplyCallback *stack, + int stack_size) { + ProtocolResult result = PROTO_OK; + while (stack_size++ < NET_CONN_MAX_PROTOCOLS) { + result = (*--stack)(device, net_buffer); + if (result != PROTO_OK) { return result; } + } + device->ops->send( + device, net_buffer->head, net_buffer->tail - net_buffer->head); + return result; +} diff --git a/src/driver/network/network_dm.c b/src/driver/network/network_dm.c new file mode 100644 index 0000000..45448d8 --- /dev/null +++ b/src/driver/network/network_dm.c @@ -0,0 +1,141 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +DriverResult network_dm_load(DeviceManager *manager); +DriverResult network_dm_unload(DeviceManager *manager); + +DeviceManagerOps network_dm_ops = { + .dm_load = network_dm_load, + .dm_unload = network_dm_unload, +}; + +NetworkDeviceManager network_dm_ext; +DeviceManager network_dm = { + .type = DEVICE_TYPE_INTERNET, + .ops = &network_dm_ops, + .private_data = &network_dm_ext, +}; + +DriverResult network_dm_load(DeviceManager *manager) { + manager->private_data = kmalloc(sizeof(NetworkDeviceManager)); + softirq_register_handler(SOFTIRQ_NETWORK, network_softirq_handler); + neighbour_init(); + return DRIVER_OK; +} + +DriverResult network_dm_unload(DeviceManager *manager) { + kfree(manager->private_data); + return DRIVER_OK; +} + +DriverResult create_network_device( + NetworkDevice **network_device, NetworkDeviceType type, + NetworkDeviceCapabilities caps, NetworkOps *net_ops, DeviceOps *ops, + PhysicalDevice *physical_device, DeviceDriver *device_driver) { + DriverResult result; + LogicalDevice *logical_device = NULL; + + result = create_logical_device( + &logical_device, physical_device, device_driver, ops, + DEVICE_TYPE_INTERNET); + if (result != DRIVER_OK) return result; + + *network_device = kmalloc(sizeof(NetworkDevice)); + if (*network_device == NULL) { + delete_logical_device(logical_device); + return DRIVER_ERROR_OUT_OF_MEMORY; + } + + NetworkDevice *net = *network_device; + logical_device->dm_ext = net; + net->type = type; + net->capabilities = caps; + net->ops = net_ops; + net->state = NET_STATE_INITED; + net->device = logical_device; + net->tx_queue.blocker = 0; + + char _name[] = "Network"; + string_t name; + string_new_with_number( + &name, _name, sizeof(_name) - 1, network_dm_ext.device_count); + network_dm_ext.new_device_num++; + network_dm_ext.device_count++; + + Object *obj = create_object(&device_object, &name, device_object_attr); + if (obj == NULL) { + kfree(net); + delete_logical_device(logical_device); + return DRIVER_ERROR_OBJECT; + } + obj->value.device.kind = DEVICE_KIND_LOGICAL; + obj->value.device.logical = logical_device; + obj->in.type = TRANSFER_TYPE_NONE; + obj->out.type = TRANSFER_TYPE_STREAM; + obj->out.stream = network_transfer; + logical_device->object = obj; + + switch (type) { + case NETWORK_TYPE_ETHERNET: { + EthernetDevice *eth = kmalloc(sizeof(EthernetDevice)); + net->ethernet = eth; + eth->acd_state = ACD_STATE_NONE; + eth->arp_conn = net_create_conn(obj); + + conn_buffer(eth->arp_conn) = net_buffer_create(128); + + net_buffer_init(conn_buffer(eth->arp_conn), 128, 0, 0); + timer_init(ð->timer); + eth_register(eth->arp_conn); + break; + } + default: + break; + } + + return DRIVER_OK; +} + +DriverResult delete_network_device(NetworkDevice *network_device) { + network_dm_ext.device_count--; + LogicalDevice *logical_device = network_device->device; + + logical_device->object->out.type = TRANSFER_TYPE_NONE; + logical_device->object->out.stream = NULL; + if (network_device->type == NETWORK_TYPE_ETHERNET) { + net_buffer_delete(conn_buffer(network_device->ethernet->arp_conn)); + kfree(network_device->ethernet); + } + + delete_logical_device(logical_device); + int result = kfree(network_device); + if (result < 0) return DRIVER_ERROR_MEMORY_FREE; + return DRIVER_OK; +} + +NetworkDevice *network_get_device(Object *object) { + // if (object->attr->type != OBJECT_TYPE_DEVICE) return NULL; + LogicalDevice *device = object->value.device.logical; + // if (device->device_driver->type != DEVICE_TYPE_SOUND) return NULL; + return device->dm_ext; +} + +NetworkDeviceType network_get_type(Object *object) { + NetworkDevice *network_device = network_get_device(object); + if (network_device == NULL) return NETWORK_TYPE_UNKNOWN; + return network_device->type; +} diff --git a/src/driver/network/protocols/Makefile b/src/driver/network/protocols/Makefile new file mode 100644 index 0000000..dcd9585 --- /dev/null +++ b/src/driver/network/protocols/Makefile @@ -0,0 +1,3 @@ +SRC += ipv4/ +SRC += udp.c +SRC += tcp.c \ No newline at end of file diff --git a/src/driver/network/protocols/config.toml b/src/driver/network/protocols/config.toml new file mode 100644 index 0000000..f619b0e --- /dev/null +++ b/src/driver/network/protocols/config.toml @@ -0,0 +1,2 @@ +dir = ["ipv4/"] +c = ["tcp.c", "udp.c"] diff --git a/src/driver/network/protocols/ipv4/Makefile b/src/driver/network/protocols/ipv4/Makefile new file mode 100644 index 0000000..441e15d --- /dev/null +++ b/src/driver/network/protocols/ipv4/Makefile @@ -0,0 +1,5 @@ +SRC += acd.c +SRC += arp.c +SRC += dhcp.c +SRC += icmp.c +SRC += ipv4.c \ No newline at end of file diff --git a/src/driver/network/protocols/ipv4/acd.c b/src/driver/network/protocols/ipv4/acd.c new file mode 100644 index 0000000..4da6a98 --- /dev/null +++ b/src/driver/network/protocols/ipv4/acd.c @@ -0,0 +1,83 @@ +/** + * @file acd.c + * @author your name (you@domain.com) + * @brief Address Conflict Detection + * References: + * - RFC5227: IPv4 Address Conflict Detection + */ +#include +#include +#include +#include +#include +#include +#include +#include + +void acd_timer_callback(void *arg) { + NetworkDevice *device = arg; + EthernetDevice *eth_device = device->ethernet; + + switch (eth_device->acd_state) { + case ACD_STATE_PROBE: + if (eth_device->probe_count < ACD_PROBE_NUM) { + eth_device->probe_count++; + timer_set_timeout(ð_device->timer, ACD_PROBE_MIN * 1000); + timer_callback_enable(ð_device->timer); + + NeighbourKey key = ipv4_hash(device->ipv4.ip); + NeighbourEntry *entry = + neighbour_table_lookup(device, key, device->ipv4.ip, 4); + arp_send_request(entry, arg); + } else { + // 确认没有冲突,发送公告 + acd_announce(device); + } + break; + case ACD_STATE_ANNOUNCE: + if (eth_device->announce_count < ACD_ANNOUNCE_NUM) { + eth_device->announce_count++; + timer_set_timeout(ð_device->timer, ACD_ANNOUNCE_INTERVAL * 1000); + timer_callback_enable(ð_device->timer); + arp_announce(device, device->ipv4.ip); + } else { + eth_device->acd_state = ACD_STATE_NONE; + } + break; + default: + break; + } +} + +ProtocolResult acd_conflict_detected(NetworkDevice *device) { + EthernetDevice *eth_device = device->ethernet; + timer_callback_cancel(ð_device->timer); + eth_device->acd_state = ACD_STATE_CONFLICT; + if (eth_device->acd_conflict_callback) + eth_device->acd_conflict_callback(device); + return PROTO_OK; +} + +void acd_probe(NetworkDevice *device) { + EthernetDevice *eth_device = device->ethernet; + eth_device->probe_count = 0; + + eth_device->timer.callback = acd_timer_callback; + eth_device->timer.arg = device; + + eth_device->acd_state = ACD_STATE_PROBE; + timer_set_timeout(ð_device->timer, ACD_PROBE_WAIT * 1000); + timer_callback_enable(ð_device->timer); +} + +void acd_announce(NetworkDevice *device) { + EthernetDevice *eth_device = device->ethernet; + eth_device->announce_count = 0; + + eth_device->timer.callback = acd_timer_callback; + eth_device->timer.arg = device; + + eth_device->acd_state = ACD_STATE_ANNOUNCE; + timer_set_timeout(ð_device->timer, ACD_ANNOUNCE_WAIT * 1000); + timer_callback_enable(ð_device->timer); +} diff --git a/src/driver/network/protocols/ipv4/arp.c b/src/driver/network/protocols/ipv4/arp.c new file mode 100644 index 0000000..800f5e7 --- /dev/null +++ b/src/driver/network/protocols/ipv4/arp.c @@ -0,0 +1,206 @@ +/** + * @file arp.c + * @author Jiajun Wang (ryan1202@foxmail.com) + * @brief ARP + * + * Reference: + * RFC 826: An Ethernet Address Resolution Protocol + * + */ +#include "driver/network/buffer.h" +#include "driver/network/ethernet/ethernet.h" +#include "driver/network/network_dm.h" +#include "kernel/list.h" +#include "kernel/spinlock.h" +#include +#include +#include +#include +#include +#include +#include +#include + +NeighbourProtoOps arp_proto_ops = { + .request = arp_send_request, + .probe = acd_probe, + .announce = acd_announce, +}; + +ProtocolResult arp_recv(NetworkDevice *device, NetBuffer *net_buffer) { + ArpHeader *arp_header = (ArpHeader *)net_buffer->data; + + void *p = (void *)(arp_header + 1); + void *src_haddr = p; + void *src_paddr = p + arp_header->hlen; + void *dst_haddr = p + arp_header->hlen + arp_header->plen; + void *dst_paddr = p + arp_header->hlen * 2 + arp_header->plen; + + // 检查硬件类型 + uint16_t htype = BE2HOST_WORD(arp_header->htype); + uint8_t haddr[8]; + uint8_t *mac_addr = device->ethernet->mac_addr; + if (htype == ARP_HTYPE_ETH && device->type == NETWORK_TYPE_ETHERNET) { + if (arp_header->hlen == ETH_IDENTIFIER_SIZE) { + if (memcmp(dst_haddr, mac_addr, arp_header->hlen) == 0) { + // 处理本地地址 + p = dst_haddr; + goto next; + } else if ( + memcmp(dst_haddr, eth_broadcast_mac, arp_header->hlen) == 0 || + memcmp(dst_haddr, eth_null_mac, arp_header->hlen) == 0) { + // 处理其他地址 + p = mac_addr; + goto next; + } + } + } + return PROTO_ERROR_UNSUPPORT; // 不支持的硬件类型 +next: + memcpy(haddr, p, arp_header->hlen); + + bool merge_flag = false; + NeighbourKey hash_key = NEIGH_BUCKET_SIZE; + + // 检查协议类型 + uint8_t *paddr = NULL; + uint16_t ptype = BE2HOST_WORD(arp_header->ptype); + if (ptype == ETH_PROTO_TYPE_IPV4 && arp_header->plen == 4) { + hash_key = ipv4_hash(src_paddr) % NEIGH_BUCKET_SIZE; + paddr = device->ipv4.ip; + if (memcmp(src_paddr, paddr, 4) == 0) { + // 源地址与本机IP冲突 + acd_conflict_detected(device); + } + } else { + return PROTO_ERROR_UNSUPPORT; // 不支持的协议类型 + } + + if (hash_key >= NEIGH_BUCKET_SIZE) { return PROTO_ERROR_UNSUPPORT; } + + NeighbourEntry *entry, *next; + spin_lock(&neighbour_table.lock[hash_key]); + list_for_each_owner_safe ( + entry, next, &neighbour_table.buckets[hash_key], list) { + spin_lock(&entry->lock); + if (arp_header->plen == entry->ip_length && + memcmp(entry->ip_addr, src_paddr, arp_header->plen) == 0) { + merge_flag = true; + break; + } + spin_unlock(&entry->lock); + } + spin_unlock(&neighbour_table.lock[hash_key]); + + if (memcmp(dst_paddr, device->ipv4.ip, 4)) return PROTO_OK; + + if (!merge_flag) { + // Create a new neighbour entry + entry = neighbour_entry_create( + device, hash_key, src_paddr, arp_header->plen); + if (!entry) return PROTO_ERROR_OTHER; + + spin_lock(&entry->lock); + } else { + } + entry->state = NEIGH_STATE_REACHABLE; + entry->hlen = arp_header->hlen; + memcpy(entry->haddr, src_haddr, arp_header->hlen); + spin_unlock(&entry->lock); + + uint16_t opcode = BE2HOST_WORD(arp_header->opcode); + if (opcode == ARP_OP_REQUEST) { + memcpy(dst_haddr, src_haddr, arp_header->hlen); + memcpy(dst_paddr, src_paddr, arp_header->plen); + memcpy(src_haddr, haddr, arp_header->hlen); + memcpy(src_paddr, paddr, arp_header->plen); + arp_header->opcode = HOST2BE_WORD(ARP_OP_REPLY); + device->ops->send( + device, net_buffer->head, net_buffer->tail - net_buffer->head); + } + + return PROTO_OK; +} + +void arp_send_request(NeighbourEntry *entry, void *arg) { + NetworkDevice *device = entry->device; + EthernetDevice *eth_device = device->ethernet; + NetworkConnection *conn = eth_device->arp_conn; + + net_buffer_reset(conn->buffer); + + // Fill in the ARP request details + ArpHeader *arp_header = (ArpHeader *)conn_buffer(conn)->data; + arp_header->htype = HOST2BE_WORD(ARP_HTYPE_ETH); + arp_header->ptype = HOST2BE_WORD(ETH_PROTO_TYPE_IPV4); + arp_header->hlen = 6; + arp_header->plen = 4; + arp_header->opcode = HOST2BE_WORD(ARP_OP_REQUEST); + + void *p = (void *)(arp_header + 1); + void *src_haddr = p; + void *src_paddr = p + arp_header->hlen; + void *dst_haddr = p + arp_header->hlen + arp_header->plen; + void *dst_paddr = p + arp_header->hlen * 2 + arp_header->plen; + + // Copy the sender's hardware and protocol addresses + memcpy(src_haddr, eth_device->mac_addr, arp_header->hlen); + memcpy(src_paddr, device->ipv4.ip, arp_header->plen); + + // Copy the target's hardware and protocol addresses + uint8_t eth_dst_addr[ETH_IDENTIFIER_SIZE] = {0}; + memcpy(dst_haddr, eth_dst_addr, arp_header->hlen); + memcpy(dst_paddr, entry->ip_addr, arp_header->plen); + + uint8_t size = + sizeof(ArpHeader) + arp_header->hlen * 2 + arp_header->plen * 2; + net_buffer_put(conn_buffer(conn), size); + + // Send the ARP request + eth_wrap( + conn_buffer(conn), device->ethernet->mac_addr, eth_broadcast_mac, + ETH_PROTO_TYPE_ARP); + entry->state = NEIGH_STATE_WAITING; + + NETWORK_SEND(device, eth_device->arp_conn); +} + +void arp_announce(NetworkDevice *device, uint8_t *ip_addr) { + EthernetDevice *eth_device = device->ethernet; + NetworkConnection *conn = eth_device->arp_conn; + + net_buffer_reset(conn->buffer); + + // Fill in the ARP request details + ArpHeader *arp_header = (ArpHeader *)conn_buffer(conn)->data; + arp_header->htype = HOST2BE_WORD(ARP_HTYPE_ETH); + arp_header->ptype = HOST2BE_WORD(ETH_PROTO_TYPE_IPV4); + arp_header->hlen = ETH_IDENTIFIER_SIZE; + arp_header->plen = 4; + arp_header->opcode = HOST2BE_WORD(ARP_OP_REQUEST); + + void *p = (void *)(arp_header + 1); + void *src_haddr = p; + void *src_paddr = p + arp_header->hlen; + void *dst_haddr = p + arp_header->hlen + arp_header->plen; + void *dst_paddr = p + arp_header->hlen * 2 + arp_header->plen; + + // Copy the sender's hardware and protocol addresses + memcpy(src_haddr, eth_device->mac_addr, arp_header->hlen); + memcpy(src_paddr, ip_addr, arp_header->plen); + + // Copy the target's hardware and protocol addresses + uint8_t haddr[8] = {0}; + memcpy(dst_haddr, haddr, arp_header->hlen); + memcpy(dst_paddr, ip_addr, arp_header->plen); + + uint8_t size = + sizeof(ArpHeader) + arp_header->hlen * 2 + arp_header->plen * 2; + net_buffer_put(conn_buffer(conn), size); + + // Send the ARP request + eth_wrap( + conn_buffer(conn), device->ethernet->mac_addr, eth_broadcast_mac, + ETH_PROTO_TYPE_ARP); + NETWORK_SEND(device, conn); +} diff --git a/src/driver/network/protocols/ipv4/config.toml b/src/driver/network/protocols/ipv4/config.toml new file mode 100644 index 0000000..2382354 --- /dev/null +++ b/src/driver/network/protocols/ipv4/config.toml @@ -0,0 +1 @@ +c = ["acd.c", "arp.c", "dhcp.c", "icmp.c", "ipv4.c"] diff --git a/src/driver/network/protocols/ipv4/dhcp.c b/src/driver/network/protocols/ipv4/dhcp.c new file mode 100644 index 0000000..3e9e4ad --- /dev/null +++ b/src/driver/network/protocols/ipv4/dhcp.c @@ -0,0 +1,596 @@ +/** + * @file dhcp.c + * @author Jiajun Wang (ryan1202@foxmail.com) + * @brief DHCP + * + * Reference: + * RFC 2131: Dynamic Host Configuration Protocol + * RFC 1533: DHCP Options and BOOTP Vendor Extensions + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define OPTION_SET_BASE(buf, len, type, value) \ + { \ + *buf = type; \ + buf++; \ + *buf = len; \ + buf++; \ + *buf = value; \ + buf++; \ + } +#define OPTION_SET_HEADER(buf, len, type) \ + { \ + *buf = type; \ + buf++; \ + *buf = len; \ + buf++; \ + } + +#define DHCP_INIT_TIMEOUT(dhcp) \ + ({ \ + dhcp->retry_times = 0; \ + DHCP_RETRANSMIT_DELAY(dhcp->retry_times); \ + }) +#define DHCP_SET_TIMEOUT(dhcp, timeout) \ + { \ + timer_set_timeout(&dhcp->timeout_timer, timeout); \ + timer_callback_enable(&dhcp->timeout_timer); \ + } + +static uint8_t dhcp_discover_option_list[] = { + DHCP_OPTION_SUBNET_MASK, DHCP_OPTION_ROUTER, DHCP_OPTION_BROADCAST_ADDRESS, + DHCP_OPTION_DOMAIN_NAME_SERVER, DHCP_OPTION_NTP_SERVERS}; +const int dhcp_discover_option_list_size = sizeof(dhcp_discover_option_list); + +ProtocolResult dhcp_discover(DhcpClient *dhcp); +ProtocolResult dhcp_select(DhcpClient *dhcp); +void *dhcp_create_message(DhcpClient *dhcp, DhcpHeader *header, uint8_t op); +ProtocolResult dhcp_send(DhcpClient *dhcp, uint16_t len); +void dhcp_reset(DhcpClient *dhcp, NetworkConnection *conn); + +ProtocolResult dhcp_retransmit(DhcpClient *dhcp) { + TransferResult result = NETWORK_SEND(dhcp->device, dhcp->conn); + if (result != TRANSFER_OK) { + printk("[DHCP] Failed to send DHCP message: %d\n", result); + return PROTO_ERROR_SEND_FAILED; + } + + int timeout = DHCP_RETRANSMIT_DELAY(dhcp->retry_times); + DHCP_SET_TIMEOUT(dhcp, timeout); + + return PROTO_OK; +} + +void dhcp_timeout_handler(void *arg) { + DhcpClient *dhcp = arg; + if (dhcp != NULL) { + dhcp->retry_times++; + switch (dhcp->state) { + case DHCP_STAT_INIT: + // 刚发送完DHCPDECLINE,需要重新请求 + dhcp_reset(dhcp, dhcp->conn); + dhcp_discover(dhcp); + break; + case DHCP_STAT_SELECTING: + case DHCP_STAT_REQUESTING: + case DHCP_STAT_RENEWING: + case DHCP_STAT_REBINDING: + dhcp_retransmit(dhcp); + break; + } + } +} + +void dhcp_ip_conflict_handler(void *arg) { + DhcpClient *dhcp = arg; + + // 发送DHCPDECLINE + if (dhcp->state == DHCP_STAT_BOUND) { + memset(dhcp->ip_addr, ipv4_null_addr, 4); + memset(dhcp->server_ip_addr, ipv4_null_addr, 4); + uint8_t *ptr = + dhcp_create_message(dhcp, dhcp->conn->buffer->data, DHCP_DECLINE); + + *ptr = DHCP_OPTION_END; + + int len = 4 /* magic cookie */ + + 3 /* message type */ + + 1 /* end */; + dhcp_send(dhcp, sizeof(DhcpHeader) + len); + + // 至少等待10秒 + dhcp->state = DHCP_STAT_INIT; + timer_set_timeout(&dhcp->timeout_timer, 10 * 1000); + timer_callback_enable(&dhcp->timeout_timer); + } +} + +void dhcp_ip_lease_handler(void *arg) { + DhcpClient *dhcp = arg; + if (dhcp->state == DHCP_STAT_REBINDING) { + dhcp_reset(dhcp, dhcp->conn); + dhcp_discover(dhcp); + } else { + print_error( + "DHCP", "Lease expired in unexpected state: %d\n", dhcp->state); + } +} + +void dhcp_renew_handler(void *arg) { + DhcpClient *dhcp = arg; + if (dhcp->state == DHCP_STAT_BOUND) { + // TODO: 单播 + uint8_t *ptr = + dhcp_create_message(dhcp, dhcp->conn->buffer->data, DHCP_REQUEST); + + // TODO: 设置Max Message Size + + OPTION_SET_HEADER( + ptr, dhcp_discover_option_list_size, + DHCP_OPTION_PARAMETER_REQUEST_LIST); + for (int i = 0; i < dhcp_discover_option_list_size; i++, ptr++) { + *ptr = dhcp_discover_option_list[i]; + } + + *ptr = DHCP_OPTION_END; + + int len = 4 /* magic cookie */ + + 3 /* message type */ + + 2 + + dhcp_discover_option_list_size /* parameter request list */ + + 1 /* end */; + + int initial_timeout = DHCP_INIT_TIMEOUT(dhcp); + DHCP_SET_TIMEOUT(dhcp, initial_timeout); + + dhcp->state = DHCP_STAT_RENEWING; + ProtocolResult result = dhcp_send(dhcp, sizeof(DhcpHeader) + len); + if (result != PROTO_OK) return; + } +} + +void dhcp_rebind_handler(void *arg) { + DhcpClient *dhcp = arg; + if (dhcp->state == DHCP_STAT_RENEWING) { + // TODO: 广播 + uint8_t *ptr = + dhcp_create_message(dhcp, dhcp->conn->buffer->data, DHCP_REQUEST); + + // TODO: 设置Max Message Size + + OPTION_SET_HEADER( + ptr, dhcp_discover_option_list_size, + DHCP_OPTION_PARAMETER_REQUEST_LIST); + for (int i = 0; i < dhcp_discover_option_list_size; i++, ptr++) { + *ptr = dhcp_discover_option_list[i]; + } + + *ptr = DHCP_OPTION_END; + + int len = 4 /* magic cookie */ + + 3 /* message type */ + + 2 + + dhcp_discover_option_list_size /* parameter request list */ + + 1 /* end */; + + int initial_timeout = DHCP_INIT_TIMEOUT(dhcp); + DHCP_SET_TIMEOUT(dhcp, initial_timeout); + + dhcp->state = DHCP_STAT_REBINDING; + ProtocolResult result = dhcp_send(dhcp, sizeof(DhcpHeader) + len); + if (result != PROTO_OK) return; + } +} + +void dhcp_offer_handler( + DhcpClient *dhcp, NetworkConnection *conn, DhcpHeader *header, + uint16_t indexes[DOI_MAX]) { + // 直接选择收到的第一个OFFER的DHCP服务器 + + int index_sid = indexes[DOI_SERVER_ID]; + if (index_sid != 0) { + timer_callback_cancel(&dhcp->timeout_timer); + + memcpy(dhcp->server_ip_addr, &header->options[index_sid], 4); + memcpy(dhcp->ip_addr, &header->yiaddr, 4); + memcpy(conn->net_device->ipv4.ip, dhcp->ip_addr, 4); + memcpy(conn->ipv4.conn_info.local.ip, dhcp->ip_addr, 4); + + dhcp_select(dhcp); + } +} + +void dhcp_ack_handler( + DhcpClient *dhcp, NetworkConnection *conn, DhcpHeader *header, + uint16_t indexes[DOI_MAX]) { + NetworkDevice *device = conn->net_device; + *(uint32_t *)device->ipv4.subnet_mask = 0; + *(uint32_t *)device->ipv4.gateway_ip = 0; + memcpy(device->ipv4.ip, dhcp->ip_addr, 4); + memcpy(conn->ipv4.conn_info.local.ip, dhcp->ip_addr, 4); + + if (indexes[DOI_SUBNET_MASK] != 0) { + *(uint32_t *)device->ipv4.subnet_mask = + *(uint32_t *)&header->options[indexes[DOI_SUBNET_MASK]]; + } + + if (indexes[DOI_ROUTER] != 0) { + *(uint32_t *)device->ipv4.gateway_ip = + *(uint32_t *)&header->options[indexes[DOI_ROUTER]]; + } + + if (indexes[DOI_IP_LEASE_TIME] != 0) { + dhcp->t0 = BE2HOST_DWORD( + *(uint32_t *)&header->options[indexes[DOI_IP_LEASE_TIME]]); + } + + if (indexes[DOI_RENEWAL_TIME] != 0) { + dhcp->t1 = BE2HOST_DWORD( + *(uint32_t *)&header->options[indexes[DOI_RENEWAL_TIME]]); + } else { + dhcp->t1 = dhcp->t0 / 2; + } + + if (indexes[DOI_REBINDING_TIME] != 0) { + dhcp->t2 = BE2HOST_DWORD( + *(uint32_t *)&header->options[indexes[DOI_REBINDING_TIME]]); + } else { + dhcp->t2 = dhcp->t0 * 7 / 8; + } +} + +void dhcp_nak_handler(DhcpClient *dhcp, NetworkConnection *conn) { + dhcp_reset(dhcp, conn); + + dhcp_discover(dhcp); +} + +void dhcp_set_timers(DhcpClient *dhcp) { + timer_set_timeout(&dhcp->lease_timer, dhcp->t0 * 1000); + timer_callback_enable(&dhcp->lease_timer); + + timer_set_timeout(&dhcp->renew_timer, dhcp->t1 * 1000); + timer_callback_enable(&dhcp->renew_timer); + + timer_set_timeout(&dhcp->rebind_timer, dhcp->t2 * 1000); + timer_callback_enable(&dhcp->rebind_timer); +} + +void dhcp_parse_options( + NetBuffer *net_buffer, DhcpHeader *header, uint16_t (*indexes)[8], + uint16_t *offset) { + uint16_t *idx = *indexes; + *offset = 4; + uint16_t end = + net_buffer->tail - net_buffer->data - offsetof(DhcpHeader, options); + while (header->options[*offset] != DHCP_OPTION_END && *offset < end) { + uint8_t option = header->options[(*offset)++]; + uint8_t length = header->options[(*offset)++]; + switch (option) { + case DHCP_OPTION_PAD: + (*offset)--; + break; + case DHCP_OPTION_SUBNET_MASK: + idx[DOI_SUBNET_MASK] = *offset; + break; + case DHCP_OPTION_ROUTER: + idx[DOI_ROUTER] = *offset; + break; + case DHCP_OPTION_DOMAIN_NAME_SERVER: + idx[DOI_DNS] = *offset; + break; + case DHCP_OPTION_IP_ADDRESS_LEASE_TIME: + idx[DOI_IP_LEASE_TIME] = *offset; + break; + case DHCP_OPTION_MESSAGE_TYPE: + idx[DOI_MESSAGE_TYPE] = *offset; + break; + case DHCP_OPTION_SERVER_IDENTIFIER: + idx[DOI_SERVER_ID] = *offset; + break; + case DHCP_OPTION_RENEWAL_TIME: + idx[DOI_RENEWAL_TIME] = *offset; + break; + case DHCP_OPTION_REBINDING_TIME: + idx[DOI_REBINDING_TIME] = *offset; + break; + default: + break; + } + *offset += length; + } +} + +void dhcp_check_addr(DhcpClient *dhcp) { + NeighbourKey key = ipv4_hash(dhcp->server_ip_addr); + NeighbourEntry *entry = + neighbour_table_lookup(dhcp->device, key, dhcp->server_ip_addr, 4); + entry->ops->probe(dhcp->device); + if (entry->state == NEIGH_STATE_REACHABLE) { + entry->hlen = dhcp->haddr_len; + memcpy(dhcp->server_haddr, entry->haddr, dhcp->haddr_len); + } +} + +void dhcp_rx_handler(NetworkConnection *conn, NetBuffer *net_buffer) { + DhcpClient *dhcp = (DhcpClient *)conn->udp.private_data; + DhcpHeader *header = (DhcpHeader *)net_buffer->data; + + if (dhcp == NULL) goto end; + if (net_buffer->tail - net_buffer->data < sizeof(DhcpHeader)) { + print_warning("DHCP", "Received packet too small\n"); + goto end; + } + if (header->op != DHCP_OP_BOOTREPLY) { + print_warning("DHCP", "Received packet is not a DHCP reply\n"); + goto end; + } + if (memcmp(dhcp->haddr, header->chaddr, dhcp->haddr_len) != 0) { + print_warning("DHCP", "Received packet is not for this client\n"); + goto end; + } + if (BE2HOST_DWORD(header->xid) != dhcp->xid) { + print_warning("DHCP", "Received packet is not for this transaction\n"); + goto end; + } + + uint16_t indexes[DOI_MAX] = {0}; + uint16_t offset; + dhcp_parse_options(net_buffer, header, &indexes, &offset); + + uint8_t msg_type = header->options[indexes[DOI_MESSAGE_TYPE]]; + if (msg_type == DHCP_ACK) { + // 收到ACK,表示成功获取IP地址 + if (dhcp->state == DHCP_STAT_REQUESTING || + dhcp->state == DHCP_STAT_REBOOTING) { + dhcp->state = DHCP_STAT_BOUND; + memcpy(dhcp->ip_addr, &header->yiaddr, 4); + memcpy(dhcp->server_ip_addr, &header->siaddr, 4); + + timer_callback_cancel(&dhcp->timeout_timer); + printk( + "[DHCP]Successfully bound to IP: %d.%d.%d.%d\n", + dhcp->ip_addr[0], dhcp->ip_addr[1], dhcp->ip_addr[2], + dhcp->ip_addr[3]); + + // TODO: 检查地址冲突 + dhcp_check_addr(dhcp); + + dhcp_ack_handler(dhcp, conn, header, indexes); + dhcp_set_timers(dhcp); + } else if ( + dhcp->state == DHCP_STAT_RENEWING || + dhcp->state == DHCP_STAT_REBINDING) { + dhcp_ack_handler(dhcp, conn, header, indexes); + dhcp_set_timers(dhcp); + } + } else if (msg_type == DHCP_NAK) { + if (dhcp->state == DHCP_STAT_REQUESTING || + dhcp->state == DHCP_STAT_REBOOTING || + dhcp->state == DHCP_STAT_REBINDING || + dhcp->state == DHCP_STAT_RENEWING) { + dhcp_nak_handler(dhcp, conn); + } + } else if (msg_type == DHCP_OFFER && dhcp->state == DHCP_STAT_SELECTING) { + dhcp_offer_handler(dhcp, conn, header, indexes); + } + +end: + kfree(net_buffer->ptr); + kfree(net_buffer); +} + +void *dhcp_create_message(DhcpClient *dhcp, DhcpHeader *header, uint8_t op) { + net_buffer_reset(dhcp->conn->buffer); + header->op = DHCP_OP_BOOTREQUEST; + header->hlen = dhcp->haddr_len; + header->htype = DHCP_HTYPE_ETHERNET; + header->hops = 0; + header->xid = HOST2BE_DWORD(dhcp->xid); + + header->ciaddr = *((uint32_t *)dhcp->ip_addr); + header->yiaddr = 0; + header->siaddr = 0; + header->giaddr = 0; + memcpy(header->chaddr, dhcp->haddr, dhcp->haddr_len); + + uint8_t *ptr = (uint8_t *)&header->options; + *(uint32_t *)ptr = HOST2BE_DWORD(DHCP_MAGIC_COOKIE); + ptr += 4; + OPTION_SET_BASE(ptr, 1, DHCP_OPTION_MESSAGE_TYPE, op); + + return ptr; +} + +ProtocolResult dhcp_send(DhcpClient *dhcp, uint16_t len) { + ProtocolResult result = net_buffer_put(dhcp->conn->buffer, len); + if (result != PROTO_OK) { + printk("[DHCP] Failed to put DHCP message: %d\n", result); + return result; + } + + udp_wrap( + dhcp->conn, UDP_PORT_DHCP_CLIENT, + UDP_PORT_DHCP_SERVER); // DHCP客户端端口68,服务器端口67 + if (dhcp->state == DHCP_STAT_SELECTING || + dhcp->state == DHCP_STAT_REQUESTING || + dhcp->state == DHCP_STAT_REBINDING) { + ipv4_wrap( + dhcp->conn, IP_PROTO_UDP, (uint8_t *)&ipv4_broadcast_addr, 64); + } else { + ipv4_wrap(dhcp->conn, IP_PROTO_UDP, dhcp->server_ip_addr, 64); + } + switch (dhcp->device->type) { + case NETWORK_TYPE_ETHERNET: + eth_wrap( + dhcp->conn->buffer, dhcp->device->ethernet->mac_addr, + dhcp->server_haddr, ETH_PROTO_TYPE_IPV4); + break; + case NETWORK_TYPE_UNKNOWN: + return PROTO_ERROR_UNSUPPORT; + } + + TransferResult tresult = NETWORK_SEND(dhcp->device, dhcp->conn); + if (tresult != TRANSFER_OK) { + printk("[DHCP] Failed to send DHCP message: %d\n", tresult); + return PROTO_ERROR_OTHER; + } + return PROTO_OK; +} + +ProtocolResult dhcp_discover(DhcpClient *dhcp) { + // 申请新地址 + dhcp->state = DHCP_STAT_SELECTING; + + *((uint32_t *)dhcp->ip_addr) = 0; + uint8_t *ptr = + dhcp_create_message(dhcp, dhcp->conn->buffer->data, DHCP_DISCOVER); + + OPTION_SET_HEADER( + ptr, dhcp_discover_option_list_size, + DHCP_OPTION_PARAMETER_REQUEST_LIST); + for (int i = 0; i < dhcp_discover_option_list_size; i++, ptr++) { + *ptr = dhcp_discover_option_list[i]; + } + + *ptr = DHCP_OPTION_END; + + int len = 4 /* magic cookie */ + + 3 /* message type */ + + 2 + dhcp_discover_option_list_size /* parameter request list */ + + 1 /* end */; + + int initial_timeout = DHCP_INIT_TIMEOUT(dhcp); + DHCP_SET_TIMEOUT(dhcp, initial_timeout); + + ProtocolResult result = dhcp_send(dhcp, sizeof(DhcpHeader) + len); + if (result != PROTO_OK) return result; + + return PROTO_OK; +} + +ProtocolResult dhcp_select(DhcpClient *dhcp) { + // 选择IP地址 + dhcp->state = DHCP_STAT_REQUESTING; + + uint8_t *ptr = + dhcp_create_message(dhcp, dhcp->conn->buffer->data, DHCP_REQUEST); + + // TODO: 设置Max Message Size + + // 设置请求的IP地址 + OPTION_SET_HEADER(ptr, 4, DHCP_OPTION_REQUESTED_IP_ADDRESS); + *(uint32_t *)ptr = *((uint32_t *)dhcp->ip_addr); + ptr += 4; + + // 设置服务器ID(IP地址) + OPTION_SET_HEADER(ptr, 4, DHCP_OPTION_SERVER_IDENTIFIER); + *(uint32_t *)ptr = *((uint32_t *)dhcp->server_ip_addr); + ptr += 4; + + OPTION_SET_HEADER( + ptr, dhcp_discover_option_list_size, + DHCP_OPTION_PARAMETER_REQUEST_LIST); + for (int i = 0; i < dhcp_discover_option_list_size; i++, ptr++) { + *ptr = dhcp_discover_option_list[i]; + } + + *ptr = DHCP_OPTION_END; + + int len = 4 /* magic cookie */ + + 3 /* message type */ + + 6 /* requested ip address */ + + 6 /* server identifier */ + + 2 + dhcp_discover_option_list_size /* parameter request list */ + + 1 /* end */; + + int initial_timeout = DHCP_INIT_TIMEOUT(dhcp); + DHCP_SET_TIMEOUT(dhcp, initial_timeout); + + ProtocolResult result = dhcp_send(dhcp, sizeof(DhcpHeader) + len); + if (result != PROTO_OK) return result; + + return PROTO_OK; +} + +void dhcp_init(DhcpClient *dhcp, NetworkConnection *conn) { + dhcp->conn = conn; + conn->udp.private_data = dhcp; + + timer_init(&dhcp->timeout_timer); + timer_init(&dhcp->lease_timer); + timer_init(&dhcp->renew_timer); + timer_init(&dhcp->rebind_timer); + dhcp->timeout_timer.callback = dhcp_timeout_handler; + dhcp->lease_timer.callback = dhcp_ip_lease_handler; + dhcp->renew_timer.callback = dhcp_renew_handler; + dhcp->rebind_timer.callback = dhcp_rebind_handler; + dhcp->timeout_timer.arg = dhcp; + dhcp->lease_timer.arg = dhcp; + dhcp->renew_timer.arg = dhcp; + dhcp->rebind_timer.arg = dhcp; +} + +void dhcp_reset(DhcpClient *dhcp, NetworkConnection *conn) { + dhcp->state = DHCP_STAT_INIT; + dhcp->xid = rand(); + + memcpy(conn->net_device->ipv4.ip, &ipv4_null_addr, 4); + memset(dhcp->ip_addr, 0, sizeof(dhcp->ip_addr)); + memset(dhcp->server_ip_addr, 0, sizeof(dhcp->server_ip_addr)); + memset(dhcp->server_haddr, 0, sizeof(dhcp->server_haddr)); + net_buffer_init(conn->buffer, 576, 0, 0); + eth_register(conn); + ipv4_register(conn, NULL); + udp_register(conn); + + udp_bind(dhcp->conn, UDP_PORT_DHCP_CLIENT); + udp_set_callback(conn, dhcp_rx_handler); + + switch (dhcp->device->type) { + case NETWORK_TYPE_ETHERNET: + dhcp->haddr_len = ETH_IDENTIFIER_SIZE; + dhcp->haddr_type = DHCP_HTYPE_ETHERNET; + memcpy(dhcp->haddr, dhcp->device->ethernet->mac_addr, dhcp->haddr_len); + memcpy(dhcp->server_haddr, eth_broadcast_mac, dhcp->haddr_len); + break; + default: + break; + } + *(uint32_t *)dhcp->server_ip_addr = ipv4_broadcast_addr; +} + +ProtocolResult dhcp_start(NetworkDevice *device) { + ProtocolResult result; + + DhcpClient *dhcp = kmalloc(sizeof(DhcpClient)); + + dhcp->device = device; + + NetworkConnection *conn = net_create_conn(device->device->object); + conn->buffer = net_buffer_create(576); + + dhcp_init(dhcp, conn); + + dhcp_reset(dhcp, conn); + + result = dhcp_discover(dhcp); + + return result; +} \ No newline at end of file diff --git a/src/driver/network/protocols/ipv4/icmp.c b/src/driver/network/protocols/ipv4/icmp.c new file mode 100644 index 0000000..6a1eb65 --- /dev/null +++ b/src/driver/network/protocols/ipv4/icmp.c @@ -0,0 +1,119 @@ +#include "driver/network/network_dm.h" +#include +#include +#include +#include +#include +#include +#include + +#define ICMP_RECV_MSG_DEF(type) \ + ProtocolResult icmp_recv_##type( \ + NetworkDevice *device, NetBuffer *net_buffer, Ipv4Header *header, \ + IcmpHeader *icmp_header, ProtocolReplyCallback *stack, int stack_size) +ICMP_RECV_MSG_DEF(unsupport); +ICMP_RECV_MSG_DEF(unreachable); +ICMP_RECV_MSG_DEF(echo); + +ProtocolResult (*icmp_recv_handlers[17])( + NetworkDevice *device, NetBuffer *net_buffer, Ipv4Header *header, + IcmpHeader *icmp_header, ProtocolReplyCallback *stack, int stack_size) = { + [ICMP_TYPE_ECHO] = icmp_recv_echo, + [ICMP_TYPE_ECHO_REPLY] = icmp_recv_unsupport, + [ICMP_TYPE_DEST_UNREACHABLE] = icmp_recv_unreachable, + [ICMP_TYPE_SOURCE_QUENCH] = icmp_recv_unsupport, + [ICMP_TYPE_REDIRECT] = icmp_recv_unsupport, + [ICMP_TYPE_TIME_EXCEEDED] = icmp_recv_unsupport, + [ICMP_TYPE_PARAM_PROBLEM] = icmp_recv_unsupport, + [ICMP_TYPE_TIMESTAMP] = icmp_recv_unsupport, + [ICMP_TYPE_TIMESTAMP_REPLY] = icmp_recv_unsupport, + [ICMP_TYPE_INFO_REQUEST] = icmp_recv_unsupport, + [ICMP_TYPE_INFO_REPLY] = icmp_recv_unsupport, + [1 ... 2] = icmp_recv_unsupport, + [6 ... 7] = icmp_recv_unsupport, + [9 ... 10] = icmp_recv_unsupport, +}; + +uint16_t icmp_checksum(IcmpHeader *header, int length) { + uint32_t sum = 0; + uint16_t *data = (void *)header; + + header->checksum = 0; + + for (size_t i = 0; i < length / 2; i++) { + sum += data[i]; + if (sum > 0xFFFF) sum = (sum & 0xFFFF) + (sum >> 16); + } + return ~((uint16_t)sum); +}; + +ProtocolResult icmp_recv( + NetworkDevice *device, NetBuffer *net_buffer, Ipv4Header *header, + ProtocolReplyCallback *stack, int stack_size) { + IcmpHeader *icmp_header = (IcmpHeader *)net_buffer->data; + if (net_buffer->tail - net_buffer->data < sizeof(IcmpHeader)) { + return PROTO_ERROR_UNSUPPORT; + } + + uint16_t checksum = icmp_header->checksum; + if (icmp_checksum(icmp_header, net_buffer->tail - net_buffer->data) != + checksum) { + return PROTO_ERROR_CHECKSUM; + } + + if (icmp_header->type < 17) { + return icmp_recv_handlers[icmp_header->type]( + device, net_buffer, header, icmp_header, stack, stack_size); + } + return PROTO_ERROR_UNSUPPORT; +} + +ICMP_RECV_MSG_DEF(unsupport) { + return PROTO_ERROR_UNSUPPORT; +} + +ICMP_RECV_MSG_DEF(unreachable) { + Ipv4Header *msg_header = + (Ipv4Header *)(icmp_header + 8); // ICMP头部后面紧跟着的是IP头部 + switch (icmp_header->code) { + case ICMP_UNREACHABLE_NET: + case ICMP_UNREACHABLE_HOST: + case ICMP_UNREACHABLE_PROTOCOL: + case ICMP_UNREACHABLE_PORT: + tcp_notify_unreachable( + msg_header + 1, msg_header->src_ip, msg_header->dst_ip, 4, + icmp_header->code); + udp_notify_unreachable( + msg_header + 1, msg_header->src_ip, msg_header->dst_ip, 4, + icmp_header->code); + break; + case ICMP_UNREACHABLE_NEEDFRAG: + tcp_update_mtu( + msg_header->src_ip, msg_header->dst_ip, 4, + BE2HOST_WORD(icmp_header->pmtu.mtu)); + break; + case ICMP_UNREACHABLE_SRCFAIL: + default: + return PROTO_ERROR_UNSUPPORT; + } + return PROTO_OK; +} + +ICMP_RECV_MSG_DEF(echo) { + if (net_buffer->tail - net_buffer->data < 8) { + return PROTO_ERROR_UNSUPPORT; + } + uint32_t ip = *((uint32_t *)header->dst_ip); + *((uint32_t *)header->dst_ip) = *((uint32_t *)header->src_ip); + *((uint32_t *)header->src_ip) = ip; + ipv4_checksum(header); + + icmp_header->type = ICMP_TYPE_ECHO_REPLY; + icmp_header->checksum = 0; + icmp_header->checksum = + icmp_checksum(icmp_header, net_buffer->tail - net_buffer->data); + + protocol_reply(device, net_buffer, stack, stack_size); + + return PROTO_OK; +} \ No newline at end of file diff --git a/src/driver/network/protocols/ipv4/ipv4.c b/src/driver/network/protocols/ipv4/ipv4.c new file mode 100644 index 0000000..3bb4a90 --- /dev/null +++ b/src/driver/network/protocols/ipv4/ipv4.c @@ -0,0 +1,219 @@ +/** + * @file ipv4.c + * @author Jiajun Wang (ryan1202@foxmail.com) + * @brief IPv4 + * + * Reference: + * RFC 791: INTERNET PROTOCOL + * + */ +#include "driver/network/network_dm.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +SPINLOCK(ipv4_id_lock); +uint16_t ipv4_id_counter = 0; + +const uint32_t ipv4_broadcast_addr = 0xffffffff; +const uint32_t ipv4_null_addr = 0x00000000; + +NeighbourKey ipv4_hash(uint8_t ip[4]) { + uint32_t ip32 = *(uint32_t *)ip; + return (ip32 ^ (ip32 >> 16)) % NEIGH_BUCKET_SIZE; +} + +void ipv4_register(NetworkConnection *conn, uint8_t *ip_addr) { + conn->net_protocol = NET_PROTO_IPV4; + if (ip_addr) { + memcpy(CONN_LOCAL_IP(conn), ip_addr, 4); + } else { + memcpy(CONN_LOCAL_IP(conn), conn->net_device->ipv4.ip, 4); + } + // 默认禁用分段 + conn->ipv4.fragment.enable_fragment = 0; + conn->ipv4.fragment.last_fragment = 0; + conn->ipv4.fragment.frag_offset = 0; + conn->ipv4.id = 0; + NET_BUF_RESV_HEAD(conn, sizeof(Ipv4Header)); +} + +void ipv4_neigh_update( + NetworkDevice *device, NetBuffer *buffer, uint8_t *mac, int hlen) { + if (!buffer || !mac) return; + Ipv4Header *ipv4_header = (Ipv4Header *)buffer->data; + uint8_t *ip = ipv4_header->src_ip; + + uint32_t _ip = *(uint32_t *)ip; + if (_ip == ipv4_null_addr || _ip == ipv4_broadcast_addr) return; + + NeighbourKey hash_key = ipv4_hash(ip); + NeighbourEntry *entry = neighbour_table_try_lookup(device, hash_key, ip, 4); + if (entry == NULL) { + entry = neighbour_entry_create(device, hash_key, ip, 4); + if (entry == NULL) return; + } + spin_lock(&entry->lock); + entry->state = NEIGH_STATE_REACHABLE; + memcpy(entry->haddr, mac, hlen); + spin_unlock(&entry->lock); +} + +void ipv4_enable_fragment(NetworkConnection *conn) { + conn->ipv4.fragment.enable_fragment = 1; + conn->ipv4.fragment.last_fragment = 0; + conn->ipv4.fragment.frag_offset = 0; + + spin_lock(&ipv4_id_lock); + if (ipv4_id_counter == 0) ipv4_id_counter = rand() & 0xffff; + conn->ipv4.id = ipv4_id_counter++; + spin_unlock(&ipv4_id_lock); +} + +void ipv4_checksum(Ipv4Header *header) { + uint32_t sum = 0; + uint16_t *data = (void *)header; + uint8_t len = sizeof(Ipv4Header); + + header->checksum = 0; + + for (size_t i = 0; i < len / 2; i++) { + sum += data[i]; + if (sum > 0xFFFF) sum = (sum & 0xFFFF) + (sum >> 16); + } + header->checksum = ~((uint16_t)sum); +}; + +ProtocolResult ipv4_wrap( + NetworkConnection *conn, uint16_t protocol, uint8_t *dst_ip, uint8_t ttl) { + uint16_t size = CONN_PACKET_SIZE(conn); + + net_buffer_header_alloc(conn_buffer(conn), sizeof(Ipv4Header)); + Ipv4Header *ipv4_header = (Ipv4Header *)conn_buffer(conn)->head; + conn->ipv4.header = ipv4_header; + ipv4_header->ver_len = (0x4 << 4) | (20 >> 2); // IPv4, 20字节 + ipv4_header->tos = 0; // Type of Service + ipv4_header->total_len = HOST2BE_WORD(sizeof(Ipv4Header) + size); + ipv4_header->id = HOST2BE_WORD(conn->ipv4.id); + + ipv4_header->flags_frag_offset = HOST2BE_WORD( + (!conn->ipv4.fragment.enable_fragment) << 14 | + conn->ipv4.fragment.last_fragment << 15 | + conn->ipv4.fragment.frag_offset); + + ipv4_header->ttl = ttl; + ipv4_header->protocol = protocol; + ipv4_header->checksum = 0; + memcpy(ipv4_header->src_ip, CONN_LOCAL_IP(conn), 4); + if (dst_ip) { + memcpy(ipv4_header->dst_ip, dst_ip, 4); + } else { + *(uint32_t *)ipv4_header->dst_ip = 0xffffffff; // 广播地址 + } + ipv4_checksum(ipv4_header); + + return PROTO_OK; +} + +void ipv4_rewrap(NetworkConnection *conn) { + Ipv4Header *ipv4_header = conn->ipv4.header; + if (!ipv4_header) return; + + ipv4_header->total_len = + HOST2BE_WORD(conn->buffer->tail - (void *)ipv4_header); + ipv4_header->checksum = 0; + ipv4_checksum(ipv4_header); +} + +ProtocolResult ipv4_recv( + NetworkDevice *device, NetBuffer *net_buffer, ProtocolReplyCallback *stack, + int stack_size) { + Ipv4Header *ipv4_header = (Ipv4Header *)net_buffer->data; + int size = net_buffer->tail - net_buffer->data; + int length = ipv4_get_packet_length(ipv4_header); + + if (size < sizeof(Ipv4Header)) return PROTO_ERROR_UNSUPPORT; + + if ((ipv4_header->ver_len >> 4) != 0x4) return PROTO_ERROR_UNSUPPORT; + + if (ipv4_header->checksum != 0) { + uint16_t checksum = ipv4_header->checksum; + ipv4_checksum(ipv4_header); + if (ipv4_header->checksum != checksum) return PROTO_ERROR_CHECKSUM; + } + + uint16_t frag_offset = HOST2BE_WORD(ipv4_header->flags_frag_offset); + bool mf = (frag_offset & 0x2000) != 0; // More Fragments,还有分片 + frag_offset &= 0x1FFF; + if (frag_offset || mf) { + // 处理分片 + return PROTO_ERROR_UNSUPPORT; // 暂不支持分片 + } + + net_buffer->data += sizeof(Ipv4Header); + + ProtocolResult result = PROTO_OK; + switch (ipv4_header->protocol) { + case IP_PROTO_UDP: + result = udp_recv(net_buffer, ipv4_header); + break; + case IP_PROTO_TCP: + result = tcp_recv( + net_buffer, length, ipv4_header->src_ip, ipv4_header->dst_ip, 4); + break; + case IP_PROTO_ICMP: + result = icmp_recv(device, net_buffer, ipv4_header, stack, stack_size); + break; + default: + result = PROTO_ERROR_UNSUPPORT; + } + + return result; +} + +ProtocolResult ipv4_lookup_mac( + NetworkDevice *device, uint8_t ip[4], uint8_t mac[8]) { + if (!ip || !mac) return PROTO_ERROR_NULL_PTR; + NeighbourKey hash_key; + uint32_t subnet_mask = *(uint32_t *)device->ipv4.subnet_mask; + uint32_t gateway_ip = *(uint32_t *)device->ipv4.gateway_ip; + uint32_t _ip = *(uint32_t *)ip; + + NeighbourEntry *entry; + if ((_ip & subnet_mask) == (gateway_ip & subnet_mask)) { + // 在子网内 + hash_key = ipv4_hash(ip); + entry = neighbour_table_lookup(device, hash_key, ip, 4); + } else { + // 在子网外 + if (gateway_ip == ipv4_null_addr) { + return PROTO_ERROR_CANNOT_FIND_ROUTE; + } + hash_key = ipv4_hash(device->ipv4.gateway_ip); + entry = neighbour_table_lookup( + device, hash_key, device->ipv4.gateway_ip, 4); + } + + if (entry == NULL) return PROTO_ERROR_CANNOT_FIND; + while (entry->state == NEIGH_STATE_WAITING) { + schedule(); + } + memcpy(mac, entry->haddr, 8); + return PROTO_OK; +} + +uint16_t ipv4_get_packet_length(Ipv4Header *ipv4_header) { + return BE2HOST_WORD(ipv4_header->total_len) - + ((ipv4_header->ver_len & 0x0F) << 2); +} diff --git a/src/driver/network/protocols/tcp.c b/src/driver/network/protocols/tcp.c new file mode 100644 index 0000000..32c14ab --- /dev/null +++ b/src/driver/network/protocols/tcp.c @@ -0,0 +1,892 @@ +/** + * @file tcp.c + * @author Jiajun Wang (ryan1202@foxmail.com) + * @brief TCP + * References: + * RFC793: Transmission Control Protocol + * RFC6528: Defending against Sequence Number Attacks + * RFC6298: Computing TCP's Retransmission Timer + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define TCP_CHECKSUM_ADD(sum, data) \ + sum += (data); \ + if (sum > 0xFFFF) sum = (sum & 0xFFFF) + (sum >> 16); + +SPINLOCK(tcp_lock); +LIST_HEAD(tcp_lh); + +const int send_win_default_size = 32768; +const int recv_win_default_size = 32768; + +const int min_ephemeral_port = 32768; +const int max_ephemeral_port = 65535; + +const int tcp_max_retries = 15; + +const int tcp_fin_timeout = 60 * 1000; + +void tcp_timeout_handler(void *arg); +void tcp_reset_conn(NetworkConnection *conn, Tcp *tcp); +void tcp_send_packet( + Tcp *tcp, NetworkConnection *conn, uint8_t option_size, bool set_timer); + +uint16_t tcp_checksum( + TcpHeader *header, int length, const uint8_t *src_ip, const uint8_t *dst_ip, + int ip_len) { + uint8_t *data = (uint8_t *)header; + uint32_t sum = 0; + + // 清除校验和 + header->checksum = 0; + + // 计算伪头部校验和 + for (int j = 0; j < ip_len; j += 2) { + sum += (src_ip[j] << 8 | src_ip[j + 1]); + sum += (dst_ip[j] << 8 | dst_ip[j + 1]); + } + sum += IP_PROTO_TCP; + sum += length; + + // 计算TCP头部和数据的校验和 + int i; + for (i = 0; i + 2 <= length; i += 2) { + sum += data[i] << 8 | data[i + 1]; + sum = (sum & 0xffff0000) ? ((sum >> 16) + (sum & 0xffff)) : sum; + } + + if (length % 2) { // 如果长度是奇数,补齐一个字节 + sum += data[length - 1] << 8; + } + + while (sum & 0xffff0000) { + sum = (sum >> 16) + (sum & 0xffff); + } + + sum = ~((uint16_t)(sum)) & 0xffff; + return sum; +} + +void tcp_register(NetworkConnection *conn) { + conn->trans_protocol = TRANS_PROTO_TCP; + if (conn->tcp.info == NULL) { conn->tcp.info = kmalloc(sizeof(Tcp)); } + NET_BUF_RESV_HEAD(conn, sizeof(TcpHeader)); +} + +uint32_t tcp_generate_isn(void *ip_port_pair, int len) { + static uint32_t counter = 0; + uint32_t isn = timer_get_counter(); + counter++; + + isn += fnv1_hash_32(ip_port_pair, len); + isn += counter; + + return isn; +} + +void tcp_compute_retransmission_timer(Tcp *tcp, int r) { + if (tcp == NULL) return; + + if (r == 0) { + if (tcp->rttvar == 0) { + // 还没完成RTT测量 + tcp->rto = 1 * 1000; + } + } else { + if (tcp->rttvar == 0) { + // 完成初次RTT测量 + tcp->srtt = r; + tcp->rttvar = r / 2; + tcp->rto = tcp->srtt + MAX(1 * 1000, 4 * tcp->rttvar); + } else { + // 完成后续RTT测量 + tcp->rttvar = (3 * tcp->rttvar + 1 * abs(tcp->srtt - r)) / 4; + tcp->srtt = (7 * tcp->srtt + 1 * r) / 8; + tcp->rto = tcp->srtt + MAX(1 * 1000, 4 * tcp->rttvar); + } + tcp->rto = MIN(tcp->rto, 60 * 1000); // 最长1分钟 + } +} + +ProtocolResult tcp_bind(NetworkConnection *conn, uint16_t port) { + if (conn->tcp.info == NULL) { return PROTO_ERROR_NULL_PTR; } + Ipv4ConnInfo *conn_info = &conn->ipv4.conn_info; + if (list_in_list(&conn_info->list)) + return PROTO_ERROR_REBIND; // 已经绑定了端口 + + Ipv4ConnInfo *info; + spin_lock(&tcp_lock); + list_for_each_owner (info, &tcp_lh, list) { + if (info->local.port == port || + memcmp(info->local.ip, conn_info->local.ip, 4)) { + spin_unlock(&tcp_lock); + return PROTO_ERROR_PORT_CONFLICT; // 端口冲突 + } + } + conn_info->local.port = port; + + Tcp *tcp = conn->tcp.info; + tcp->mss = conn->pmtu - sizeof(Ipv4Header) - sizeof(TcpHeader); + tcp->cur.seq = 0; + tcp->cur.ack = 0; + tcp->state = TCP_STATE_CLOSED; + tcp->recv_window = kmalloc(recv_win_default_size); + tcp->recv.next = 0; + tcp->recv.window = recv_win_default_size; + tcp->recv.total_size = recv_win_default_size; + tcp->recv.read = 0; + tcp->rttvar = tcp->rto = tcp->srtt = 0; + tcp_compute_retransmission_timer(tcp, 0); + timer_init(&tcp->timeout_timer); + tcp->timeout_timer.callback = tcp_timeout_handler; + tcp->timeout_timer.arg = tcp; + + conn->tcp.info->conn = conn; + conn->tcp.info->thread = get_current_thread(); + + list_add_tail(&conn->ipv4.conn_info.list, &tcp_lh); + spin_unlock(&tcp_lock); + return PROTO_OK; +} + +ProtocolResult tcp_connect( + NetworkConnection *conn, uint8_t *dst_ip, uint16_t dst_port) { + Tcp *tcp = conn->tcp.info; + if (conn->tcp.info == NULL) { return PROTO_ERROR_NULL_PTR; } + if (tcp->state != TCP_STATE_CLOSED) { + // 如果没有绑定端口,随机绑定一个大于32768的端口 + uint16_t port = min_ephemeral_port + + (rand() % (max_ephemeral_port - min_ephemeral_port)); + int count = max_ephemeral_port - min_ephemeral_port + 1; + while (count-- > 0) { + ProtocolResult result = tcp_bind(conn, port); + if (result == PROTO_OK) break; + else if (result != PROTO_ERROR_PORT_CONFLICT) { return result; } + port += 1; + } + } + + Ipv4ConnInfo *conn_info = &conn->ipv4.conn_info; + memcpy(conn_info->remote.ip, dst_ip, 4); + conn_info->remote.port = dst_port; + + tcp->send.iss = + tcp_generate_isn(&conn_info, sizeof(Ipv4ConnInfo) - sizeof(list_t)); + tcp->cur.seq = tcp->send.iss; + // 构造SYN报文 + net_buffer_header_alloc(conn->buffer, sizeof(TcpHeader)); + tcp->header = (TcpHeader *)conn->buffer->head; + + int option_len = 4 /* Max Segment Size */; + TcpHeader *header = tcp->header; + header->src_port = HOST2BE_WORD(conn_info->local.port); + header->dest_port = HOST2BE_WORD(conn_info->remote.port); + header->seq = HOST2BE_DWORD(tcp->cur.seq); + header->ack = 0; + header->data_offset = ((sizeof(TcpHeader) + option_len) / 4) << 4; + header->flags = TCP_FLAG_SYN; + header->window_size = HOST2BE_WORD(tcp->recv.window); + header->urgent_pointer = 0; + + // TCP Options算在NetBuffer的data区域内 + header->options[0] = TCP_OPTION_MSS; + header->options[1] = 4; + *(uint16_t *)(header->options + 2) = HOST2BE_WORD(tcp->mss); + net_buffer_put(conn->buffer, option_len); + + header->checksum = 0; + int length = sizeof(TcpHeader) + CONN_CONTENT_SIZE(conn); + header->checksum = HOST2BE_WORD(tcp_checksum( + header, length, conn_info->local.ip, conn_info->remote.ip, 4)); + + conn_wrap(conn, PROTO_LEVEL_NETWORK); + + tcp->state = TCP_STATE_SYN_SENT; + conn->state = CONN_STATE_OPENING; + + timer_set_timeout( + &tcp->timeout_timer, timer_count_ms(&tcp->timeout_timer, tcp->rto)); + timer_callback_enable(&tcp->timeout_timer); + NETWORK_SEND(conn->net_device, conn); + + thread_set_status(TASK_INTERRUPTIBLE); + thread_wait(); + + if (tcp->state != TCP_STATE_ESTABLISHED) return PROTO_ERROR_CONNECT_FAILED; + // 建立连接后再真正分配发送窗口 + tcp->send.unack = 0; + tcp->send.next = 0; + tcp->send.wl1 = tcp->cur.ack; + tcp->send.wl2 = tcp->cur.seq; + tcp->send.total_size = send_win_default_size; + tcp->send.window = MIN(tcp->send.total_size, tcp->send.remote_window_size); + tcp->send_window = kmalloc(tcp->send.total_size); + tcp->send_time = timer_get_counter(); + + return PROTO_OK; +} + +ProtocolResult tcp_listen(NetworkConnection *conn) { + if (conn->tcp.info == NULL) { return PROTO_ERROR_NULL_PTR; } + Tcp *tcp = conn->tcp.info; + if (tcp->state != TCP_STATE_CLOSED) return PROTO_ERROR_REBIND; + + net_buffer_header_alloc(conn->buffer, sizeof(TcpHeader)); + tcp->header = (TcpHeader *)conn->buffer->head; + + tcp->mss = conn->pmtu - sizeof(Ipv4Header) - sizeof(TcpHeader); + tcp->cur.seq = 0; + tcp->cur.ack = 0; + tcp->state = TCP_STATE_LISTEN; + tcp->recv_window = kmalloc(recv_win_default_size); + tcp->recv.next = 0; + tcp->recv.window = recv_win_default_size; + tcp->recv.total_size = recv_win_default_size; + tcp->recv.read = 0; + tcp->rttvar = tcp->rto = tcp->srtt = 0; + tcp_compute_retransmission_timer(tcp, 0); + timer_init(&tcp->timeout_timer); + tcp->timeout_timer.callback = tcp_timeout_handler; + tcp->timeout_timer.arg = tcp; + conn_wrap(conn, PROTO_LEVEL_NETWORK); + + thread_set_status(TASK_INTERRUPTIBLE); + thread_wait(); + + tcp->send.unack = 0; + tcp->send.next = 0; + tcp->send.wl1 = tcp->cur.ack; + tcp->send.wl2 = tcp->cur.seq; + tcp->send.total_size = send_win_default_size; + tcp->send.window = MIN(tcp->send.total_size, tcp->send.remote_window_size); + tcp->send_window = kmalloc(tcp->send.total_size); + tcp->send_time = timer_get_counter(); + return PROTO_OK; +} + +ProtocolResult tcp_send_data( + NetworkConnection *conn, uint8_t *buf, int length) { + if (conn == NULL || buf == NULL || length <= 0) { + return PROTO_ERROR_NULL_PTR; + } + + Tcp *tcp = conn->tcp.info; + if (tcp == NULL) { return PROTO_ERROR_NULL_PTR; } + + int used_space = tcp->send.next - tcp->send.unack; + used_space = + (used_space >= 0) ? used_space : used_space + tcp->send.total_size; + int space = tcp->send.total_size - used_space; + if (space < length) { return PROTO_ERROR_NO_SPACE_LEFT; } + + // 将数据放入发送缓冲区 + if (tcp->send.unack < tcp->send.next) { + int size1 = MIN(length, tcp->send.total_size - tcp->send.next); + int size2 = MAX(length - size1, 0); + memcpy(tcp->send_window + tcp->send.next, buf, size1); + memcpy(tcp->send_window, buf + size1, size2); + } else { + int size = MIN(length, space); + memcpy(tcp->send_window + tcp->send.next, buf, size); + } + tcp->send.next = (tcp->send.next + length) % tcp->send.total_size; + used_space += length; + + // 发送数据 + net_buffer_clean_data(tcp->conn->buffer); + int total_size = 0; + int max = MIN(tcp->mss, tcp->send.window); + if (tcp->send.unack < tcp->send.next) { + int size = MIN(max, used_space); + memcpy(conn->buffer->data, tcp->send_window + tcp->send.unack, size); + tcp->send.unack += size; + tcp->send.unack %= tcp->send.total_size; + total_size = size; + } else { + int size1 = MIN(max, tcp->send.total_size - tcp->send.unack); + int size2 = MIN(MIN(max - size1, tcp->send.next), used_space - size1); + memcpy(conn->buffer->data, tcp->send_window + tcp->send.unack, size1); + memcpy(conn->buffer->data + size1, tcp->send_window, size2); + tcp->send.next += size1 + size2; + tcp->send.next %= tcp->send.total_size; + total_size = size1 + size2; + } + net_buffer_put(conn_buffer(conn), total_size); + tcp->header->flags = TCP_FLAG_PSH; + tcp->header->flags |= TCP_FLAG_ACK; + tcp_send_packet(tcp, conn, 0, true); + return PROTO_OK; +} + +ProtocolResult tcp_recv_data(Tcp *tcp, void *buffer, uint32_t *length) { + if (tcp == NULL || buffer == NULL || length == NULL) + return PROTO_ERROR_NULL_PTR; + uint32_t next = tcp->recv.next; + uint32_t read = tcp->recv.read; + uint32_t len = *length; + int real_length; + if (next >= read) { + real_length = MIN(len, next - read); + memcpy(buffer, tcp->recv_window + read, real_length); + tcp->recv.read += real_length; + } else { + int size1 = MIN(len, tcp->recv.total_size - read); + int size2 = MIN(len - size1, next); + real_length = size1 + size2; + memcpy(buffer, tcp->recv_window + read, size1); + memcpy((uint8_t *)buffer + size1, tcp->recv_window, size2); + tcp->recv.read += size1 + size2; + } + if (real_length == 0) { + switch (tcp->conn->state) { + case CONN_STATE_INIT: + case CONN_STATE_OPENING: + case CONN_STATE_CLOSED: + return PROTO_ERROR_NOT_CONNECTED; + case CONN_STATE_NET_UNREACHABLE: + return PROTO_ERROR_NET_UNREACHABLE; + case CONN_STATE_HOST_UNREACHABLE: + return PROTO_ERROR_HOST_UNREACHABLE; + default: + break; + } + } + *length = real_length; + return PROTO_OK; +} + +ProtocolResult tcp_half_close(NetworkConnection *conn, Tcp *tcp) { + while (tcp->send.unack < tcp->send.next) {} + net_buffer_clean_data(conn->buffer); + tcp->header->flags = TCP_FLAG_FIN | TCP_FLAG_ACK; + tcp->state = TCP_STATE_FIN_WAIT1; + conn->state = CONN_STATE_CLOSING; + + kfree(tcp->send_window); + tcp->send.window = 0; + tcp->send_window = NULL; + tcp_send_packet(tcp, conn, 0, true); + return PROTO_OK; +} + +ProtocolResult tcp_shutdown(NetworkConnection *conn, uint8_t how) { + if (conn == NULL) return PROTO_ERROR_NULL_PTR; + if (conn->trans_protocol != TRANS_PROTO_TCP) return PROTO_ERROR_UNSUPPORT; + + Tcp *tcp = conn->tcp.info; + if (tcp == NULL) return PROTO_ERROR_NULL_PTR; + + switch (how) { + case TCP_SHUT_RD: + kfree(tcp->recv_window); + tcp->recv_window = NULL; + break; + case TCP_SHUT_WR: + tcp_half_close(conn, tcp); + break; + case TCP_SHUT_RDWR: + kfree(tcp->recv_window); + tcp->recv_window = NULL; + tcp_half_close(conn, tcp); + break; + default: + return PROTO_ERROR_UNSUPPORT; + } + + return PROTO_OK; +} + +void tcp_reset(NetworkConnection *conn) { + if (conn == NULL) return; + if (conn->trans_protocol != TRANS_PROTO_TCP) return; + Tcp *tcp = conn->tcp.info; + tcp_reset_conn(conn, tcp); +} + +void tcp_reset_conn(NetworkConnection *conn, Tcp *tcp) { + if (conn == NULL || tcp == NULL) return; + + net_buffer_clean_data(conn->buffer); + tcp->state = TCP_STATE_CLOSED; + TcpHeader *tcp_header = tcp->header; + tcp_header->flags = TCP_FLAG_RST; + tcp_header->ack = 0; + tcp_header->checksum = HOST2BE_WORD(tcp_checksum( + tcp_header, sizeof(TcpHeader), conn->ipv4.conn_info.local.ip, + conn->ipv4.conn_info.remote.ip, 4)); + kfree(tcp->send_window); + kfree(tcp->recv_window); + + NETWORK_SEND(conn->net_device, conn); +} + +void tcp_send_packet( + Tcp *tcp, NetworkConnection *conn, uint8_t option_size, bool set_timer) { + TcpHeader *tcp_header = tcp->header; + tcp_header->seq = HOST2BE_DWORD(tcp->cur.seq); + tcp_header->ack = HOST2BE_DWORD(tcp->cur.ack); + tcp_header->window_size = HOST2BE_WORD(tcp->recv.window); + tcp_header->data_offset = ((sizeof(TcpHeader) + option_size) >> 2) << 4; + + tcp_header->checksum = tcp_checksum( + tcp_header, CONN_CONTENT_SIZE(conn) + sizeof(TcpHeader), + conn->ipv4.conn_info.local.ip, conn->ipv4.conn_info.remote.ip, 4); + tcp_header->checksum = HOST2BE_WORD(tcp_header->checksum); + + if (tcp->send_time == 0) { + tcp->send_time = timer_get_counter(); + tcp->send_seq = tcp->cur.seq; + } + if (tcp_header->flags & TCP_FLAG_FIN) { + // 记录FIN的序号,用于后续确认 + tcp->cur.fin_seq = tcp->cur.seq; + } + // 如果没有设置重传计时则设置一个 + if (set_timer && timer_is_timeout(&tcp->timeout_timer)) { + timer_set_timeout( + &tcp->timeout_timer, timer_count_ms(&tcp->timeout_timer, tcp->rto)); + timer_callback_enable(&tcp->timeout_timer); + } + ipv4_rewrap(conn); + NETWORK_SEND(conn->net_device, conn); +} + +void tcp_ack( + NetworkConnection *conn, Tcp *tcp, uint8_t option_size, + uint8_t extra_flag) { + if (conn == NULL || tcp == NULL) return; + + TcpHeader *tcp_header = tcp->header; + + tcp_header->flags = extra_flag; + + tcp_header->flags |= TCP_FLAG_ACK; + tcp_send_packet(tcp, conn, option_size, true); +} + +void tcp_ack_handler( + Tcp *tcp, TcpHeader *header, NetBuffer *net_buffer, int length) { + uint32_t seq = BE2HOST_DWORD(header->seq); + uint32_t ack = BE2HOST_DWORD(header->ack); + + if (length > 0) { + if (ack >= tcp->send_seq && tcp->send_seq != 0) { + int rtt = timer_get_counter() - tcp->send_time; + tcp_compute_retransmission_timer(tcp, rtt); + tcp->send_seq = 0; + } + if (tcp->recv_window != NULL) { + int size1 = MIN(tcp->recv.total_size - tcp->recv.next, length); + // size2 = min(length - size1, tcp->recv.window - size1) + // 由于由发送方保证了tcp->recv.window ≥ length,所以直接使用length - + // size1 + int size2 = length - size1; + memcpy(tcp->recv_window + tcp->recv.next, net_buffer->data, size1); + memcpy(tcp->recv_window, net_buffer->data + size1, size2); + tcp->recv.next += length; + tcp->recv.next %= tcp->recv.total_size; + tcp->recv.window -= length; + } + + tcp->send.wl1 = seq; + tcp->cur.ack = seq + length; + tcp_ack(tcp->conn, tcp, 0, 0); + } + + uint32_t acked = ack - tcp->send.wl2; + if (acked > 0) { + tcp->send.unack += acked; + tcp->send.unack %= tcp->send.total_size; + tcp->send.wl2 = ack; + + tcp->cur.seq += acked; + net_buffer_clean_data(tcp->conn->buffer); + } + printk("acked: %d seq=%d\n", acked, tcp->cur.seq - tcp->send.iss); +} + +void tcp_timeout_handler(void *arg) { + if (arg == NULL) return; + Tcp *tcp = arg; + + switch (tcp->state) { // 超时重传 + case TCP_STATE_SYN_SENT: + case TCP_STATE_SYN_RECEIVED: + case TCP_STATE_ESTABLISHED: + case TCP_STATE_FIN_WAIT1: + tcp->retry_times++; + if (tcp->retry_times < tcp_max_retries) { + tcp->rto <<= 1; // 指数退避 + tcp->rto = MIN(tcp->rto, 60 * 1000); + if (tcp->state == TCP_STATE_SYN_SENT || + tcp->state == TCP_STATE_SYN_RECEIVED) + tcp->rto = MIN(tcp->rto, 3 * 1000); + timer_set_timeout( + &tcp->timeout_timer, + timer_count_ms(&tcp->timeout_timer, tcp->rto)); + timer_callback_enable(&tcp->timeout_timer); + tcp_send_packet(tcp, tcp->conn, 0, true); + } else { + tcp_reset_conn(tcp->conn, tcp); + } + break; + case TCP_STATE_FIN_WAIT2: + // 进入FIN_WAIT_2后对方一直不发送FIN,强制关闭 + tcp_reset_conn(tcp->conn, tcp); + break; + case TCP_STATE_TIME_WAIT: + // 2MSL时间到,关闭连接 + tcp->state = TCP_STATE_CLOSED; + tcp->conn->state = CONN_STATE_CLOSED; + kfree(tcp->recv_window); + tcp->recv_window = NULL; + break; + default: + break; + } +} + +void tcp_options_handler( + TcpHeader *tcp_header, TcpOptionIndex indexes[TOI_MAX]) { + int options_size = + ((tcp_header->data_offset & 0xf0) >> 2) - sizeof(TcpHeader); + if (options_size <= 0) return; + + uint8_t *options = (uint8_t *)(tcp_header + 1); + int i = 0; + while (i < options_size) { + uint8_t kind = options[i]; + i++; + if (kind == TCP_OPTION_END) break; + else if (kind == TCP_OPTION_NOP) continue; + else { + if (i >= options_size) break; + uint8_t length = options[i]; + if (i + length - 1 > options_size) break; + switch (kind) { + case TCP_OPTION_MSS: + indexes[TOI_MSS] = i + 1; + break; + default: + break; + } + i += length - 1; + } + } +} + +void tcp_rx_handler( + NetworkConnection *conn, TcpHeader *tcp_header, NetBuffer *net_buffer, + int length, uint8_t *src_ip, int ip_len) { + Tcp *tcp = conn->tcp.info; + bool syn_flag = tcp_header->flags & TCP_FLAG_SYN; + bool ack_flag = tcp_header->flags & TCP_FLAG_ACK; + uint32_t seq = BE2HOST_DWORD(tcp_header->seq); + uint32_t ack = BE2HOST_DWORD(tcp_header->ack); + + uint8_t extra_flags = 0; + if (tcp_header->flags & TCP_FLAG_RST) { + tcp->state = TCP_STATE_CLOSED; + conn->state = CONN_STATE_CLOSED; + } + + TcpOptionIndex indexes[TOI_MAX] = {TOI_MAX}; + tcp_options_handler(tcp_header, indexes); + switch (tcp->state) { + case TCP_STATE_CLOSED: + tcp_reset_conn(conn, tcp); + break; + case TCP_STATE_LISTEN: + if (syn_flag) { + if (indexes[TOI_MSS] < TOI_MAX) { + uint16_t mss = BE2HOST_WORD( + *(uint16_t *)(tcp_header->options + indexes[TOI_MSS])); + tcp->mss = MIN(mss, tcp->mss); + } + + conn->ipv4.conn_info.remote.port = + BE2HOST_WORD(tcp_header->src_port); + memcpy(conn->ipv4.conn_info.remote.ip, src_ip, ip_len); + memcpy(conn->ipv4.header->dst_ip, src_ip, ip_len); + tcp->header->src_port = + HOST2BE_WORD(conn->ipv4.conn_info.local.port); + tcp->header->dest_port = + HOST2BE_WORD(conn->ipv4.conn_info.remote.port); + tcp->send.iss = tcp_generate_isn( + &conn->ipv4.conn_info, sizeof(Ipv4ConnInfo) - sizeof(list_t)); + tcp->cur.seq = tcp->send.iss; + tcp->recv.irs = seq; + tcp->cur.ack = seq + 1; + tcp->send.remote_window_size = + BE2HOST_WORD(tcp_header->window_size); + tcp->state = TCP_STATE_SYN_RECEIVED; + extra_flags |= TCP_FLAG_SYN; + net_buffer_clean_data(tcp->conn->buffer); + tcp_header->options[0] = TCP_OPTION_MSS; + tcp_header->options[1] = 4; + *(uint16_t *)(tcp_header->options + 2) = HOST2BE_WORD(tcp->mss); + net_buffer_put(tcp->conn->buffer, 4); + tcp_ack(conn, tcp, 4, extra_flags); + } + break; + case TCP_STATE_SYN_SENT: + // 处理SYN + if (!syn_flag) { + // 异常,重置连接 + tcp_reset_conn(conn, tcp); + break; + } else { + tcp->send.remote_window_size = + BE2HOST_WORD(tcp_header->window_size); + tcp->recv.irs = seq; + tcp->cur.ack = seq + 1; + tcp->state = TCP_STATE_SYN_RECEIVED; + } + if (indexes[TOI_MSS] < TOI_MAX) { + uint16_t mss = BE2HOST_WORD( + *(uint16_t *)(tcp_header->options + indexes[TOI_MSS])); + tcp->mss = MIN(mss, tcp->mss); + } + timer_callback_cancel(&tcp->timeout_timer); + // 处理ACK + if (ack_flag) { + if (ack != tcp->cur.seq + 1) { + tcp_reset_conn(conn, tcp); + break; + } + tcp->cur.seq = ack; + conn->state = CONN_STATE_OPENED; + tcp->state = TCP_STATE_ESTABLISHED; + } + net_buffer_clean_data(tcp->conn->buffer); + tcp_ack(conn, tcp, 0, extra_flags); + thread_unblock(tcp->thread); + break; + case TCP_STATE_SYN_RECEIVED: + if (indexes[TOI_MSS] < TOI_MAX) { + uint16_t mss = BE2HOST_WORD( + *(uint16_t *)(tcp_header->options + indexes[TOI_MSS])); + tcp->mss = MIN(mss, tcp->mss); + } + timer_callback_cancel(&tcp->timeout_timer); + // 处理ACK + if (ack_flag) { + if (ack != tcp->cur.seq + 1) { + tcp_reset_conn(conn, tcp); + break; + } + tcp->cur.seq = ack; + conn->state = CONN_STATE_OPENED; + tcp->state = TCP_STATE_ESTABLISHED; + } + net_buffer_clean_data(tcp->conn->buffer); + thread_unblock(tcp->thread); + break; + case TCP_STATE_ESTABLISHED: + tcp_ack_handler(tcp, tcp_header, net_buffer, length); + if (tcp_header->flags & TCP_FLAG_FIN) { + tcp->cur.seq = ack; + tcp->cur.ack++; + tcp->state = TCP_STATE_CLOSE_WAIT; + conn->state = CONN_STATE_CLOSING; + net_buffer_clean_data(tcp->conn->buffer); + tcp_ack(conn, tcp, 0, extra_flags); + break; + } + break; + case TCP_STATE_CLOSING: + if (ack_flag) tcp_ack_handler(tcp, tcp_header, net_buffer, length); + if (ack_flag && ack > tcp->cur.fin_seq) { + tcp->cur.seq = ack; + tcp->state = TCP_STATE_TIME_WAIT; + extra_flags |= TCP_FLAG_FIN; + } + net_buffer_clean_data(tcp->conn->buffer); + tcp_ack(conn, tcp, 0, extra_flags); + break; + case TCP_STATE_CLOSE_WAIT: + tcp_reset_conn(conn, tcp); + break; + case TCP_STATE_FIN_WAIT1: + if (ack_flag) tcp_ack_handler(tcp, tcp_header, net_buffer, length); + if (ack_flag && ack > tcp->cur.fin_seq) { + tcp->cur.seq = ack; + tcp->state = TCP_STATE_FIN_WAIT2; + extra_flags |= TCP_FLAG_FIN; + + timer_callback_cancel(&tcp->timeout_timer); + timer_set_timeout( + &tcp->timeout_timer, + timer_count_ms(&tcp->timeout_timer, tcp_fin_timeout)); + timer_callback_enable(&tcp->timeout_timer); + } + if (tcp_header->flags & TCP_FLAG_FIN) { + tcp->cur.ack++; + tcp->state = TCP_STATE_CLOSING; + } + break; + case TCP_STATE_FIN_WAIT2: + if (ack_flag) tcp_ack_handler(tcp, tcp_header, net_buffer, length); + if (tcp_header->flags & TCP_FLAG_FIN) { + tcp->cur.ack++; + tcp->state = TCP_STATE_TIME_WAIT; + extra_flags |= TCP_FLAG_ACK; + + timer_callback_cancel(&tcp->timeout_timer); + uint32_t count = timer_count_ms(&tcp->timeout_timer, 2 * TCP_MSL); + timer_set_timeout(&tcp->timeout_timer, count); + timer_callback_enable(&tcp->timeout_timer); + net_buffer_clean_data(tcp->conn->buffer); + tcp_ack(conn, tcp, 0, extra_flags); + } + break; + case TCP_STATE_LAST_ACK: + if (ack_flag && ack > tcp->cur.fin_seq) { + tcp->cur.seq = ack; + tcp->state = TCP_STATE_CLOSED; + conn->state = CONN_STATE_CLOSED; + } + break; + case TCP_STATE_TIME_WAIT: + tcp_reset_conn(conn, tcp); + break; + } + thread_unblock(tcp->thread); +} + +ProtocolResult tcp_recv( + NetBuffer *net_buffer, int length, uint8_t *src_ip, uint8_t *dst_ip, + int ip_len) { + TcpHeader *tcp_header = (TcpHeader *)net_buffer->data; + + int header_length = (tcp_header->data_offset >> 4) * 4; + if (header_length < sizeof(TcpHeader)) + return PROTO_ERROR_UNSUPPORT; // 数据包太小 + int data_length = length - header_length; + + uint16_t checksum = tcp_header->checksum; + uint16_t calc_checksum = + tcp_checksum(tcp_header, length, src_ip, dst_ip, ip_len); + if (HOST2BE_WORD(calc_checksum) != checksum) return PROTO_ERROR_CHECKSUM; + + net_buffer->data += header_length; + + if (list_empty(&tcp_lh)) { + // 没有绑定的连接 + goto drop; + } + Ipv4ConnInfo *info, *next; + spin_lock(&tcp_lock); + list_for_each_owner_safe (info, next, &tcp_lh, list) { + if (info->local.port == BE2HOST_WORD(tcp_header->dest_port) && + (info->remote.port == BE2HOST_WORD(tcp_header->src_port) || + info->remote.port == 0)) { + if (memcmp(info->local.ip, dst_ip, ip_len) == 0 && + (memcmp(info->remote.ip, src_ip, ip_len) == 0 || + memcmp(info->remote.ip, &ipv4_null_addr, ip_len) == 0)) { + NetworkConnection *conn = + container_of(info, NetworkConnection, ipv4.conn_info); + tcp_rx_handler( + conn, tcp_header, net_buffer, data_length, src_ip, ip_len); + + spin_unlock(&tcp_lock); + return PROTO_OK; + } + } + } + // 没有找到匹配的连接,丢弃数据包 +drop: + // TODO: 改成发送RST + kfree(net_buffer->ptr); + kfree(net_buffer); + return PROTO_DROP; +} + +void tcp_notify_unreachable( + void *data, uint8_t *src_ip, uint8_t *dst_ip, int ip_len, int code) { + Ipv4ConnInfo *info, *next; + NetworkConnection *conn; + TcpHeader *header = (TcpHeader *)data; + bool flag = false; + + spin_lock(&tcp_lock); + list_for_each_owner_safe (info, next, &tcp_lh, list) { + if (info->local.port == BE2HOST_WORD(header->dest_port) && + (info->remote.port == BE2HOST_WORD(header->src_port))) { + if (memcmp(info->local.ip, dst_ip, ip_len) == 0 && + memcmp(info->remote.ip, src_ip, ip_len) == 0) { + flag = true; + break; + } + } + } + spin_unlock(&tcp_lock); + if (!flag) return; + + conn = container_of(info, NetworkConnection, ipv4.conn_info); + switch (code) { + case ICMP_UNREACHABLE_NET: + tcp_reset_conn(conn, conn->tcp.info); + conn->state = CONN_STATE_NET_UNREACHABLE; + break; + case ICMP_UNREACHABLE_HOST: + tcp_reset_conn(conn, conn->tcp.info); + conn->state = CONN_STATE_HOST_UNREACHABLE; + break; + default: + break; + } +} + +void tcp_update_mtu(uint8_t *src_ip, uint8_t *dst_ip, int ip_len, int mtu) { + Ipv4ConnInfo *info, *next; + NetworkConnection *conn; + bool flag = false; + + spin_lock(&tcp_lock); + list_for_each_owner_safe (info, next, &tcp_lh, list) { + // if (memcmp(info->local.ip, dst_ip, ip_len) == 0 && + // memcmp(info->remote.ip, src_ip, ip_len) == 0) { + flag = true; + break; + // } + } + spin_unlock(&tcp_lock); + if (!flag) return; + + conn = container_of(info, NetworkConnection, ipv4.conn_info); + Tcp *tcp = conn->tcp.info; + if (mtu < conn->pmtu && mtu > 0) { + mtu = MIN(MAX(IPv4_DEFAULT_MSS, mtu), conn->pmtu); + conn->pmtu = mtu; + tcp->mss = mtu - sizeof(Ipv4Header) - sizeof(TcpHeader); + if (conn->state == CONN_STATE_OPENED) { + conn->buffer->tail = + MIN(conn->buffer->tail, conn->buffer->data + tcp->mss); + ipv4_rewrap(conn); + NETWORK_SEND(conn->net_device, conn); + } + } else if (mtu > conn->pmtu) { + conn->pmtu = mtu; + tcp->mss = mtu - sizeof(Ipv4Header) - sizeof(TcpHeader); + } +} diff --git a/src/driver/network/protocols/udp.c b/src/driver/network/protocols/udp.c new file mode 100644 index 0000000..f3f4690 --- /dev/null +++ b/src/driver/network/protocols/udp.c @@ -0,0 +1,203 @@ +/** + * @file udp.c + * @author Jiajun Wang (ryan1202@foxmail.com) + * @brief UDP + * + * Reference: + * RFC 768: User Datagram Protocol + * + */ +#include "bits.h" +#include "driver/network/buffer.h" +#include "driver/network/protocols/protocols.h" +#include "kernel/memory.h" +#include "kernel/spinlock.h" +#include "kernel/thread.h" +#include +#include +#include +#include +#include +#include + +#define UDP_CHECKSUM_ADD(sum, data) \ + sum += (data); \ + if (sum > 0xFFFF) sum = (sum & 0xFFFF) + (sum >> 16); + +LIST_HEAD(udp_lh); + +uint16_t udp_checksum( + NetBuffer *net_buffer, void *ip[2], int ip_len, UdpHeader *udp_header) { + uint16_t *data = (uint16_t *)udp_header; + uint32_t sum = 0; + uint16_t len = net_buffer->tail - net_buffer->data; + + // 清除校验和 + udp_header->checksum = 0; + + // 计算伪头部校验和 + for (int j = 0; j < ip_len / 2; j++) { + UDP_CHECKSUM_ADD(sum, ((uint16_t *)ip[0])[j]); + } + for (int j = 0; j < ip_len / 2; j++) { + UDP_CHECKSUM_ADD(sum, ((uint16_t *)ip[1])[j]); + } + UDP_CHECKSUM_ADD(sum, HOST2BE_WORD(IP_PROTO_UDP)); + UDP_CHECKSUM_ADD(sum, udp_header->length); + + // 计算UDP头部和数据的校验和 + for (size_t i = 0; i < len / 2; i++) { + UDP_CHECKSUM_ADD(sum, data[i]); + } + + if (len % 2) { // 如果长度是奇数,补齐一个字节 + sum += ((uint8_t *)data)[len - 1]; + } + + return ~((uint16_t)(sum + (sum >> 16))); +} + +void udp_register(NetworkConnection *conn) { + conn->trans_protocol = TRANS_PROTO_UDP; + NET_BUF_RESV_HEAD(conn, sizeof(UdpHeader)); +} + +void udp_enqueue_packet(NetworkConnection *conn, NetBuffer *net_buffer) { + disable_preempt(); + spin_lock(&conn->recv_lock); + + list_add_tail(&net_buffer->list, &conn->recv_lh); + + spin_unlock(&conn->recv_lock); + thread_unblock(conn->thread); + enable_preempt(); +} + +/* + * 设置UDP回调函数 + */ +void udp_set_callback( + NetworkConnection *conn, + void (*callback)(NetworkConnection *conn, NetBuffer *buffer)) { + if (conn != NULL && conn->trans_protocol == TRANS_PROTO_UDP && + callback != NULL) { + conn->udp.callback = callback; + } else { + printk("[UDP] Invalid connection or callback function\n"); + } +} + +void udp_wrap(NetworkConnection *conn, uint16_t src_port, uint16_t dst_port) { + uint16_t size = CONN_PACKET_SIZE(conn); + net_buffer_header_alloc(conn_buffer(conn), sizeof(UdpHeader)); + UdpHeader *udp_header = (UdpHeader *)conn_buffer(conn)->head; + udp_header->src_port = HOST2BE_WORD(src_port); + udp_header->dst_port = HOST2BE_WORD(dst_port); + udp_header->length = HOST2BE_WORD(sizeof(UdpHeader) + size); + udp_header->checksum = 0; // 暂时不计算校验和 +} + +void udp_bind(NetworkConnection *conn, uint16_t port) { + Ipv4ConnInfo *conn_info = &conn->ipv4.conn_info; + if (list_in_list(&conn_info->list)) return; // 已经绑定了端口 + conn_info->local.port = port; + list_add_tail(&conn_info->list, &udp_lh); + conn->state = CONN_STATE_OPENED; +} + +void udp_unbind(NetworkConnection *conn) { + Ipv4ConnInfo *conn_info = &conn->ipv4.conn_info; + if (!list_in_list(&conn_info->list)) return; // 没有绑定端口 + list_del(&conn_info->list); + conn->state = CONN_STATE_CLOSED; +} + +ProtocolResult udp_recv(NetBuffer *net_buffer, Ipv4Header *ipv4_header) { + UdpHeader *udp_header = (UdpHeader *)net_buffer->data; + int size = net_buffer->tail - net_buffer->data; + + int length = BE2HOST_WORD(udp_header->length); + if (length < sizeof(UdpHeader)) return PROTO_ERROR_UNSUPPORT; // 数据包太小 + if (length > size) return PROTO_ERROR_EXCEED_MAX_SIZE; // 长度不合法 + + // TODO: 先检查目标是否为本机IP + + // 计算校验和(如果需要) + if (udp_header->checksum != 0) { + uint16_t checksum = udp_header->checksum; + void *ip[2] = { + ipv4_header->src_ip, // 源IP地址 + ipv4_header->dst_ip, // 目的IP地址 + }; + + uint16_t calc_checksum = udp_checksum(net_buffer, ip, 4, udp_header); + if (calc_checksum != checksum) { return PROTO_ERROR_CHECKSUM; } + } + + net_buffer->data += sizeof(UdpHeader); + + // IPv4 + Ipv4ConnInfo *info, *next; + list_for_each_owner_safe (info, next, &udp_lh, list) { + if (info->local.port == BE2HOST_WORD(udp_header->dst_port) && + (info->remote.port == 0 || + info->remote.port == BE2HOST_WORD(udp_header->src_port))) { + NetworkConnection *conn = + container_of(info, NetworkConnection, ipv4.conn_info); + if (memcmp(info->local.ip, ipv4_header->dst_ip, 4)) { + if (memcmp( + info->local.ip, (void *)&ipv4_null_addr, + 4) != 0 && // 不是发送到0.0.0.0 + memcmp( + ipv4_header->dst_ip, (void *)&ipv4_broadcast_addr, + 4) != 0) // 也不是广播 + continue; + } + + // 找到匹配的连接 + + if (conn->udp.callback) { + conn->udp.callback(conn, net_buffer); + } else { + goto drop; + } + + return PROTO_OK; + } + } + // 没有找到匹配的连接,丢弃数据包 +drop: + kfree(net_buffer->ptr); + kfree(net_buffer); + return PROTO_DROP; +} + +void udp_notify_unreachable( + void *data, uint8_t *src_ip, uint8_t *dst_ip, int ip_len, int code) { + Ipv4ConnInfo *info, *next; + NetworkConnection *conn; + UdpHeader *udp_header = (UdpHeader *)data; + + bool flag = false; + list_for_each_owner_safe (info, next, &udp_lh, list) { + if (info->local.port == BE2HOST_WORD(udp_header->dst_port) && + (info->remote.port == 0 || + info->remote.port == BE2HOST_WORD(udp_header->src_port))) { + conn = container_of(info, NetworkConnection, ipv4.conn_info); + if (memcmp(info->local.ip, dst_ip, 4)) { + if (memcmp( + info->local.ip, (void *)&ipv4_null_addr, + 4) != 0 && // 不是发送到0.0.0.0 + memcmp( + dst_ip, (void *)&ipv4_broadcast_addr, + 4) != 0) // 也不是广播 + continue; + } + + // 找到匹配的连接 + flag = true; + break; + } + } + if (!flag) return; +} diff --git a/src/driver/serial/Makefile b/src/driver/serial/Makefile new file mode 100644 index 0000000..135a857 --- /dev/null +++ b/src/driver/serial/Makefile @@ -0,0 +1 @@ +SRC += serial_dm.c \ No newline at end of file diff --git a/src/driver/serial/config.toml b/src/driver/serial/config.toml new file mode 100644 index 0000000..341ca48 --- /dev/null +++ b/src/driver/serial/config.toml @@ -0,0 +1 @@ +c = ["serial_dm.c"] diff --git a/src/driver/serial/serial_dm.c b/src/driver/serial/serial_dm.c new file mode 100644 index 0000000..fbe0de5 --- /dev/null +++ b/src/driver/serial/serial_dm.c @@ -0,0 +1,103 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +string_t serial_object = STRING_INIT("Serial"); + +DriverResult serial_dm_load(DeviceManager *manager); + +DeviceManagerOps serial_dm_ops = { + .dm_load = serial_dm_load, + .dm_unload = NULL, +}; +SerialDeviceManager serial_dm_ext; +DeviceManager serial_dm = { + .type = DEVICE_TYPE_SERIAL, + .ops = &serial_dm_ops, + .private_data = &serial_dm_ext, +}; + +DriverResult serial_dm_load(DeviceManager *manager) { + serial_dm_ext.new_device_num = 0; + serial_dm_ext.device_count = 0; + return DRIVER_OK; +} + +DriverResult create_serial_device( + SerialDevice **serial_device, SerialOps *serial_ops, DeviceOps *ops, + PhysicalDevice *physical_device, DeviceDriver *device_driver) { + LogicalDevice *logical_device = NULL; + + DRIVER_RESULT_PASS(create_logical_device( + &logical_device, physical_device, device_driver, ops, + DEVICE_TYPE_SERIAL)); + + *serial_device = kmalloc(sizeof(SerialDevice)); + if (*serial_device == NULL) { + delete_logical_device(logical_device); + return DRIVER_ERROR_OUT_OF_MEMORY; + } + SerialDevice *serial = *serial_device; + logical_device->dm_ext = serial; + serial->device = logical_device; + serial->ops = serial_ops; + + char _name[] = "Serial"; + string_t name; + string_new_with_number( + &name, _name, sizeof(_name) - 1, serial_dm_ext.new_device_num); + serial_dm_ext.new_device_num++; + serial_dm_ext.device_count++; + + logical_device->object = + create_object(&device_object, &name, device_object_attr); + if (logical_device->object == NULL) { + kfree(serial); + delete_logical_device(logical_device); + return DRIVER_ERROR_OBJECT; + } + + Object *obj = logical_device->object; + obj->value.device.kind = DEVICE_KIND_LOGICAL; + obj->value.device.logical = logical_device; + + return DRIVER_OK; +} + +DriverResult delete_serial_device(SerialDevice *serial_device) { + serial_dm_ext.device_count--; + + LogicalDevice *logical_device = serial_device->device; + + delete_logical_device(logical_device); + int result = kfree(serial_device); + if (result < 0) return DRIVER_ERROR_MEMORY_FREE; + return DRIVER_OK; +} + +DriverResult serial_device_open( + Object *serial_object, SerialBaudRate baud_rate, + void (*receive)(uint8_t data)) { + LogicalDevice *device = serial_object->value.device.logical; + SerialDevice *serial_device = device->dm_ext; + + DRIVER_RESULT_PASS(init_logical_device(device)); + + serial_device->ops->set_baud_rate(serial_device, baud_rate); + serial_device->ops->set_recv_mode( + serial_device, SERIAL_RECV_MODE_LOW_LATENCY); + DRIVER_RESULT_PASS(serial_device->ops->self_test(serial_device)); + + serial_device->receive = receive; + + DRIVER_RESULT_PASS(start_logical_device(device)); + + return DRIVER_OK; +} diff --git a/src/driver/sound/Makefile b/src/driver/sound/Makefile new file mode 100644 index 0000000..558b465 --- /dev/null +++ b/src/driver/sound/Makefile @@ -0,0 +1,2 @@ +SRC += sound_dm.c +SRC += pcm.c \ No newline at end of file diff --git a/src/driver/sound/config.toml b/src/driver/sound/config.toml new file mode 100644 index 0000000..ba9d00e --- /dev/null +++ b/src/driver/sound/config.toml @@ -0,0 +1 @@ +c = ["pcm.c", "sound_dm.c"] diff --git a/src/driver/sound/pcm.c b/src/driver/sound/pcm.c new file mode 100644 index 0000000..7e64a23 --- /dev/null +++ b/src/driver/sound/pcm.c @@ -0,0 +1,368 @@ +#include "kernel/console.h" +#include "kernel/spinlock.h" +#include "kernel/thread.h" +#include "kernel/wait_queue.h" +#include "stdint.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +TransferResult sound_pcm_transfer( + Object *object, struct ObjectHandle *handle, TransferDirection direction, + uint8_t *buf, size_t size); + +PcmDevice *sound_register_pcm( + SoundDevice *sound_device, PcmOps *pcm_ops, size_t size) { + PcmDevice *pcm = kmalloc(sizeof(PcmDevice)); + if (pcm == NULL) return NULL; + + sound_device->pcm = pcm; + pcm->sound_device = sound_device; + pcm->ops = pcm_ops; + pcm->buf = NULL; + pcm->buffer_bytes = size; + pcm->status = PCM_STATUS_CLOSE; + pcm->boundary = size; + while (pcm->boundary * 2 < __SIZE_MAX__ / 2 - size) + pcm->boundary *= 2; + + return pcm; +} + +DriverResult pcm_register_stream( + PcmDevice *pcm, PcmStream **stream, PcmStreamOps *ops, void *private_data) { + *stream = kmalloc(sizeof(PcmStream)); + if (*stream == NULL) return DRIVER_ERROR_OUT_OF_MEMORY; + PcmStream *s = *stream; + + s->pcm = pcm; + s->sound_device = pcm->sound_device; + s->ops = ops; + s->private_data = private_data; + // s->buf = ptr; + // s->status = ptr + sizeof(void *) * pcm->max_buf_count; + s->device_ptr_base = 0; + s->device_period_ptr = 0; + s->host_ptr_base = 0; + s->host_period_ptr = 0; + s->host_ptr = 0; + spinlock_init(&s->lock); + wait_queue_init(&s->wq); + + return DRIVER_OK; +} + +DriverResult pcm_register_dma( + PcmDevice *pcm, void *dma, void *param, DmaOps *ops) { + Dma *_dma = kmalloc(sizeof(Dma)); + if (_dma == NULL) return DRIVER_ERROR_OUT_OF_MEMORY; + _dma->dma = dma; + _dma->param = param; + _dma->ops = ops; + pcm->dma = _dma; + return DRIVER_OK; +} + +DriverResult sound_pcm_alloc(PcmStream *stream) { + PcmDevice *pcm = stream->pcm; + pcm->buf = pcm->dma->ops->dma_alloc(pcm->dma, pcm->buffer_bytes); + stream->device_ptr_base = stream->host_ptr_base = 0; + stream->device_period_ptr = stream->host_period_ptr = 0; + stream->host_ptr = 0; + return DRIVER_OK; +} + +DriverResult pcm_set_data_type(PcmStream *stream, PcmDataType data_type) { + DRIVER_RESULT_PASS(stream->ops->set_data_type(stream, data_type)); + stream->data_type = data_type; + return DRIVER_OK; +} + +DriverResult pcm_set_channel(PcmStream *stream, uint8_t channel) { + DRIVER_RESULT_PASS(stream->ops->set_channel(stream, channel)); + stream->channel = channel; + return DRIVER_OK; +} + +DriverResult pcm_set_sample_rate(PcmDevice *pcm, uint32_t sample_rate) { + DRIVER_RESULT_PASS(pcm->ops->set_sample_rate(pcm, sample_rate)); + pcm->sample_rate = sample_rate; + return DRIVER_OK; +} + +DriverResult sound_pcm_open( + Object *object, int mode, DEF_MRET(PcmDevice *, pcm), + DEF_MRET(PcmStream *, stream)) { + SoundDevice *sound_device = sound_get_device(object); + PcmStream *cur_stream; + + if (sound_device->type != SOUND_TYPE_PCM) + return DRIVER_ERROR_UNSUPPORT_FEATURE; + + PcmDevice *pcm = sound_device->pcm; + if (mode == SOUND_DEVICE_MODE_PLAY) { + pcm->play_stream->ops->open(sound_device, pcm->play_stream); + cur_stream = pcm->play_stream; + } else if (mode == SOUND_DEVICE_MODE_RECORED) { + pcm->record_stream->ops->open(sound_device, pcm->record_stream); + cur_stream = pcm->record_stream; + } else { + return DRIVER_ERROR_UNSUPPORT_FEATURE; + } + cur_stream->ops->set_default_params(cur_stream); + + MRET(pcm) = pcm; + MRET(stream) = cur_stream; + object->in.type = TRANSFER_TYPE_STREAM; + object->in.stream = sound_pcm_transfer; + object->out.type = TRANSFER_TYPE_STREAM; + object->out.stream = sound_pcm_transfer; + return DRIVER_OK; +} + +DriverResult sound_pcm_set_frame_count(PcmStream *stream, size_t count) { + stream->frame_per_period = count; + stream->frame_bytes = stream->channel * stream->pcm->data_bytes; + stream->period_bytes = stream->frame_per_period * stream->frame_bytes; + return DRIVER_OK; +} + +DriverResult sound_pcm_set_mode(PcmStream *stream, PcmMode mode) { + stream->user_mode = mode; + return stream->ops->set_mode(stream, mode); +} + +int sound_pcm_left_space(PcmStream *stream) { + int left_space = stream->device_period_ptr + stream->pcm->buffer_bytes - + (stream->host_ptr_base + stream->host_ptr); + if (left_space >= stream->pcm->boundary) { + // 跨越边界 + left_space -= stream->pcm->boundary; + } + return left_space; +} + +void pcm_interleaved2noninterleaved( + PcmStream *stream, uint8_t *in, uint8_t *out, uint32_t frame_count) { + PcmDevice *pcm = stream->pcm; + uint8_t *src = in; + uint8_t *dst = out; + uint8_t *_dst; + uint32_t offset = stream->period_bytes / stream->channel; + int i, j, k; + for (i = 0; i < frame_count; i++) { + _dst = dst; + for (j = 0; j < stream->channel; j++) { + for (k = 0; k < pcm->data_bytes; k++) { + _dst[k] = src[k]; + } + _dst += offset; + src += pcm->data_bytes; + } + dst += pcm->data_bytes; + } +} +void pcm_noninterleaved2interleaved( + PcmStream *stream, uint8_t *in, uint8_t *out, uint32_t frame_count) { + PcmDevice *pcm = stream->pcm; + uint8_t *src = in; + uint8_t *dst = out; + uint8_t *_src; + uint32_t offset = stream->period_bytes / stream->channel; + int i, j, k; + for (i = 0; i < frame_count; i++) { + _src = src; + for (j = 0; j < stream->channel; j++) { + for (k = 0; k < pcm->data_bytes; k++) { + dst[k] = _src[k]; + } + _src += offset; + dst += pcm->data_bytes; + } + src += pcm->data_bytes; + } +} + +DriverResult sound_pcm_copy_interleaved( + PcmStream *stream, uint8_t *dst, uint8_t *src, uint32_t frame_count) { + if (frame_count > stream->frame_per_period) + return DRIVER_ERROR_EXCEED_MAX_SIZE; + if (stream->hw_mode == PCM_MODE_INTERLEAVED) { + // 模式相同,直接复制 + memcpy(dst, src, frame_count * stream->frame_bytes); + } else { + // 模式不同,需要转换 + // 输入为交织模式,输出为非交织模式 + pcm_interleaved2noninterleaved(stream, src, dst, frame_count); + } + return DRIVER_OK; +} + +DriverResult sound_pcm_copy_noninterleaved( + PcmStream *stream, uint8_t *dst, uint8_t *src, uint32_t frame_count) { + if (stream->hw_mode == PCM_MODE_NONINTERLEAVED) { + // 模式相同,直接复制 + memcpy(dst, src, frame_count * stream->frame_bytes); + } else { + // 模式不同,需要转换 + // 输入为非交织模式,输出为交织模式 + pcm_noninterleaved2interleaved(stream, src, dst, frame_count); + } + return DRIVER_OK; +} + +DriverResult pcm_transfer( + PcmStream *stream, uint8_t *user_buf, uint8_t *dma_buf, + uint32_t frame_count, TransferDirection direction) { + PcmDevice *pcm = stream->pcm; + uint32_t count; + uint8_t *user_buf_cur = user_buf, *dma_buf_cur = dma_buf; + uint8_t *src, *dst; + + int flags = spin_lock_irqsave(&stream->lock); + int left_space = sound_pcm_left_space(stream); + + size_t done = 0; + size_t size, left_size = frame_count * stream->frame_bytes; + while (left_size > 0) { + while (left_space == 0) { + thread_set_status(TASK_INTERRUPTIBLE); + wait_queue_add(&stream->wq); + spin_unlock_irqrestore(&stream->lock, flags); + + thread_wait(); + + spin_lock_irqsave(&stream->lock); + left_space = sound_pcm_left_space(stream); + } + dma_buf_cur = dma_buf + stream->host_ptr; + size = MIN(left_space, left_size); + size = MIN(size, pcm->buffer_bytes - stream->host_ptr); + spin_unlock_irqrestore(&stream->lock, flags); + + count = size / stream->frame_bytes; + + src = (direction == TRANSFER_IN) ? dma_buf_cur : user_buf_cur; + dst = (direction == TRANSFER_IN) ? user_buf_cur : dma_buf_cur; + if (stream->user_mode == PCM_MODE_INTERLEAVED) { + sound_pcm_copy_interleaved(stream, dst, src, count); + } else { + sound_pcm_copy_noninterleaved(stream, dst, src, count); + } + user_buf_cur += size; + left_space -= size; + left_size -= size; + done += count; + + flags = spin_lock_irqsave(&stream->lock); + stream->host_ptr += size; + + if (stream->host_ptr >= pcm->buffer_bytes) { + stream->host_ptr -= pcm->buffer_bytes; + stream->host_ptr_base += pcm->buffer_bytes; + if (stream->host_ptr_base > pcm->boundary) { + stream->host_ptr_base = 0; + } + } + } + if ((direction == TRANSFER_OUT && done > 0) || + (direction == TRANSFER_IN && done < frame_count)) { + if ((pcm->status == PCM_STATUS_PREPARED || + pcm->status == PCM_STATUS_PAUSED)) { + if (sound_pcm_left_space(stream) >= stream->start_threshold) { + stream->ops->trigger(stream, PCM_TRIGGER_START); + pcm->status = PCM_STATUS_RUNNING; + } + } + int position = stream->host_ptr; + position -= position % stream->period_bytes; + stream->host_period_ptr = stream->host_ptr_base + position; + } + spin_unlock_irqrestore(&stream->lock, flags); + if (done < frame_count) { return DRIVER_ERROR_BUSY; }; + + return DRIVER_OK; +} + +DriverResult sound_pcm_read( + PcmStream *stream, uint8_t *buf, uint32_t frame_count) { + return pcm_transfer( + stream, buf, stream->pcm->buf, frame_count, TRANSFER_IN); +} + +DriverResult sound_pcm_write( + PcmStream *stream, uint8_t *buf, uint32_t frame_count) { + return pcm_transfer( + stream, buf, stream->pcm->buf, frame_count, TRANSFER_OUT); +} + +DriverResult sound_pcm_prepare(PcmStream *stream) { + PcmDevice *pcm = stream->pcm; + pcm->current_stream = stream; + + pcm->status = PCM_STATUS_PREPARED; + + DRIVER_RESULT_PASS( + stream->ops->prepare(stream, pcm->buf, pcm->buffer_bytes)); + + return DRIVER_OK; +} + +DriverResult sound_pcm_done(PcmStream *stream) { + PcmDevice *pcm = stream->pcm; + size_t position = stream->ops->position(stream); + size_t old_period_ptr = stream->device_period_ptr; + position -= position % stream->period_bytes; + + int flags = spin_lock_irqsave(&stream->lock); + + size_t new_device_base = stream->device_ptr_base; + size_t new_period_ptr = new_device_base + position; + + if (new_period_ptr < old_period_ptr) { + // 当前DMA缓冲区发生回环,切换到下一个虚拟缓冲区 + new_device_base += pcm->buffer_bytes; + new_period_ptr = new_device_base + position; + } + + if (new_period_ptr >= pcm->boundary) { + // 当前虚拟缓冲区超出边界,切换到第一个虚拟缓冲区 + new_device_base = 0; + new_period_ptr = new_device_base + position; + } + + stream->device_ptr_base = new_device_base; + stream->device_period_ptr = new_period_ptr; + + // if (sound_pcm_left_space(stream) <= stream->stop_threshold) { + // stream->ops->trigger(stream, PCM_TRIGGER_PAUSE); + // stream->pcm->status = PCM_STATUS_PAUSED; + // } + + wait_queue_wakeup(&stream->wq); + spin_unlock_irqrestore(&stream->lock, flags); + + return DRIVER_OK; +} + +TransferResult sound_pcm_transfer( + Object *object, struct ObjectHandle *handle, TransferDirection direction, + uint8_t *buf, size_t size) { + SoundDevice *sound_device = sound_get_device(object); + PcmDevice *pcm = sound_device->pcm; + if (direction == TRANSFER_OUT) { + sound_pcm_write(pcm->play_stream, buf, size); + } else { + sound_pcm_read(pcm->record_stream, buf, size); + } + + return TRANSFER_OK; +} diff --git a/src/driver/sound/sound_dm.c b/src/driver/sound/sound_dm.c new file mode 100644 index 0000000..bfd32d2 --- /dev/null +++ b/src/driver/sound/sound_dm.c @@ -0,0 +1,104 @@ +#include "kernel/device.h" +#include "kernel/list.h" +#include "objects/object.h" +#include +#include +#include +#include +#include + +DriverResult sound_dm_load(DeviceManager *manager); +DriverResult sound_dm_unload(DeviceManager *manager); + +DeviceManagerOps sound_dm_ops = { + .dm_load = sound_dm_load, + .dm_unload = sound_dm_unload, +}; + +SoundDeviceManager sound_dm_ext; +DeviceManager sound_dm = { + .type = DEVICE_TYPE_SOUND, + .ops = &sound_dm_ops, + .private_data = &sound_dm_ext, +}; + +DriverResult sound_dm_load(DeviceManager *manager) { + manager->private_data = kmalloc(sizeof(SoundDeviceManager)); + sound_dm_ext.new_device_num = 0; + sound_dm_ext.device_count = 0; + return DRIVER_OK; +} + +DriverResult sound_dm_unload(DeviceManager *manager) { + kfree(manager->private_data); + return DRIVER_OK; +} + +DriverResult create_sound_device( + SoundDevice **sound_device, SoundDeviceType type, + SoundDeviceCapabilities caps, SoundOps *sound_ops, DeviceOps *ops, + PhysicalDevice *physical_device, DeviceDriver *device_driver) { + DriverResult result; + LogicalDevice *logical_device = NULL; + + result = create_logical_device( + &logical_device, physical_device, device_driver, ops, + DEVICE_TYPE_SOUND); + if (result != DRIVER_OK) return result; + + *sound_device = kmalloc(sizeof(SoundDevice)); + if (*sound_device == NULL) { + delete_logical_device(logical_device); + return DRIVER_ERROR_OUT_OF_MEMORY; + } + SoundDevice *snd; + logical_device->dm_ext = *sound_device; + snd = *sound_device; + snd->device = logical_device; + snd->type = type; + snd->ops = sound_ops; + snd->capabilities = caps; + + char _name[] = "Sound"; + string_t name; + string_new_with_number( + &name, _name, sizeof(_name) - 1, sound_dm_ext.new_device_num); + sound_dm_ext.new_device_num++; + sound_dm_ext.device_count++; + + Object *obj = create_object(&device_object, &name, device_object_attr); + if (obj == NULL) { + kfree(snd); + delete_logical_device(logical_device); + return DRIVER_ERROR_OBJECT; + } + obj->value.device.kind = DEVICE_KIND_LOGICAL; + obj->value.device.logical = logical_device; + logical_device->object = obj; + + return DRIVER_OK; +} + +DriverResult delete_sound_device(SoundDevice *sound_device) { + sound_dm_ext.device_count--; + LogicalDevice *logical_device = sound_device->device; + + list_del(&logical_device->dm_device_list); + delete_logical_device(logical_device); + int result = kfree(sound_device); + if (result < 0) return DRIVER_ERROR_MEMORY_FREE; + return DRIVER_OK; +} + +SoundDevice *sound_get_device(Object *object) { + // if (object->attr->type != OBJECT_TYPE_DEVICE) return NULL; + LogicalDevice *device = object->value.device.logical; + // if (device->type != DEVICE_TYPE_SOUND) return NULL; + return device->dm_ext; +} + +SoundDeviceType sound_get_type(Object *object) { + SoundDevice *sound_device = sound_get_device(object); + if (sound_device == NULL) return SOUND_TYPE_UNKNOWN; + return sound_device->type; +} diff --git a/src/driver/storage/Makefile b/src/driver/storage/Makefile new file mode 100644 index 0000000..c889628 --- /dev/null +++ b/src/driver/storage/Makefile @@ -0,0 +1,5 @@ +SRC += disk/ +SRC += storage_dm.c +SRC += storage_io_queue.c +SRC += storage_io.c +SRC += volume.c \ No newline at end of file diff --git a/src/driver/storage/config.toml b/src/driver/storage/config.toml new file mode 100644 index 0000000..b9158a0 --- /dev/null +++ b/src/driver/storage/config.toml @@ -0,0 +1,2 @@ +dir = ["disk/"] +c = ["storage_dm.c", "storage_io_queue.c", "storage_io.c", "volume.c"] diff --git a/src/driver/storage/disk/Makefile b/src/driver/storage/disk/Makefile new file mode 100644 index 0000000..36e641e --- /dev/null +++ b/src/driver/storage/disk/Makefile @@ -0,0 +1,2 @@ +SRC += mbr.c +SRC += disk.c \ No newline at end of file diff --git a/src/driver/storage/disk/config.toml b/src/driver/storage/disk/config.toml new file mode 100644 index 0000000..376e353 --- /dev/null +++ b/src/driver/storage/disk/config.toml @@ -0,0 +1 @@ +c = ["disk.c", "mbr.c"] diff --git a/src/driver/storage/disk/disk.c b/src/driver/storage/disk/disk.c new file mode 100644 index 0000000..ac7426e --- /dev/null +++ b/src/driver/storage/disk/disk.c @@ -0,0 +1,58 @@ +#include +#include +#include +#include + +TransferResult disk_transfer_in_async( + Object *object, ObjectHandle *obj_handle, TransferDirection direction, + uint8_t *buf, uint32_t position, size_t count, void **handle) { + Partition *partition = object->value.partition; + + return TRANSFER_IN_BLOCK_ASYNC( + partition->storage_object, obj_handle, buf, + position + partition->start_lba, count, handle); +} + +TransferResult disk_transfer_in( + Object *object, ObjectHandle *obj_handle, TransferDirection direction, + uint8_t *buf, uint32_t position, size_t count) { + Partition *partition = object->value.partition; + + return TRANSFER_IN_BLOCK( + partition->storage_object, obj_handle, buf, + position + partition->start_lba, count); +} + +TransferResult disk_transfer_out_async( + Object *object, ObjectHandle *obj_handle, TransferDirection direction, + uint8_t *buf, uint32_t position, size_t count, void **handle) { + Partition *partition = object->value.partition; + + return TRANSFER_OUT_BLOCK_ASYNC( + partition->storage_object, obj_handle, buf, + position + partition->start_lba, count, handle); +} + +TransferResult disk_transfer_out( + Object *object, ObjectHandle *obj_handle, TransferDirection direction, + uint8_t *buf, uint32_t position, size_t count) { + Partition *partition = object->value.partition; + + return TRANSFER_OUT_BLOCK( + partition->storage_object, obj_handle, buf, + position + partition->start_lba, count); +} + +TransferResult disk_is_transfer_in_done( + Object *object, void **handle, bool *is_done) { + Partition *partition = object->value.partition; + + return TRANSFER_IN_IS_DONE(partition->storage_object, handle, is_done); +} + +TransferResult disk_is_transfer_out_done( + Object *object, void **handle, bool *is_done) { + Partition *partition = object->value.partition; + + return TRANSFER_OUT_IS_DONE(partition->storage_object, handle, is_done); +} diff --git a/src/driver/storage/disk/mbr.c b/src/driver/storage/disk/mbr.c new file mode 100644 index 0000000..eb73821 --- /dev/null +++ b/src/driver/storage/disk/mbr.c @@ -0,0 +1,58 @@ +#include "kernel/device.h" +#include "kernel/memory.h" +#include +#include +#include +#include +#include +#include +#include + +#define MBR_PARTITION_ENTRY_SIZE 16 +#define MBR_PARTITION_TABLE_OFFSET 446 +#define MBR_PARTITION_COUNT 4 + +bool disk_is_mbr(StorageDevice *storage_device) { + return storage_device->superblock[510] == 0x55 && + storage_device->superblock[511] == 0xAA; +} + +void parse_mbr_partition_table(StorageDevice *storage_device) { + int partition_count = 0; + MBRPartitionEntry *partition_table = + (MBRPartitionEntry *)&storage_device + ->superblock[MBR_PARTITION_TABLE_OFFSET]; + + for (int i = 0; i < MBR_PARTITION_COUNT; i++) { + if (partition_table[i].fs_type != 0) { + string_t name; + string_new_with_number(&name, "Partition", 9, partition_count); + ObjectAttr attr = device_object_attr; + attr.type = OBJECT_TYPE_PARTITION; + Object *object = create_object(storage_device->object, &name, attr); + + Partition *partition = kmalloc(sizeof(Partition)); + partition->storage_object = storage_device->device->object; + partition->type = PARTITION_TYPE_MBR; + partition->start_lba = partition_table[i].start_lba; + partition->size_lba = partition_table[i].size; + partition->mbr = &partition_table[i]; + partition->index = partition_count; + partition->object = object; + object->value.partition = partition; + + object->in.type = TRANSFER_TYPE_BLOCK; + object->in.block = disk_transfer_in; + object->in.block_async = disk_transfer_in_async; + object->in.is_transfer_done = disk_is_transfer_in_done; + object->out.type = TRANSFER_TYPE_BLOCK; + object->out.block = disk_transfer_out; + object->out.block_async = disk_transfer_out_async; + object->out.is_transfer_done = disk_is_transfer_out_done; + + probe_volume(partition); + + partition_count++; + } + } +} \ No newline at end of file diff --git a/src/driver/storage/storage_dm.c b/src/driver/storage/storage_dm.c new file mode 100644 index 0000000..c5b5dda --- /dev/null +++ b/src/driver/storage/storage_dm.c @@ -0,0 +1,150 @@ +#include "kernel/spinlock.h" +#include "kernel/wait_queue.h" +#include "objects/attr.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern void storage_periodic_task(void *arg); +DriverResult start_storage_device( + DeviceManager *manager, LogicalDevice *device); + +DeviceManagerOps storage_dm_ops = { + .dm_load = NULL, + .dm_unload = NULL, + + .init_device_hook = NULL, + .start_device_hook = start_storage_device, + .stop_device_hook = NULL, + .destroy_device_hook = NULL, +}; + +typedef struct StorageDeviceManager { + uint8_t new_device_num; + uint8_t device_count; +} StorageDeviceManager; + +StorageDeviceManager storage_dm_ext; +struct DeviceManager storage_dm = { + .type = DEVICE_TYPE_STORAGE, + .ops = &storage_dm_ops, + .private_data = &storage_dm_ext, +}; + +DriverResult create_storage_device( + StorageDevice **storage_device, StorageDeviceOps *storage_ops, + DeviceOps *ops, PhysicalDevice *physical_device, + DeviceDriver *device_driver) { + DriverResult result; + LogicalDevice *logical_device = NULL; + + result = create_logical_device( + &logical_device, physical_device, device_driver, ops, + DEVICE_TYPE_STORAGE); + if (result != DRIVER_OK) return result; + + *storage_device = kmalloc(sizeof(StorageDevice)); + if (*storage_device == NULL) { + delete_logical_device(logical_device); + return DRIVER_ERROR_OUT_OF_MEMORY; + } + + StorageDevice *storage = *storage_device; + logical_device->dm_ext = storage; + storage->device = logical_device; + storage->ops = storage_ops; + + spinlock_init(&storage->queue_lock); + list_init(&storage->io_queue_lh); + wait_queue_init(&storage->wq); + + char _name[] = "Storage"; + string_t name; + string_new_with_number( + &name, _name, sizeof(_name) - 1, storage_dm_ext.new_device_num); + storage_dm_ext.new_device_num++; + storage_dm_ext.device_count++; + + Object *obj = create_object(&device_object, &name, device_object_attr); + logical_device->object = obj; + if (logical_device->object == NULL) { + kfree(storage); + delete_logical_device(logical_device); + return DRIVER_ERROR_OBJECT; + } + + obj->in.type = TRANSFER_TYPE_BLOCK; + obj->in.block = storage_transfer; + obj->in.block_async = storage_transfer_async; + obj->in.is_transfer_done = storage_is_transfer_done; + obj->out.type = TRANSFER_TYPE_BLOCK; + obj->out.block = storage_transfer; + obj->out.block_async = storage_transfer_async; + obj->out.is_transfer_done = storage_is_transfer_done; + obj->value.device.kind = DEVICE_KIND_LOGICAL; + obj->value.device.logical = logical_device; + + storage->periodic_task.func = storage_periodic_task; + storage->periodic_task.arg = storage; + storage->name = name; + periodic_task_add(&storage->periodic_task); + + ObjectAttr attr = base_obj_sys_attr; + attr.type = OBJECT_TYPE_DIRECTORY; + storage->object = create_object_directory(&device_object, &name, attr); + + return DRIVER_OK; +} + +DriverResult delete_storage_device(StorageDevice *storage_device) { + // TODO: delete_object_directory + // TODO: periodic_task_remove + + list_del(&storage_device->device->dm_device_list); + delete_logical_device(storage_device->device); + int result; + if (storage_device->device->state == DEVICE_STATE_ACTIVE) { + result = kfree(storage_device->superblock); + if (result < 0) return DRIVER_ERROR_MEMORY_FREE; + } + result = kfree(storage_device); + if (result < 0) return DRIVER_ERROR_MEMORY_FREE; + return DRIVER_OK; +} + +DriverResult start_storage_device( + DeviceManager *manager, LogicalDevice *device) { + StorageDevice *storage_device = device->dm_ext; + + storage_device->superblock = kmalloc(2 * SECTOR_SIZE); + storage_transfer( + device->object, NULL, TRANSFER_IN, storage_device->superblock, 0, 2); + + if (storage_device->type == STORAGE_DEVICE_TYPE_HARDDISK) { + if (disk_is_mbr(storage_device)) { + parse_mbr_partition_table(storage_device); + } + list_init(&storage_device->block_cache_lh); + } else { + storage_device->block_cache_lh.next = NULL; + storage_device->block_cache_lh.prev = NULL; + } + return DRIVER_OK; +} diff --git a/src/driver/storage/storage_io.c b/src/driver/storage/storage_io.c new file mode 100644 index 0000000..12733ec --- /dev/null +++ b/src/driver/storage/storage_io.c @@ -0,0 +1,140 @@ +/** + * 默认的存储设备IO实现 + */ +#include "kernel/device.h" +#include "kernel/driver.h" +#include "kernel/thread.h" +#include "multiple_return.h" +#include "stdint.h" +#include +#include +#include +#include +#include +#include +#include +#include + +// 检查请求大小是否超过设备允许的最大请求大小 +bool storage_check_request_size( + StorageDevice *device, StorageRequest *request) { + if (request->count > device->max_block_per_request) { return false; } + return true; +} + +// 将过大的请求分割成多个小请求 +DriverResult storage_generate_request( + StorageDevice *device, int rw, void *buf, size_t position, size_t count, + DEF_MRET(StorageRequest *, last_request)) { + // 计算需要分割成几个请求 + uint32_t num_requests = DIV_ROUND_UP(count, device->max_block_per_request); + uint32_t remaining_blocks = count; + uint32_t current_position = position; + + StorageRequest *first_request = NULL; + StorageRequest *request; + struct task_s *cur_thread = get_current_thread(); + + // uint32_t t, t0, t1, t2, t3; + // 分割请求 + for (uint32_t i = 0; i < num_requests; i++) { + // 计算当前分片的大小 + uint32_t current_count = + MIN(remaining_blocks, device->max_block_per_request); + + // 创建新的请求 + request = kmalloc(sizeof(StorageRequest)); + if (request == NULL && first_request != NULL) { + return DRIVER_ERROR_OUT_OF_MEMORY; + } + + // 设置新请求的参数 + request->position = current_position; + request->count = current_count; + request->rw = rw; + request->is_finished = 0; + request->storage_device = device; + request->next_merged_request = NULL; + request->thread = cur_thread; + + // 分配或指向原始缓冲区中对应的部分 + request->buf = + buf + i * device->max_block_per_request * device->block_size; + + storage_add_request(device, request); + + // 更新剩余块和当前位置 + remaining_blocks -= current_count; + current_position += current_count; + if (first_request == NULL) { first_request = request; } + } + MRET(last_request) = request; + return DRIVER_OK; +} + +TransferResult storage_transfer_async( + Object *object, ObjectHandle *obj_handle, TransferDirection direction, + uint8_t *buf, uint32_t position, size_t count, void **handle) { + while (object->attr->type == OBJECT_TYPE_SYM_LINK) { + object = object->value.sym_link; + } + LogicalDevice *device = object->value.device.logical; + storage_generate_request( + device->dm_ext, (direction == TRANSFER_IN) ? 0 : 1, buf, position, + count, (StorageRequest **)handle); + + return TRANSFER_OK; +} + +TransferResult storage_transfer( + Object *object, ObjectHandle *obj_handle, TransferDirection direction, + uint8_t *buf, uint32_t position, size_t count) { + while (object->attr->type == OBJECT_TYPE_SYM_LINK) { + object = object->value.sym_link; + } + LogicalDevice *device = object->value.device.logical; + + StorageRequest *request; + StorageDevice *storage_device = device->dm_ext; + + thread_set_status(TASK_INTERRUPTIBLE); + wait_queue_add(&storage_device->wq); + + DriverResult result = storage_generate_request( + storage_device, (direction == TRANSFER_IN) ? 0 : 1, buf, position, + count, &request); + if (result != DRIVER_OK) { + wait_queue_del(&storage_device->wq); + return TRANSFER_ERROR_FAILED; + } + + thread_wait(); + while (!request->is_finished) { + thread_set_status(TASK_INTERRUPTIBLE); + wait_queue_add(&storage_device->wq); + thread_wait(); + } + + return TRANSFER_OK; +} + +TransferResult storage_is_transfer_done( + Object *object, void **handle, bool *done) { + if (object->attr->type != OBJECT_TYPE_DEVICE) { + return TRANSFER_ERROR_INVALID_PARAMETER; + } + LogicalDevice *device = object->value.device.logical; + + if (device->type != DEVICE_TYPE_STORAGE) { + return TRANSFER_ERROR_INVALID_PARAMETER; + } + StorageDevice *storage_device = device->dm_ext; + + StorageRequest *req = *handle; + if (req->storage_device != storage_device || done == NULL) { + return TRANSFER_ERROR_INVALID_PARAMETER; + } + *done = req->is_finished; + + return TRANSFER_OK; +} \ No newline at end of file diff --git a/src/driver/storage/storage_io_queue.c b/src/driver/storage/storage_io_queue.c new file mode 100644 index 0000000..2bd4ead --- /dev/null +++ b/src/driver/storage/storage_io_queue.c @@ -0,0 +1,187 @@ +#include "kernel/block_cache.h" +#include "kernel/rwlock.h" +#include "kernel/spinlock.h" +#include "kernel/wait_queue.h" +#include +#include +#include +#include +#include +#include +#include +#include + +PRIVATE void storage_modify_merged_request( + StorageRequest *new_request, StorageRequest *request) { + StorageRequest *last_request = request->next_merged_request; + while (last_request->next_merged_request != NULL) { + last_request = last_request->next_merged_request; + } + + request->position = MIN(request->position, new_request->position); + request->count = MAX(new_request->position + new_request->count, + request->position + request->count) - + request->position; + + last_request->next_merged_request = new_request; +} + +PRIVATE void storage_new_merge_request( + StorageRequest *new_request, StorageRequest *request) { + StorageRequest *req = kmalloc(sizeof(StorageRequest)); + req->buf = NULL; // 缓冲区先不申请,等到真正提交时再申请 + req->position = MIN(new_request->position, request->position); + req->count = MAX(new_request->position + new_request->count, + request->position + request->count) - + req->position; + req->rw = new_request->rw; + req->is_finished = 0; + req->storage_device = new_request->storage_device; + + req->next_merged_request = request; + request->next_merged_request = new_request; + + list_add_before(&req->list, &request->list); + list_del(&request->list); +} + +bool storage_try_merge_request( + StorageRequest *new_request, StorageRequest *request, size_t max_count) { + if (new_request->rw == request->rw) { // 读写类型相同 + if (new_request->count + request->count > max_count) return false; + if (new_request->position + new_request->count < request->position && + new_request->position > request->position + request->count) { + // 两个请求没有交集 + return false; + } + + if (request->next_merged_request != NULL) { + // 如果是被合并过的请求,就继续合并 + storage_modify_merged_request(new_request, request); + } else { // 未合并过 + // 因为不能修改已有的请求,就新申请一个请求替换掉 + storage_new_merge_request(new_request, request); + } + } + return false; +} + +void storage_add_request( + StorageDevice *storage_device, StorageRequest *request) { + request->storage_device = storage_device; + request->is_finished = 0; + + spin_lock(&storage_device->queue_lock); + + if (list_empty(&storage_device->io_queue_lh) && + !storage_device->ops->is_busy(storage_device)) { + storage_submit_request(request); + spin_unlock(&storage_device->queue_lock); + return; + } + spin_unlock(&storage_device->queue_lock); + + StorageRequest *req; + spin_lock(&storage_device->queue_lock); + list_for_each_owner (req, &storage_device->io_queue_lh, list) { + if (storage_try_merge_request( + request, req, storage_device->max_block_per_request)) { + return; + } + if (req->position > request->position) { + list_add_before(&request->list, &req->list); + return; + } + } + list_add_tail(&request->list, &storage_device->io_queue_lh); + spin_unlock(&storage_device->queue_lock); +} + +void storage_periodic_task(void *arg) { + StorageDevice *storage_device = (StorageDevice *)arg; + + if (!storage_device->ops->is_busy(storage_device)) { + spin_lock(&storage_device->queue_lock); + if (!list_empty(&storage_device->io_queue_lh)) { + StorageRequest *request = list_first_owner( + &storage_device->io_queue_lh, StorageRequest, list); + storage_submit_request(request); + } else if ( + list_in_list(&storage_device->block_cache_lh) && + !list_empty(&storage_device->block_cache_lh)) { + BlockCacheEntry *entry = list_first_owner( + &storage_device->block_cache_lh, BlockCacheEntry, list); + + rwlock_read_lock(&entry->lock); + + entry->cache->write( + entry, entry->cache->size, entry->cache->private_data); + list_del(&entry->list); + entry->dirty = false; + + rwlock_read_unlock(&entry->lock); + } + spin_unlock(&storage_device->queue_lock); + } +} + +// 需要修改storage_finish_request函数,支持分割请求的完成 +void storage_finish_request(StorageRequest *storage_request) { + storage_request->is_finished = true; + + // 处理合并请求的情况 + StorageRequest *req = storage_request->next_merged_request; + if (req) { + while (req) { + req->is_finished = true; + req = req->next_merged_request; + } + } + wait_queue_wakeup_thread( + &storage_request->storage_device->wq, storage_request->thread); +} + +void storage_submit_request(StorageRequest *request) { + StorageDevice *storage_device = request->storage_device; + if (request->buf == NULL && request->next_merged_request != NULL) { + request->buf = kmalloc(request->count * storage_device->block_size); + } + if (request->rw) { + storage_device->ops->submit_write_request(storage_device, request); + } else { + storage_device->ops->submit_read_request(storage_device, request); + } + if (list_in_list(&request->list)) list_del(&request->list); // TODO: bug +} + +void storage_solve_read_request(StorageRequest *request) { + // 处理合并请求的情况 + StorageRequest *req = request->next_merged_request; + if (req) { + uint32_t start = request->position; + while (req) { + uint32_t offset = + (req->position - start) * request->storage_device->block_size; + memcpy( + req->buf, request->buf + offset, + req->count * req->storage_device->block_size); + req = req->next_merged_request; + } + } +} + +void storage_solve_write_request(StorageRequest *request) { + StorageRequest *req = request->next_merged_request; + if (req) { + uint32_t start = request->position; + while (req) { + uint32_t offset = + (req->position - start) * request->storage_device->block_size; + // 写入需要分先后,由于合并请求时已经按顺序排列了,直接覆盖就好 + memcpy( + request->buf + offset, req->buf, + req->count * req->storage_device->block_size); + req = req->next_merged_request; + } + } +} diff --git a/src/driver/storage/volume.c b/src/driver/storage/volume.c new file mode 100644 index 0000000..2e65659 --- /dev/null +++ b/src/driver/storage/volume.c @@ -0,0 +1,45 @@ +#include "objects/object.h" +#include "string.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +void probe_volume(Partition *partition) { + Object *object = partition->storage_object; + StorageDevice *storage_device = + partition->storage_object->value.device.logical->dm_ext; + string_t prefix = storage_device->name; + partition->superblock = kmalloc(2 * SECTOR_SIZE); + + storage_transfer( + object, NULL, TRANSFER_IN, partition->superblock, partition->start_lba, + 2); + + if (partition->type == PARTITION_TYPE_MBR) { + FileSystem *fs; + list_for_each_owner (fs, &fs_list_head, list) { + if (fs->ops->fs_check(partition) == FS_OK) { + FileSystemInfo *fs_info = kmalloc(sizeof(FileSystemInfo)); + fs_info->partition = partition; + fs_info->ops = fs->ops; + string_t name; + string_new_with_string_number( + &name, prefix.text, prefix.length - 1, "Volume", 6, + partition->index); + ObjectAttr attr = device_object_attr; + Object *root_object = + create_object_directory(&volumes_object, &name, attr); + partition->object->fs_info = fs_info; + + object_mount(partition->object, root_object); + break; + } + } + } +} \ No newline at end of file diff --git a/src/driver/time_dm.c b/src/driver/time_dm.c new file mode 100644 index 0000000..3b744bb --- /dev/null +++ b/src/driver/time_dm.c @@ -0,0 +1,77 @@ +#include "kernel/device.h" +#include +#include +#include +#include +#include +#include + +DriverResult timer_dm_load(DeviceManager *manager); +DriverResult timer_dm_unload(DeviceManager *manager); + +DeviceManagerOps time_dm_ops = { + .dm_load = NULL, + .dm_unload = NULL, + + .init_device_hook = NULL, + .start_device_hook = NULL, + .stop_device_hook = NULL, + .destroy_device_hook = NULL, +}; + +TimeDeviceManager time_dm_ext; +DeviceManager time_dm = { + .type = DEVICE_TYPE_TIME, + .ops = &time_dm_ops, + .private_data = &time_dm_ext, +}; + +DriverResult create_time_device( + TimeDevice **time_device, TimeOps *time_ops, DeviceOps *ops, + PhysicalDevice *physical_device, DeviceDriver *device_driver) { + DriverResult result; + LogicalDevice *logical_device = NULL; + + result = create_logical_device( + &logical_device, physical_device, device_driver, ops, DEVICE_TYPE_TIME); + if (result != DRIVER_OK) return result; + + *time_device = kmalloc(sizeof(TimeDevice)); + if (*time_device == NULL) { + delete_logical_device(logical_device); + return DRIVER_ERROR_OUT_OF_MEMORY; + } + + TimeDevice *time = *time_device; + logical_device->dm_ext = time; + time->device = logical_device; + time->ops = time_ops; + return DRIVER_OK; +} + +DriverResult time_device_start(LogicalDevice *device) { + TimeDevice *time = (TimeDevice *)device->dm_ext; + + if (time_dm_ext.time_devices[time->device->type] == NULL) { + time_dm_ext.time_devices[time->device->type] = time; + } + return DRIVER_OK; +} + +DriverResult delete_time_device(TimeDevice *time_device) { + int result = 0; + + list_del(&time_device->device->dm_device_list); + DRIVER_RESULT_PASS(delete_logical_device(time_device->device)); + result = kfree(time_device); + if (result < 0) return DRIVER_ERROR_MEMORY_FREE; + return DRIVER_OK; +} + +DriverResult get_current_time(TimeType type, Time *time) { + TimeDevice *time_device = time_dm_ext.time_devices[type]; + if (time_device != NULL) { + return time_device->ops->get_time(time_device, type, time); + } + return DRIVER_ERROR_UNSUPPORT_FEATURE; +} diff --git a/src/driver/timer/Makefile b/src/driver/timer/Makefile new file mode 100644 index 0000000..e3dda15 --- /dev/null +++ b/src/driver/timer/Makefile @@ -0,0 +1,2 @@ +SRC += timer_dm.c +SRC += timer.c \ No newline at end of file diff --git a/src/driver/timer/config.toml b/src/driver/timer/config.toml new file mode 100644 index 0000000..1c2fc4c --- /dev/null +++ b/src/driver/timer/config.toml @@ -0,0 +1 @@ +c = ["timer_dm.c", "timer.c"] diff --git a/src/driver/timer/timer.c b/src/driver/timer/timer.c new file mode 100644 index 0000000..e833bd7 --- /dev/null +++ b/src/driver/timer/timer.c @@ -0,0 +1,88 @@ +#include "kernel/func.h" +#include +#include +#include +#include +#include +#include +#include + +extern TimerDeviceManager timer_dm_ext; + +DriverResult timer_init(Timer *timer) { + timer->timer_device = timer_dm_ext.scheduler_timer->dm_ext; + timer->timeout = 0; + return DRIVER_OK; +} + +DriverResult timer_set_timeout(Timer *timer, uint32_t count) { + if (timer->timer_device == NULL) return DRIVER_ERROR_NOT_EXIST; + uint32_t counter = timer->timer_device->counter; + timer->timeout = counter + count; + timer->will_wrap = (timer->timeout > counter) ? false : true; + + return DRIVER_OK; +} + +DriverResult timer_callback_enable(Timer *timer) { + if (timer == NULL || timer->timer_device == NULL) + return DRIVER_ERROR_NOT_EXIST; + // 在插入时排序 + if (!list_empty(&timer->timer_device->timer_callback_lh)) { + Timer *last_timer = list_last_owner( + &timer->timer_device->timer_callback_lh, Timer, list); + while (last_timer->timeout > timer->timeout) { + last_timer = list_prev_owner(last_timer, list); + } + list_add_after(&timer->list, &last_timer->list); + } else { + list_add_tail(&timer->list, &timer->timer_device->timer_callback_lh); + } + return DRIVER_OK; +} + +DriverResult timer_callback_cancel(Timer *timer) { + if (timer == NULL || timer->timer_device == NULL) + return DRIVER_ERROR_NOT_EXIST; + + if (list_in_list(&timer->list)) list_del(&timer->list); + else return DRIVER_ERROR_OTHER; + + return DRIVER_OK; +} + +uint32_t timer_count_ms(Timer *timer, uint32_t ms) { + uint32_t freq = timer->timer_device->current_frequency; + if (freq < 1000) { + return DIV_ROUND_UP(ms * freq, 1000); + } else { + return DIV_ROUND_UP(ms, (freq / 1000)); + } +} + +void delay_ms(Timer *timer, uint32_t ms) { + uint32_t count = timer_count_ms(timer, ms); + timer_set_timeout(timer, count); + + uint32_t status = load_interrupt_status(); + enable_interrupt(); + while (!timer_is_timeout(timer)) + io_hlt(); + store_interrupt_status(status); +} + +void delay_ms_async(Timer *timer, uint32_t ms) { + uint32_t count = timer_count_ms(timer, ms); + timer_set_timeout(timer, count); + // 设置完立即返回 +} + +bool timer_is_timeout(Timer *timer) { + uint32_t counter = timer->timer_device->counter; + return timer->will_wrap ? timer->timeout >= counter + : timer->timeout <= counter; +} + +size_t timer_get_counter() { + return ((TimerDevice *)timer_dm_ext.scheduler_timer->dm_ext)->counter; +} diff --git a/src/driver/timer/timer_dm.c b/src/driver/timer/timer_dm.c new file mode 100644 index 0000000..4c06e89 --- /dev/null +++ b/src/driver/timer/timer_dm.c @@ -0,0 +1,173 @@ +#include "kernel/console.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +const int default_frequencies[] = {100, 250, 1000}; + +DriverResult timer_dm_load(DeviceManager *manager); +DriverResult timer_dm_unload(DeviceManager *manager); +DriverResult timer_device_init(DeviceManager *manager, LogicalDevice *device); + +DeviceManagerOps timer_dm_ops = { + .dm_load = timer_dm_load, + .dm_unload = timer_dm_unload, + + .init_device_hook = timer_device_init, + .start_device_hook = NULL, + .stop_device_hook = NULL, + .destroy_device_hook = NULL, +}; + +TimerDeviceManager timer_dm_ext; + +struct DeviceManager timer_dm = { + .type = DEVICE_TYPE_TIMER, + + .ops = &timer_dm_ops, + + .private_data = &timer_dm_ext, +}; + +DriverResult timer_dm_load(DeviceManager *manager) { + timer_dm_ext.scheduler_timer = NULL; + + return DRIVER_OK; +} + +DriverResult timer_dm_unload(DeviceManager *manager) { + TimerDeviceManager *timer_manager = manager->private_data; + timer_manager->scheduler_timer = NULL; + + return DRIVER_OK; +} + +DriverResult timer_device_init(DeviceManager *manager, LogicalDevice *device) { + TimerDevice *timer_device = (TimerDevice *)device->dm_ext; + + const int count = + sizeof(default_frequencies) / sizeof(typeof(default_frequencies[0])); + int freq; + int min_error = 0xfffffff; // 误差 + int i; + for (i = 0; i < count; i++) { + int error = timer_device->source_frequency % default_frequencies[i]; + if (error < min_error || + (error == min_error && default_frequencies[i] > freq)) { + min_error = timer_device->source_frequency % default_frequencies[i]; + freq = default_frequencies[i]; + } + } + DRIVER_RESULT_PASS(timer_set_frequency(device, freq)); + + TimerDeviceManager *timer_manager = manager->private_data; + if (timer_manager->scheduler_timer == NULL) { + timer_manager->scheduler_timer = device; + } else { + TimerDevice *scheduler_timer_device = + (TimerDevice *)timer_manager->scheduler_timer->dm_ext; + if (scheduler_timer_device->priority < timer_device->priority) { + timer_manager->scheduler_timer = device; + } + } + return DRIVER_OK; +} + +int timer_get_schedule_tick(int priority) { + if (priority <= 0) { return 0; } + TimerDevice *timer_device = (TimerDevice *)timer_dm.private_data; + int ticks = priority * timer_device->current_frequency / 1000; + if (ticks == 0) { ticks = 1; } // 如果小于粒度,至少1个tick + return ticks; +} + +DriverResult timer_set_frequency(LogicalDevice *device, uint32_t frequency) { + TimerDevice *timer_device = (TimerDevice *)device->dm_ext; + + TimerResult result = + timer_device->timer_ops->set_frequency(timer_device, frequency); + + timer_device->current_frequency = frequency; + timer_device->counter = 0; + if (result != TIMER_RESULT_OK) { return DRIVER_ERROR_OTHER; } + return DRIVER_OK; +} + +void timer_irq_handler(LogicalDevice *device) { + TimerDevice *timer_device = (TimerDevice *)device->dm_ext; + timer_device->counter++; + + Timer *cur, *next; + list_for_each_owner_safe ( + cur, next, &timer_device->timer_callback_lh, list) { + if (!timer_is_timeout(cur)) { break; } + + list_del(&cur->list); + cur->timeout = 0; + if (cur->callback != NULL) cur->callback(cur->arg); + } + + if (!list_empty(&thread_all)) { + // 已启用多任务 + if (device == timer_dm_ext.scheduler_timer) { + struct task_s *cur_thread = get_current_thread(); + cur_thread->elapsed_ticks++; + + if (cur_thread->ticks == 0) { + // printk("need resched\n"); + cur_thread->flags.need_resched = 1; + } else { + cur_thread->ticks--; + } + } + } +} + +DriverResult create_timer_device( + TimerDevice **timer_device, TimerOps *timer_ops, DeviceOps *ops, + PhysicalDevice *physical_device, DeviceDriver *device_driver) { + DriverResult result; + LogicalDevice *logical_device = NULL; + + result = create_logical_device( + &logical_device, physical_device, device_driver, ops, + DEVICE_TYPE_TIMER); + if (result != DRIVER_OK) return result; + + *timer_device = kmalloc(sizeof(TimerDevice)); + if (*timer_device == NULL) { + delete_logical_device(logical_device); + return DRIVER_ERROR_OUT_OF_MEMORY; + } + TimerDevice *timer = *timer_device; + logical_device->dm_ext = timer; + timer->device = logical_device; + timer->timer_ops = timer_ops; + + list_init(&timer->timer_callback_lh); + + return DRIVER_OK; +} + +DriverResult delete_timer_device(TimerDevice *timer_device) { + Timer *timer, *next; + list_for_each_owner_safe ( + timer, next, &timer_device->timer_callback_lh, list) { + timer->timer_device = NULL; + timer->timeout = 0; + list_del(&timer->list); + } + + DRIVER_RESULT_PASS(delete_logical_device(timer_device->device)); + int result = kfree(timer_device); + if (result < 0) return DRIVER_ERROR_MEMORY_FREE; + + return DRIVER_OK; +} diff --git a/src/drivers/Makefile b/src/drivers/Makefile new file mode 100644 index 0000000..1460fd8 --- /dev/null +++ b/src/drivers/Makefile @@ -0,0 +1,2 @@ +SRC += bus/ +SRC += usb/ \ No newline at end of file diff --git a/src/drivers/bus/Makefile b/src/drivers/bus/Makefile new file mode 100644 index 0000000..3a34463 --- /dev/null +++ b/src/drivers/bus/Makefile @@ -0,0 +1 @@ +SRC += usb/ \ No newline at end of file diff --git a/src/drivers/bus/config.toml b/src/drivers/bus/config.toml new file mode 100644 index 0000000..21c43fe --- /dev/null +++ b/src/drivers/bus/config.toml @@ -0,0 +1 @@ +dir = ["usb/"] diff --git a/src/drivers/bus/usb/Makefile b/src/drivers/bus/usb/Makefile new file mode 100644 index 0000000..9547e5f --- /dev/null +++ b/src/drivers/bus/usb/Makefile @@ -0,0 +1,2 @@ +SRC += hcd.c +SRC += usb.c \ No newline at end of file diff --git a/src/drivers/bus/usb/config.toml b/src/drivers/bus/usb/config.toml new file mode 100644 index 0000000..5a38118 --- /dev/null +++ b/src/drivers/bus/usb/config.toml @@ -0,0 +1 @@ +c = ["hcd.c", "usb.c"] diff --git a/src/drivers/bus/usb/hcd.c b/src/drivers/bus/usb/hcd.c new file mode 100644 index 0000000..70720be --- /dev/null +++ b/src/drivers/bus/usb/hcd.c @@ -0,0 +1,79 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +LIST_HEAD(hcd_list); + +extern BusOps usb_bus_ops; + +DriverResult usb_create_hcd( + DEF_MRET(UsbHcd *, hcd), uint32_t port_cnt, UsbHcdOps *hcd_ops, + DeviceOps *ops, PhysicalDevice *physical_device, + DeviceDriver *device_driver) { + DriverResult ret = DRIVER_OK; + + if (usb_bus_driver.state != DRIVER_STATE_REGISTERED) + return DRIVER_ERROR_WAITING; + + LogicalDevice *logical_device = NULL; + DRIVER_RESULT_PASS(create_logical_device( + &logical_device, physical_device, device_driver, ops, + DEVICE_TYPE_BUS_CONTROLLER)); + + UsbHcd *hcd = kmalloc(sizeof(UsbHcd)); + if (hcd == NULL) { + ret = DRIVER_ERROR_OUT_OF_MEMORY; + goto failed_create_hcd; + } + MRET(hcd) = hcd; + hcd->device = logical_device; + hcd->ops = hcd_ops; + hcd->new_device_num = 0; + hcd->device_count = 0; + hcd->device = logical_device; + logical_device->dm_ext = hcd; + spinlock_init(&hcd->lock); + + ret = create_bus(&hcd->bus, &usb_bus_driver, &usb_bus_ops); + if (ret != DRIVER_OK) goto failed_create_bus; + + hcd->ports = kmalloc(sizeof(UsbHcdPort) * port_cnt); + if (hcd->ports == NULL) { + ret = DRIVER_ERROR_OUT_OF_MEMORY; + goto failed_create_ports; + } + for (int i = 0; i < port_cnt; i++) { + hcd->ports[i].port = i; + hcd->ports[i].hcd = hcd; + hcd->ports[i].connected = 0; + } + + list_add_tail(&hcd->list, &hcd_list); + list_add_tail(&hcd->bus->bus_check_list, &bus_check_lh); + list_init(&hcd->usb_device_lh); + + return DRIVER_OK; +failed_create_ports: + delete_bus(hcd->bus); + +failed_create_bus: + kfree(hcd); + +failed_create_hcd: + delete_logical_device(logical_device); + + return ret; +} diff --git a/src/drivers/bus/usb/usb.c b/src/drivers/bus/usb/usb.c new file mode 100644 index 0000000..1d6c783 --- /dev/null +++ b/src/drivers/bus/usb/usb.c @@ -0,0 +1,109 @@ +#include "kernel/device.h" +#include "kernel/spinlock.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define LH_INIT(type) [type] = LIST_HEAD_INIT(usb_driver_lh[type]) + +DriverResult usb_probe(BusDriver *bus_driver, Bus *bus); + +list_t usb_driver_lh[USB_INTERFACE_TYPE_MAX] = { + LH_INIT(USB_INTERFACE_TYPE_HID), + LH_INIT(USB_INTERFACE_TYPE_MASS_STORAGE), + LH_INIT(USB_INTERFACE_TYPE_HUB), + LH_INIT(USB_INTERFACE_TYPE_CDC_DATA), + LH_INIT(USB_INTERFACE_TYPE_SMART_CARD), + LH_INIT(USB_INTERFACE_TYPE_CONTENT_SECURITY), + LH_INIT(USB_INTERFACE_TYPE_VIDEO), + LH_INIT(USB_INTERFACE_TYPE_PERSONAL_HEALTHCARE), + LH_INIT(USB_INTERFACE_TYPE_AUDIO_VIDEO), + LH_INIT(USB_INTERFACE_TYPE_BILLBOARD), + LH_INIT(USB_INTERFACE_TYPE_TYPE_C_BRIDGE), + LH_INIT(USB_INTERFACE_TYPE_BULK_DISPLAY_PROTOCOL), + LH_INIT(USB_INTERFACE_TYPE_MTCP), + LH_INIT(USB_INTERFACE_TYPE_I3C), + LH_INIT(USB_INTERFACE_TYPE_DIAGNOSTIC), + LH_INIT(USB_INTERFACE_TYPE_WIRELESS_CONTROLLER), + LH_INIT(USB_INTERFACE_TYPE_MISCELLANEOUS), + LH_INIT(USB_INTERFACE_TYPE_APPLICATION_SPECIFIC), + LH_INIT(USB_INTERFACE_TYPE_VENDOR_SPECIFIC), +}; + +BusOps usb_bus_ops = { + .scan_bus = NULL, + .probe_device = usb_probe, +}; + +Driver usb_driver = { + .short_name = STRING_INIT("UsbDriver"), +}; +BusDriver usb_bus_driver = { + .name = STRING_INIT("USB"), +}; + +DriverResult usb_probe(BusDriver *bus_driver, Bus *bus) { + UsbDriver *usb_driver; + PhysicalDevice *device; + UsbInterface *interface; + list_for_each_owner (device, &bus->device_lh, device_list) { + UsbDevice *usb_device = device->bus_ext; + if (usb_device->state == USB_STATE_INITED) { + list_for_each_owner (interface, &usb_device->interface_lh, list) { + if (interface->usb_driver != NULL) { continue; } + uint8_t interface_type = + usb_interface_map[interface->desc->bInterfaceClass]; + list_for_each_owner ( + usb_driver, &usb_driver_lh[interface_type], list) { + if (usb_driver->probe != NULL) { + usb_driver->probe(usb_device, interface); + } + } + } + } + } + + return DRIVER_OK; +} + +DriverResult register_usb_driver(UsbDriver *usb_driver) { + list_add_tail( + &usb_driver->list, &usb_driver_lh[usb_driver->interface_type]); + return DRIVER_OK; +} + +DriverResult unregister_usb_driver(UsbDriver *usb_driver) { + list_del(&usb_driver->list); + return DRIVER_OK; +} + +static __init void usb_bus_driver_entry(void) { + DriverResult result; + + result = register_driver(&usb_driver); + if (result != DRIVER_OK) goto failed_register_driver; + + ObjectAttr attr = driver_object_attr; + result = + register_bus_driver(&usb_driver, BUS_TYPE_USB, &usb_bus_driver, &attr); + if (result != DRIVER_OK) goto failed_register_bus_driver; + + softirq_register_handler(SOFTIRQ_USB, usb_softirq_handler); + + return; +failed_register_bus_driver: + unregister_driver(&usb_driver); + +failed_register_driver: + return; +} + +driver_initcall(usb_bus_driver_entry); diff --git a/src/drivers/config.toml b/src/drivers/config.toml new file mode 100644 index 0000000..7442c33 --- /dev/null +++ b/src/drivers/config.toml @@ -0,0 +1 @@ +dir = ["bus/", "usb/"] diff --git a/src/drivers/usb/Makefile b/src/drivers/usb/Makefile new file mode 100644 index 0000000..bf1da59 --- /dev/null +++ b/src/drivers/usb/Makefile @@ -0,0 +1,2 @@ +SRC += hid/ +SRC += core/ \ No newline at end of file diff --git a/src/drivers/usb/config.toml b/src/drivers/usb/config.toml new file mode 100644 index 0000000..1571f7c --- /dev/null +++ b/src/drivers/usb/config.toml @@ -0,0 +1 @@ +dir = ["core/", "hid/"] diff --git a/src/drivers/usb/core/Makefile b/src/drivers/usb/core/Makefile new file mode 100644 index 0000000..96f2352 --- /dev/null +++ b/src/drivers/usb/core/Makefile @@ -0,0 +1,4 @@ +SRC += func.c +SRC += hub.c +SRC += usb.c +SRC += urb.c \ No newline at end of file diff --git a/src/drivers/usb/core/config.toml b/src/drivers/usb/core/config.toml new file mode 100644 index 0000000..985a26e --- /dev/null +++ b/src/drivers/usb/core/config.toml @@ -0,0 +1 @@ +c = ["func.c", "hub.c", "urb.c", "usb.c"] diff --git a/src/drivers/usb/core/func.c b/src/drivers/usb/core/func.c new file mode 100644 index 0000000..888af30 --- /dev/null +++ b/src/drivers/usb/core/func.c @@ -0,0 +1,261 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +void *usb_get_descriptor( + UsbHcd *hcd, UsbDevice *device, uint8_t type, uint8_t recipient, + uint8_t index, uint8_t value_hi, uint8_t value_lo, uint16_t desc_size) { + void *desc = kmalloc(desc_size); + + UsbControlRequest usb_req = USB_BUILD_REQUEST( + USB_REQ_DEVICE_TO_HOST, USB_REQ_TYPE_STANDARD, recipient, + USB_REQ_GET_DESCRIPTOR, value_hi, value_lo, index, desc_size); + + hcd->ops->ctrl_transfer_in(hcd, device, desc, desc_size, &usb_req); + return desc; +} + +void *usb_set_descriptor( + UsbHcd *hcd, UsbDevice *device, uint8_t type, uint8_t recipient, + uint8_t index, uint8_t value_hi, uint8_t value_lo, uint16_t desc_size) { + void *desc = kmalloc(desc_size); + + UsbControlRequest usb_req = USB_BUILD_REQUEST( + USB_REQ_HOST_TO_DEVICE, USB_REQ_TYPE_STANDARD, recipient, + USB_REQ_SET_DESCRIPTOR, value_hi, value_lo, index, desc_size); + + hcd->ops->ctrl_transfer_out(hcd, device, desc, desc_size, &usb_req); + return desc; +} + +struct UsbConfigDescriptor *usb_get_config_descriptor( + UsbHcd *hcd, UsbDevice *usb_device) { + struct UsbConfigDescriptor *desc = + kmalloc(sizeof(struct UsbConfigDescriptor)); + + UsbControlRequest usb_req = USB_BUILD_REQUEST( + USB_REQ_DEVICE_TO_HOST, USB_REQ_TYPE_STANDARD, USB_REQ_RECIPIENT_DEVICE, + USB_REQ_GET_DESCRIPTOR, USB_DESC_TYPE_CONFIG, 0, 0, + USB_DESC_TYPE_CONFIG_SIZE); + hcd->ops->ctrl_transfer_in( + hcd, usb_device, desc, USB_DESC_TYPE_CONFIG_SIZE, &usb_req); + + uint8_t *buffer = kmalloc(desc->wTotalLength); + usb_req.wLength = desc->wTotalLength; + hcd->ops->ctrl_transfer_in( + hcd, usb_device, buffer, usb_req.wLength, &usb_req); + + UsbInterface *interface = NULL; + int ep_num; + int length = desc->wTotalLength; + while (length > 0) { + uint8_t type = buffer[1]; + if (type == USB_DESC_TYPE_INTERFACE) { + struct UsbInterfaceDescriptor *interface_desc = + (struct UsbInterfaceDescriptor *)buffer; + interface = kmalloc( + sizeof(UsbInterface) + + sizeof(UsbEndpoint *) * interface_desc->bNumEndpoints); + + interface->usb_driver = NULL; + interface->desc = interface_desc; + + list_add_tail(&interface->list, &usb_device->interface_lh); + + ep_num = 0; + } else if (type == USB_DESC_TYPE_ENDPOINT) { + struct UsbEndpointDescriptor *endpoint_desc = + (struct UsbEndpointDescriptor *)buffer; + + UsbEndpoint *ep = kmalloc(sizeof(UsbEndpoint)); + usb_init_endpoint(usb_device, ep, endpoint_desc); + + if (interface) { + interface->endpoints[ep_num] = ep; + ep_num++; + } + list_add_tail(&ep->list, &usb_device->ep_lh); + } + length -= buffer[0]; + buffer += buffer[0]; + } + return desc; +} + +uint8_t usb_get_config(UsbHcd *hcd, UsbDevice *device) { + uint8_t config; + + UsbControlRequest usb_req = USB_BUILD_REQUEST( + USB_REQ_DEVICE_TO_HOST, USB_REQ_TYPE_STANDARD, USB_REQ_RECIPIENT_DEVICE, + USB_REQ_GET_CONFIGURATION, 0, 0, 0, 1); + hcd->ops->ctrl_transfer_in(hcd, device, &config, 1, &usb_req); + + return config; +} + +UsbSetupStatus usb_set_config(UsbHcd *hcd, UsbDevice *device, uint8_t config) { + + UsbControlRequest usb_req = USB_BUILD_REQUEST( + USB_REQ_HOST_TO_DEVICE, USB_REQ_TYPE_STANDARD, USB_REQ_RECIPIENT_DEVICE, + USB_REQ_SET_CONFIGURATION, config, 0, 0, 0); + return hcd->ops->ctrl_transfer_out(hcd, device, NULL, 0, &usb_req); +} + +struct UsbHubDescriptor *usb_get_hub_descriptor(UsbHub *hub) { + UsbDevice *device = hub->usb_device; + UsbHcd *hcd = device->hcd; + struct UsbHubDescriptor *desc = kmalloc(sizeof(struct UsbHubDescriptor)); + + UsbControlRequest usb_req = USB_BUILD_REQUEST( + USB_REQ_DEVICE_TO_HOST, USB_REQ_TYPE_CLASS, USB_REQ_RECIPIENT_DEVICE, + USB_REQ_GET_DESCRIPTOR, USB_DESC_TYPE_HUB, 0, 0, + USB_DESC_TYPE_HUB_SIZE); + hcd->ops->ctrl_transfer_in( + hcd, device, desc, USB_DESC_TYPE_HUB_SIZE, &usb_req); + return desc; +} + +uint32_t usb_get_hub_status(UsbHub *hub) { + uint32_t stat; + UsbDevice *device = hub->usb_device; + UsbHcd *hcd = device->hcd; + + UsbControlRequest usb_req = USB_BUILD_REQUEST( + USB_REQ_DEVICE_TO_HOST, USB_REQ_TYPE_STANDARD, USB_REQ_RECIPIENT_DEVICE, + USB_REQ_GET_STATUS, 0, 0, 0, 4); + hcd->ops->ctrl_transfer_in(hcd, device, &stat, 4, &usb_req); + return stat; +} + +uint32_t usb_get_port_status(UsbHub *hub, uint8_t port) { + uint32_t stat; + UsbDevice *device = hub->usb_device; + UsbHcd *hcd = device->hcd; + + UsbControlRequest usb_req = USB_BUILD_REQUEST( + USB_REQ_DEVICE_TO_HOST, USB_REQ_TYPE_CLASS, USB_REQ_RECIPIENT_OTHER, + USB_REQ_GET_STATUS, 0, 0, port, REQ_GET_PORT_STATUS_SIZE); + hcd->ops->ctrl_transfer_in( + hcd, device, &stat, REQ_GET_PORT_STATUS_SIZE, &usb_req); + return stat; +} + +struct UsbStringDescriptor *usb_get_string_descriptor( + UsbHcd *hcd, UsbDevice *device, uint8_t index) { + uint8_t buffer[2]; + + UsbControlRequest usb_req = USB_BUILD_REQUEST( + USB_REQ_DEVICE_TO_HOST, USB_REQ_TYPE_STANDARD, USB_REQ_RECIPIENT_DEVICE, + USB_REQ_GET_DESCRIPTOR, USB_DESC_TYPE_STRING, index, 0x0409, 2); + + hcd->ops->ctrl_transfer_in(hcd, device, buffer, 2, &usb_req); + + struct UsbStringDescriptor *desc = + kmalloc(sizeof(struct UsbStringDescriptor) + buffer[0]); + usb_req.wLength = buffer[0]; + hcd->ops->ctrl_transfer_in(hcd, device, desc, buffer[0], &usb_req); + + return desc; +} + +UsbSetupStatus usb_set_address( + UsbHcd *hcd, UsbDevice *device, uint32_t address) { + + UsbControlRequest req = USB_BUILD_REQUEST( + USB_REQ_HOST_TO_DEVICE, USB_REQ_TYPE_STANDARD, USB_REQ_RECIPIENT_DEVICE, + USB_REQ_SET_ADDRESS, address >> 8, address & 0xff, 0, 0); + + UsbSetupStatus status = + hcd->ops->ctrl_transfer_out(hcd, device, NULL, 0, &req); + + if (status == USB_SETUP_SUCCESS) device->address = address; + return status; +} + +UsbSetupStatus usb_clear_port_feature( + UsbHub *hub, uint8_t port, uint16_t feature) { + UsbDevice *device = hub->usb_device; + UsbHcd *hcd = device->hcd; + + UsbControlRequest req = USB_BUILD_REQUEST( + USB_REQ_HOST_TO_DEVICE, USB_REQ_TYPE_CLASS, USB_REQ_RECIPIENT_OTHER, + USB_REQ_CLEAR_FEATURE, feature >> 8, feature & 0xff, port, 0); + + return hcd->ops->ctrl_transfer_out(hcd, device, NULL, 0, &req); +} + +UsbSetupStatus usb_set_port_feature( + UsbHub *hub, uint8_t port, uint16_t feature) { + UsbDevice *device = hub->usb_device; + UsbHcd *hcd = device->hcd; + + UsbControlRequest req = USB_BUILD_REQUEST( + USB_REQ_HOST_TO_DEVICE, USB_REQ_TYPE_CLASS, USB_REQ_RECIPIENT_OTHER, + USB_REQ_SET_FEATURE, feature >> 8, feature & 0xff, port, 0); + + return hcd->ops->ctrl_transfer_out(hcd, device, NULL, 0, &req); +} + +void usb_show_device_descriptor( + UsbHcd *hcd, UsbDevice *device, struct UsbDeviceDescriptor *desc) { + printk("\nUSB Device Descriptor:\n"); + printk("Length: %d\n", desc->bLength); + printk("DescriptorType: %d\n", desc->bDescriptorType); + printk( + "Support USB Version: %x.%02x\n", desc->bcdUSB >> 8, + desc->bcdUSB & 0xff); + printk("Device Class: %d\n", desc->bDeviceClass); + printk("Device SubClass: %d\n", desc->bDeviceSubClass); + printk("Device Protocol: %d\n", desc->bDeviceProtocol); + printk("Max Packet Size: %d\n", desc->bMaxPacketSize0); + printk("Vendor ID: %d\n", desc->idVendor); + printk("Product ID: %d\n", desc->idProduct); + printk( + "Device Version: %x.%02x\n", desc->bcdDevice >> 8, + desc->bcdDevice & 0xff); + + printk("Manufacturer: "); + struct UsbStringDescriptor *str1 = + usb_get_string_descriptor(hcd, device, desc->iManufacturer); + for (int i = 0; i < (str1->bLength - 2) / 2; i++) { + printk("%c", str1->wData[i]); + } + printk("\n"); + + printk("Product: "); + struct UsbStringDescriptor *str2 = + usb_get_string_descriptor(hcd, device, desc->iProduct); + for (int i = 0; i < (str2->bLength - 2) / 2; i++) { + printk("%c", str2->wData[i]); + } + printk("\n"); + + printk("Serial Number: "); + struct UsbStringDescriptor *str3 = + usb_get_string_descriptor(hcd, device, desc->iSerialNumber); + for (int i = 0; i < (str3->bLength - 2) / 2; i++) { + printk("%c", str3->wData[i]); + } + printk("\n"); + + printk("Number of Configurations: %d\n", desc->bNumConfigurations); +} + +void usb_show_hub_descriptor(struct UsbHubDescriptor *desc) { + printk("\nUSB Hub Descriptor:\n"); + printk("Length: %d\n", desc->bLength); + printk("DescriptorType: %d\n", desc->bDescriptorType); + printk("Number of Ports: %d\n", desc->bNbrPorts); + printk("Characteristics: %d\n", desc->wHubCharacteristics); + printk("Power On To Power Good Time: %d\n", desc->bPwrOn2PwrGood); + printk("Hub Controller Current: %d\n", desc->bHubContrCurrent); + printk("Device Removable: %d\n", desc->DeviceRemovable); + printk("Port Power Control Mask: %d\n", desc->PortPwrCtrlMask); +} diff --git a/src/drivers/usb/core/hub.c b/src/drivers/usb/core/hub.c new file mode 100644 index 0000000..6155bc8 --- /dev/null +++ b/src/drivers/usb/core/hub.c @@ -0,0 +1,65 @@ +#include "kernel/console.h" +#include "kernel/thread.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +UsbHubOps usb_hub_ops = { + .init = NULL, + .clear_port_feature = usb_clear_port_feature, + .set_port_feature = usb_set_port_feature, + .get_hub_status = usb_get_hub_status, + .get_port_status = usb_get_port_status, +}; + +void usb_init_hub(UsbHcd *hcd, UsbHub *hub, UsbDevice *usb_device) { + Timer timer; + timer_init(&timer); + + uint32_t status = hub->ops->get_hub_status(hub); + + int i; + UsbSetupStatus status2; + + uint32_t port_status[hub->desc->bNbrPorts]; + for (i = 0; i < hub->desc->bNbrPorts; i++) { + port_status[i] = hub->ops->get_port_status(hub, i + 1); + if (BIN_IS_EN(port_status[i], USB_PORT_STAT_CONNECTION)) { + status2 = + hub->ops->set_port_feature(hub, i + 1, HUB_FEAT_PORT_POWER); + if (status2 == USB_SETUP_CRC_TIMEOUT_ERR) continue; + } + } + delay_ms(&timer, hub->desc->bPwrOn2PwrGood * 2); + + for (i = 0; i < hub->desc->bNbrPorts; i++) { + if (BIN_IS_EN(port_status[i], USB_PORT_STAT_CONNECTION)) { + status2 = + hub->ops->set_port_feature(hub, i + 1, HUB_FEAT_PORT_RESET); + if (status2 == USB_SETUP_CRC_TIMEOUT_ERR) continue; + } + } + + delay_ms(&timer, 200); + + for (i = 0; i < hub->desc->bNbrPorts; i++) { + status = port_status[i]; + if (BIN_IS_EN(status, USB_PORT_STAT_CONNECTION)) { + UsbDeviceSpeed speed = + BIN_IS_EN(status, USB_PORT_STAT_LOW_SPEED) ? USB_SPEED_LOW + : BIN_IS_EN(status, USB_PORT_STAT_HIGH_SPEED) ? USB_SPEED_HIGH + : USB_SPEED_FULL; + + usb_probe_device(hcd, hub, speed); + } + } + delay_ms(&timer, 100); +} \ No newline at end of file diff --git a/src/drivers/usb/core/urb.c b/src/drivers/usb/core/urb.c new file mode 100644 index 0000000..33596a0 --- /dev/null +++ b/src/drivers/usb/core/urb.c @@ -0,0 +1,28 @@ +#include "drivers/usb/core/usb.h" +#include +#include +#include + +LIST_HEAD(urb_lh); + +void usb_softirq_handler(void) { + UsbRequestBlock *urb, *next; + list_for_each_owner_safe (urb, next, &urb_lh, list) { + list_del(&urb->list); + if (urb->complete != NULL) { urb->complete(urb); } + } +} + +UsbRequestBlock *usb_create_urb( + UsbEndpoint *ep, void *context, uint8_t *buffer, uint32_t len, + void (*complete)(struct UsbRequestBlock *urb)) { + UsbRequestBlock *urb = kmalloc(sizeof(UsbRequestBlock)); + urb->ep = ep; + urb->context = context; + urb->buffer = buffer; + urb->len = len; + urb->actual_len = 0; + urb->status = USB_STATUS_ACK; + urb->complete = complete; + return urb; +} diff --git a/src/drivers/usb/core/usb.c b/src/drivers/usb/core/usb.c new file mode 100644 index 0000000..eff68d5 --- /dev/null +++ b/src/drivers/usb/core/usb.c @@ -0,0 +1,125 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +DeviceOps usb_device_ops = { + .init = NULL, + .start = NULL, + .stop = NULL, + .destroy = NULL, +}; + +struct UsbEndpointDescriptor ep0_desc = { + .bLength = sizeof(struct UsbEndpointDescriptor), + .bDescriptorType = USB_DESC_TYPE_ENDPOINT, + .bEndpointAddress = USB_EP_OUT << 7 | 0, // ep0 out + .bmAttributes = USB_EP_CONTROL, + .wMaxPacketSize = HOST2LE_WORD(64), + .bInterval = 0, +}; + +UsbDevice *usb_create_device( + UsbHcd *hcd, UsbHub *hub, UsbDeviceSpeed speed, uint8_t address) { + ObjectAttr attr = device_object_attr; + DriverResult result; + PhysicalDevice *physical_device; + + result = create_physical_device(&physical_device, hcd->bus, &attr); + if (result != DRIVER_OK) return NULL; + + UsbDevice *usb_device = (UsbDevice *)kmalloc(sizeof(UsbDevice)); + list_init(&usb_device->ep_lh); + list_init(&usb_device->interface_lh); + usb_device->desc = kmalloc(sizeof(struct UsbDeviceDescriptor)); + usb_device->speed = speed; + usb_device->address = address; + usb_device->state = USB_STATE_UNINITED; + usb_device->device = physical_device; + usb_device->hcd = hcd; + usb_device->hub = hub; + physical_device->bus_ext = usb_device; + + usb_device->ep0 = kmalloc(sizeof(UsbEndpoint)); + usb_init_endpoint(usb_device, usb_device->ep0, &ep0_desc); + + register_physical_device(physical_device, &usb_device_ops); + + return usb_device; +} + +int usb_destroy_device(UsbDevice *device) { + return kfree(device); +} + +UsbControlRequest *usb_create_request( + uint8_t direction, uint8_t type, uint8_t recipient, uint8_t request_id, + uint8_t value_hi, uint8_t value_lo, uint16_t index, uint16_t length) { + UsbControlRequest *request = + (UsbControlRequest *)kmalloc(sizeof(UsbControlRequest)); + request->bmRequestType = direction << 7 | type << 5 | recipient; + request->bRequest = request_id; + request->wValue = HOST2LE_WORD(value_hi << 8 | value_lo); + request->wIndex = HOST2LE_WORD(index); + request->wLength = HOST2LE_WORD(length); + return request; +} + +void usb_init_endpoint( + UsbDevice *usb_device, UsbEndpoint *ep, + struct UsbEndpointDescriptor *desc) { + ep->desc = desc; + + ep->pipe = usb_device->hcd->ops->create_pipeline(usb_device, ep); +} + +int usb_probe_device(UsbHcd *hcd, UsbHub *hub, UsbDeviceSpeed speed) { + UsbDevice *usb_device = usb_create_device(hcd, hub, speed, 0); + + struct UsbDeviceDescriptor *desc = + usb_get_device_descriptor(hcd, usb_device); + // usb_show_device_descriptor(hcd, device, desc); + + uint8_t address; + spin_lock(&hcd->lock); + hcd->new_device_num++; + hcd->device_count++; + address = hcd->new_device_num; + spin_unlock(&hcd->lock); + usb_set_address(hcd, usb_device, address); + + Timer timer; + timer_init(&timer); + delay_ms(&timer, 2); + + usb_device->address = address; + usb_get_config_descriptor(hcd, usb_device); + + usb_set_config(hcd, usb_device, 1); + + if (desc->bDeviceClass == USB_CLASS_HUB) { + UsbHub *new_hub = kmalloc(sizeof(UsbHub)); + new_hub->usb_device = usb_device; + new_hub->ops = &usb_hub_ops; + new_hub->hcd = hcd; + + new_hub->desc = usb_get_hub_descriptor(new_hub); + // usb_show_hub_descriptor(desc); + + usb_init_hub(hcd, new_hub, usb_device); + } + + usb_device->state = USB_STATE_INITED; + return 0; +} \ No newline at end of file diff --git a/src/drivers/usb/hid/Makefile b/src/drivers/usb/hid/Makefile new file mode 100644 index 0000000..49bfe7d --- /dev/null +++ b/src/drivers/usb/hid/Makefile @@ -0,0 +1,3 @@ +SRC += hid.c +SRC += mouse.c +SRC += keyboard.c \ No newline at end of file diff --git a/src/drivers/usb/hid/config.toml b/src/drivers/usb/hid/config.toml new file mode 100644 index 0000000..76102a6 --- /dev/null +++ b/src/drivers/usb/hid/config.toml @@ -0,0 +1 @@ +c = ["hid.c", "keyboard.c", "mouse.c"] diff --git a/src/drivers/usb/hid/hid.c b/src/drivers/usb/hid/hid.c new file mode 100644 index 0000000..ee12be0 --- /dev/null +++ b/src/drivers/usb/hid/hid.c @@ -0,0 +1,71 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +DriverResult usb_hid_probe(UsbDevice *device, UsbInterface *interface); + +DriverDependency usb_hid_dependencies[] = { + { + .in_type = DRIVER_DEPENDENCY_TYPE_BUS, + .dependency_in_bus = {BUS_TYPE_USB, 0}, + .out_bus = NULL, + }, +}; + +Driver usb_hid_driver = { + .short_name = STRING_INIT("HID"), +}; +UsbDriver usb_hid_usb_driver = { + .driver = &usb_hid_driver, + .interface_type = USB_INTERFACE_TYPE_HID, + .probe = usb_hid_probe, + .remove = NULL, +}; + +DriverResult usb_hid_probe(UsbDevice *usb_device, UsbInterface *interface) { + switch (interface->desc->bInterfaceSubClass) { + case USB_HID_SUBCLASS_NO: + // printk("HID Interface Found\n"); + return DRIVER_ERROR_UNSUPPORT_DEVICE; + case USB_HID_SUBCLASS_BOOT: + // printk("HID Boot Interface Found\n"); + break; + } + + switch (interface->desc->bInterfaceProtocol) { + case USB_HID_PROTOCOL_NONE: + printk("HID Protocol: None\n"); + break; + case USB_HID_PROTOCOL_KEYBOARD: + // printk("HID Protocol: Keyboard\n"); + if (interface->desc->bInterfaceSubClass == USB_HID_SUBCLASS_BOOT) { + usb_hid_keyboard_probe(usb_device, interface); + } + break; + case USB_HID_PROTOCOL_MOUSE: + // printk("HID Protocol: Mouse\n"); + if (interface->desc->bInterfaceSubClass == USB_HID_SUBCLASS_BOOT) { + // 先用基础功能,TODO: Report Descriptor + usb_hid_mouse_probe(usb_device, interface); + } + break; + default: + printk( + "HID Protocol: Unknown (%d)\n", + interface->desc->bInterfaceProtocol); + break; + } + return DRIVER_OK; +} + +static __init void usb_hid_driver_entry(void) { + register_driver(&usb_hid_driver); + register_usb_driver(&usb_hid_usb_driver); +} + +driver_initcall(usb_hid_driver_entry); diff --git a/src/drivers/usb/hid/keyboard.c b/src/drivers/usb/hid/keyboard.c new file mode 100644 index 0000000..5c37611 --- /dev/null +++ b/src/drivers/usb/hid/keyboard.c @@ -0,0 +1,147 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +DeviceDriver usb_hid_keyboard_device_driver; + +DriverResult usb_hid_keyboard_init(void *_device); +DriverResult usb_hid_keyboard_start(void *_device); + +DeviceOps usb_hid_keyboard_device_ops = { + .init = usb_hid_keyboard_init, + .start = usb_hid_keyboard_start, + .destroy = NULL, + .stop = NULL, +}; + +DeviceDriver usb_hid_keyboard_device_driver; +InputDevice usb_hid_keyboard_input_device = { + .type = INPUT_TYPE_KEYBOARD, +}; + +void usb_hid_keyboard_handler(UsbRequestBlock *urb) { + UsbHidKeyboardReport *report = (UsbHidKeyboardReport *)urb->buffer; + UsbHidKeyboard *keyboard = urb->context; + UsbDevice *usb_device = keyboard->usb_device; + if (urb->status == USB_STATUS_ACK) { + if (report->modifier_keys != keyboard->last_keys[0]) { + for (int i = 0; i < 8; i++) { + uint8_t mask = 1 << i; + if ((report->modifier_keys & mask) | + (keyboard->last_keys[0] & mask)) { + new_key_event( + INPUT_KEY_EVENT_MODIFIER_BASE + i, + keyboard->last_keys[0] & mask ? 0 : 1, + INPUT_KEY_PAGE_KEYBOARD_KEYPAD); + } + } + } + if (memcmp(&keyboard->last_keys[1], report->keycodes, 6) != 0) { + // 有按键变化 + for (int i = 0; i < 6; i++) { + if (report->keycodes[i] == keyboard->last_keys[i + 1]) { + continue; + } + + bool found1 = false, found2 = false; + for (int j = i; j < 6; j++) { + if (report->keycodes[i] == keyboard->last_keys[j + 1]) { + found1 = true; + } + if (keyboard->last_keys[i + 1] == report->keycodes[j]) { + found2 = true; + } + if (found1 && found2) break; + } + if (!found1) { + new_key_event( + INPUT_KEY_EVENT_KEYBOARD_BASE + report->keycodes[i], 1, + INPUT_KEY_PAGE_KEYBOARD_KEYPAD); + } + if (!found2) { + new_key_event( + INPUT_KEY_EVENT_KEYBOARD_BASE + + keyboard->last_keys[i + 1], + 0, INPUT_KEY_PAGE_KEYBOARD_KEYPAD); + } + } + } + memcpy(&keyboard->last_keys[1], report->keycodes, 6); + keyboard->last_keys[0] = report->modifier_keys; + urb->ep->data_toggle ^= 1; + usb_device->hcd->ops->interrupt_transfer(usb_device->hcd, urb->ep); + } else { + printk("Keyboard URB Error: %d\n", urb->status); + } +} + +DriverResult usb_hid_keyboard_init(void *_device) { + LogicalDevice *device = _device; + UsbHidKeyboard *keyboard = device->private_data; + struct UsbInterfaceDescriptor *interface = keyboard->interface->desc; + + UsbEndpoint *ep; + for (int i = 0; i < interface->bNumEndpoints; i++) { + ep = keyboard->interface->endpoints[i]; + if ((ep->desc->bmAttributes & 0x03) == USB_EP_INTERRUPT && + (ep->desc->bEndpointAddress >> 7) == USB_EP_IN) { + // 找到中断输入端点 + int size = ep->desc->wMaxPacketSize & 0x7ff; + keyboard->buffer = kmalloc(size); + keyboard->urb = usb_create_urb( + ep, keyboard, keyboard->buffer, size, usb_hid_keyboard_handler); + break; + } + } + return DRIVER_OK; +} + +DriverResult usb_hid_keyboard_start(void *_device) { + LogicalDevice *device = _device; + UsbHidKeyboard *keyboard = device->private_data; + UsbEndpoint *ep = keyboard->urb->ep; + ep->data_toggle = 1; + keyboard->usb_device->hcd->ops->add_interrupt_transfer( + keyboard->usb_device->hcd, keyboard->usb_device, ep, keyboard->urb); + return DRIVER_OK; +} + +DriverResult usb_hid_keyboard_probe( + UsbDevice *usb_device, UsbInterface *interface) { + PhysicalDevice *physical_device = usb_device->device; + + interface->usb_driver = &usb_hid_usb_driver; + + InputDevice *input_device; + DRIVER_RESULT_PASS(create_input_device( + &input_device, INPUT_TYPE_KEYBOARD, &usb_hid_keyboard_device_ops, + physical_device, &usb_hid_keyboard_device_driver)); + + UsbHidKeyboard *keyboard = kmalloc(sizeof(UsbHidKeyboard)); + keyboard->device = input_device; + keyboard->usb_device = usb_device; + keyboard->interface = interface; + input_device->device->private_data = keyboard; + + usb_device->state = USB_STATE_ACTIVE; + + return DRIVER_OK; +} + +static __init void usb_hid_keyboard_initcall() { + register_device_driver(&usb_hid_driver, &usb_hid_keyboard_device_driver); +} + +driver_initcall(usb_hid_keyboard_initcall); diff --git a/src/drivers/usb/hid/mouse.c b/src/drivers/usb/hid/mouse.c new file mode 100644 index 0000000..0342509 --- /dev/null +++ b/src/drivers/usb/hid/mouse.c @@ -0,0 +1,120 @@ +#include "driver/input/key_events.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +DeviceDriver usb_hid_mouse_device_driver; + +DriverResult usb_hid_mouse_init(void *_device); +DriverResult usb_hid_mouse_start(void *_device); + +DeviceOps usb_hid_mouse_device_ops = { + .init = usb_hid_mouse_init, + .start = usb_hid_mouse_start, + .destroy = NULL, + .stop = NULL, +}; + +DeviceDriver usb_hid_mouse_device_driver; +InputDevice usb_hid_mouse_input_device = { + .type = INPUT_TYPE_MOUSE, +}; + +void usb_hid_mouse_handler(UsbRequestBlock *urb) { + UsbHidMouseReport *report = (UsbHidMouseReport *)urb->buffer; + UsbHidMouse *mouse = urb->context; + UsbDevice *usb_device = mouse->usb_device; + if (urb->status == USB_STATUS_ACK) { + if (report->x != 0 || report->y != 0) { + new_pointer_event(report->x, report->y, POINTER_TYPE_MOVE); + } + if ((report->buttons ^ mouse->last_buttons) & 0x01) { // 左键变化 + new_key_event( + INPUT_KEY_EVENT_MOUSE_BASE + KEY_MOUSE_LEFT, + report->buttons & 0x01, INPUT_KEY_PAGE_KEYBOARD_KEYPAD); + } + if ((report->buttons ^ mouse->last_buttons) & 0x02) { // 右键变化 + new_key_event( + INPUT_KEY_EVENT_MOUSE_BASE + KEY_MOUSE_RIGHT, + (report->buttons >> 1) & 0x01, INPUT_KEY_PAGE_KEYBOARD_KEYPAD); + } + if ((report->buttons ^ mouse->last_buttons) & 0x04) { // 中键变化 + new_key_event( + INPUT_KEY_EVENT_MOUSE_BASE + KEY_MOUSE_MIDDLE, + (report->buttons >> 2) & 0x01, INPUT_KEY_PAGE_KEYBOARD_KEYPAD); + } + urb->ep->data_toggle ^= 1; + usb_device->hcd->ops->interrupt_transfer(usb_device->hcd, urb->ep); + } else { + printk("Mouse URB Error: %d\n", urb->status); + } +} + +DriverResult usb_hid_mouse_init(void *_device) { + LogicalDevice *device = _device; + UsbHidMouse *mouse = device->private_data; + struct UsbInterfaceDescriptor *interface = mouse->interface->desc; + + UsbEndpoint *ep; + for (int i = 0; i < interface->bNumEndpoints; i++) { + ep = mouse->interface->endpoints[i]; + if ((ep->desc->bmAttributes & 0x03) == USB_EP_INTERRUPT && + (ep->desc->bEndpointAddress >> 7) == USB_EP_IN) { + // 找到中断输入端点 + int size = ep->desc->wMaxPacketSize & 0x7ff; + mouse->buffer = kmalloc(size); + mouse->urb = usb_create_urb( + ep, mouse, mouse->buffer, size, usb_hid_mouse_handler); + break; + } + } + return DRIVER_OK; +} + +DriverResult usb_hid_mouse_start(void *_device) { + LogicalDevice *device = _device; + UsbHidMouse *mouse = device->private_data; + UsbEndpoint *ep = mouse->urb->ep; + ep->data_toggle = 1; + mouse->usb_device->hcd->ops->add_interrupt_transfer( + mouse->usb_device->hcd, mouse->usb_device, ep, mouse->urb); + return DRIVER_OK; +} + +DriverResult usb_hid_mouse_probe( + UsbDevice *usb_device, UsbInterface *interface) { + PhysicalDevice *physical_device = usb_device->device; + + interface->usb_driver = &usb_hid_usb_driver; + + InputDevice *input_device; + DRIVER_RESULT_PASS(create_input_device( + &input_device, INPUT_TYPE_MOUSE, &usb_hid_mouse_device_ops, + physical_device, &usb_hid_mouse_device_driver)); + + UsbHidMouse *mouse = kmalloc(sizeof(UsbHidMouse)); + mouse->device = input_device; + mouse->usb_device = usb_device; + mouse->interface = interface; + input_device->device->private_data = mouse; + + usb_device->state = USB_STATE_ACTIVE; + + return DRIVER_OK; +} + +static __init void usb_hid_mouse_initcall() { + register_device_driver(&usb_hid_driver, &usb_hid_mouse_device_driver); +} + +driver_initcall(usb_hid_mouse_initcall); diff --git a/src/fs/Makefile b/src/fs/Makefile index 50c90e4..5d0ed13 100644 --- a/src/fs/Makefile +++ b/src/fs/Makefile @@ -1,3 +1,5 @@ -SRC += fat32.c +# SRC += fat32.c SRC += fs.c -SRC += vfs.c \ No newline at end of file +# SRC += vfs.c + +SRC += fat/ \ No newline at end of file diff --git a/src/fs/config.toml b/src/fs/config.toml new file mode 100644 index 0000000..e211fa6 --- /dev/null +++ b/src/fs/config.toml @@ -0,0 +1,2 @@ +dir = ["fat/"] +c = ["fs.c"] diff --git a/src/fs/fat/Makefile b/src/fs/fat/Makefile new file mode 100644 index 0000000..4827668 --- /dev/null +++ b/src/fs/fat/Makefile @@ -0,0 +1,7 @@ +SRC += fat.c +SRC += cluster.c +SRC += dir.c +SRC += name.c +SRC += entry.c +SRC += time.c +SRC += attr.c \ No newline at end of file diff --git a/src/fs/fat/attr.c b/src/fs/fat/attr.c new file mode 100644 index 0000000..3cf7d5e --- /dev/null +++ b/src/fs/fat/attr.c @@ -0,0 +1,83 @@ +#include "fs/fs.h" +#include "include/dir.h" +#include "include/fat.h" +#include "kernel/driver_interface.h" +#include +#include +#include +#include +#include + +FsResult fat_attr_to_sys_attr( + ShortDir *short_dir, ObjectAttr *attr, FatLocation *location) { + uint8_t fat_attr = short_dir->attr; + if (fat_attr & ATTR_ARCHIVE) { + attr->fs_location = kmalloc_from_template(*location); + attr->size = short_dir->file_size; + attr->is_mounted = 0; + Permission *all_user = &attr->all_user_permission; + Permission *system = &attr->system_permission; + Permission *owner = &attr->owner_permission; + Permission *admin = &attr->admin_permission; + memset(&all_user->permission, 0xff, sizeof(all_user->permission)); + memset(&system->permission, 0xff, sizeof(system->permission)); + memset(&owner->permission, 0xff, sizeof(owner->permission)); + memset(&admin->permission, 0xff, sizeof(admin->permission)); + all_user->subject_id = SUBJECT_ID_ALL; + system->subject_id = SUBJECT_ID_SYSTEM; + admin->subject_id = SUBJECT_ID_ADMIN; + + if (fat_attr & ATTR_SYSTEM) { + all_user->permission.read = 0; + all_user->permission.write = 0; + all_user->permission.execute = 0; + all_user->permission.delete = 0; + all_user->permission.rename = 0; + admin->permission.delete = 0; + admin->permission.rename = 0; + admin->permission.write = 0; + owner->subject_id = SUBJECT_ID_SYSTEM; + attr->owner_id = SUBJECT_ID_SYSTEM; + } else { + owner->subject_id = SUBJECT_ID_ALL; + attr->owner_id = SUBJECT_ID_ALL; + } + if (fat_attr & ATTR_DIRECTORY) { + attr->type = OBJECT_TYPE_DIRECTORY; + if (fat_attr & ATTR_SYSTEM) { all_user->permission.execute = 1; } + } else { + attr->type = OBJECT_TYPE_FILE; + } + + if (fat_attr & ATTR_READ_ONLY) { + attr->all_user_permission.permission.write = 0; + } + if (fat_attr & ATTR_HIDDEN) { + attr->all_user_permission.permission.visible = 0; + } + } + return FS_OK; +} + +FsResult fat_attr_from_sys_attr( + ShortDir *short_dir, ObjectAttr *attr, FatLocation *location) { + Permission *all_user = &attr->all_user_permission; + Permission *owner = &attr->owner_permission; + + short_dir->attr = ATTR_ARCHIVE; + location = attr->fs_location; + if (all_user->permission.write == 0 && all_user->permission.read == 1) { + short_dir->attr |= ATTR_READ_ONLY; + } + if (all_user->permission.visible == 0) { short_dir->attr |= ATTR_HIDDEN; } + if (attr->type == OBJECT_TYPE_DIRECTORY) { + short_dir->attr |= ATTR_DIRECTORY; + } else { + short_dir->file_size = attr->size; + } + if (owner->subject_id == SUBJECT_ID_SYSTEM) { + short_dir->attr |= ATTR_SYSTEM; + } + + return FS_OK; +} diff --git a/src/fs/fat/cluster.c b/src/fs/fat/cluster.c new file mode 100644 index 0000000..caff24c --- /dev/null +++ b/src/fs/fat/cluster.c @@ -0,0 +1,320 @@ +#include "include/cluster.h" +#include "include/dir.h" +#include "include/fat.h" +#include "multiple_return.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +inline uint32_t cluster2sector(FatInfo *fat_info, uint32_t cluster) { + return fat_info->data_start + (cluster - 2) * fat_info->bpb->BPB_SecPerClus; +} + +FsResult fat_table_read( + BlockCacheEntry *entry, size_t cache_size, void *private_data) { + FatInfo *fat_info = private_data; + Partition *partition = fat_info->partition; + + int count = cache_size / SECTOR_SIZE; + + TRANSFER_IN_BLOCK( + partition->storage_object, NULL, entry->data, + fat_info->fat_start + entry->position, count); + return FS_OK; +} + +FsResult fat_table_write( + BlockCacheEntry *entry, size_t cache_size, void *private_data) { + FatInfo *fat_info = private_data; + Partition *partition = fat_info->partition; + + int count = cache_size / SECTOR_SIZE; + + for (int i = 0; i < fat_info->bpb->BPB_NumFATs; i++) { + TRANSFER_OUT_BLOCK( + partition->storage_object, NULL, entry->data, + fat_info->fat_start + entry->position, count); + } + + return FS_OK; +} + +uint32_t get_next_cluster(FatInfo *fat_info, uint32_t cluster) { + uint32_t index = cluster / fat_info->num_count; + uint32_t offset = cluster % fat_info->num_count; + + BlockCacheEntry *entry = block_cache_read(fat_info->fat_table_cache, index); + if (entry == NULL) return 0xffffffff; + uint32_t data = 0xffffffff; + if (fat_info->type == FAT_TYPE_FAT32) { + data = ((uint32_t *)entry->data)[offset]; + } else if (fat_info->type == FAT_TYPE_FAT16) { + data = ((uint16_t *)entry->data)[offset]; + } + block_cache_read_done(entry); + + return data; +} + +void set_cluster(FatInfo *fat_info, uint32_t cluster, uint32_t data) { + uint32_t index = cluster / fat_info->num_count; + uint32_t offset = cluster % fat_info->num_count; + + BlockCacheEntry *entry = + block_cache_write(fat_info->fat_table_cache, index); + + if (fat_info->type == FAT_TYPE_FAT32) { + ((uint32_t *)entry->data)[offset] = data; + } else if (fat_info->type == FAT_TYPE_FAT16) { + ((uint16_t *)entry->data)[offset] = data & 0xffff; + } + + block_cache_write_done(fat_info->storage_device, entry); +} + +FsResult alloc_cluster( + FatInfo *fat_info, uint32_t last_cluster, bool is_first_cluster, + uint32_t *out_cluster) { + + // 1.先找到一个空闲的簇 + uint32_t index = fat_info->last_cluster / fat_info->num_count; + uint32_t offset = fat_info->last_cluster % fat_info->num_count; + + int i; + bool finded = false; + while (index < fat_info->fat_sectors && !finded) { + BlockCacheEntry *entry = + block_cache_read(fat_info->fat_table_cache, index); + for (i = offset; i < fat_info->num_count; i++) { + if (((uint32_t *)entry->data)[i] == 0) { + finded = true; + break; + } + } + block_cache_read_done(entry); + + index++; + offset = 0; + } + fat_info->last_cluster = index * fat_info->num_count + i; + if (finded) { + set_cluster(fat_info, index * fat_info->num_count + i, 0x0fffffff); + *out_cluster = index * fat_info->num_count + i; + } else { + return FS_ERROR_NO_SPARE_SPACE; + } + + if (!is_first_cluster) { + // 2.将上一个簇的FAT表项指向新分配的簇 + set_cluster(fat_info, last_cluster, *out_cluster); + } + + return FS_OK; +} + +FsResult free_cluster( + FatInfo *fat_info, uint32_t cluster, uint32_t *out_cluster) { + uint32_t index = cluster / fat_info->num_count; + uint32_t offset = cluster % fat_info->num_count; + + BlockCacheEntry *entry; + + if (out_cluster != NULL) { + entry = block_cache_read(fat_info->fat_table_cache, index); + if (fat_info->type == FAT_TYPE_FAT32) { + *out_cluster = ((uint32_t *)entry->data)[offset]; + } else if (fat_info->type == FAT_TYPE_FAT16) { + *out_cluster = ((uint16_t *)entry->data)[offset]; + } + block_cache_read_done(entry); + } + + set_cluster(fat_info, cluster, 0); + + return FS_OK; +} + +inline bool is_eof(FatInfo *fat_info, uint32_t cluster) { + if (fat_info->type == FAT_TYPE_FAT32) { + return cluster >= 0x0FFFFFF8; + } else if (fat_info->type == FAT_TYPE_FAT16) { + return cluster >= 0xFFF8; + } else if (fat_info->type == FAT_TYPE_FAT12) { + return cluster >= 0x0FF8; + } + return false; +} + +FsResult get_cluster_segment(FatInfo *fat_info, FatDirEntry *entry) { + DynArray *arr = entry->cluster_list; + ClusterSegment segment; + + uint32_t cluster; + if (arr->size == 0) { + // 如果为空使用第一个簇 + cluster = entry->short_dir.first_cluster_low; + if (fat_info->type == FAT_TYPE_FAT32) { + cluster |= entry->short_dir.first_cluster_high << 16; + } + } else { + // 否则使用最后一个簇的下一个簇 + cluster = + ((ClusterSegment)dyn_array_get(arr, ClusterSegment, arr->size - 1)) + .end; + if (is_eof(fat_info, cluster)) { return FS_ERROR_END_OF_FILE; } + cluster = get_next_cluster(fat_info, cluster); + } + segment.start = cluster; + + int offset = cluster % fat_info->bpb->BPB_BytesPerSec; + int max = cluster + fat_info->bpb->BPB_BytesPerSec - offset; + while (!is_eof(fat_info, cluster) && cluster < max) { + uint32_t tmp = get_next_cluster(fat_info, cluster); + if (tmp != cluster + 1) { + segment.end = cluster; + dyn_array_append(arr, ClusterSegment, segment); + if (tmp < 2) return FS_ERROR_ILLEGAL_DATA; + else return FS_OK; + } + cluster = tmp; + } + if (cluster == max) { + segment.end = cluster; + dyn_array_append(arr, ClusterSegment, segment); + return FS_OK; + } + + segment.start = segment.end = 0x0fffffff; + dyn_array_append(arr, ClusterSegment, segment); + + return FS_OK; +} + +FsResult fat_cluster_list_get( + FatInfo *fat_info, FatDirEntry *entry, uint32_t index, + CurrentCluster *cur_cluster) { + DynArray *arr = entry->cluster_list; + + int counter = index; + + ClusterSegment *clus_seg; + dyn_array_foreach(arr, ClusterSegment, clus_seg) { + int length = clus_seg->end - clus_seg->start + 1; + if (counter < length) { + cur_cluster->cluster = clus_seg->start + counter; + cur_cluster->offset = _block_offset; + cur_cluster->block = _block; + cur_cluster->index = index; + cur_cluster->entry = entry; + return FS_OK; + } + counter -= length; + } + + return FS_OK; +} + +FsResult fat_cluster_list_get_next( + FatInfo *fat_info, FatDirEntry *entry, CurrentCluster *cur_cluster) { + FsResult result; + ClusterSegment *seg = + &((ClusterSegment *)cur_cluster->block->data)[cur_cluster->offset]; + if (cur_cluster->cluster < seg->end) { + cur_cluster->cluster++; + } else { + cur_cluster->offset++; + if (cur_cluster->offset >= entry->cluster_list->block_size) { + cur_cluster->offset = 0; + if (cur_cluster->block->next == NULL) { + result = get_cluster_segment(fat_info, entry); + if (result != FS_OK) return result; + } + cur_cluster->block = cur_cluster->block->next; + } + seg = + &((ClusterSegment *)cur_cluster->block->data)[cur_cluster->offset]; + if (cur_cluster->offset >= (entry->cluster_list->block_size - + cur_cluster->block->left_space)) { + FS_RESULT_PASS(get_cluster_segment(fat_info, entry)); + } + cur_cluster->cluster = seg->start; + } + cur_cluster->index++; + return FS_OK; +} + +uint32_t get_remaining_continuous_clusters( + FatInfo *fat_info, CurrentCluster *cur_cluster) { + uint32_t current = cur_cluster->cluster; + ClusterSegment *seg = + &((ClusterSegment *)cur_cluster->block->data)[cur_cluster->offset]; + if (seg->end == current) { + FsResult result = fat_cluster_list_get_next( + fat_info, cur_cluster->entry, cur_cluster); + if (result != FS_OK) return 0; + seg = + &((ClusterSegment *)cur_cluster->block->data)[cur_cluster->offset]; + } + + return seg->end - current; +} + +FsResult fat_cluster_list_skip( + FatInfo *fat_info, FatDirEntry *entry, CurrentCluster *cur_cluster, + int count) { + ClusterSegment *seg = + &((ClusterSegment *)cur_cluster->block->data)[cur_cluster->offset]; + uint32_t current = cur_cluster->cluster; + uint32_t end = seg->end; + if (current + count <= end) { + cur_cluster->cluster += count; + } else { + count -= end - current + 1; + cur_cluster->offset++; + if (cur_cluster->offset >= entry->cluster_list->block_size) { + cur_cluster->block = cur_cluster->block->next; + cur_cluster->offset = 0; + } + seg = + &((ClusterSegment *)cur_cluster->block->data)[cur_cluster->offset]; + while (count > seg->end - seg->start + 1) { + count -= seg->end - seg->start + 1; + cur_cluster->offset++; + if (cur_cluster->offset >= entry->cluster_list->block_size) { + if (cur_cluster->block->next == NULL) { + FS_RESULT_PASS(get_cluster_segment(fat_info, entry)); + } + cur_cluster->block = cur_cluster->block->next; + cur_cluster->offset = 0; + } + seg = &((ClusterSegment *) + cur_cluster->block->data)[cur_cluster->offset]; + } + cur_cluster->cluster = seg->start + count; + } + return FS_OK; +} + +FsResult get_last_cluster( + FatInfo *fat_info, FatDirEntry *entry, DEF_MRET(uint32_t, last_cluster)) { + DynArray *arr = entry->cluster_list; + ClusterSegment seg, tmp; + + tmp = dyn_array_get(arr, ClusterSegment, arr->size - 1); + if (!is_eof(fat_info, tmp.end)) { + while (!is_eof(fat_info, tmp.end)) { + seg = tmp; + FS_RESULT_PASS(get_cluster_segment(fat_info, entry)); + tmp = dyn_array_get(arr, ClusterSegment, arr->size - 1); + } + } + MRET(last_cluster) = seg.end; + return FS_OK; +} diff --git a/src/fs/fat/config.toml b/src/fs/fat/config.toml new file mode 100644 index 0000000..370b264 --- /dev/null +++ b/src/fs/fat/config.toml @@ -0,0 +1 @@ +c = ["attr.c", "cluster.c", "dir.c", "entry.c", "fat.c", "name.c"] diff --git a/src/fs/fat/dir.c b/src/fs/fat/dir.c new file mode 100644 index 0000000..c68139d --- /dev/null +++ b/src/fs/fat/dir.c @@ -0,0 +1,262 @@ +#include "include/dir.h" +#include "include/cluster.h" +#include "include/entry.h" +#include "include/fat.h" +#include "include/name.h" +#include "multiple_return.h" +#include "types.h" +#include +#include +#include +#include +#include +#include + +void fat_dir_iterator_init( + FatDirIterator *iter, FatInfo *fat_info, FatDirEntry *dir) { + iter->fat_info = fat_info; + iter->dir_entry = dir; + fat_cluster_list_get(fat_info, dir, 0, &iter->current_cluster); + iter->entry_index = 0; + if (fat_info->use_longname) { + iter->longname_buf = kmalloc(MAX_LONGNAME * sizeof(uint16_t)); + } else { + iter->longname_buf = NULL; + } + iter->longname_len = 0; + iter->checksum = 0; + iter->longname_valid = false; + iter->longname_cluster = iter->current_cluster.cluster; + iter->longname_entry_index = 0; + iter->last_cluster = 0; + iter->last_entry_index = 0; +} + +void fat_dir_iterator_next(FatDirIterator *iter) { + // 重置长名状态 + iter->longname_len = 0; + iter->longname_valid = false; +} + +void fat_dir_iterator_destroy(FatDirIterator *iter) { + if (iter->longname_buf != NULL) kfree(iter->longname_buf); +} + +static inline FsResult fat_read_entry(FatDirIterator *iter, uint8_t *buf) { + return fat_entry_read( + iter->fat_info, iter->dir_entry, iter->current_cluster.cluster, + iter->entry_index, buf); +} + +static inline bool is_long_entry(ShortDir *short_dir) { + return short_dir->attr == ATTR_LONG_NAME; +} + +PRIVATE void process_long_entry( + FatDirIterator *iter, uint32_t current_cluster, int current_entry_index, + LongDir *entry) { + // 检查顺序标识 + uint8_t order = entry->order & 0x3F; + if (order == 0) return; + + // 起始条目初始化缓冲区 + if (entry->order & 0x40) { + iter->longname_len = 0; + iter->checksum = entry->checksum; + iter->longname_cluster = current_cluster; + iter->longname_entry_index = current_entry_index; + iter->longname_valid = true; + } + + iter->longname_len += + read_long_name(entry, iter->longname_buf + (order - 1) * 13); +} + +PRIVATE FsResult process_short_entry( + FatDirIterator *iter, ShortDir *short_dir, uint32_t current_cluster, + int current_entry_index) { + // 验证长名校验和 + if (iter->longname_len > 0) { + if (fat_checksum(&short_dir->name) != iter->checksum) { + iter->longname_len = 0; + } + } + return FS_OK; +} + +FsResult fat32_read_dir_entry( + FatDirIterator *iter, DEF_MRET(ShortDir, short_dir)) { + uint8_t entry_buf[32]; + ShortDir *short_dir = (ShortDir *)entry_buf; + LongDir *long_dir; + + while (1) { + // 读取当前条目 + FS_RESULT_PASS(fat_read_entry(iter, entry_buf)); + iter->last_cluster = iter->current_cluster.cluster; + iter->last_entry_index = iter->entry_index; + // 读取完立即更新索引 + if (++iter->entry_index >= iter->fat_info->entry_per_cluster) { + // 获取下一个簇 + uint32_t next = fat_cluster_list_get_next( + iter->fat_info, iter->dir_entry, &iter->current_cluster); + if (is_eof(iter->fat_info, next)) return FS_ERROR_CANNOT_FIND; + iter->entry_index = 0; + } + + // 处理目录结束标记 + if (entry_buf[0] == 0x00) return FS_ERROR_CANNOT_FIND; + // 跳过已删除条目 + if (entry_buf[0] == 0xE5) continue; + + if (is_long_entry(short_dir)) { + // 处理长文件名条目 + long_dir = (LongDir *)entry_buf; + process_long_entry( + iter, iter->last_cluster, iter->last_entry_index, long_dir); + } else { + MRET(short_dir) = *short_dir; + // 处理短文件名条目 + return process_short_entry( + iter, short_dir, iter->last_cluster, iter->last_entry_index); + } + } +} + +FsResult fat_read_dir_entry( + FatDirIterator *iter, DEF_MRET(ShortDir, short_dir)) { + uint8_t entry_buf[32]; + ShortDir *short_dir; + + uint32_t current_cluster; + int current_entry_index; + + while (1) { + // 读取当前条目 + FS_RESULT_PASS(fat_read_entry(iter, entry_buf)); + current_cluster = iter->current_cluster.cluster; + current_entry_index = iter->entry_index; + // 读取完立即更新索引 + if (++iter->entry_index >= iter->fat_info->entry_per_cluster) { + // 跳转到下一个簇 + uint32_t next = fat_cluster_list_get_next( + iter->fat_info, iter->dir_entry, &iter->current_cluster); + if (is_eof(iter->fat_info, next)) return FS_ERROR_CANNOT_FIND; + iter->entry_index = 0; + } + + short_dir = (ShortDir *)entry_buf; + + // 处理目录结束标记 + if (entry_buf[0] == 0x00) return FS_ERROR_CANNOT_FIND; + + // 跳过已删除条目 + if (entry_buf[0] == 0xE5) continue; + + // 处理短文件名条目 + MRET(short_dir) = *short_dir; + return process_short_entry( + iter, short_dir, current_cluster, current_entry_index); + } +} + +FsResult fat32_dir_lookup( + FatInfo *fat_info, FatDirEntry *parent_entry, string_t name, + DEF_MRET(FatLocation, location), DEF_MRET(ShortDir, short_dir)) { + FatDirIterator iter; + string_t _name; + uint8_t entry_buf[0x20]; + ShortDir *short_dir = (ShortDir *)entry_buf; + fat_dir_iterator_init(&iter, fat_info, parent_entry); + while (fat32_read_dir_entry(&iter, short_dir) == FS_OK) { + // 生成文件名 + if (iter.longname_valid) { + fat_utf16_to_utf8(iter.longname_buf, iter.longname_len, &_name); + } else { + _name = read_short_name(short_dir); + } + fat_dir_iterator_next(&iter); + + if (strncmp(_name.text, name.text, name.length) == 0) { + string_del(&_name); + fat_dir_iterator_destroy(&iter); + MRET(location).longname_cluster = iter.longname_cluster; + MRET(location).longname_offset = iter.longname_entry_index; + MRET(location).shortname_cluster = iter.last_cluster; + MRET(location).shortname_offset = iter.last_entry_index; + MRET(location).parent_cluster = + parent_entry->short_dir.first_cluster_high << 16 | + parent_entry->short_dir.first_cluster_low; + MRET(location).first_cluster = short_dir->first_cluster_high << 16 | + short_dir->first_cluster_low; + MRET(short_dir) = *short_dir; + return FS_OK; + } + } + fat_dir_iterator_destroy(&iter); + return FS_ERROR_CANNOT_FIND; +} + +FsResult fat_dir_lookup( + FatInfo *fat_info, FatDirEntry *parent_entry, string_t name, + DEF_MRET(FatLocation, location), DEF_MRET(ShortDir, short_dir)) { + FatDirIterator iter; + string_t _name; + uint8_t entry_buf[0x20]; + ShortDir *short_dir = (ShortDir *)entry_buf; + + fat_dir_iterator_init(&iter, fat_info, parent_entry); + while (fat_read_dir_entry(&iter, short_dir) == FS_OK) { + // 生成文件名 + if (iter.longname_valid) { + fat_utf16_to_utf8(iter.longname_buf, iter.longname_len, &_name); + } else { + _name = read_short_name(short_dir); + } + fat_dir_iterator_next(&iter); + + if (strncmp(_name.text, name.text, name.length) == 0) { + string_del(&_name); + fat_dir_iterator_destroy(&iter); + MRET(location).longname_cluster = iter.longname_cluster; + MRET(location).longname_offset = iter.longname_entry_index; + MRET(location).shortname_cluster = iter.last_cluster; + MRET(location).shortname_offset = iter.last_entry_index; + MRET(location).parent_cluster = + parent_entry->short_dir.first_cluster_high << 16 | + parent_entry->short_dir.first_cluster_low; + MRET(location).first_cluster = short_dir->first_cluster_high << 16 | + short_dir->first_cluster_low; + MRET(short_dir) = *short_dir; + return FS_OK; + } + } + fat_dir_iterator_destroy(&iter); + return FS_ERROR_CANNOT_FIND; +} + +bool fat_dir_is_empty(FatInfo *fat_info, FatDirEntry *parent_entry) { + FatDirIterator iter; + + uint8_t entry_buf[0x20]; + ShortDir *short_dir = (ShortDir *)entry_buf; + + FsResult result = FS_OK; + + fat_dir_iterator_init(&iter, fat_info, parent_entry); + while (1) { + result = fat_read_entry(&iter, entry_buf); + if (result != FS_OK) break; + + if (entry_buf[0] == 0xe5 || entry_buf[0] == 0x05) continue; + if (short_dir->attr == ATTR_LONG_NAME) continue; + if (entry_buf[0] == '.') continue; + + if (entry_buf[0] != 0) { + fat_dir_iterator_destroy(&iter); + return false; + } + } + fat_dir_iterator_destroy(&iter); + return true; +} diff --git a/src/fs/fat/entry.c b/src/fs/fat/entry.c new file mode 100644 index 0000000..21243a2 --- /dev/null +++ b/src/fs/fat/entry.c @@ -0,0 +1,329 @@ +#include "include/entry.h" +#include "include/attr.h" +#include "include/cluster.h" +#include "include/dir.h" +#include "include/fat.h" +#include "include/name.h" +#include "include/time.h" +#include "kernel/memory.h" +#include "multiple_return.h" +#include "objects/object.h" +#include +#include +#include +#include +#include +#include +#include + +PRIVATE FsResult +entry_read(BlockCacheEntry *entry, size_t cache_size, void *private_data) { + FatInfo *fat_info = private_data; + Partition *partition = fat_info->partition; + + int count = DIV_ROUND_UP(cache_size, fat_info->bpb->BPB_BytesPerSec); + uint32_t sector = cluster2sector(fat_info, entry->position); + + TRANSFER_IN_BLOCK( + partition->storage_object, NULL, entry->data, sector, count); + return FS_OK; +} + +PRIVATE FsResult +entry_write(BlockCacheEntry *entry, size_t cache_size, void *private_data) { + FatInfo *fat_info = private_data; + Partition *partition = fat_info->partition; + + int count = DIV_ROUND_UP(cache_size, fat_info->bpb->BPB_BytesPerSec); + uint32_t sector = cluster2sector(fat_info, entry->position); + + for (int i = 0; i < fat_info->bpb->BPB_NumFATs; i++) { + TRANSFER_OUT_BLOCK( + partition->storage_object, NULL, entry->data, sector, count); + } + + return FS_OK; +} + +PUBLIC void entry_cache_init( + FatInfo *fat_info, FatDirEntry *entry, size_t cache_size) { + + entry->cache = + block_cache_create(cache_size, 1, entry_read, entry_write, fat_info); + BlockCacheEntry *cache_entry = block_cache_read(entry->cache, 0); + block_cache_read_done(cache_entry); +} + +PUBLIC FsResult fat_entry_read( + FatInfo *fat_info, FatDirEntry *parent_entry, int cluster, int number, + uint8_t *entry) { + BlockCacheEntry *cache_entry = + block_cache_read(parent_entry->cache, cluster); + memcpy( + entry, cache_entry->data + number * sizeof(ShortDir), sizeof(ShortDir)); + block_cache_read_done(cache_entry); + return FS_OK; +} + +PUBLIC FsResult fat_entry_write( + FatInfo *fat_info, FatDirEntry *parent_entry, int cluster, int number, + uint8_t *entry) { + BlockCacheEntry *cache_entry = + block_cache_write(parent_entry->cache, cluster); + memcpy( + cache_entry->data + number * sizeof(ShortDir), entry, sizeof(ShortDir)); + block_cache_write_done(fat_info->storage_device, cache_entry); + return FS_OK; +} + +PRIVATE FsResult fat_dir_get_new_entry( + FatInfo *fat_info, FatDirEntry *entry, DEF_MRET(uint32_t, last_cluster), + DEF_MRET(int, last_number)) { + + int number = entry->new_entry_number; + uint32_t cluster; + uint8_t buf[32]; + FS_RESULT_PASS(get_last_cluster(fat_info, entry, &cluster)); + do { + FS_RESULT_PASS(fat_entry_read(fat_info, entry, cluster, number, buf)); + number++; + } while (buf[0] != 0 && number <= fat_info->entry_per_cluster); + number -= 1; + if (number == fat_info->entry_per_cluster && buf[0] != 0) { + FS_RESULT_PASS(alloc_cluster(fat_info, cluster, false, &cluster)); + number = 0; + } + entry->new_entry_number = number; + MRET(last_cluster) = cluster; + MRET(last_number) = number; + return FS_OK; +} + +PRIVATE int fat_increase_new_entry_number( + FatInfo *fat_info, FatDirEntry *entry, uint32_t *cluster) { + entry->new_entry_number++; + if (entry->new_entry_number == fat_info->entry_per_cluster) { + FS_RESULT_PASS(alloc_cluster(fat_info, *cluster, false, cluster)); + entry->new_entry_number = 0; + } + return entry->new_entry_number; +} + +PRIVATE FsResult fat_longname_entry_write( + FatInfo *fat_info, FatDirEntry *parent_entry, string_t name, + uint8_t checksum, uint32_t *cluster, int *number) { + LongDir long_dir; + int len8, len16; + int longdir_count; + + uint16_t *utf16_name = kmalloc(name.length); + fat_utf8_to_utf16((uint8_t *)name.text, utf16_name, &len8, &len16); + longdir_count = DIV_ROUND_UP(len16, 13); + + long_dir.attr = ATTR_LONG_NAME; + long_dir.checksum = checksum; + long_dir.first_cluster = 0; + long_dir.type = 0; + + uint16_t *p = utf16_name + (longdir_count - 1) * 13; + for (int i = 0; i < longdir_count; i++) { + long_dir.order = longdir_count - i; + if (i == 0) { + long_dir.order |= 0x40; + int j = 0, k; + int len = len16 % 13; + for (k = 0; k < 5; j++, k++) { + if (j < len) long_dir.name1[k] = p[j]; + else long_dir.name1[k] = 0xffff; + } + for (k = 0; k < 6; j++, k++) { + if (j < len) long_dir.name2[k] = p[j]; + else long_dir.name2[k] = 0xffff; + } + for (j = 0; j < 2; j++) { + if (j < len) long_dir.name3[k] = p[j]; + else long_dir.name3[k] = 0xffff; + } + } else { + memcpy(long_dir.name1, p, 5 * sizeof(uint16_t)); + memcpy(long_dir.name2, p + 5, 6 * sizeof(uint16_t)); + memcpy(long_dir.name3, p + 11, 2 * sizeof(uint16_t)); + } + FS_RESULT_PASS(fat_entry_write( + fat_info, parent_entry, *cluster, *number, (uint8_t *)&long_dir)); + p -= 13; + + *number = + fat_increase_new_entry_number(fat_info, parent_entry, cluster); + } + return FS_OK; +} + +PUBLIC FatDirEntry *generate_dir_entry( + FatInfo *fat_info, FatDirEntry *parent_entry, ShortDir *short_dir, + string_t name, FatLocation *location, ObjectAttr *attr) { + FatDirEntry *entry = kmalloc(sizeof(FatDirEntry)); + entry->name.text = kmalloc(name.length); + memcpy(entry->name.text, name.text, name.length); + entry->name.length = name.length; + entry->name.max_length = name.length; + + memcpy(&entry->short_dir, short_dir, sizeof(ShortDir)); + bool is_directory = short_dir->attr & ATTR_DIRECTORY; + uint32_t cluster = location->shortname_cluster; + int number = location->shortname_offset; + uint32_t longname_cluster = location->longname_cluster; + int longname_number = location->longname_offset; + + entry->cluster_list = dyn_array_new(sizeof(ClusterSegment), 8); + get_cluster_segment(fat_info, entry); + + Object *object; + ObjectAttr *_attr = attr; + if (_attr == NULL) { + _attr = kmalloc(sizeof(ObjectAttr)); + fat_attr_to_sys_attr(short_dir, _attr, location); + } + + if (is_directory) { + FsResult result = fs_obj_create_dir( + parent_entry->object, fat_info->fs_info, &entry->name, &object, + _attr); + if (result != FS_OK) { return NULL; } + object->value.directory.data = entry; + entry_cache_init(fat_info, entry, fat_info->bytes_per_cluster); + } else { + FsResult result = fs_obj_create_file( + parent_entry->object, fat_info->fs_info, &entry->name, &object, + _attr); + if (result != FS_OK) { return NULL; } + object->value.file.data = entry; + object->value.file.offset = 0; + object->value.file.size = entry->short_dir.file_size; + } + entry->longname_cluster = longname_cluster; + entry->longname_number = longname_number; + entry->shortname_cluster = cluster; + entry->shortname_number = number; + entry->object = object; + + return entry; +} + +PUBLIC FsResult fat_create_entry( + FatInfo *fat_info, FatDirEntry *parent_entry, string_t name, + bool is_directory, FatDirEntry **out_entry) { + + Time time; + DriverResult result = get_current_time(TIME_TYPE_LOCAL, &time); + if (result != DRIVER_OK) { return FS_ERROR_OTHER; } + TimeFull full_time = time.time; + uint16_t cur_time = + FAT_TIME(full_time.hour, full_time.minute, full_time.second); + uint16_t cur_date = + FAT_DATE(full_time.year, full_time.month, full_time.day); + + uint32_t first_cluster; + FS_RESULT_PASS(alloc_cluster(fat_info, 0, true, &first_cluster)); + + NameType type = + check_name(fat_info->type, (uint8_t *)name.text, name.length); + ShortName short_name; + if (fat_info->type != FAT_TYPE_FAT32 && type == LONG_NAME) { + return FS_ERROR_INVALID_PATH_OR_NAME; + } + FS_RESULT_PASS(long_name2short_name( + fat_info, parent_entry, name, is_directory, &short_name)); + + int caps = check_name_caps((uint8_t *)name.text, 11); + int ntres = 0; + if ((caps & 0x03) == 0x01) ntres |= FAT32_BASE_L; + if ((caps & 0x0c) == 0x04) ntres |= FAT32_BASE_L; + + ShortDir short_dir; + short_dir.name = short_name; + short_dir.attr = ATTR_ARCHIVE; + short_dir.nt_res = ntres; + short_dir.crt_time_tenth = (full_time.second % 2) * 100; + short_dir.crt_time = cur_time; + short_dir.crt_date = cur_date; + short_dir.last_access_date = cur_date; + short_dir.first_cluster_high = first_cluster >> 16; + short_dir.write_time = cur_time; + short_dir.write_date = cur_date; + short_dir.first_cluster_low = first_cluster & 0xffff; + short_dir.file_size = 0; + if (is_directory) { short_dir.attr |= ATTR_DIRECTORY; } + + int checksum = fat_checksum(&short_dir.name); + + uint32_t cluster, longname_cluster = 0; + int number, longname_number = 0; + fat_dir_get_new_entry(fat_info, parent_entry, &cluster, &number); + if (fat_info->type == FAT_TYPE_FAT32 && type == LONG_NAME) { + longname_cluster = cluster; + longname_number = number; + FS_RESULT_PASS(fat_longname_entry_write( + fat_info, parent_entry, name, checksum, &cluster, &number)); + } + FS_RESULT_PASS(fat_entry_write( + fat_info, parent_entry, cluster, number, (uint8_t *)&short_dir)); + + FatDirEntry *entry; + FatLocation location; + location.longname_cluster = longname_cluster; + location.longname_offset = longname_number; + location.shortname_cluster = cluster; + location.shortname_offset = number; + entry = generate_dir_entry( + fat_info, parent_entry, &short_dir, name, &location, NULL); + + if (is_directory) { + static ShortName dot = {". ", " "}; + short_dir.name = dot; + short_dir.attr = ATTR_DIRECTORY; + FS_RESULT_PASS(fat_entry_write( + fat_info, entry, first_cluster, 0, (uint8_t *)&short_dir)); + + short_dir.name.base[1] = '.'; + short_dir.first_cluster_low = parent_entry->short_dir.first_cluster_low; + short_dir.first_cluster_high = + parent_entry->short_dir.first_cluster_high; + FS_RESULT_PASS(fat_entry_write( + fat_info, entry, first_cluster, 1, (uint8_t *)&short_dir)); + entry->new_entry_number = 1; + } + return FS_OK; +} + +PUBLIC FsResult fat_delete_entry( + FatInfo *fat_info, FatDirEntry *parent, FatLocation *location) { + uint32_t cluster = location->shortname_cluster; + uint32_t num = location->shortname_offset; + + uint8_t buf[32]; + FS_RESULT_PASS(fat_entry_read(fat_info, parent, cluster, num, buf)); + buf[0] = 0xe5; + FS_RESULT_PASS(fat_entry_write(fat_info, parent, cluster, num, buf)); + + if (fat_info->type == FAT_TYPE_FAT32 && location->longname_cluster != 0) { + uint32_t cluster = location->longname_cluster; + int number = location->longname_offset; + + while (cluster <= location->shortname_cluster && + number < location->shortname_offset) { + FS_RESULT_PASS( + fat_entry_read(fat_info, parent, cluster, number, buf)); + buf[0] = 0xe5; + FS_RESULT_PASS( + fat_entry_write(fat_info, parent, cluster, number, buf)); + number++; + if (number == fat_info->entry_per_cluster) { + cluster = get_next_cluster(fat_info, cluster); + num = 0; + } + } + } + + return FS_OK; +} diff --git a/src/fs/fat/fat.c b/src/fs/fat/fat.c new file mode 100644 index 0000000..7a3b3fe --- /dev/null +++ b/src/fs/fat/fat.c @@ -0,0 +1,507 @@ +#include "include/fat.h" +#include "include/attr.h" +#include "include/cluster.h" +#include "include/dir.h" +#include "include/entry.h" +#include "math.h" +#include "objects/handle.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +FsResult fat_check(Partition *partition); +FsResult fat_mount(FileSystemInfo *fs_info, Object *root_object); + +FsResult fat_lookup( + FileSystemInfo *fs_info, Object *parent_obj, string_t *name, + ObjectAttr **attr); +FsResult fat_open( + FileSystemInfo *fs_info, Object *parent_obj, ObjectAttr *attr, + string_t *name, Object **object); +FsResult fat_close(Object *object); +FsResult fat_seek(Object *file, size_t offset); +FsResult fat_read(Object *file, ObjectHandle *handle, void *buf, size_t size); +FsResult fat_write( + Object *object, ObjectHandle *handle, void *buf, size_t size); +FsResult fat_create_handle(ObjectHandle *handle); +FsResult fat_delete_handle(ObjectHandle *handle); + +FsResult fat_opendir( + FileSystemInfo *fs_info, Object *parent_obj, void **iterator); +FsResult fat_readdir( + FileSystemInfo *fs_info, ObjectIterator *iterator, Object **object); +FsResult fat_closedir(ObjectIterator *iterator); +FsResult fat_create_file(Object *parent_obj, string_t *name, Object **object); +FsResult fat_delete_file(Object *parent_obj, ObjectAttr *attr, string_t *name); +FsResult fat_mkdir(Object *parent_obj, string_t *name, Object **object); +FsResult fat_rmdir(Object *parent_obj, ObjectAttr *attr, string_t *name); +FsResult fat_get_attr(Object *object, ObjectAttr *attr); +FsResult fat_set_attr(Object *object, ObjectAttr *attr); + +FileSystemOps fat_ops = { + .fs_check = fat_check, + .fs_mount = fat_mount, +}; + +FsFileOps fat_file_ops = { + .fs_open = fat_open, + .fs_close = fat_close, + .fs_seek = fat_seek, + .fs_read = fat_read, + .fs_write = fat_write, + .fs_get_attr = fat_get_attr, + .fs_set_attr = fat_set_attr, + .fs_create_handle = fat_create_handle, + .fs_delete_handle = fat_delete_handle, +}; + +FsDirectoryOps fat_dir_ops = { + .fs_lookup = fat_lookup, + .fs_opendir = fat_opendir, + .fs_readdir = fat_readdir, + .fs_closedir = fat_closedir, + .fs_create_file = fat_create_file, + .fs_delete_file = fat_delete_file, + .fs_mkdir = fat_mkdir, + .fs_rmdir = fat_rmdir, + .fs_get_attr = fat_get_attr, + .fs_set_attr = fat_set_attr, +}; + +FileSystem fat_fs = { + .name = STRING_INIT("FAT"), + .ops = &fat_ops, +}; + +FatPrivOps fat32_priv_ops = { + .fat_dir_lookup = fat32_dir_lookup, + .fat_read_dir_entry = fat32_read_dir_entry, +}; +FatPrivOps fat_priv_ops = { + .fat_dir_lookup = fat_dir_lookup, + .fat_read_dir_entry = fat_read_dir_entry, +}; + +FatType fat_type_determine(FatInfo *fat_info); + +FsResult fat_check(Partition *partition) { + if (partition->type == PARTITION_TYPE_MBR) { + if (partition->mbr->fs_type == 0x0b || + partition->mbr->fs_type == 0x0c) { + return FS_OK; + } + } + return FS_ERROR_UNSUPPORT; +} + +FsResult fat_mount(FileSystemInfo *fs_info, Object *root_object) { + FatBpb *bpb = (FatBpb *)fs_info->partition->superblock; + FatFsInfo *fat_fs_info = + (FatFsInfo *)(fs_info->partition->superblock + SECTOR_SIZE); + FatInfo *fat_info = kmalloc(sizeof(FatInfo)); + fat_info->fs_info = fs_info; + fs_info->private_data = fat_info; + + fat_info->partition = fs_info->partition; + + fat_info->bpb = bpb; + fat_info->fat_fs_info = fat_fs_info; + + int root_dir_sectors = + ((bpb->BPB_RootEntCnt * 32) + (bpb->BPB_BytesPerSec - 1)) / + bpb->BPB_BytesPerSec; + + fat_info->fat_sectors = + (bpb->BPB_FATSz16 != 0) ? (bpb->BPB_FATSz16) : (bpb->fat32.BPB_FATSz32); + + fat_info->total_sectors = + (bpb->BPB_TotSec16 != 0) ? (bpb->BPB_TotSec16) : (bpb->BPB_TotSec32); + + fat_info->data_sectors = + fat_info->total_sectors - + (bpb->BPB_RevdSecCnt + (bpb->BPB_NumFATs * fat_info->fat_sectors) + + root_dir_sectors); + + fat_info->type = fat_type_determine(fat_info); + + fat_info->fat_start = fs_info->partition->start_lba + bpb->BPB_RevdSecCnt; + fat_info->data_start = + fat_info->fat_start + (bpb->BPB_NumFATs * fat_info->fat_sectors); + fat_info->sector_per_cluster = bpb->BPB_SecPerClus; + fat_info->bytes_per_cluster = + fat_info->sector_per_cluster * bpb->BPB_BytesPerSec; + fat_info->entry_per_cluster = fat_info->bytes_per_cluster / 32; + + int cache_size = fat_info->bytes_per_cluster; + + if (fat_info->type == FAT_TYPE_FAT32) { + fat_info->num_count = cache_size / 4; + } else if (fat_info->type == FAT_TYPE_FAT16) { + fat_info->num_count = cache_size / 2; + } + + fat_info->fat_table_cache = block_cache_create( + fat_info->bytes_per_cluster, 4, fat_table_read, fat_table_write, + fat_info); + + const string_t root_name = STRING_INIT(""); + const ShortDir root_short_dir = { + {" ", " "}, + ATTR_DIRECTORY, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0 + }; + const FatDirEntry root_entry = { + root_name, root_short_dir, 0, 0, 0, 0, {0}, NULL, NULL, + }; + fat_info->root_entry = root_entry; + + fat_info->root_entry.object = root_object; + root_object->value.directory.data = &fat_info->root_entry; + fat_info->root_entry.cluster_list = + dyn_array_new(sizeof(ClusterSegment), 8); + entry_cache_init( + fat_info, &fat_info->root_entry, fat_info->bytes_per_cluster); + get_cluster_segment(fat_info, &fat_info->root_entry); + + root_object->fs_info->private_data = fat_info; + root_object->fs_info->file_ops = fat_file_ops; + root_object->fs_info->dir_ops = fat_dir_ops; + fat_info->storage_device = + fs_info->partition->storage_object->value.device.logical->dm_ext; + + return FS_OK; +} + +FatType fat_type_determine(FatInfo *fat_info) { + + int count_of_cluster = + fat_info->data_sectors / fat_info->bpb->BPB_SecPerClus; + + if (count_of_cluster < 4085) { + fat_info->max_cluster = 0xFF8; + fat_info->ops = &fat_priv_ops; + return FAT_TYPE_FAT12; + } else if (count_of_cluster < 65525) { + fat_info->max_cluster = 0xFFF8; + fat_info->ops = &fat_priv_ops; + return FAT_TYPE_FAT16; + } else { + fat_info->max_cluster = 0x0FFFFFF8; + fat_info->ops = &fat32_priv_ops; + fat_info->use_longname = true; + return FAT_TYPE_FAT32; + } +} + +FsResult fat_lookup( + FileSystemInfo *fs_info, Object *parent_obj, string_t *name, + ObjectAttr **attr) { + FatInfo *fat_info = fs_info->private_data; + FatDirEntry *parent_entry = parent_obj->value.directory.data; + + FatLocation location; + ShortDir short_dir; + FS_RESULT_PASS(fat_info->ops->fat_dir_lookup( + fat_info, parent_entry, *name, &location, &short_dir)); + ObjectAttr *tmp_attr = kmalloc(sizeof(ObjectAttr)); + fat_attr_to_sys_attr(&short_dir, tmp_attr, &location); + + *attr = tmp_attr; + + return FS_OK; +} + +FsResult fat_open( + FileSystemInfo *fs_info, Object *parent_obj, ObjectAttr *attr, + string_t *name, Object **object) { + FatInfo *fat_info = fs_info->private_data; + FatDirEntry *entry, *parent_entry = parent_obj->value.directory.data; + FatLocation *location = attr->fs_location; + ShortDir short_dir; + + fat_entry_read( + fat_info, parent_entry, location->shortname_cluster, + location->shortname_offset, (uint8_t *)&short_dir); + + entry = generate_dir_entry( + fat_info, parent_entry, &short_dir, *name, location, attr); + *object = entry->object; + return FS_OK; +} + +FsResult fat_close(Object *object) { + FatDirEntry *entry = object->value.file.data; + if (entry->cache != NULL) block_cache_destroy(entry->cache); + dyn_array_delete(entry->cluster_list); + string_del(&entry->name); + kfree(entry); + return FS_OK; +} + +FsResult fat_opendir( + FileSystemInfo *fs_info, Object *parent_obj, void **iterator) { + FatInfo *fat_info = fs_info->private_data; + FatDirEntry *parent = parent_obj->value.directory.data; + + *iterator = kmalloc(sizeof(FatDirIterator)); + if (fat_info->type == FAT_TYPE_FAT32) { + fat_dir_iterator_init(*iterator, fat_info, parent); + } else { + fat_dir_iterator_init(*iterator, fat_info, parent); + } + return FS_OK; +} + +FsResult fat_readdir( + FileSystemInfo *fs_info, ObjectIterator *iterator, Object **object) { + FatInfo *fat_info = fs_info->private_data; + FatDirEntry *entry; + string_t name; + ShortDir short_dir; + FatDirIterator *iter = iterator->fs_iterator; + Object *parent_obj = iterator->parent_object; + + FS_RESULT_PASS(fat_info->ops->fat_read_dir_entry(iter, &short_dir)); + + Object *cur; + list_for_each_owner (cur, &parent_obj->value.directory.children, list) { + FatLocation *location = cur->attr->fs_location; + if (location->shortname_cluster == iter->last_cluster && + location->shortname_offset == iter->last_entry_index) { + *object = cur; + return FS_OK; + } + } + + FatLocation location; + location.longname_cluster = iter->longname_cluster; + location.longname_offset = iter->longname_entry_index; + location.shortname_cluster = iter->last_cluster; + location.shortname_offset = iter->last_entry_index; + + // 生成文件名 + if (iter->longname_valid) { + fat_utf16_to_utf8(iter->longname_buf, iter->longname_len, &name); + } else { + name = read_short_name(&short_dir); + } + fat_dir_iterator_next(iter); + + entry = generate_dir_entry( + fat_info, iter->dir_entry, &short_dir, name, &location, NULL); + + *object = entry->object; + return FS_OK; +} + +FsResult fat_closedir(ObjectIterator *iterator) { + fat_dir_iterator_destroy(iterator->fs_iterator); + kfree(iterator); + return FS_OK; +} + +FsResult fat_seek(Object *object, size_t offset) { + object->value.file.offset = offset; + return FS_OK; +} + +FsResult fat_create_handle(ObjectHandle *handle) { + if (handle == NULL || handle->object == NULL) + return FS_ERROR_INVALID_PARAMS; + Object *file = handle->object; + if (file->fs_info == NULL) return FS_ERROR_INVALID_PARAMS; + FatInfo *fat_info = file->fs_info->private_data; + CurrentCluster *cur_cluster = kmalloc(sizeof(CurrentCluster)); + if (cur_cluster == NULL) return FS_ERROR_OUT_OF_MEMORY; + fat_cluster_list_get(fat_info, file->value.file.data, 0, cur_cluster); + handle->handle_data = cur_cluster; + return FS_OK; +} + +FsResult fat_delete_handle(ObjectHandle *handle) { + if (handle == NULL) return FS_ERROR_INVALID_PARAMS; + kfree(handle->handle_data); + return FS_OK; +} + +FsResult fat_transfer( + BlockTransfer transfer, TransferDirection direction, + IsTransferDone is_transfer_done, FatInfo *fat_info, Object *storage_object, + Object *file, ObjectHandle *handle, void *buf, size_t size) { + FatDirEntry *entry = file->value.file.data; + + uint32_t cluster_index = + file->value.file.offset / fat_info->bytes_per_cluster; + + CurrentCluster *cur_cluster = handle->handle_data; + + if (cluster_index - cur_cluster->index > 1) { + fat_cluster_list_get(fat_info, entry, cluster_index, cur_cluster); + } else if (cluster_index - cur_cluster->index == 1) { + fat_cluster_list_get_next(fat_info, entry, cur_cluster); + } + + uint32_t offset = file->value.file.offset % fat_info->bytes_per_cluster; + uint32_t done = 0; + + while (size > 0) { + uint32_t read_size = fat_info->bytes_per_cluster - offset; + if (read_size > size) { read_size = size; } + + uint32_t sector = cluster2sector(fat_info, cur_cluster->cluster); + + if (offset + read_size == fat_info->bytes_per_cluster) { + CurrentCluster next = *cur_cluster; + + int count = 0; + int total_count = DIV_ROUND_UP(size, fat_info->bytes_per_cluster); + count = get_remaining_continuous_clusters(fat_info, &next); + if (count == 0) { return FS_ERROR_END_OF_FILE; } + count = MIN(count, total_count); + fat_cluster_list_skip(fat_info, entry, cur_cluster, count); + + TransferResult result = transfer( + storage_object, NULL, direction, buf + done, sector, + count * fat_info->sector_per_cluster); + if (result != TRANSFER_OK) return FS_ERROR_TRANSFER; + + done += read_size + (count - 1) * fat_info->bytes_per_cluster; + size -= read_size + (count - 1) * fat_info->bytes_per_cluster; + offset = 0; + } else { + TransferResult result = transfer( + storage_object, NULL, direction, buf + done, sector, + fat_info->sector_per_cluster); + if (result != TRANSFER_OK) return FS_ERROR_TRANSFER; + + done += read_size; + size -= read_size; + offset += read_size; + + if (offset == fat_info->bytes_per_cluster) { + offset = 0; + fat_cluster_list_get_next(fat_info, entry, cur_cluster); + } + } + } + file->value.file.offset += done; + + return FS_OK; +} + +FsResult fat_read(Object *file, ObjectHandle *handle, void *buf, size_t size) { + FatInfo *fat_info = file->fs_info->private_data; + Object *storage_object = fat_info->partition->storage_object; + return fat_transfer( + storage_object->in.block, TRANSFER_IN, + storage_object->in.is_transfer_done, fat_info, storage_object, file, + handle, buf, size); +} + +FsResult fat_write(Object *file, ObjectHandle *handle, void *buf, size_t size) { + FatInfo *fat_info = file->fs_info->private_data; + Object *storage_object = fat_info->partition->storage_object; + return fat_transfer( + storage_object->out.block, TRANSFER_OUT, + storage_object->out.is_transfer_done, fat_info, storage_object, file, + handle, buf, size); +} + +FsResult fat_create_file(Object *parent_obj, string_t *name, Object **object) { + FatInfo *fat_info = parent_obj->fs_info->private_data; + FatDirEntry *entry, *parent = parent_obj->value.directory.data; + + FatLocation location; + ShortDir short_dir; + FsResult result = fat_info->ops->fat_dir_lookup( + fat_info, parent, *name, &location, &short_dir); + if (result == FS_OK) { return FS_ERROR_ALREADY_EXISTS; } + + fat_create_entry(fat_info, parent, *name, false, &entry); + + *object = entry->object; + return FS_OK; +} + +FsResult fat_delete_file(Object *parent_obj, ObjectAttr *attr, string_t *name) { + FatInfo *fat_info = parent_obj->fs_info->private_data; + FatDirEntry *parent = parent_obj->value.directory.data; + + FatLocation *location = attr->fs_location; + + fat_delete_entry(fat_info, parent, location); + return FS_OK; +} + +FsResult fat_mkdir(Object *parent_obj, string_t *name, Object **object) { + FatInfo *fat_info = parent_obj->fs_info->private_data; + FatDirEntry *entry, *parent = parent_obj->value.directory.data; + + FatLocation location; + ShortDir short_dir; + FsResult result = fat_info->ops->fat_dir_lookup( + fat_info, parent, *name, &location, &short_dir); + if (result == FS_OK) { return FS_ERROR_ALREADY_EXISTS; } + + entry = generate_dir_entry( + fat_info, parent, &short_dir, *name, &location, NULL); + + fat_create_entry(fat_info, parent, *name, true, &entry); + + *object = entry->object; + return FS_OK; +} + +FsResult fat_rmdir(Object *parent_obj, ObjectAttr *attr, string_t *name) { + FatInfo *fat_info = parent_obj->fs_info->private_data; + FatDirEntry *entry, *parent = parent_obj->value.directory.data; + + FatLocation *location = attr->fs_location; + ShortDir short_dir; + FsResult result = fat_entry_read( + fat_info, parent, location->shortname_cluster, + location->shortname_offset, (uint8_t *)&short_dir); + if (result != FS_OK) { return result; } + + entry = + generate_dir_entry(fat_info, parent, &short_dir, *name, location, attr); + + if (!fat_dir_is_empty(fat_info, entry)) return FS_ERROR_NOT_EMPTY; + + fat_delete_entry(fat_info, parent, location); + return FS_OK; +} + +FsResult fat_get_attr(Object *object, ObjectAttr *attr) { + FatDirEntry *entry = object->value.file.data; + + fat_attr_to_sys_attr(&entry->short_dir, attr, object->attr->fs_location); + return FS_OK; +} + +FsResult fat_set_attr(Object *object, ObjectAttr *attr) { + FatInfo *fat_info = object->fs_info->private_data; + FatDirEntry *entry = object->value.file.data; + FatDirEntry *parent = object->parent->value.directory.data; + fat_attr_from_sys_attr(&entry->short_dir, attr, object->attr->fs_location); + fat_entry_write( + fat_info, parent, entry->shortname_cluster, entry->shortname_number, + (uint8_t *)&entry->short_dir); + return FS_OK; +} + +void fat_initcall() { + register_fs(&fat_fs); +} + +fs_initcall(fat_initcall); diff --git a/src/fs/fat/include/attr.h b/src/fs/fat/include/attr.h new file mode 100644 index 0000000..af58a3f --- /dev/null +++ b/src/fs/fat/include/attr.h @@ -0,0 +1,13 @@ +#ifndef _FAT_ATTR_H +#define _FAT_ATTR_H + +#include "dir.h" +#include "fat.h" +#include + +FsResult fat_attr_to_sys_attr( + ShortDir *short_dir, ObjectAttr *attr, FatLocation *location); +FsResult fat_attr_from_sys_attr( + ShortDir *short_dir, ObjectAttr *attr, FatLocation *location); + +#endif \ No newline at end of file diff --git a/src/fs/fat/include/cluster.h b/src/fs/fat/include/cluster.h new file mode 100644 index 0000000..9fb990b --- /dev/null +++ b/src/fs/fat/include/cluster.h @@ -0,0 +1,64 @@ +#ifndef _FAT_CLUSTER_H +#define _FAT_CLUSTER_H + +#include "dyn_array.h" +#include "fs/fs.h" +#include "kernel/block_cache.h" +#include +#include +#include + +// 保存一个连续的簇链 +typedef struct ClusterSegment { + uint32_t start; + uint32_t end; +} ClusterSegment; + +struct FatDirEntry; +typedef struct CurrentCluster { + struct FatDirEntry *entry; + uint32_t cluster; + int offset; + int index; + DynArrayBlock *block; +} CurrentCluster; + +struct FatInfo; +struct FatDirEntry; +uint32_t cluster2sector(struct FatInfo *fat_info, uint32_t cluster); + +FsResult fat_table_read( + BlockCacheEntry *entry, size_t cache_size, void *private_data); +FsResult fat_table_write( + BlockCacheEntry *entry, size_t cache_size, void *private_data); + +uint32_t get_next_cluster(struct FatInfo *fat_info, uint32_t clus); +void set_cluster(struct FatInfo *fat_info, uint32_t cluster, uint32_t data); +FsResult alloc_cluster( + struct FatInfo *fat_info, uint32_t last_cluster, bool is_first_cluster, + uint32_t *out_clus); +FsResult free_cluster( + struct FatInfo *fat_info, uint32_t cluster, uint32_t *out_clus); +bool is_eof(struct FatInfo *fat_info, uint32_t clus); +FsResult get_cluster_segment( + struct FatInfo *fat_info, struct FatDirEntry *entry); + +FsResult fat_cluster_list_get( + struct FatInfo *fat_info, struct FatDirEntry *entry, uint32_t index, + CurrentCluster *cur_cluster); +FsResult fat_cluster_list_get_next( + struct FatInfo *fat_info, struct FatDirEntry *entry, + CurrentCluster *cur_cluster); +uint32_t get_remaining_continuous_clusters( + struct FatInfo *info, CurrentCluster *cur_cluster); +FsResult fat_cluster_list_skip( + struct FatInfo *fat_info, struct FatDirEntry *entry, + CurrentCluster *cur_cluster, int count); +inline bool fat_cluster_list_is_last( + struct FatInfo *fat_info, struct FatDirEntry *entry, + CurrentCluster *cur_cluster); +FsResult get_last_cluster( + struct FatInfo *fat_info, struct FatDirEntry *entry, + DEF_MRET(uint32_t, last_cluster)); + +#endif \ No newline at end of file diff --git a/src/fs/fat/include/dir.h b/src/fs/fat/include/dir.h new file mode 100644 index 0000000..12f620e --- /dev/null +++ b/src/fs/fat/include/dir.h @@ -0,0 +1,113 @@ +#ifndef _FAT_DIR_H +#define _FAT_DIR_H + +#include "cluster.h" +#include "dyn_array.h" +#include "fs/fs.h" +#include "kernel/block_cache.h" +#include "name.h" +#include "objects/object.h" +#include "stdint.h" +#include "string.h" +#include + +#define ATTR_READ_ONLY 0x01 +#define ATTR_HIDDEN 0x02 +#define ATTR_SYSTEM 0x04 +#define ATTR_VOLUME_ID 0x08 +#define ATTR_DIRECTORY 0x10 +#define ATTR_ARCHIVE 0x20 +#define ATTR_LONG_NAME 0x0f + +#define FAT32_BASE_L 0x08 +#define FAT32_EXT_L 0x10 + +typedef struct ShortDir { + ShortName name; + uint8_t attr; + uint8_t nt_res; + uint8_t crt_time_tenth; + uint16_t crt_time; + uint16_t crt_date; + uint16_t last_access_date; + uint16_t first_cluster_high; + uint16_t write_time; + uint16_t write_date; + uint16_t first_cluster_low; + uint32_t file_size; +} __attribute__((packed)) ShortDir; + +typedef struct LongDir { + uint8_t order; + uint16_t name1[5]; + uint8_t attr; + uint8_t type; + uint8_t checksum; + uint16_t name2[6]; + uint16_t first_cluster; + uint16_t name3[2]; +} __attribute__((packed)) LongDir; + +typedef struct FatDirEntry { + string_t name; + ShortDir short_dir; + + // 短目录项所在的簇号 + uint32_t shortname_cluster; + // 短目录项所在的簇内的序号 + uint8_t shortname_number; + + // 长目录项所在的簇号 + uint32_t longname_cluster; + // 长目录项所在的簇内的序号 + uint8_t longname_number; + + union { + // 文件夹已知的最后一个子目录项的序号 + int new_entry_number; + }; + + DynArray *cluster_list; + BlockCache *cache; + + Object *object; +} FatDirEntry; + +struct FatInfo; +typedef struct FatDirIterator { + struct FatInfo *fat_info; // 文件系统信息 + FatDirEntry *dir_entry; // 当前遍历的目录项 + CurrentCluster current_cluster; // 当前簇号 + int entry_index; // 当前簇内条目索引 + uint16_t *longname_buf; // 长文件名缓存(UTF-16) + int longname_len; // 当前累积的长名长度 + uint8_t checksum; // 长名校验和 + bool longname_valid; // 长名有效性标志 + uint32_t longname_cluster; // 长名所在簇号 + int longname_entry_index; // 长名所在簇内条目索引 + uint32_t last_cluster; // 上一个簇号 + int last_entry_index; // 上一个簇内条目索引 +} FatDirIterator; + +struct FatInfo; +struct FatLocation; + +void fat_dir_iterator_init( + FatDirIterator *iter, struct FatInfo *fat, FatDirEntry *dir); +void fat_dir_iterator_next(FatDirIterator *iter); +void fat_dir_iterator_destroy(FatDirIterator *iter); +FsResult fat32_read_dir_entry( + FatDirIterator *iter, DEF_MRET(ShortDir, short_dir)); +FsResult fat_read_dir_entry( + FatDirIterator *iter, DEF_MRET(ShortDir, short_dir)); +FsResult fat32_dir_lookup( + struct FatInfo *fat_info, FatDirEntry *parent_entry, string_t name, + DEF_MRET(struct FatLocation, location), DEF_MRET(ShortDir, short_dir)); +FsResult fat_dir_lookup( + struct FatInfo *fat_info, FatDirEntry *parent_entry, string_t name, + DEF_MRET(struct FatLocation, location), DEF_MRET(ShortDir, short_dir)); +void entry_cache_init( + struct FatInfo *fat_info, FatDirEntry *entry, size_t cache_size); +bool fat_dir_is_empty(struct FatInfo *fat_info, FatDirEntry *parent_entry); + +#endif \ No newline at end of file diff --git a/src/fs/fat/include/entry.h b/src/fs/fat/include/entry.h new file mode 100644 index 0000000..e1315b2 --- /dev/null +++ b/src/fs/fat/include/entry.h @@ -0,0 +1,26 @@ +#ifndef _FAT_ENTRY_H +#define _FAT_ENTRY_H + +#include "dir.h" +#include "fs/fs.h" + +struct FatInfo; +struct FatDirEntry; +FsResult fat_entry_read( + struct FatInfo *fat_info, struct FatDirEntry *parent_entry, int cluster, + int number, uint8_t *entry); +FsResult fat_entry_write( + struct FatInfo *fat_info, struct FatDirEntry *parent_entry, int cluster, + int number, uint8_t *entry); +FatDirEntry *generate_dir_entry( + struct FatInfo *fat_info, struct FatDirEntry *parent_entry, + ShortDir *short_dir, string_t name, struct FatLocation *location, + ObjectAttr *attr); +FsResult fat_create_entry( + struct FatInfo *fat_info, FatDirEntry *parent_entry, string_t name, + bool is_directory, FatDirEntry **out_entry); +FsResult fat_delete_entry( + struct FatInfo *fat_info, FatDirEntry *parent, + struct FatLocation *location); + +#endif \ No newline at end of file diff --git a/src/fs/fat/include/fat.h b/src/fs/fat/include/fat.h new file mode 100644 index 0000000..f027565 --- /dev/null +++ b/src/fs/fat/include/fat.h @@ -0,0 +1,120 @@ +#ifndef _FAT_H +#define _FAT_H + +#include "dir.h" +#include "driver/storage/disk/disk.h" +#include "driver/storage/storage_dm.h" +#include "fs/fs.h" +#include "kernel/block_cache.h" +#include + +#define FAT_CACHE_SIZE 2 + +typedef enum FatType { + FAT_TYPE_FAT12, + FAT_TYPE_FAT16, + FAT_TYPE_FAT32, + FAT_TYPE_EXFAT +} FatType; + +typedef struct FatBpb { + uint8_t BS_jmpBoot[3]; + char BS_OEMName[8]; + uint16_t BPB_BytesPerSec; + uint8_t BPB_SecPerClus; + uint16_t BPB_RevdSecCnt; + uint8_t BPB_NumFATs; + uint16_t BPB_RootEntCnt; + uint16_t BPB_TotSec16; + uint8_t BPB_Media; + uint16_t BPB_FATSz16; + uint16_t BPB_SecPerTrk; + uint16_t BPB_NumHeads; + uint32_t BPB_HiddSec; + uint32_t BPB_TotSec32; + union { + struct { + uint8_t BS_DrvNum; + uint8_t BS_Reserved1; + uint8_t BS_BootSig; + uint32_t BS_VolID; + char BS_VolLab[11]; + char BS_FilSysType[8]; + } __attribute__((packed)) fat12_16; + struct { + uint32_t BPB_FATSz32; + uint16_t BPB_ExtFlags; + uint16_t BPB_FSVer; + uint32_t BPB_RootClus; + uint16_t BPB_FSInfo; + uint16_t BPB_BkBootSec; + uint8_t BPB_Reserved[12]; + uint8_t BS_DrvNum; + uint8_t BS_Reserved1; + uint8_t BS_BootSig; + uint32_t BS_VolID; + char BS_VolLab[11]; + char BS_FilSysType[8]; + } __attribute__((packed)) fat32; + }; +} __attribute__((packed)) FatBpb; + +typedef struct FatFsInfo { + uint32_t FSI_LeadSig; + uint8_t FSI_Reserved1[480]; + uint32_t FSI_StrucSig; + uint32_t FSI_Free_Count; + uint32_t FSI_Nxt_Free; + uint8_t FSI_Reserved2[12]; + uint32_t FSI_TrailSig; +} __attribute__((packed)) FatFsInfo; + +typedef struct FatInfo { + Partition *partition; + FileSystemInfo *fs_info; + FatType type; + + StorageDevice *storage_device; + + FatBpb *bpb; + FatFsInfo *fat_fs_info; + + uint32_t fat_start; + uint32_t data_start; + int fat_sectors; + int data_sectors; + int total_sectors; + int bytes_per_cluster; + int sector_per_cluster; + int entry_per_cluster; + int num_count; + int max_cluster; + bool use_longname; + + struct FatPrivOps *ops; + + BlockCache *fat_table_cache; + + uint32_t last_cluster; + + FatDirEntry root_entry; +} FatInfo; + +typedef struct FatLocation { + uint32_t longname_cluster; // 长文件名所在簇号 + uint32_t longname_offset; // 长文件名所在簇内的序号 + uint32_t shortname_cluster; // 短文件名所在簇号 + uint32_t shortname_offset; // 短文件名所在簇内的序号 + uint32_t parent_cluster; // 父目录所在簇号 + uint32_t first_cluster; // 文件数据所在簇号 +} FatLocation; + +typedef struct FatPrivOps { + FsResult (*fat_dir_lookup)( + struct FatInfo *fat_info, FatDirEntry *parent_entry, string_t name, + DEF_MRET(FatLocation, location), DEF_MRET(ShortDir, short_dir)); + FsResult (*fat_read_dir_entry)( + FatDirIterator *iter, DEF_MRET(ShortDir, short_dir)); +} FatPrivOps; + +#endif \ No newline at end of file diff --git a/src/fs/fat/include/name.h b/src/fs/fat/include/name.h new file mode 100644 index 0000000..fc1625a --- /dev/null +++ b/src/fs/fat/include/name.h @@ -0,0 +1,43 @@ +#ifndef _FAT_NAME_H +#define _FAT_NAME_H + +#include "fs/fs.h" +#include "multiple_return.h" + +#define MAX_LONGNAME 256 + +typedef struct ShortName { + char base[8]; + char ext[3]; +} __attribute__((packed)) ShortName; + +typedef enum NameType { + SHORT_NAME, + LONG_NAME, + INVALID_NAME_TYPE, +} NameType; + +enum FatType; +struct FatInfo; +struct FatDirEntry; +struct ShortDir; +struct LongDir; +int check_name_caps(uint8_t *name, int len); +bool is_available_short_name_char(uint8_t c); +bool check_short_name(uint8_t *text, int len, int dot); +NameType check_name(enum FatType type, uint8_t *text, int len); +FsResult short_name_new(string_t name, ShortName *short_name); +uint8_t fat_checksum(ShortName *short_name); +int read_long_name(struct LongDir *long_dir, uint16_t *utf16_name); +string_t read_short_name(struct ShortDir *short_dir); +FsResult long_name2short_name( + struct FatInfo *fat_info, struct FatDirEntry *parent, string_t long_name, + bool is_directory, ShortName *short_name); + +void fat_utf16_to_utf8(uint16_t *utf16, int utf16_length, string_t *utf8); +void fat_utf8_to_utf16( + uint8_t *utf8, uint16_t *utf16, DEF_MRET(int, utf8_length), + DEF_MRET(int, utf16_length)); +int fat_utf16_count_utf8_length(uint16_t *utf16, int utf16_length); + +#endif \ No newline at end of file diff --git a/src/fs/fat/include/time.h b/src/fs/fat/include/time.h new file mode 100644 index 0000000..a565b3f --- /dev/null +++ b/src/fs/fat/include/time.h @@ -0,0 +1,8 @@ +#ifndef _FAT_TIME_H +#define _FAT_TIME_H + +#define FAT_DATE(year, month, day) (((year - 1980) << 9) | (month << 5) | day) +#define FAT_TIME(hour, minute, second) \ + ((hour << 11) | (minute << 5) | (second >> 1)) + +#endif \ No newline at end of file diff --git a/src/fs/fat/name.c b/src/fs/fat/name.c new file mode 100644 index 0000000..804992b --- /dev/null +++ b/src/fs/fat/name.c @@ -0,0 +1,438 @@ +#include "include/name.h" +#include "include/dir.h" +#include "include/fat.h" +#include "math.h" +#include "multiple_return.h" +#include +#include +#include +#include + +/** + * @brief 确认文件名与扩展名的大小写状况 + * + * @param name 文件名 + * @param len 文件名长度 + */ +int check_name_caps(uint8_t *name, int len) { + int ret = 0; + int flag = 0; + for (int i = 0; i < len; i++) { + if (name[i] == '.') { + flag = 2; + continue; + } + if ('a' <= name[i] && name[i] <= 'z') { + ret |= 1 << flag; + } else if ('A' <= name[i] && name[i] <= 'Z') { + ret |= 2 << flag; + } + } + return ret; +} + +bool is_available_short_name_char(uint8_t c) { + // 非ASCII字符 + if (c >= 0x80) { return false; } + // '^', '_', '`', a-z, '{' + if ('^' <= c && c <= '{') { return true; } + // '@', A-Z + if ('@' <= c && c <= 'Z') { return true; } + // 0-9 + if ('0' <= c && c <= '9') { return true; } + // ' ', '!', '#', $', '%', '&', '\'' ,'(', ')' + if (' ' <= c && c <= ')' && c != '\"') { return true; } + // '-', '}', '~' + if (c == '-' || c == '}' || c == '~') { return true; } + return false; +} + +bool is_available_long_name_char(uint8_t c) { + // '@', A-Z, '[', ']', + if ('@' <= c && c <= ']') { return true; } + // '^', '_', '`', a-z, '{' + if ('^' <= c && c <= '{') { return true; } + // 0-9 + if ('0' <= c && c <= '9') { return true; } + // '+', ',', '-', '.' + if ('+' <= c && c <= '.') { return true; } + // ' ', '!', '#', '$', '%', '&', '\'', '(', ')' + if (' ' <= c && c <= ')' && c != '\"') { return true; } + // ';', '}', '~' + if (c == ';' || c == '}' || c == '~') { return true; } + return false; +} + +/** + * @brief 确认文件名是否能直接作为短文件名 + * + * @param name 文件名 + */ +bool check_short_name(uint8_t *text, int len, int dot) { + // 如果文件名和扩展名的长度超过了8.3 + if (dot > 8 || dot < len - 3) return false; + + // 如果存在大小写混合 + int caps = check_name_caps(text, len); + if ((caps & 0x03) || (caps & 0x0c) == 0x0c) return false; + + for (int i = 0; i < len; i++) { + if (i == dot) continue; + if (!is_available_short_name_char(text[i])) return false; + } + return true; +} + +bool check_long_name(uint8_t *text, int len) { + for (int i = 0; i < len; i++) { + if (text[i] == 0) break; + if (text[i] >= 0x80) { + // 跳过UTF-8字符 + if ((text[i] & 0xe0) == 0xc0) i++; + if ((text[i] & 0xf0) == 0xe0) i += 2; + if ((text[i] & 0xf8) == 0xf0) i += 3; + } else if (!is_available_long_name_char(text[i])) return false; + } + return true; +} + +NameType check_name(FatType type, uint8_t *text, int len) { + int dot = 0; + while (text[dot] != '.' && dot < len) { + dot++; + } + if (!check_short_name(text, len, dot)) { + if (type == FAT_TYPE_FAT32 && check_long_name(text, len)) { + return LONG_NAME; + } + return INVALID_NAME_TYPE; + } + return SHORT_NAME; +} + +FsResult short_name_new(string_t name, ShortName *short_name) { + int len = name.length; + uint8_t *text = (uint8_t *)name.text; + + int dot = len - 1; + while (text[dot] != '.' && dot >= 0) { + dot--; + } + + if (!check_short_name(text, len, dot)) { + return FS_ERROR_INVALID_PATH_OR_NAME; + } + + for (int i = 0; i < 8; i++) { + if (i < dot) { + if ('a' <= text[i] && text[i] <= 'z') { + short_name->base[i] = text[i] - 32; + } else { + short_name->base[i] = text[i]; + } + } else { + short_name->base[i] = ' '; + } + } + for (int i = 0; i < 3; i++) { + if (i < len - dot) { + char c = text[dot + 1 + i]; + if ('a' <= c && c <= 'z') { + short_name->ext[i] = c - 32; + } else { + short_name->ext[i] = c; + } + } else { + short_name->ext[i] = ' '; + } + } + + return FS_OK; +} + +uint8_t fat_checksum(ShortName *short_name) { + uint8_t *name = (uint8_t *)short_name; + + uint8_t sum = 0; + for (int i = 11; i != 0; i--) { + sum = ((sum & 1) ? 0x80 : 0) + (sum >> 1) + *name++; + } + return sum; +} + +int read_long_name(LongDir *long_dir, uint16_t *utf16_name) { + int x; + int pos = 0; + for (x = 0; x < 5; x++) { + if (long_dir->name1[x] == 0xffff || long_dir->name1[x] == 0x00) break; + else utf16_name[pos++] = long_dir->name1[x]; + } + for (x = 0; x < 6; x++) { + if (long_dir->name2[x] == 0xffff || long_dir->name2[x] == 0x00) break; + else utf16_name[pos++] = long_dir->name2[x]; + } + for (x = 0; x < 2; x++) { + if (long_dir->name3[x] == 0xffff || long_dir->name3[x] == 0x00) break; + else utf16_name[pos++] = long_dir->name3[x]; + } + return pos++; +} + +string_t read_short_name(ShortDir *short_dir) { + int j = 0; + int x; + string_t name; + name.text = kmalloc(13); + name.max_length = 13; + + for (x = 0; x < 8; x++) { + char c = short_dir->name.base[x]; + if (c != ' ') { + if ('A' <= c && c <= 'Z') { + name.text[j++] = + (short_dir->nt_res & FAT32_BASE_L) ? c + 32 : c; + } else { + name.text[j++] = c; + } + } + } + if (short_dir->name.ext[0] == ' ' && short_dir->name.ext[1] == ' ' && + short_dir->name.ext[2] == ' ') { + name.length = j; + return name; + } + name.text[j++] = '.'; + for (x = 0; x < 3; x++) { + char c = short_dir->name.ext[x]; + if (c != ' ') { + if ('A' <= c && c <= 'Z') { + name.text[j++] = (short_dir->nt_res & FAT32_EXT_L) ? c + 32 : c; + } else { + name.text[j++] = c; + } + } + } + return name; +} + +FsResult long_name2short_name( + FatInfo *fat_info, FatDirEntry *parent, string_t long_name, + bool is_directory, ShortName *short_name) { + + int len = long_name.length; + uint8_t *text = (uint8_t *)long_name.text; + bool flag = true; + + int dot = len; + if (!is_directory) { + dot--; + while (text[dot] != '.' && dot >= 0) { + dot--; + } + } + int base_name_len = 0; + int ext_name_len = 0; + char tmp_name[12] = " "; + + int i, j, k; + uint8_t c; + char *q; + for (i = 0, j = 0, k = 0; k < 8; k++) { + if (i < dot) { + c = text[i]; + q = &short_name->base[j]; + i++; + if (is_available_short_name_char(c)) { + if ('a' <= c && c <= 'z') *q = c - 32; + else *q = c; + } else if (c >= 0x80) { // 跳过UTF-8字符 + if ((c & 0xe0) == 0xc0) i++; + if ((c & 0xf0) == 0xe0) i += 2; + if ((c & 0xf8) == 0xf0) i += 3; + flag = false; + *q = '_'; + } else continue; + tmp_name[k] = *q; + base_name_len++; + j++; + } else short_name->base[k] = ' '; + } + + if (!is_directory) { + tmp_name[j++] = '.'; + for (i = dot + 1, k = 0; k < 3; k++) { + if (i < len) { + c = text[i]; + q = &short_name->ext[k]; + i++; + if (is_available_short_name_char(c)) { + if ('a' <= c && c <= 'z') *q = c - 32; + else *q = c; + } else if (c >= 0x80) { // 跳过UTF-8字符 + if ((c & 0xe0) == 0xc0) i++; + if ((c & 0xf0) == 0xe0) i += 2; + if ((c & 0xf8) == 0xf0) i += 3; + flag = false; + *q = '_'; + } else continue; + tmp_name[j] = *q; + ext_name_len++; + j++; + } else short_name->ext[k] = ' '; + } + } + + string_t name; + name.text = tmp_name; + name.length = base_name_len + ext_name_len + 1; + name.max_length = name.length; + + FatLocation location; + ShortDir short_dir; + if (!flag && check_short_name((uint8_t *)short_name, 11, dot)) { + // 完全满足短文件名条件,检查是否重名 + return fat_info->ops->fat_dir_lookup( + fat_info, parent, name, &location, &short_dir); + } else { + for (int n = 1; n < 999999; n++) { + // 统计位数 + int x = n; + int i = MIN(base_name_len, 7); + while (x != 0 && i > 1) { + char c = (x % 10) + '0'; + short_name->base[i] = c; + x /= 10; + i--; + } + short_name->base[i] = '~'; + + // 检查是否重名 + FsResult result = fat_info->ops->fat_dir_lookup( + fat_info, parent, name, &location, &short_dir); + if (result == FS_ERROR_CANNOT_FIND) { + // 找不到说明可用 + return FS_OK; + } + // 找得到说明重名,继续循环 + } + } + + return FS_ERROR_INVALID_PATH_OR_NAME; +} + +uint32_t fat_utf16_to_unicode(uint16_t **utf16) { + uint16_t *buf = *utf16; + uint32_t unicode = buf[0]; + if (((buf[0] & 0xfc00) == 0xdc00) && ((buf[1] & 0xfc00) == 0xd800)) { + unicode = (buf[1] & 0x03ff) << 16; + unicode |= buf[0] & 0x03ff; + (*utf16)++; + } + (*utf16)++; + return unicode; +} + +uint32_t fat_utf8_to_unicode(uint8_t **utf8) { + uint32_t unicode = 0; + uint8_t *buf = *utf8; + if (buf[0] < 0x80) { + unicode = buf[0]; + (*utf8)++; + } else if (buf[0] < 0xe0) { + unicode = (buf[0] & 0x1f) << 6; + unicode |= buf[1] & 0x3f; + (*utf8) += 2; + } else if (buf[0] < 0xf0) { + unicode = (buf[0] & 0x0f) << 12; + unicode |= (buf[1] & 0x3f) << 6; + unicode |= buf[2] & 0x3f; + (*utf8) += 3; + } else { + unicode = (buf[0] & 0x07) << 18; + unicode |= (buf[1] & 0x3f) << 12; + unicode |= (buf[2] & 0x3f) << 6; + unicode |= buf[3] & 0x3f; + (*utf8) += 4; + } + return unicode; +} + +void fat_unicode_to_utf16(uint32_t unicode, uint16_t **utf16) { + uint16_t *buf = *utf16; + if (unicode < 0x10000) { + buf[0] = unicode; + } else { + buf[0] = 0xd800 | ((unicode >> 10) & 0x03ff); + buf[1] = 0xdc00 | (unicode & 0x03ff); + (*utf16)++; + } + (*utf16)++; +} + +int fat_utf16_count_utf8_length(uint16_t *utf16, int utf16_length) { + int utf8_length = 0; + uint16_t *p = utf16; + for (int i = 0; i < utf16_length; i++) { + uint32_t unicode = fat_utf16_to_unicode(&p); + + if (unicode < 0x80) { + utf8_length += 1; + } else if (unicode < 0x800) { + utf8_length += 2; + } else if (unicode < 0x10000) { + utf8_length += 3; + } else { + utf8_length += 4; + } + } + return utf8_length; +} + +void fat_utf16_to_utf8(uint16_t *utf16, int utf16_length, string_t *utf8) { + int utf8_length = fat_utf16_count_utf8_length(utf16, utf16_length); + utf8->text = kmalloc(utf8_length + 1); + utf8->length = utf8_length; + utf8->max_length = utf8_length + 1; + + uint16_t *p = utf16; + uint8_t *q = (uint8_t *)utf8->text; + for (int i = 0; i < utf16_length; i++) { + uint32_t unicode = fat_utf16_to_unicode(&p); + + if (unicode < 0x80) { + q[0] = unicode; + q++; + } else if (unicode < 0x800) { + q[0] = 0xc0 | (unicode >> 6); + q[1] = 0x80 | (unicode & 0x3f); + q += 2; + } else if (unicode < 0x10000) { + q[0] = 0xe0 | (unicode >> 12); + q[1] = 0x80 | ((unicode >> 6) & 0x3f); + q[2] = 0x80 | (unicode & 0x3f); + q += 3; + } else { + q[0] = 0xf0 | (unicode >> 18); + q[1] = 0x80 | ((unicode >> 12) & 0x3f); + q[2] = 0x80 | ((unicode >> 6) & 0x3f); + q[3] = 0x80 | (unicode & 0x3f); + q += 4; + } + } + return; +} + +void fat_utf8_to_utf16( + uint8_t *utf8, uint16_t *utf16, DEF_MRET(int, utf8_length), + DEF_MRET(int, utf16_length)) { + uint32_t unicode; + uint8_t *p = utf8; + uint16_t *q = utf16; + while (*p != '\0' || *(p + 1) != '\0') { + unicode = fat_utf8_to_unicode(&p); + fat_unicode_to_utf16(unicode, &q); + } + MRET(utf8_length) = p - utf8; + MRET(utf16_length) = q - utf16; + return; +} diff --git a/src/fs/fat32.c b/src/fs/fat32.c deleted file mode 100644 index fcca895..0000000 --- a/src/fs/fat32.c +++ /dev/null @@ -1,843 +0,0 @@ -/** - * @file fat32.c - * @author Ryan Wang (ryan1202@foxmail.com) - * @brief FAT32文件系统 - * @version 1.1 - * @date 2023-01-23 - * - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -// struct FAT_clus_list *clus_list; - -fs_operations_t fat32_fs_ops = { - .fs_check = fat32_check, - .fs_read_superblock = fat32_readsuperblock, - .fs_open = FAT32_open, - .fs_opendir = FAT32_find_dir, - .fs_close = FAT32_close, - .fs_read = FAT32_read, - .fs_write = FAT32_write, - .fs_create = FAT32_create_file, - .fs_delete = FAT32_delete_file, -}; - -status_t fat32_check(struct partition_table *pt) { - if (pt->fs_type == 0x0b || pt->fs_type == 0x0c) { return SUCCUESS; } - return FAILED; -} - -status_t fat32_readsuperblock(partition_t *partition, char *data) { - struct FAT32_dir sdir; - struct pt_fat32 *fat32 = kmalloc(sizeof(struct pt_fat32)); - struct index_node *dev = partition->device->inode; - memcpy(fat32, data, SECTOR_SIZE); - dev->f_ops.seek(dev, partition->start_lba + 1, 0); - dev->f_ops.read(dev, (uint8_t *)&fat32->FSInfo, SECTOR_SIZE); - - if (fat32->FSInfo.FSI_LeadSig == 0x41615252) { - partition->root->device = partition->device; - struct directory *dir = kmalloc(sizeof(struct directory)); - fat32->fat_buffer = kmalloc(SECTOR_SIZE); - - dir->start = 2; // 根目录在2号簇 - dir->inode = partition->root; - fat32->fat_start = partition->start_lba + fat32->BPB_RevdSecCnt; - fat32->data_start = fat32->fat_start + fat32->BPB_NumFATs * fat32->BPB_FATSz32; - fat32->buffer_pos = 0; - partition->private_data = fat32; - partition->root->dir = dir; - - dev->f_ops.seek(dev, fat32->data_start, 0); - dev->f_ops.read(dev, (uint8_t *)&sdir, sizeof(struct FAT32_dir)); - if (sdir.DIR_Attr == FAT32_ATTR_VOLUME_ID) { - string_del(&partition->name); - int cnt = 0; - while (sdir.DIR_Name[cnt] != ' ' && cnt < 11) - cnt++; - string_new(&partition->name, (char *)sdir.DIR_Name, cnt); - } - - return SUCCUESS; - } - kfree(fat32); - return FAILED; -} - -int FAT32_read(struct index_node *inode, uint8_t *buffer, uint32_t length) { - struct file *fp = inode->fp; - struct index_node *dev = inode->part->device->inode; - struct pt_fat32 *fat32 = fs_FAT32(inode->part->private_data); - int cnt, off = 0, tmp; - int pos; - const uint32_t clus_size = SECTOR_SIZE * fat32->BPB_SecPerClus; - const uint8_t *buf = kmalloc(clus_size); - - cnt = fp->offset / (clus_size); - pos = fp->index_table[cnt]; - dev->f_ops.seek(dev, - (fp->offset / SECTOR_SIZE) % fat32->BPB_SecPerClus + fat32->data_start + - (pos - 2) * fat32->BPB_SecPerClus, - 0); - if (fp->offset % (clus_size)) { - tmp = clus_size - fp->offset % (clus_size); - dev->f_ops.read(dev, (uint8_t *)buf, SECTOR_SIZE); - memcpy(buffer, buf + fp->offset % (clus_size), tmp); - off += tmp; - cnt++; - } - while (length - off > clus_size) { - pos = fp->index_table[cnt++]; - dev->f_ops.seek(dev, fat32->data_start + (pos - 2) * fat32->BPB_SecPerClus, 0); - dev->f_ops.read(dev, buffer + off, MIN(clus_size, length - off)); - off += clus_size; - } - tmp = fp->offset; - fp->offset += length; - if (fp->offset >= fp->size) { fp->offset = fp->size; } - return fp->offset - tmp; -} - -int FAT32_write(struct index_node *inode, uint8_t *buffer, uint32_t length) { - int i; - int pos; - struct file *fp = inode->fp; - struct pt_fat32 *fat32 = inode->part->private_data; - const uint8_t *buf = kmalloc(SECTOR_SIZE * fat32->BPB_SecPerClus); - struct FAT32_dir *sdir; - struct index_node *dev = inode->device->inode; - - int cnt = DIV_ROUND_UP(fp->offset, (SECTOR_SIZE * fat32->BPB_SecPerClus)); - int off = fp->offset % SECTOR_SIZE; - int off2 = cnt % fat32->BPB_SecPerClus; - - if (cnt > inode->fp->size / SECTOR_SIZE / fat32->BPB_SecPerClus) { - cnt = inode->fp->size / SECTOR_SIZE / fat32->BPB_SecPerClus; - } - pos = inode->fp->index_table[cnt]; - - dev->f_ops.seek(dev, off2 + (fat32->data_start + (pos - 2) * fat32->BPB_SecPerClus), 0); - dev->f_ops.write(dev, (uint8_t *)buf, MIN(SECTOR_SIZE - off, off + length)); - if (fp->offset % SECTOR_SIZE + length <= SECTOR_SIZE) goto done; - else { length -= SECTOR_SIZE - off; } - - i = 0; - while (length > 0) { - if (i % 2 == 0 && i != 0) { pos = fat_next(inode, pos, 1, 1); } - dev->f_ops.seek(dev, (i % 2 + (pos - 2) * fat32->BPB_SecPerClus + fat32->data_start), 0); - } - -done: - pos = fat_next(inode, fp->dir_start, fp->dir_offset / (SECTOR_SIZE * fat32->BPB_SecPerClus), 0); - dev->f_ops.seek(dev, fat32->data_start + (pos - 2) * fat32->BPB_SecPerClus + fp->dir_offset / SECTOR_SIZE, - 0); - dev->f_ops.read(dev, (uint8_t *)buf, SECTOR_SIZE); - sdir = (struct FAT32_dir *)(buf + fp->dir_offset % SECTOR_SIZE); - - inode->last_access_date.year = inode->write_date.year = BCD2BIN(CMOS_READ(CMOS_YEAR)); - inode->last_access_date.month = inode->write_date.month = BCD2BIN(CMOS_READ(CMOS_MONTH)); - inode->last_access_date.day = inode->write_date.day = BCD2BIN(CMOS_READ(CMOS_DAY_OF_MONTH)); - inode->write_time.hour = BCD2BIN(CMOS_READ(CMOS_HOURS)); - inode->write_time.minute = BCD2BIN(CMOS_READ(CMOS_MINUTES)); - inode->write_time.second = BCD2BIN(CMOS_READ(CMOS_SECONDS)); - sdir->DIR_LastAccDate = sdir->DIR_WrtDate = - (inode->write_date.year + 20) << 9 | inode->write_date.month << 5 | inode->write_date.day; - sdir->DIR_WrtTime = - inode->write_time.hour << 11 | inode->write_time.minute << 5 | inode->write_time.second; - dev->f_ops.seek(dev, fat32->data_start + (pos - 2) * fat32->BPB_SecPerClus + fp->dir_offset / SECTOR_SIZE, - 0); - dev->f_ops.write(dev, (uint8_t *)buf, SECTOR_SIZE); - - fp->offset += length; - return length; -} - -struct index_node *FAT32_create_file(partition_t *part, struct index_node *parent, char *name, int len) { - struct index_node *dev = part->device->inode; - char buf[SECTOR_SIZE], filename_short[11]; - unsigned int pos, i = 0, j, len2, name_count = 1, count = 1, name_len; - unsigned char checksum; - struct directory *dir = parent->dir; - struct pt_fat32 *fat32 = part->private_data; - struct FAT32_long_dir *ldir; - struct FAT32_dir *sdir; - struct index_node *inode = vfs_create(name, ATTR_FILE, parent); - struct file *file = kmalloc(sizeof(struct file)); - uint32_t offset; - int flag; - - file->inode = inode; - file->dir_start = parent->dir->start; - file->cur_pos = 0; - file->start = 0; - inode->fp = file; - inode->device = parent->device; - inode->part = part; - inode->f_ops = parent->f_ops; - pos = dir->start; - do { - // 如果到了下一个扇区,重新读取 - if (i % SECTOR_SIZE == 0) { - offset = fat32->data_start + (pos - 2) * fat32->BPB_SecPerClus + i / SECTOR_SIZE; - dev->f_ops.seek(dev, offset, 0); - dev->f_ops.read(dev, (uint8_t *)buf, SECTOR_SIZE); - } - - /** - * 统计短目录项重名个数(只在目录项是长文件名时使用) - * 如有重名,则短目录名以以下格式命名: SAMEFI~N.TXT (假设原名为samefilename.txt) - * 如果当前数字不够,则将'~'前移 - */ - if (buf[i % SECTOR_SIZE + 11] != FAT32_ATTR_LONG_NAME) { - flag = 1; - for (j = 0; j < 8 && buf[i % SECTOR_SIZE + j] != '~'; j++) { - if (buf[i % SECTOR_SIZE + j] != name[j]) { - flag = 0; - break; - } - } - if (flag) { name_count++; } - } - i += 0x20; - - if (i / SECTOR_SIZE / fat32->BPB_SecPerClus) pos = fat_next(inode, pos, 1, 1); - } while (buf[i]); - - flag = 0; - pos = ((pos - 2) * fat32->BPB_SecPerClus) * SECTOR_SIZE + i; - int len_without_ext; - int len_ext; - - for (i = 0; i < len && name[i] != '.'; i++) - if (islower(name[i])) flag |= 0x1; // 文件名含小写 - else if (isupper(name[i])) flag |= 0x2; // 文件名含大写 - - len_without_ext = i; - len_ext = len - len_without_ext - 1; - - if (i >= len) len_ext++; // 无扩展名文件 - for (; i < len; i++) - if (islower(name[i])) flag |= 0x4; // 扩展名含小写 - else if (isupper(name[i])) flag |= 0x8; // 扩展名含大写 - - // 文件名和扩展名混杂大小写或长度过长则作为长目录项 - if (len > 11 || len_ext > 3 || len_without_ext > 8 || (flag & 0x03) == 0x03 || (flag & 0x0c) == 0x0c) { - len2 = DIV_ROUND_UP(len, 13); - int tmp = name_count / 10; - while (tmp) { - count++; - tmp /= 10; - } - name_len = min(6, 8 - count - 1); - tmp = 10000000; - for (i = 0; i < 8; i++) { - if (i < name_len) filename_short[i] = toupper(name[i] ? name[i] : ' '); - else if (i == name_len) filename_short[i] = '~'; - else if (i - name_len < count) filename_short[i] = (name_count / tmp % 10 + '0'); - else filename_short[i] = ' '; - tmp /= 10; - } - for (; i < 11; i++) { - if (i - 8 < len_ext) filename_short[i] = name[len - len_ext + i - 8]; - else filename_short[i] = ' '; - } - FAT32_checksum(filename_short, checksum); - for (i = 0; i < len2; i++) { - int k; - if ((pos + i * 0x20) % SECTOR_SIZE == 0) { - dev->f_ops.seek(dev, offset, 0); - dev->f_ops.write(dev, (uint8_t *)buf, SECTOR_SIZE); - offset = fat32->data_start + (pos + i * 0x20) / SECTOR_SIZE; - dev->f_ops.seek(dev, offset, 0); - dev->f_ops.read(dev, (uint8_t *)buf, SECTOR_SIZE); - } - ldir = (struct FAT32_long_dir *)(buf + (pos + i * 0x20) % SECTOR_SIZE); - ldir->LDIR_Ord = len2 - i; - if (i == 0) ldir->LDIR_Ord |= 0x40; - int f = 0; - for (j = 0; (j % 13) < 5; j++) { - if (j < len - (len2 - i - 1) * 13) { - ldir->LDIR_Name1[j] = name[j]; - f = 1; - } else { - if (f) ldir->LDIR_Name1[j] = 0xffff; - else { - f = 0; - ldir->LDIR_Name1[j] = 0; - } - } - } - ldir->LDIR_Attr = FAT32_ATTR_LONG_NAME; - ldir->LDIR_Type = 0; - ldir->LDIR_Chksum = checksum; - for (; (j % 13) < 11; j++) { - if (j < len - (len2 - i - 1) * 13) { - ldir->LDIR_Name2[j - 5] = name[j]; - f = 1; - } else { - if (f) ldir->LDIR_Name2[j - 5] = 0xffff; - else { - f = 0; - ldir->LDIR_Name2[j - 5] = 0; - } - } - } - ldir->LDIR_FstClusLO = 0; - for (k = (j % 13); k < 13; k++) { - if (k < len - (len2 - i - 1) * 13) { - ldir->LDIR_Name3[k - 11] = name[j]; - f = 1; - } else { - if (f) ldir->LDIR_Name3[k - 11] = 0xffff; - else { - f = 0; - ldir->LDIR_Name3[k - 11] = 0; - } - } - } - } - pos += i * 0x20; - if (pos % SECTOR_SIZE == 0) { - dev->f_ops.seek(dev, offset, 0); - dev->f_ops.write(dev, (uint8_t *)buf, SECTOR_SIZE); - offset = fat32->data_start + pos / SECTOR_SIZE; - dev->f_ops.seek(dev, offset, 0); - dev->f_ops.read(dev, (uint8_t *)buf, SECTOR_SIZE); - } - for (i = 0; i < 11; i++) { - buf[pos % SECTOR_SIZE + i] = filename_short[i]; - } - sdir = (struct FAT32_dir *)(buf + pos % SECTOR_SIZE); - sdir->DIR_Attr = FAT32_ATTR_ARCHIVE; - - int year = BCD2BIN(CMOS_READ(CMOS_YEAR)) + 20; - int month = BCD2BIN(CMOS_READ(CMOS_MONTH)); - int day = BCD2BIN(CMOS_READ(CMOS_DAY_OF_MONTH)); - sdir->DIR_LastAccDate = sdir->DIR_CrtDate = sdir->DIR_WrtDate = year << 9 | month << 5 | day; - int hour = BCD2BIN(CMOS_READ(CMOS_HOURS)); - int minute = BCD2BIN(CMOS_READ(CMOS_MINUTES)); - int second = BCD2BIN(CMOS_READ(CMOS_SECONDS)); - sdir->DIR_CrtTime = sdir->DIR_WrtTime = hour << 11 | minute << 5 | second >> 1; - sdir->DIR_CrtTimeTenth = second * 10; - - int file_clus = fat32_alloc_clus(part, 0, 1); - sdir->DIR_FstClusHI = file_clus >> 16; - sdir->DIR_FstClusLO = file_clus & 0xffff; - sdir->DIR_FileSize = 0; - } else { - for (i = 0, j = 0; i < 8 && name[i] != '.' && j < len; i++, j++) - buf[pos % SECTOR_SIZE + i] = toupper(name[j]); - for (; i < 8; i++) - buf[pos % SECTOR_SIZE + i] = ' '; - for (j++; i < 11; i++, j++) { - if (j < len) buf[pos % SECTOR_SIZE + i] = toupper(name[j]); - else buf[pos % SECTOR_SIZE + i] = ' '; - } - - sdir = (struct FAT32_dir *)(buf + pos % SECTOR_SIZE); - sdir->DIR_Attr = FAT32_ATTR_ARCHIVE; - - sdir->DIR_NTRes = 0; - if (flag & 0x01) sdir->DIR_NTRes |= FAT32_BASE_L; - if (flag & 0x04) sdir->DIR_NTRes |= FAT32_EXT_L; - - int year = BCD2BIN(CMOS_READ(CMOS_YEAR)) + 20; - int month = BCD2BIN(CMOS_READ(CMOS_MONTH)); - int day = BCD2BIN(CMOS_READ(CMOS_DAY_OF_MONTH)); - sdir->DIR_LastAccDate = sdir->DIR_CrtDate = sdir->DIR_WrtDate = year << 9 | month << 5 | day; - int hour = BCD2BIN(CMOS_READ(CMOS_HOURS)); - int minute = BCD2BIN(CMOS_READ(CMOS_MINUTES)); - int second = BCD2BIN(CMOS_READ(CMOS_SECONDS)); - sdir->DIR_CrtTime = sdir->DIR_WrtTime = hour << 11 | minute << 5 | second >> 1; - sdir->DIR_CrtTimeTenth = second * 10; - - int file_clus = fat32_alloc_clus(part, 0, 1); - sdir->DIR_FstClusHI = file_clus >> 16; - sdir->DIR_FstClusLO = file_clus & 0xffff; - sdir->DIR_FileSize = 0; - } - construct_idxtbl(inode); - file->dir_offset = (pos % (SECTOR_SIZE * fat32->BPB_SecPerClus)); - file->start = sdir->DIR_FstClusHI << 16 | sdir->DIR_FstClusLO; - sdir = kmalloc(sizeof(struct FAT32_dir)); - memcpy(sdir, buf + pos % SECTOR_SIZE, sizeof(struct FAT32_dir)); - file->private_data = sdir; - dev->f_ops.seek(dev, offset, 0); - dev->f_ops.write(dev, (uint8_t *)buf, SECTOR_SIZE); - return inode; -} - -void FAT32_delete_file(partition_t *part, struct index_node *inode) { - char buf[SECTOR_SIZE]; - unsigned int pos, i; - struct file *file = inode->fp; - struct pt_fat32 *fat32 = part->private_data; - struct index_node *dev = inode->device->inode; - uint32_t offset; - bool f = true; - offset = fat32->data_start + (inode->fp->dir_start - 2) * fat32->BPB_SecPerClus + - inode->fp->dir_offset / SECTOR_SIZE; - dev->f_ops.seek(dev, offset, 0); - dev->f_ops.read(dev, (uint8_t *)buf, SECTOR_SIZE); - pos = inode->fp->dir_offset; - do { - if (pos % SECTOR_SIZE == 0 && pos >= SECTOR_SIZE) { - dev->f_ops.seek(dev, offset, 0); - dev->f_ops.write(dev, (uint8_t *)buf, SECTOR_SIZE); - offset -= 1; - dev->f_ops.seek(dev, offset, 0); - dev->f_ops.read(dev, (uint8_t *)buf, SECTOR_SIZE); - } - buf[pos % SECTOR_SIZE] = 0xe5; - pos -= 0x20; - } while (buf[pos % SECTOR_SIZE + 11] & FAT32_ATTR_LONG_NAME); - dev->f_ops.seek(dev, offset, 0); - dev->f_ops.write(dev, (uint8_t *)buf, SECTOR_SIZE); - pos = file->start; // 释放文件在文件分配表中对应的簇 - while (f) { - i = find_member_in_fat(part, pos); - if (i >= 0x0fffffff) f = 0; - fat32_free_clus(part, 0, pos); - pos = i; - } -} - -void FAT32_close(struct index_node *inode) { - struct file *file; - file = inode->fp; - kfree(file->private_data); - return; -} - -struct index_node *FAT32_open(struct _partition_s *part, struct index_node *parent, char *filename) { - int i, j, x; - struct FAT32_long_dir *ldir; - struct FAT32_dir *sdir; - struct directory *dir = parent->dir; - struct file *file = kmalloc(sizeof(struct file)); - struct index_node *inode = vfs_create(filename, ATTR_FILE, parent); - struct index_node *dev = part->device->inode; - struct pt_fat32 *fat32 = part->private_data; - uint32_t offset; - uint8_t flag = 0, f = 1; - unsigned int cc; - uint8_t buf[fat32->BPB_SecPerClus * SECTOR_SIZE]; - file->inode = inode; - inode->fp = file; - inode->part = parent->part; - inode->f_ops = parent->f_ops; - inode->device = parent->device; - int len = strlen(filename); - cc = dir->start; - - while (f) { - if (find_member_in_fat(part, cc) >= 0x0fffffff) f = 0; - offset = fat32->data_start + (cc - 2) * fat32->BPB_SecPerClus; - dev->f_ops.seek(dev, offset, 0); - dev->f_ops.read(dev, (uint8_t *)buf, fat32->BPB_SecPerClus * SECTOR_SIZE); - for (i = 0x00; i < SECTOR_SIZE * fat32->BPB_SecPerClus; i += 0x20) { - if (buf[i + 11] == FAT32_ATTR_LONG_NAME) continue; - if (buf[i] == 0xe5 || buf[i] == 0x00 || buf[i] == 0x05) continue; - ldir = (struct FAT32_long_dir *)(buf + i) - 1; - sdir = (struct FAT32_dir *)(buf + i); - j = 0; - - // 如果是长目录项 - while (ldir->LDIR_Attr == FAT32_ATTR_LONG_NAME && ldir->LDIR_Ord != 0xe5) { - for (x = 0; x < 5; x++) { - if (j > len && ldir->LDIR_Name1[x] == 0xffff) continue; - else if (j > len || ldir->LDIR_Name1[x] != (unsigned short)(filename[j++])) goto cmp_fail; - } - for (x = 0; x < 6; x++) { - if (j > len && ldir->LDIR_Name2[x] == 0xffff) continue; - else if (j > len || ldir->LDIR_Name2[x] != (unsigned short)(filename[j++])) goto cmp_fail; - } - for (x = 0; x < 2; x++) { - if (j > len && ldir->LDIR_Name3[x] == 0xffff) continue; - else if (j > len || ldir->LDIR_Name3[x] != (unsigned short)(filename[j++])) goto cmp_fail; - } - - if (j >= len) { - flag = 1; - goto cmp_success; - } - - ldir--; - } - - // 如果是短目录项 - j = 0; - if (sdir->DIR_Attr & FAT32_ATTR_DIRECTORY) continue; - for (x = 0; x < 8; x++) { - if (sdir->DIR_Name[x] == ' ') { - if (!(sdir->DIR_Attr & FAT32_ATTR_DIRECTORY)) { - if (filename[j] == '.' || filename[j] == 0) continue; - else if (sdir->DIR_Name[x] == filename[j]) { - j++; - continue; - } else goto cmp_fail; - } else goto cmp_fail; - } else if ((sdir->DIR_Name[x] >= 'A' && sdir->DIR_Name[x] <= 'Z') || - (sdir->DIR_Name[x] >= 'a' && sdir->DIR_Name[x] <= 'z')) { - if (sdir->DIR_NTRes & FAT32_BASE_L) { - if (j < len && sdir->DIR_Name[x] + 32 == filename[j]) { - j++; - continue; - } else goto cmp_fail; - } else { - if (j < len && sdir->DIR_Name[x] == filename[j]) { - j++; - continue; - } else goto cmp_fail; - } - } else if (sdir->DIR_Name[x] >= '0' && sdir->DIR_Name[x] <= '9') { - if (j < len && sdir->DIR_Name[x] == filename[j]) { - j++; - continue; - } else goto cmp_fail; - } else { - j++; - } - } - j++; - for (x = 0; x < 3; x++) { - if ((sdir->DIR_Ext[x] >= 'A' && sdir->DIR_Ext[x] <= 'Z') || - (sdir->DIR_Ext[x] >= 'a' && sdir->DIR_Ext[x] <= 'z')) { - if (sdir->DIR_NTRes & FAT32_BASE_L) { - if (j < len && sdir->DIR_Ext[x] + 32 == filename[j]) { - j++; - continue; - } else goto cmp_fail; - } else { - if (j < len && sdir->DIR_Ext[x] == filename[j]) { - j++; - continue; - } else goto cmp_fail; - } - } else if (sdir->DIR_Ext[x] >= '0' && sdir->DIR_Ext[x] <= '9') { - if (j < len && sdir->DIR_Ext[x] == filename[j]) { - j++; - continue; - } else goto cmp_fail; - } else if (sdir->DIR_Ext[x] == ' ') { - if (sdir->DIR_Ext[x] == filename[j]) { - if (sdir->DIR_Ext[x] == filename[j]) { - j++; - continue; - } else goto cmp_fail; - } - } else { - goto cmp_fail; - } - } - flag = 1; - goto cmp_success; - cmp_fail:; - } - cc = find_member_in_fat(part, cc); - }; -cmp_success: - if (flag) { - string_init(&inode->name); - string_new(&inode->name, filename, len); - file->dir_start = cc; - file->dir_offset = i; - file->start = file->cur_pos = (sdir->DIR_FstClusHI << 16 | sdir->DIR_FstClusLO) & 0x0fffffff; - file->private_data = kmalloc(sizeof(struct FAT32_dir)); - file->size = sdir->DIR_FileSize; - memcpy(file->private_data, sdir, sizeof(struct FAT32_dir)); - - inode->create_date.year = (sdir->DIR_CrtDate >> 9) - 20; - inode->create_date.month = (sdir->DIR_CrtDate >> 5) & 0x0f; - inode->create_date.day = sdir->DIR_CrtDate & 0x1f; - inode->write_date.year = (sdir->DIR_WrtDate >> 9) - 20; - inode->write_date.month = (sdir->DIR_WrtDate >> 5) & 0x0f; - inode->write_date.day = sdir->DIR_WrtDate & 0x1f; - inode->last_access_date.year = (sdir->DIR_LastAccDate >> 9) - 20; - inode->last_access_date.month = (sdir->DIR_LastAccDate >> 5) & 0x0f; - inode->last_access_date.day = sdir->DIR_LastAccDate & 0x1f; - inode->create_time.hour = sdir->DIR_CrtTime >> 11; - inode->create_time.minute = (sdir->DIR_CrtTime >> 5) & 0x3f; - inode->create_time.second = sdir->DIR_CrtTime & 0x1f; - inode->write_time.hour = sdir->DIR_WrtTime >> 11; - inode->write_time.minute = (sdir->DIR_WrtTime >> 5) & 0x3f; - inode->write_time.second = sdir->DIR_WrtTime & 0x1f; - - construct_idxtbl(inode); - return inode; - } else { - vfs_close(inode); - kfree(file); - return NULL; - } -} - -struct index_node *FAT32_find_dir(struct _partition_s *part, struct index_node *parent, char *name) { - unsigned int i, j, cc, x; - bool flag, f; - uint8_t *buf = kmalloc(((struct pt_fat32 *)part->private_data)->BPB_SecPerClus * SECTOR_SIZE); - struct directory *dir = kmalloc(sizeof(struct directory)); - struct pt_fat32 *fat32 = part->private_data; - struct index_node *dev = part->device->inode; - struct FAT32_long_dir *ldir; - struct FAT32_dir *sdir; - int len = strlen(name); - uint32_t offset; - dir->inode = kmalloc(sizeof(struct index_node)); - dir->inode->attribute = ATTR_DIR; - dir->inode->parent = parent; - dir->inode->f_ops = parent->f_ops; - dir->inode->device = part->device; - dir->inode->part = part; - list_init(&dir->inode->childs); - list_add_tail(&dir->inode->list, &parent->childs); - string_init(&dir->inode->name); - string_new(&dir->inode->name, name, len); - flag = 0; - f = 1; - cc = parent->dir->start; - while (f) { - if (find_member_in_fat(part, cc) >= 0x0fffffff) f = 0; - offset = fat32->data_start + (cc - 2) * fat32->BPB_SecPerClus; - dev->f_ops.seek(dev, offset, 0); - dev->f_ops.read(dev, (uint8_t *)buf, fat32->BPB_SecPerClus * SECTOR_SIZE); - for (i = 0x00; i < SECTOR_SIZE * fat32->BPB_SecPerClus; i += 0x20) { - if (buf[i + 11] == FAT32_ATTR_LONG_NAME) continue; - if (buf[i] == 0xe5 || buf[i] == 0x00 || buf[i] == 0x05) continue; - ldir = (struct FAT32_long_dir *)(buf + i) - 1; - j = 0; - - // 如果是长目录项 - while (ldir->LDIR_Attr == FAT32_ATTR_LONG_NAME && ldir->LDIR_Ord != 0xe5) { - for (x = 0; x < 5; x++) { - if (j > len && ldir->LDIR_Name1[x] == 0xffff) continue; - else if (j > len || ldir->LDIR_Name1[x] != (unsigned short)(name[j++])) goto cmp_fail; - } - for (x = 0; x < 6; x++) { - if (j > len && ldir->LDIR_Name2[x] == 0xffff) continue; - else if (j > len || ldir->LDIR_Name2[x] != (unsigned short)(name[j++])) goto cmp_fail; - } - for (x = 0; x < 2; x++) { - if (j > len && ldir->LDIR_Name3[x] == 0xffff) continue; - else if (j > len || ldir->LDIR_Name3[x] != (unsigned short)(name[j++])) goto cmp_fail; - } - - if (j >= len) { - flag = true; - goto cmp_success; - } - - ldir--; - } - - // 如果是短目录项 - j = 0; - sdir = (struct FAT32_dir *)(buf + i); - for (x = 0; x < 11; x++) { - if (sdir->DIR_Name[x] == ' ') { - if (sdir->DIR_Attr & FAT32_ATTR_DIRECTORY) { - if (sdir->DIR_Name[x] == name[j]) { - j++; - continue; - } else { - goto cmp_fail; - } - } - } else if ((sdir->DIR_Name[x] >= 'A' && sdir->DIR_Name[x] <= 'Z') || - (sdir->DIR_Name[x] >= 'a' && sdir->DIR_Name[x] <= 'z')) { - if (sdir->DIR_NTRes & FAT32_BASE_L) { - if (j < len && sdir->DIR_Name[x] + 32 == name[j]) { - j++; - continue; - } else { - goto cmp_fail; - } - } else { - if (j < len && sdir->DIR_Name[x] == name[j]) { - j++; - continue; - } else { - goto cmp_fail; - } - } - - } else if (j < len && sdir->DIR_Name[x] == name[j]) { - j++; - continue; - } else if (sdir->DIR_Name[x] >= '0' && sdir->DIR_Name[x] <= '9') { - goto cmp_fail; - } else { - goto cmp_fail; - } - } - flag = true; - goto cmp_success; - cmp_fail:; - } - cc = find_member_in_fat(part, cc); - }; -cmp_success: - if (flag) { - sdir = (struct FAT32_dir *)(buf + i); - dir->dir_start = cc; - dir->dir_offset = i; - dir->start = (sdir->DIR_FstClusHI << 16 | sdir->DIR_FstClusLO); - dir->inode->dir = dir; - - dir->inode->create_date.year = (sdir->DIR_CrtDate >> 9) - 20; - dir->inode->create_date.month = (sdir->DIR_CrtDate >> 5) & 0x0f; - dir->inode->create_date.day = sdir->DIR_CrtDate & 0x1f; - dir->inode->write_date.year = (sdir->DIR_WrtDate >> 9) - 20; - dir->inode->write_date.month = (sdir->DIR_WrtDate >> 5) & 0x0f; - dir->inode->write_date.day = sdir->DIR_WrtDate & 0x1f; - dir->inode->last_access_date.year = (sdir->DIR_LastAccDate >> 9) - 20; - dir->inode->last_access_date.month = (sdir->DIR_LastAccDate >> 5) & 0x0f; - dir->inode->last_access_date.day = sdir->DIR_LastAccDate & 0x1f; - dir->inode->create_time.hour = sdir->DIR_CrtTime >> 11; - dir->inode->create_time.minute = (sdir->DIR_CrtTime >> 5) & 0x3f; - dir->inode->create_time.second = sdir->DIR_CrtTime & 0x1f; - dir->inode->write_time.hour = sdir->DIR_WrtTime >> 11; - dir->inode->write_time.minute = (sdir->DIR_WrtTime >> 5) & 0x3f; - dir->inode->write_time.second = sdir->DIR_WrtTime & 0x1f; - kfree(buf); - return dir->inode; - } else { - vfs_close(dir->inode); - kfree(dir); - kfree(buf); - return NULL; - } -} - -void construct_idxtbl(struct index_node *inode) { - int i; - - struct pt_fat32 *fat32 = inode->part->private_data; - int cnt = inode->fp->size / SECTOR_SIZE / fat32->BPB_SecPerClus; - inode->fp->index_table = kmalloc(cnt * sizeof(uint32_t)); - - inode->fp->index_table[0] = inode->fp->start; - for (i = 1; i < cnt; i++) { - inode->fp->index_table[i] = find_member_in_fat(inode->part, inode->fp->index_table[i - 1]); - } -} - -int fat32_alloc_clus(partition_t *part, int last_clus, int first) { - int i, j; - struct pt_fat32 *fat32 = part->private_data; - uint32_t offset = fat32->fat_start; - struct index_node *dev = part->device->inode; - - i = 3; - if (DIV_ROUND_UP(i, 128) != fat32->buffer_pos) { - dev->f_ops.seek(dev, offset, 0); - dev->f_ops.read(dev, (uint8_t *)fat32->fat_buffer, SECTOR_SIZE); - } - while (fat32->fat_buffer[i % 128]) { - if (i % 128 == 0) { - offset = fat32->fat_start + (i / 128); - dev->f_ops.seek(dev, offset, 0); - dev->f_ops.read(dev, (uint8_t *)fat32->fat_buffer, SECTOR_SIZE); - } - i++; - } - for (j = 0; j < fat32->BPB_NumFATs; j++) { - offset = fat32->fat_start + j * fat32->BPB_FATSz32 + (i / 128); - dev->f_ops.seek(dev, offset, 0); - dev->f_ops.read(dev, (uint8_t *)fat32->fat_buffer, SECTOR_SIZE); - fat32->fat_buffer[i % 128] = 0x0fffffff; - dev->f_ops.write(dev, (uint8_t *)fat32->fat_buffer, SECTOR_SIZE); - if (!first) { - offset = fat32->fat_start + j * fat32->BPB_FATSz32 + (last_clus / 128); - dev->f_ops.seek(dev, offset, 0); - dev->f_ops.read(dev, (uint8_t *)fat32->fat_buffer, SECTOR_SIZE); - fat32->fat_buffer[last_clus % 128] = i; - dev->f_ops.write(dev, (uint8_t *)fat32->fat_buffer, SECTOR_SIZE); - } - } - return i; -} - -int fat32_free_clus(partition_t *part, int last_clus, int clus) { - int buf1[128], buf2[128]; - int j; - struct pt_fat32 *fat32 = part->private_data; - uint32_t offset; - if (last_clus < 3 && clus < 3) return -1; - for (j = 0; j < fat32->BPB_NumFATs; j++) { - if (last_clus > 2 && clus > 2) { - offset = fat32->fat_start + j * fat32->BPB_FATSz32 + last_clus / 128; - dev->f_ops.seek(dev, offset, 0); - dev->f_ops.read(dev, (uint8_t *)buf1, SECTOR_SIZE); - if (clus / 128 != last_clus / 128) { - offset = fat32->fat_start + j * fat32->BPB_FATSz32 + clus / 128; - dev->f_ops.seek(dev, offset, 0); - dev->f_ops.read(dev, (uint8_t *)buf2, SECTOR_SIZE); - buf1[last_clus % 128] = buf2[clus % 128]; - buf2[clus % 128] = 0x00; - dev->f_ops.write(dev, (uint8_t *)buf2, SECTOR_SIZE); - } else { - buf1[last_clus % 128] = buf1[clus % 128]; - buf1[clus % 128] = 0x00; - } - offset = fat32->fat_start + j * fat32->BPB_FATSz32 + last_clus / 128; - dev->f_ops.seek(dev, offset, 0); - dev->f_ops.write(dev, (uint8_t *)buf1, SECTOR_SIZE); - } else if (clus > 2) { - offset = fat32->fat_start + j * fat32->BPB_FATSz32 + clus / 128; - dev->f_ops.seek(dev, offset, 0); - dev->f_ops.read(dev, (uint8_t *)buf1, SECTOR_SIZE); - buf1[clus % 128] = 0x00; - dev->f_ops.write(dev, (uint8_t *)buf1, SECTOR_SIZE); - } - } - return 0; -} - -unsigned int find_member_in_fat(struct _partition_s *part, int i) { - struct index_node *dev = part->device->inode; - unsigned int next_clus; - struct pt_fat32 *fat32 = part->private_data; - uint32_t offset = part->start_lba + fat32->BPB_RevdSecCnt + (i / 128); - if (DIV_ROUND_UP(i, 128) != fat32->buffer_pos) { - dev->f_ops.seek(dev, offset, 0); - dev->f_ops.read(dev, (uint8_t *)fat32->fat_buffer, SECTOR_SIZE); - } - next_clus = fat32->fat_buffer[i % 128]; - return next_clus; -} - -uint32_t fat_next(struct index_node *inode, uint32_t clus, int next, int alloc) { - uint32_t i, tmp, c = clus; - partition_t *part = inode->part; - - if (inode->fp->cur_pos - inode->fp->start < clus) { c = c - (inode->fp->cur_pos - inode->fp->start); } - - for (i = 0; i < next; i++) { - tmp = find_member_in_fat(part, c); - if (tmp < 0x0ffffff8) c = tmp; - else { - if (alloc) { c = fat32_alloc_clus(part, c, 0); } - break; - } - } - - inode->fp->cur_pos = c; - return c; -} - -static __init void fat32_fs_entry(void) { - fs_register("FAT32", &fat32_fs_ops); -} - -fs_initcall(fat32_fs_entry); diff --git a/src/fs/fs.c b/src/fs/fs.c index 3815f01..d66f207 100644 --- a/src/fs/fs.c +++ b/src/fs/fs.c @@ -2,184 +2,73 @@ #include #include #include -#include +#include +#include +#include +#include -LIST_HEAD(part_list_head); LIST_HEAD(fs_list_head); -struct file_operations fs_fops = { - .open = fs_open, .close = fs_close, .read = NULL, .write = NULL, .seek = fs_seek, .ioctl = NULL}; - -struct file *fds[FD_MAX_NR]; -int fd_num; +void register_fs(FileSystem *fs) { + list_add_tail(&fs->list, &fs_list_head); +} -void init_fs(void) { - int i; - struct index_node *inode, *next, *part_inode; - struct partition_table *pt; - for (i = 0; i < FD_MAX_NR; i++) { - fds[i] = NULL; - } - char *buffer = kmalloc(SECTOR_SIZE); - list_for_each_owner_safe (inode, next, &dev->childs, list) { - if (inode->device->type == DEV_STORAGE) { - fs_t *fs, *fs_next; - inode->f_ops.seek(inode, 0, 0); - inode->f_ops.read(inode, (uint8_t *)buffer, SECTOR_SIZE); - for (i = 0; i < 4; i++) { - pt = (struct partition_table *)(buffer + 0x1be + i * sizeof(struct partition_table)); - if (pt->sign != 0x80 && pt->sign != 0x00) continue; - list_for_each_owner_safe (fs, fs_next, &fs_list_head, list) { - if (fs->fs_ops->fs_check(pt) == FAILED) continue; - char *path = kmalloc(inode->name.length + 3); - path[0] = '/'; - strcpy(path + 1, inode->name.text); - path[inode->name.length + 1] = 'p'; - path[inode->name.length + 2] = i + '1'; - part_inode = vfs_mkdir(path); - part_inode->f_ops = fs_fops; - part_inode->f_ops.read = fs->fs_ops->fs_read; - part_inode->f_ops.write = fs->fs_ops->fs_write; - part_inode->part = kmalloc(sizeof(partition_t)); - part_inode->part->fs = fs; - part_inode->part->root = part_inode; - part_inode->part->device = inode->device; - part_inode->part->start_lba = pt->start_lba; - list_add_tail(&part_inode->part->list, &part_list_head); - char *superblock = kmalloc(SECTOR_SIZE); - inode->f_ops.seek(inode, pt->start_lba, 0); - inode->f_ops.read(inode, (uint8_t *)superblock, SECTOR_SIZE); - fs->fs_ops->fs_read_superblock(part_inode->part, superblock); - } - } - } - } +void unregister_fs(FileSystem *fs) { + list_del(&fs->list); } -int fs_register(char *name, fs_operations_t *fs_ops) { - fs_t *fs = kmalloc(sizeof(fs_t)); - string_init(&fs->name); - string_new(&fs->name, name, strlen(name)); - fs->fs_ops = fs_ops; - list_add_tail(&fs->list, &fs_list_head); - return 0; +// 为文件系统实现对象树的接口 +TransferResult fs_obj_read( + struct Object *object, struct ObjectHandle *handle, + TransferDirection direction, uint8_t *buf, size_t size) { + if (object == NULL || handle == NULL) + return TRANSFER_ERROR_INVALID_PARAMETER; + if (object->fs_info == NULL || object->fs_info->file_ops.fs_read == NULL) + return TRANSFER_ERROR_INVALID_PARAMETER; + FsResult result = + object->fs_info->file_ops.fs_read(object, handle, buf, size); + if (result == FS_OK) return TRANSFER_OK; + else return TRANSFER_ERROR_OTHER; } -int alloc_fd(void) { - if (fd_num >= FD_MAX_NR - 1) { - int i; - for (i = 0; i < FD_MAX_NR; i++) { - if (fds[i] == NULL) { - fds[i] = (struct file *)-1; - return i; - } - } - return -1; - } - fd_num++; - return fd_num - 1; +TransferResult fs_obj_write( + struct Object *object, struct ObjectHandle *handle, + TransferDirection direction, uint8_t *buf, size_t size) { + if (object == NULL || handle == NULL) + return TRANSFER_ERROR_INVALID_PARAMETER; + if (object->fs_info == NULL || object->fs_info->file_ops.fs_write == NULL) + return TRANSFER_ERROR_INVALID_PARAMETER; + FsResult result = + object->fs_info->file_ops.fs_write(object, handle, buf, size); + if (result == FS_OK) return TRANSFER_OK; + else return TRANSFER_ERROR_OTHER; } -struct index_node *fs_opendir(char *path) { - struct index_node *inode, *parent, *next; - partition_t *part, *pnext; - uint8_t f; - int l = strlen(path); - char *name = kmalloc(l), *p; - strcpy(name, path); - p = name; - if (p[0] == '/' && p[1] == 0) return root; - int cnt = l; - while (p[cnt] != '/') - cnt--; - p[cnt] = 0; - if ((inode = vfs_opendir(p)) != NULL) return inode; +FsResult fs_obj_create_file( + Object *parent, FileSystemInfo *info, string_t *name, Object **object, + ObjectAttr *attr) { + *object = create_object(parent, name, *attr); + Object *out = *object; + if (out == NULL) return FS_ERROR_OTHER; - int length = 0; - if (*p != '/') return NULL; // 绝对路径以"/"开始 - else if (p[1] == '\0') { return root; } - p++; - while (p[length] != '/' && p[length] != '\0') - length++; - p[length] = 0; - f = 1; - list_for_each_owner_safe (part, pnext, &part_list_head, list) { - if (strncmp(p, part->root->name.text, length) == 0) { - f = 0; - inode = part->root; - break; - } - } - if (f) return NULL; - while (*p != '\0') { - f = 1; - p += length + 1; - parent = inode; - length = 0; - while (p[length] != '/' && p[length] != '\0') - length++; - p[length] = 0; - // inode = vfs_find(inode, p); - list_for_each_owner_safe (inode, next, &parent->childs, list) { - if (strncmp(p, inode->name.text, length - 1) == 0 && inode->attribute == ATTR_DIR) { - f = 0; - break; - } - } - if (f) inode = parent->part->fs->fs_ops->fs_opendir(parent->part, parent, p); - if (inode == NULL) return NULL; - if (p + length >= name + cnt && inode->attribute == ATTR_DIR) { - string_init(&inode->name); - string_new(&inode->name, p, strlen(p)); - return inode; - } - } - return NULL; -} + out->in.type = TRANSFER_TYPE_STREAM; + out->in.stream = fs_obj_read; + out->out.type = TRANSFER_TYPE_STREAM; + out->out.stream = fs_obj_write; -struct index_node *fs_open(char *path) { - struct index_node *inode, *parent, *next; - inode = vfs_open(path); - if (inode == NULL) { - int cnt = strlen(path) - 1; - while (path[cnt] != '/') - cnt--; - parent = fs_opendir(path); - path[cnt] = 0; - path += cnt + 1; - list_for_each_owner_safe (inode, next, &parent->childs, list) { - if (strncmp(path, inode->name.text, strlen(path) - 1) == 0 && inode->attribute != ATTR_DIR) { - return inode; - } - } - inode = parent->part->fs->fs_ops->fs_open(parent->part, parent, path); - } - return inode; -} + out->fs_info = info; -int fs_close(struct index_node *inode) { - inode->part->fs->fs_ops->fs_close(inode); - kfree(inode->fp); - string_del(&inode->name); - return 0; + return FS_OK; } -int fs_seek(struct index_node *inode, unsigned int offset, unsigned int origin) { - inode->fp->offset = origin + offset; - return 0; -} +FsResult fs_obj_create_dir( + Object *parent, FileSystemInfo *info, string_t *name, Object **object, + ObjectAttr *attr) { + *object = create_object_directory(parent, name, *attr); + Object *out = *object; + if (out == NULL) return FS_ERROR_OTHER; -int fs_create(struct index_node *parent, char *name) { - struct index_node *inode = vfs_create(name, ATTR_FILE, parent); - inode->fp = parent->fp; - inode->part = parent->part; - inode->f_ops = parent->f_ops; - inode->part->fs->fs_ops->fs_create(inode->part, parent, name, strlen(name)); - return 0; -} + out->fs_info = info; -int fs_delete(struct index_node *inode) { - inode->part->fs->fs_ops->fs_delete(inode->part, inode); - fs_close(inode); - return 0; -} \ No newline at end of file + return FS_OK; +} diff --git a/src/fs/vfs.c b/src/fs/vfs.c deleted file mode 100644 index 2f5c704..0000000 --- a/src/fs/vfs.c +++ /dev/null @@ -1,168 +0,0 @@ -#include -#include -#include -#include - -struct index_node *root; - -struct index_node *vfs_mkdir(char *path) { - int length = strlen(path) - 1; - char *name = kmalloc(length); - strcpy(name, path); - if (name[length] == '/') name[length] = 0, length--; - while (name[length] != '/') - length--; - length++; - name += length; - path[length] = 0; - struct index_node *parent = vfs_opendir(path), *inode; - inode = kmalloc(sizeof(struct index_node)); - memset(inode, 0, sizeof(struct index_node)); - inode->attribute = ATTR_DIR; - inode->parent = parent; - list_add_tail(&inode->list, &parent->childs); - inode->create_date.year = inode->write_date.year = inode->last_access_date.year = - BCD2BIN(CMOS_READ(CMOS_YEAR)); - inode->create_date.month = inode->write_date.month = inode->last_access_date.month = - BCD2BIN(CMOS_READ(CMOS_MONTH)); - inode->create_date.day = inode->write_date.day = inode->last_access_date.day = - BCD2BIN(CMOS_READ(CMOS_DAY_OF_MONTH)); - inode->create_time.hour = inode->write_time.hour = inode->last_access_time.hour = - BCD2BIN(CMOS_READ(CMOS_HOURS)); - inode->create_time.minute = inode->write_time.minute = inode->last_access_time.minute = - BCD2BIN(CMOS_READ(CMOS_MINUTES)); - inode->create_time.second = inode->write_time.second = inode->last_access_time.second = - BCD2BIN(CMOS_READ(CMOS_SECONDS)); - - string_init(&inode->name); - string_new(&inode->name, name, strlen(name)); - list_init(&inode->childs); - return inode; -} - -void vfs_rm(struct index_node *inode) { - struct index_node *child, *next; - string_del(&inode->name); - if (!list_empty(&inode->childs)) { - list_for_each_owner_safe (child, next, &inode->childs, childs) { - vfs_rm(child); - } - } - list_del(&inode->list); - kfree(inode); -} - -void vfs_rename(struct index_node *inode, char *name) { - string_del(&inode->name); - string_new(&inode->name, name, strlen(name)); -} - -/* - * 函数名: vfs_find - * 描述: 找到并返回目录的inode - * 参数: - * @parent 目录的父目录 - * @name 目录的名称 - * 返回: inode 找到目录 - * NULL 找不到目录 - */ -struct index_node *vfs_find(struct index_node *parent, char *name) { - struct index_node *inode, *next; - list_for_each_owner_safe (inode, next, &parent->childs, list) { - if (strcmp(name, inode->name.text) == 0) { - if (inode->attribute == ATTR_DIR) { return inode; } - } - } - return NULL; -} - -struct index_node *vfs_open(char *path) { - struct index_node *inode = root, *tmp; - - char *name = kmalloc(strlen(path)), *p; - strcpy(name, path); - p = name; - int length; - if (*path != '/') return NULL; // 绝对路径以"/"开始 - else if (path[1] == '\0') { return root; } - p++; - while (*path != '\0') { - length = 0; - while (p[length] != '/' && p[length] != '\0') - length++; - p[length] = 0; - tmp = vfs_find(inode, p); - if (tmp == NULL) break; - else inode = tmp; - p += length + 1; - } - struct index_node *cur, *next; - list_for_each_owner_safe (cur, next, &inode->childs, list) { - if (strcmp(p, cur->name.text) == 0) { - if (cur->attribute != ATTR_DIR) { return cur; } - } - } - return NULL; -} - -void vfs_close(struct index_node *inode) { - if (inode->attribute == ATTR_FILE) { - fs_close(inode); - string_del(&inode->name); - list_del(&inode->list); - kfree(inode); - } -} - -struct index_node *vfs_opendir(char *path) { - struct index_node *inode = root; - int l = strlen(path); - char *name = kmalloc(l), *p; - strcpy(name, path); - p = name; - int length; - if (*path != '/') return NULL; // 绝对路径以"/"开始 - else if (path[1] == '\0') { return root; } - p++; - while (*path != '\0') { - length = 0; - while (p[length] != '/' && p[length] != '\0') - length++; - p[length] = 0; - inode = vfs_find(inode, p); - if (inode == NULL) return NULL; - if (p + length >= name + l && inode->attribute == ATTR_DIR) { return inode; } - p += length + 1; - } - return NULL; -} - -struct index_node *vfs_create(char *name, inode_attr_t attr, struct index_node *parent) { - struct index_node *inode = kmalloc(sizeof(struct index_node)); - list_init(&inode->childs); - string_init(&inode->name); - string_new(&inode->name, name, strlen(name)); - inode->attribute = attr; - inode->parent = parent; - if (parent != NULL) list_add_tail(&inode->list, &parent->childs); - return inode; -} - -void vfs_delete(struct index_node *inode) { - string_del(&inode->name); - list_del(&inode->list); - kfree(inode); -} - -void init_vfs(void) { - // 根目录作为名称为""的文件夹初始化 - root = kmalloc(sizeof(struct index_node)); - memset(root, 0, sizeof(struct index_node)); - root->attribute = ATTR_DIR; - - string_init(&root->name); - string_new(&root->name, "", strlen("")); - list_init(&root->childs); - - dev = vfs_mkdir("/dev/"); -} \ No newline at end of file diff --git a/src/include/bits.h b/src/include/bits.h index 296d689..98a516f 100644 --- a/src/include/bits.h +++ b/src/include/bits.h @@ -23,14 +23,16 @@ #define HOST2LE_WORD(n) (n) #define HOST2LE_DWORD(n) (n) -#define BIT(n) (1 << n) -#define BIT_FFS_R(n) (bsf(n)) // 从低到高找到第一个非0位的位置 -#define BIT_FFS_L(n) (bsr(n)) // 从高到低找到第一个非0位的位置 - -#define BIN_EN(n, x) ((n) | x) -#define BIN_DIS(n, x) ((n) & ~x) -#define BIN_IS_DIS(n, x) (!BIN_EN(n, x)) -#define BIN_IS_EN(n, x) (!BIN_IS_DIS(n, x)) +#define BIT(n) (1 << (n)) +#define BIT_FFS_R(n) (bsf(n)) // 从低到高找到第一个非0位的位置 +#define BIT_FFS_L(n) (bsr(n)) // 从高到低找到第一个非0位的位置 +#define BIT_FFZ_R(n) (bsf(~(n))) // 从低到高找到第一个为0位的位置 +#define BIT_FFZ_L(n) (bsr(~(n))) // 从高到低找到第一个为0位的位置 + +#define BIN_EN(n, x) ((n) | (x)) +#define BIN_DIS(n, x) ((n) & ~(x)) +#define BIN_IS_DIS(n, x) (!((n) & (x))) +#define BIN_IS_EN(n, x) ((!BIN_IS_DIS(n, x))) #endif diff --git a/src/include/config.h b/src/include/config.h index 930d7cc..30950f1 100644 --- a/src/include/config.h +++ b/src/include/config.h @@ -1,6 +1,8 @@ #ifndef _CONFIG_H #define _CONFIG_H -#define ARCH_X86 +#ifdef __GNUC__ +#define HAS_BUILTIN_CLZ +#endif #endif \ No newline at end of file diff --git a/src/include/const.h b/src/include/const.h index dcd2c8e..20ea277 100644 --- a/src/include/const.h +++ b/src/include/const.h @@ -1,6 +1,4 @@ #ifndef _CONST_H #define _CONST_H -#define SECTOR_SIZE 512 - #endif \ No newline at end of file diff --git a/src/include/ctype.h b/src/include/ctype.h index 09037f7..da3f51f 100644 --- a/src/include/ctype.h +++ b/src/include/ctype.h @@ -1,29 +1,29 @@ #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 _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) diff --git a/src/include/driver/bus_dm.h b/src/include/driver/bus_dm.h new file mode 100644 index 0000000..c1b6b57 --- /dev/null +++ b/src/include/driver/bus_dm.h @@ -0,0 +1,7 @@ +#ifndef _BUS_DM_H +#define _BUS_DM_H + +#include +extern DeviceManager bus_controller_dm; + +#endif \ No newline at end of file diff --git a/src/include/driver/framebuffer/console_backend.h b/src/include/driver/framebuffer/console_backend.h new file mode 100644 index 0000000..4fffcd0 --- /dev/null +++ b/src/include/driver/framebuffer/console_backend.h @@ -0,0 +1,48 @@ +#ifndef FB_CONSOLE_BACKEND_H +#define FB_CONSOLE_BACKEND_H + +#include "kernel/spinlock.h" +#include +#include +#include + +#define FB_DEFAULT_FG_COLOR 0xAAAAAA +#define FB_DEFAULT_BG_COLOR 0x000000 + +typedef struct { + ConsoleBackend backend; + + struct FrameBufferDevice *fb_device; + + char **line_ends; + uint16_t *line_widths; + char *text_buffer; + char *current; + char *last_update; + int buffer_size; + + uint8_t *font; + + uint16_t width; + uint16_t height; + uint16_t real_height; + + uint16_t x, y; + uint16_t last_update_y; + uint16_t last_update_x; + + uint32_t foreground_color; + uint32_t default_fg_color; + uint32_t background_color; + uint32_t default_bg_color; + + PeriodicTask periodic_task; + + spinlock_t lock; +} FrameBufferConsoleBackend; + +void fb_console_backend_init(void *context); +void fb_console_backend_put_string( + void *context, const char *string, int length); + +#endif \ No newline at end of file diff --git a/src/include/driver/framebuffer/fb.h b/src/include/driver/framebuffer/fb.h new file mode 100644 index 0000000..5fb2e50 --- /dev/null +++ b/src/include/driver/framebuffer/fb.h @@ -0,0 +1,30 @@ +#ifndef _DRIVER_FRAMEBUFFER_H +#define _DRIVER_FRAMEBUFFER_H + +#include "stdint.h" + +typedef struct FramebufferOps { + void (*write_pixel_raw)(uint8_t *vram, uint32_t color); + void (*write_pixel_rgb)(uint8_t *vram, uint8_t r, uint8_t g, uint8_t b); +} FramebufferOps; + +struct FrameBufferDevice; +struct FrameBufferModeInfo; +void draw_rect( + struct FrameBufferDevice *fb_device, int x, int y, int width, int height, + int color); +void draw_rect_rgb( + struct FrameBufferDevice *fb_device, int x, int y, int width, int height, + uint8_t r, uint8_t g, uint8_t b); +void print_word( + FramebufferOps *ops, struct FrameBufferModeInfo *mode_info, uint8_t *vram, + uint8_t *ascii, int color); +void print_word_rgb( + FramebufferOps *ops, struct FrameBufferModeInfo *mode_info, uint8_t *vram, + char *ascii, uint8_t r, uint8_t g, uint8_t b); + +extern FramebufferOps fb_ops_8; +extern FramebufferOps fb_ops_16; +extern FramebufferOps fb_ops_24; +extern FramebufferOps fb_ops_32; +#endif \ No newline at end of file diff --git a/src/include/driver/framebuffer/fb_dm.h b/src/include/driver/framebuffer/fb_dm.h new file mode 100644 index 0000000..b95a154 --- /dev/null +++ b/src/include/driver/framebuffer/fb_dm.h @@ -0,0 +1,46 @@ +#ifndef _FRAMEBUFFER_DM_H +#define _FRAMEBUFFER_DM_H + +#include +#include +#include +#include +#include +#include +#include + +typedef struct FrameBufferModeInfo { + uint16_t width; + uint16_t height; + uint8_t bits_per_pixel; + uint8_t bytes_per_pixel; +} FrameBufferModeInfo; + +typedef struct FrameBufferDevice { + list_t fb_list_lh; + + LogicalDevice *device; + FrameBufferModeInfo mode_info; + uint8_t *framebuffer_address; + + FramebufferOps *framebuffer_ops; + + FrameBufferConsoleBackend console_backend; +} FrameBufferDevice; + +typedef struct FrameBufferDeviceManager { + LogicalDevice *main_display_device; + uint8_t new_fb_device_num; + uint8_t fb_device_count; +} FrameBufferDeviceManager; + +extern struct DeviceManager framebuffer_dm; + +DriverResult create_framebuffer_device( + FrameBufferDevice **fb_device, DeviceOps *ops, + PhysicalDevice *physical_device, DeviceDriver *device_driver); +DriverResult delete_framebuffer_device(FrameBufferDevice *framebuffer_device); +DriverResult framebuffer_start_all(); +DriverResult framebuffer_get_device( + int in_index, FrameBufferDevice **out_device); +#endif \ No newline at end of file diff --git a/src/include/driver/input/input_dm.h b/src/include/driver/input/input_dm.h new file mode 100644 index 0000000..523af29 --- /dev/null +++ b/src/include/driver/input/input_dm.h @@ -0,0 +1,73 @@ +#ifndef _INPUT_DM_H +#define _INPUT_DM_H + +#include "kernel/spinlock.h" +#include +#include +#include +#include +#include + +#define INPUT_EVENT_QUEUE_SIZE 256 + +#define INPUT_KEY_EVENT_MOUSE_BASE 0 +#define INPUT_KEY_EVENT_MODIFIER_BASE 8 +#define INPUT_KEY_EVENT_KEYBOARD_BASE 16 + +#define INPUT_KEY_PAGE_KEYBOARD_KEYPAD 0x07 +#define INPUT_KEY_PAGE_CONSUMER 0x0c +#define INPUT_KEY_PAGE_GENERAL_DESKTOP 0x01 + +typedef enum { + INPUT_TYPE_UNKNOWN, + INPUT_TYPE_KEYBOARD, + INPUT_TYPE_MOUSE, + INPUT_TYPE_MAX, +} InputDeviceType; + +typedef struct InputDevice { + LogicalDevice *device; + InputDeviceType type; +} InputDevice; + +typedef struct KeyEvent { + uint16_t keycode; + uint8_t pressed; // 1: pressed, 0: released + uint8_t page; +} KeyEvent; + +typedef struct PointerEvent { + int16_t dx; + int16_t dy; + enum PointerEventType { + POINTER_TYPE_MOVE, + POINTER_TYPE_SCROLL, + POINTER_TYPE_PRESSURE, + } type; +} PointerEvent; + +typedef struct InputDeviceManager { + int new_device_num[INPUT_TYPE_MAX]; + int device_count[INPUT_TYPE_MAX]; + spinlock_t lock[INPUT_TYPE_MAX]; + + int key_event_w, key_event_r; + bool key_event_full; + KeyEvent *key_events; + + int pointer_event_w, pointer_event_r; + bool pointer_event_full; + PointerEvent *pointer_events; +} InputDeviceManager; + +DriverResult create_input_device( + InputDevice **input_device, InputDeviceType type, DeviceOps *ops, + PhysicalDevice *physical_device, DeviceDriver *device_driver); +DriverResult delete_input_device(InputDevice *input_device); + +extern DeviceManager input_dm; + +void new_key_event(uint16_t keycode, uint8_t pressed, uint8_t page); +void new_pointer_event(int16_t dx, int16_t dy, enum PointerEventType type); + +#endif \ No newline at end of file diff --git a/src/include/driver/input/key_events.h b/src/include/driver/input/key_events.h new file mode 100644 index 0000000..465bd97 --- /dev/null +++ b/src/include/driver/input/key_events.h @@ -0,0 +1,373 @@ +#ifndef _INPUT_KEY_EVENTS_H +#define _INPUT_KEY_EVENTS_H + +/** + * @brief 除标准鼠标按键外使用HID Usage Tables定义的按键码 + * References: + * https://www.usb.org/sites/default/files/hut1_6.pdf + */ + +// 鼠标按键 +#define KEY_MOUSE_LEFT 0x01 +#define KEY_MOUSE_RIGHT 0x02 +#define KEY_MOUSE_MIDDLE 0x03 + +// General Desktop Page +// ... +#define KEY_GDP_SYSTEM_POWER_DOWN 0x81 +#define KEY_GDP_SYSTEM_SLEEP 0x82 +#define KEY_GDP_SYSTEM_WAKEUP 0x83 +#define KEY_GDP_SYSTEM_CONTEXT_MENU 0x84 +#define KEY_GDP_SYSTEM_MAIN_MENU 0x85 +#define KEY_GDP_SYSTEM_APP_MENU 0x86 +#define KEY_GDP_SYSTEM_MENU_HELP 0x87 +#define KEY_GDP_SYSTEM_MENU_EXIT 0x88 +#define KEY_GDP_SYSTEM_MENU_SELECT 0x89 +// ... +#define KEY_GDP_SYSTEM_COLD_RESTART 0x8E +#define KEY_GDP_SYSTEM_WARM_RESTART 0x8F +// ... + +// Keyboard/Keypad Page +#define KEY_A 0x04 +#define KEY_B 0x05 +#define KEY_C 0x06 +#define KEY_D 0x07 +#define KEY_E 0x08 +#define KEY_F 0x09 +#define KEY_G 0x0A +#define KEY_H 0x0B +#define KEY_I 0x0C +#define KEY_J 0x0D +#define KEY_K 0x0E +#define KEY_L 0x0F +#define KEY_M 0x10 +#define KEY_N 0x11 +#define KEY_O 0x12 +#define KEY_P 0x13 +#define KEY_Q 0x14 +#define KEY_R 0x15 +#define KEY_S 0x16 +#define KEY_T 0x17 +#define KEY_U 0x18 +#define KEY_V 0x19 +#define KEY_W 0x1A +#define KEY_X 0x1B +#define KEY_Y 0x1C +#define KEY_Z 0x1D +#define KEY_1 0x1E +#define KEY_2 0x1F +#define KEY_3 0x20 +#define KEY_4 0x21 +#define KEY_5 0x22 +#define KEY_6 0x23 +#define KEY_7 0x24 +#define KEY_8 0x25 +#define KEY_9 0x26 +#define KEY_0 0x27 +#define KEY_ENTER 0x28 +#define KEY_ESC 0x29 +#define KEY_BACKSPACE 0x2A +#define KEY_TAB 0x2B +#define KEY_SPACE 0x2C +#define KEY_MINUS 0x2D // '-' +#define KEY_EQUAL 0x2E // '=' +#define KEY_LEFTBRACE 0x2F // '[' +#define KEY_RIGHTBRACE 0x30 // ']' +#define KEY_BACKSLASH 0x31 // '\' +#define KEY_SEMICOLON 0x33 // ';' +#define KEY_APOSTROPHE 0x34 // '\'' +#define KEY_GRAVE 0x35 // '`' +#define KEY_COMMA 0x36 // ',' +#define KEY_DOT 0x37 // '.' +#define KEY_SLASH 0x38 // '/' +#define KEY_CAPSLOCK 0x39 +#define KEY_F1 0x3A +#define KEY_F2 0x3B +#define KEY_F3 0x3C +#define KEY_F4 0x3D +#define KEY_F5 0x3E +#define KEY_F6 0x3F +#define KEY_F7 0x40 +#define KEY_F8 0x41 +#define KEY_F9 0x42 +#define KEY_F10 0x43 +#define KEY_F11 0x44 +#define KEY_F12 0x45 +#define KEY_PRINTSCREEN 0x46 +#define KEY_SCROLLLOCK 0x47 +#define KEY_PAUSE 0x48 +#define KEY_INSERT 0x49 +#define KEY_HOME 0x4A +#define KEY_PAGEUP 0x4B +#define KEY_DELETE 0x4C +#define KEY_END 0x4D +#define KEY_PAGEDOWN 0x4E +#define KEY_RIGHT 0x4F +#define KEY_LEFT 0x50 +#define KEY_DOWN 0x51 +#define KEY_UP 0x52 +#define KEY_NUMLOCK 0x53 +#define KEY_KEYPAD_SLASH 0x54 // '/' +#define KEY_KEYPAD_ASTERISK 0x55 // '*' +#define KEY_KEYPAD_MINUS 0x56 // '-' +#define KEY_KEYPAD_PLUS 0x57 // '+' +#define KEY_KEYPAD_ENTER 0x58 +#define KEY_KEYPAD_1 0x59 +#define KEY_KEYPAD_2 0x5A +#define KEY_KEYPAD_3 0x5B +#define KEY_KEYPAD_4 0x5C +#define KEY_KEYPAD_5 0x5D +#define KEY_KEYPAD_6 0x5E +#define KEY_KEYPAD_7 0x5F +#define KEY_KEYPAD_8 0x60 +#define KEY_KEYPAD_9 0x61 +#define KEY_KEYPAD_0 0x62 +#define KEY_KEYPAD_DOT 0x63 +#define KEY_NON_US_64 0x64 // "<>" or "\|" +#define KEY_APPLICATION 0x65 +#define KEY_POWER 0x66 +#define KEY_KEYPAD_EQUAL 0x67 // '=' +#define KEY_F13 0x68 +#define KEY_F14 0x69 +#define KEY_F15 0x6A +#define KEY_F16 0x6B +#define KEY_F17 0x6C +#define KEY_F18 0x6D +#define KEY_F19 0x6E +#define KEY_F20 0x6F +#define KEY_F21 0x70 +#define KEY_F22 0x71 +#define KEY_F23 0x72 +#define KEY_F24 0x73 +#define KEY_EXECUTE 0x74 +#define KEY_HELP 0x75 +#define KEY_MENU 0x76 +#define KEY_SELECT 0x77 +#define KEY_STOP 0x78 +#define KEY_AGAIN 0x79 +#define KEY_UNDO 0x7A +#define KEY_CUT 0x7B +#define KEY_COPY 0x7C +#define KEY_PASTE 0x7D +#define KEY_FIND 0x7E +#define KEY_MUTE 0x7F +#define KEY_VOLUMEUP 0x80 +#define KEY_VOLUMEDOWN 0x81 +#define KEY_LOCKING_CAPSLOCK 0x82 +#define KEY_LOCKING_NUMLOCK 0x83 +#define KEY_LOCKING_SCROLLLOCK 0x84 +#define KEY_KEYPAD_COMMA 0x85 +#define KEY_KEYPAD_EQUAL_SIGN 0x86 +#define KEY_INTERNATIONAL1 0x87 +#define KEY_INTERNATIONAL2 0x88 +#define KEY_INTERNATIONAL3 0x89 +#define KEY_INTERNATIONAL4 0x8A +#define KEY_INTERNATIONAL5 0x8B +#define KEY_INTERNATIONAL6 0x8C +#define KEY_INTERNATIONAL7 0x8D +#define KEY_INTERNATIONAL8 0x8E +#define KEY_INTERNATIONAL9 0x8F +#define KEY_LANG1 0x90 // "Hangul/English" +#define KEY_LANG2 0x91 // "Hanja" +#define KEY_LANG3 0x92 // "Katakana" +#define KEY_LANG4 0x93 // "Hiragana" +#define KEY_LANG5 0x94 // "Zenkaku/Hankaku" +#define KEY_LANG6 0x95 // "Reserved" +#define KEY_LANG7 0x96 // "Reserved" +#define KEY_LANG8 0x97 // "Reserved" +#define KEY_LANG9 0x98 // "Reserved" +#define KEY_ALTERASE 0x99 +#define KEY_SYSREQ 0x9A +#define KEY_CANCEL 0x9B +#define KEY_CLEAR 0x9C +#define KEY_PRIOR 0x9D +#define KEY_RETURN 0x9E +#define KEY_SEPARATOR 0x9F +#define KEY_OUT 0xA0 +#define KEY_OPER 0xA1 +#define KEY_CLEARAGAIN 0xA2 +#define KEY_CRSEL 0xA3 +#define KEY_EXSEL 0xA4 + +#define KEY_KEYPAD_00 0xB0 +#define KEY_KEYPAD_000 0xB1 +#define KEY_KEYPAD_THOUSANDS_SEPARATOR 0xB2 +#define KEY_KEYPAD_DECIMAL_SEPARATOR 0xB3 +#define KEY_KEYPAD_CURRENCY_UNIT 0xB4 +#define KEY_KEYPAD_CURRENCY_SUBUNIT 0xB5 +#define KEY_KEYPAD_LEFT_PARENTHESIS 0xB6 // '(' +#define KEY_KEYPAD_RIGHT_PARENTHESIS 0xB7 // ')' +#define KEY_KEYPAD_LEFT_BRACE 0xB8 // '{' +#define KEY_KEYPAD_RIGHT_BRACE 0xB9 // '}' +#define KEY_KEYPAD_TAB 0xBA +#define KEY_KEYPAD_BACKSPACE 0xBB +#define KEY_KEYPAD_A 0xBC +#define KEY_KEYPAD_B 0xBD +#define KEY_KEYPAD_C 0xBE +#define KEY_KEYPAD_D 0xBF +#define KEY_KEYPAD_E 0xC0 +#define KEY_KEYPAD_F 0xC1 +#define KEY_KEYPAD_XOR 0xC2 // '^' +#define KEY_KEYPAD_CARET 0xC3 // '^' +#define KEY_KEYPAD_PERCENT 0xC4 // '%' +#define KEY_KEYPAD_LESS_THAN 0xC5 // '<' +#define KEY_KEYPAD_GREATER_THAN 0xC6 +#define KEY_KEYPAD_AMPERSAND 0xC7 // '&' +#define KEY_KEYPAD_AMPERSAND_AMPERSAND 0xC8 // "&&" +#define KEY_KEYPAD_PIPE 0xC9 // '|' +#define KEY_KEYPAD_PIPE_PIPE 0xCA // "||" +#define KEY_KEYPAD_COLON 0xCB // ':' +#define KEY_KEYPAD_HASH 0xCC // '#' +#define KEY_KEYPAD_SPACE 0xCD +#define KEY_KEYPAD_AT 0xCE // '@' +#define KEY_KEYPAD_EXCLAMATION 0xCF // '!' +#define KEY_KEYPAD_MEMORY_STORE 0xD0 +#define KEY_KEYPAD_MEMORY_RECALL 0xD1 +#define KEY_KEYPAD_MEMORY_CLEAR 0xD2 +#define KEY_KEYPAD_MEMORY_ADD 0xD3 +#define KEY_KEYPAD_MEMORY_SUBTRACT 0xD4 +#define KEY_KEYPAD_MEMORY_MULTIPLY 0xD5 +#define KEY_KEYPAD_MEMORY_DIVIDE 0xD6 +#define KEY_KEYPAD_PLUS_MINUS 0xD7 // '±' +#define KEY_KEYPAD_CLEAR 0xD8 +#define KEY_KEYPAD_CLEAR_ENTRY 0xD9 +#define KEY_KEYPAD_BINARY 0xDA +#define KEY_KEYPAD_OCTAL 0xDB +#define KEY_KEYPAD_DECIMAL 0xDC +#define KEY_KEYPAD_HEXADECIMAL 0xDD + +#define KEY_LEFTCTRL 0xE0 +#define KEY_LEFTSHIFT 0xE1 +#define KEY_LEFTALT 0xE2 +#define KEY_LEFTGUI 0xE3 +#define KEY_RIGHTCTRL 0xE4 +#define KEY_RIGHTSHIFT 0xE5 +#define KEY_RIGHTALT 0xE6 +#define KEY_RIGHTGUI 0xE7 + +// Consumer Page (0x0C) +#define KEY_CP_CONSUMER_CONTROL 0x01 +#define KEY_CP_NUMERIC_KEYPAD 0x02 +#define KEY_CP_PROGRAMMABLE_BUTTONS 0x03 +#define KEY_CP_MICROPHONE 0x04 +#define KEY_CP_HEADPHONE 0x05 +#define KEY_CP_GRAPHICS_EQUALIZER 0x06 +#define KEY_CP_PLUS10 0x20 +#define KEY_CP_PLUS100 0x21 +#define KEY_CP_AM_PM 0x22 +#define KEY_CP_POWER 0x30 +#define KEY_CP_RESET 0x31 +#define KEY_CP_SLEEP 0x32 +#define KEY_CP_SLEEP_AFTER 0x33 +#define KEY_CP_SLEEP_MODE 0x34 +#define KEY_CP_ILLUMINATION 0x35 +#define KEY_CP_FUNCTION_BUTTONS 0x36 +#define KEY_CP_MENU 0x40 +#define KEY_CP_MENU_PICK 0x41 +#define KEY_CP_MENU_UP 0x42 +#define KEY_CP_MENU_DOWN 0x43 +#define KEY_CP_MENU_LEFT 0x44 +#define KEY_CP_MENU_RIGHT 0x45 +#define KEY_CP_MENU_ESCAPE 0x46 +#define KEY_CP_MENU_VALUE_INCREASE 0x47 +#define KEY_CP_MENU_VALUE_DECREASE 0x48 +#define KEY_CP_DATA_ON_SCREEN 0x60 +#define KEY_CP_CLOSED_CAPTION 0x61 +#define KEY_CP_CLOSED_CAPTION_SELECT 0x62 +#define KEY_CP_VCR_TV 0x63 +#define KEY_CP_BROADCAST_MODE 0x64 +#define KEY_CP_SNAPSHOT 0x65 +#define KEY_CP_STILL 0x66 +#define KEY_CP_PIC_IN_PIC_TOGGLE 0x67 +#define KEY_CP_PIC_IN_PIC_SWAP 0x68 +#define KEY_CP_RED_MENU 0x69 +#define KEY_CP_GREEN_MENU 0x6A +#define KEY_CP_BLUE_MENU 0x6B +#define KEY_CP_YELLOW_MENU 0x6C +#define KEY_CP_ASPECT 0x6D +#define KEY_CP_3D_MODE_SELECT 0x6E +#define KEY_CP_DISPLAY_BRIGHTNESS_INCREMENT 0x6F +#define KEY_CP_DISPLAY_BRIGHTNESS_DECREMENT 0x70 +#define KEY_CP_DISPLAY_BRIGHTNESS 0x71 +#define KEY_CP_DISPLAY_BACKLIGHT_TOGGLE 0x72 +#define KEY_CP_DISPLAY_SET_BRIGHTNESS_TO_MINIMUM 0x73 +#define KEY_CP_DISPLAY_SET_BRIGHTNESS_TO_MAXIMUM 0x74 +#define KEY_CP_DISPLAY_AUTOBRIGHTNESS_MODE 0x75 +// ... +#define KEY_CP_KEYBOARD_BRIGHTNESS_INCREMENT 0x7F +#define KEY_CP_KEYBOARD_BRIGHTNESS_DECREMENT 0x80 +#define KEY_CP_KEYBOARD_BACKLIGHT_SET_LEVEL 0x81 +#define KEY_CP_KEYBOARD_BACKLIGHT_OOC 0x82 +#define KEY_CP_KEYBOARD_BACKLIGHT_SET_MINIMUM 0x83 +#define KEY_CP_KEYBOARD_BACKLIGHT_SET_MAXIMUM 0x84 +#define KEY_CP_KEYBOARD_BACKLIGHT_AUTO 0x85 +// ... +#define KEY_CP_PLAY 0xB0 +#define KEY_CP_PAUSE 0xB1 +#define KEY_CP_RECORD 0xB2 +#define KEY_CP_FAST_FORWARD 0xB3 +#define KEY_CP_REWIND 0xB4 +#define KEY_CP_NEXT_TRACK 0xB5 +#define KEY_CP_PREVIOUS_TRACK 0xB6 +#define KEY_CP_STOP 0xB7 +#define KEY_CP_EJECT 0xB8 +#define KEY_CP_RANDOM_PLAY 0xB9 +#define KEY_CP_SELECT_DISC 0xBA +#define KEY_CP_ENTER_DISC 0xBB +#define KEY_CP_REPEAT 0xBC +#define KEY_CP_TRACKING 0xBD +#define KEY_CP_TRACK_NORMAL 0xBE +#define KEY_CP_SLOW_TRACKING 0xBF +#define KEY_CP_FRAME_FORWARD 0xC0 +#define KEY_CP_FRAME_BACK 0xC1 +#define KEY_CP_MARK 0xC2 +#define KEY_CP_CLEAR_MARK 0xC3 +#define KEY_CP_REPEAT_FROM_MARK 0xC4 +#define KEY_CP_RETURN_TO_MARK 0xC5 +#define KEY_CP_SEARCH_MARK_FORWARD 0xC6 +#define KEY_CP_SEARCH_MARK_BACKWARDS 0xC7 +#define KEY_CP_COUNTER_RESET 0xC8 +#define KEY_CP_SHOW_COUNTER 0xC9 +#define KEY_CP_TRACKING_INCREMENT 0xCA +#define KEY_CP_TRACKING_DECREMENT 0xCB +#define KEY_CP_STOP_EJECT 0xCC +#define KEY_CP_PLAY_PAUSE 0xCD +#define KEY_CP_PLAY_SKIP 0xCE +#define KEY_CP_VOICE_COMMAND 0xCF +// ... +#define KEY_CP_VOLUME 0xE0 +#define KEY_CP_BALANCE 0xE1 +#define KEY_CP_MUTE 0xE2 +#define KEY_CP_BASS 0xE3 +#define KEY_CP_TREBLE 0xE4 +#define KEY_CP_BASS_BOOST 0xE5 +#define KEY_CP_SURROUND_MODE 0xE6 +#define KEY_CP_LOUDNESS 0xE7 +#define KEY_CP_MPX 0xE8 +#define KEY_CP_VOLUME_INCREMENT 0xE9 +#define KEY_CP_VOLUME_DECREMENT 0xEA +// ... +#define KEY_CP_AL_CONSUMER_CONTROL_CONFIGURATION 0x183 +// ... +#define KEY_CP_AL_EMAIL_READER 0x18A +// ... +#define KEY_CP_AL_CALC 0x192 +// ... +#define KEY_CP_AL_INTERNET_BROWSER 0x196 +// ... +#define KEY_CP_AL_FILE_BROWSER 0x1B4 +// ... +#define KEY_CP_AL_RESEARCH_SEARCH_BROWSER 0x1C6 +// ... +#define KEY_CP_AC_HOME 0x223 +#define KEY_CP_AC_BACK 0x224 +#define KEY_CP_AC_FORWARD 0x225 +#define KEY_CP_AC_STOP 0x226 +#define KEY_CP_AC_REFRESH 0x227 +#define KEY_CP_AC_PREVIOUS_LINK 0x228 +#define KEY_CP_AC_NEXT_LINK 0x229 +#define KEY_CP_AC_BOOKMARKS 0x22A +// ... + +#endif \ No newline at end of file diff --git a/src/include/driver/interrupt/interrupt_dm.h b/src/include/driver/interrupt/interrupt_dm.h new file mode 100644 index 0000000..fe82421 --- /dev/null +++ b/src/include/driver/interrupt/interrupt_dm.h @@ -0,0 +1,38 @@ +#ifndef _INTERRUPT_DM_H +#define _INTERRUPT_DM_H + +#include +#include +#include +#include +#include + +struct InterruptDevice; + +typedef struct InterruptDeviceOps { + int (*redirect_irq)(struct InterruptDevice *device, int irq); + DriverResult (*enable_irq)(struct InterruptDevice *device, int irq); + DriverResult (*disable_irq)(struct InterruptDevice *device, int irq); + void (*eoi)(struct InterruptDevice *device, int irq); +} InterruptDeviceOps; + +typedef struct InterruptDevice { + LogicalDevice *device; + InterruptDeviceOps *ops; + uint8_t priority; +} InterruptDevice; + +DriverResult create_interrupt_device( + InterruptDevice **interrupt_device, DeviceOps *ops, + PhysicalDevice *physical_device, DeviceDriver *device_driver, + InterruptDeviceOps *int_ops, int priority); + +extern struct DeviceManager interrupt_dm; + +DriverResult interrupt_dm_start(); +uint32_t interrupt_redirect_irq(int irq); +DriverResult interrupt_enable_irq(int irq); +DriverResult interrupt_disable_irq(int irq); +void interrupt_eoi(int irq); + +#endif \ No newline at end of file diff --git a/src/include/driver/network/buffer.h b/src/include/driver/network/buffer.h new file mode 100644 index 0000000..0878753 --- /dev/null +++ b/src/include/driver/network/buffer.h @@ -0,0 +1,39 @@ +#ifndef _NET_BUFFER_H +#define _NET_BUFFER_H + +#include "kernel/list.h" +#include "protocols/protocols.h" +#include + +#define NET_BUF_RESV_HEAD(conn, n) \ + (conn)->buffer->head += (n); \ + (conn)->buffer->data += (n); \ + (conn)->buffer->tail += (n) + +typedef struct NetBuffer { + list_t list; + + void *ptr; // 缓冲区的地址 + uint16_t size; // 缓冲区的大小 + + void *head; // 包头的起始地址 + void *data; // 数据的起始地址 + void *tail; // 数据的结束地址,也是包尾的起始地址 +} NetBuffer; + +NetBuffer *net_buffer_create(uint16_t size); +void net_buffer_delete(NetBuffer *buffer); +void net_buffer_init( + NetBuffer *buffer, uint16_t size, uint16_t head, uint16_t tail); + +struct NetworkConnection; +ProtocolResult net_buffer_data_alloc(NetBuffer *buffer, uint16_t size); +void net_buffer_reset(NetBuffer *buffer); +void net_buffer_clean_data(NetBuffer *buffer); +void net_buffer_header_alloc(NetBuffer *buffer, uint16_t size); +void net_buffer_header_free(NetBuffer *buffer, uint16_t size); +void net_buffer_tail_alloc(NetBuffer *buffer, uint16_t size); +void net_buffer_tail_free(NetBuffer *buffer, uint16_t size); +ProtocolResult net_buffer_put(NetBuffer *buffer, uint16_t size); + +#endif \ No newline at end of file diff --git a/src/include/driver/network/conn.h b/src/include/driver/network/conn.h new file mode 100644 index 0000000..faeca59 --- /dev/null +++ b/src/include/driver/network/conn.h @@ -0,0 +1,115 @@ +#ifndef _NET_CONN_H +#define _NET_CONN_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define NET_CONN_MAX_PROTOCOLS 8 + +#define CONN_PACKET_SIZE(conn) ((conn)->buffer->tail - (conn)->buffer->head) +#define CONN_CONTENT_SIZE(conn) ((conn)->buffer->tail - (conn)->buffer->data) + +#define conn_buffer(conn) ((conn)->buffer) + +struct NetworkConnection; +typedef struct NetProtocol { + uint16_t head_size; + uint16_t tail_size; +} NetProtocol; + +struct Tcp; +typedef struct NetworkConnection { + Object *object; + ObjectHandle *handle; + NetworkDevice *net_device; + enum { + CONN_STATE_INIT, + CONN_STATE_OPENING, + CONN_STATE_OPENED, + CONN_STATE_CLOSING, + CONN_STATE_CLOSED, + CONN_STATE_HOST_UNREACHABLE, + CONN_STATE_NET_UNREACHABLE, + } state; + + NetBuffer *buffer; + + struct task_s *thread; + + // physical layer protocol + enum { + PHY_PROTO_NONE, + PHY_PROTO_ETHERNET, + } phy_protocol; + union { + struct { + uint8_t mac[6]; + } ethernet; + }; + int pmtu; + + // data link layer protocol + enum { + DL_PROTO_NONE, + DL_PROTO_ARP, + } dl_protocol; + union {}; + + // network layer protocol + enum { + NET_PROTO_NONE, + NET_PROTO_IPV4, + } net_protocol; + union { + struct { + uint16_t id; + struct { + uint16_t enable_fragment : 1; + uint16_t last_fragment : 1; + uint16_t frag_offset : 13; + } fragment; + Ipv4Header *header; + struct Ipv4ConnInfo conn_info; // 连接信息 + } ipv4; + }; + + // transport layer protocol + enum { + TRANS_PROTO_NONE, + TRANS_PROTO_TCP, + TRANS_PROTO_UDP, + } trans_protocol; + union { + struct { + void *private_data; + void (*callback)( + struct NetworkConnection *conn, NetBuffer *net_buffer); + } udp; + struct { + struct Tcp *info; + } tcp; + }; + spinlock_t recv_lock; + list_t recv_lh; +} NetworkConnection; + +typedef enum ProtocolLevel { + PROTO_LEVEL_TRANSPORT, + PROTO_LEVEL_NETWORK, + PROTO_LEVEL_DATA_LINK, + PROTO_LEVEL_PHYSICAL +} ProtocolLevel; + +NetworkConnection *net_create_conn(Object *object); +void net_destroy_conn(NetworkConnection *conn); +ProtocolResult conn_wrap(NetworkConnection *conn, ProtocolLevel level); + +#endif \ No newline at end of file diff --git a/src/include/driver/network/ethernet/ethernet.h b/src/include/driver/network/ethernet/ethernet.h new file mode 100644 index 0000000..9f7ed39 --- /dev/null +++ b/src/include/driver/network/ethernet/ethernet.h @@ -0,0 +1,60 @@ +#ifndef _NETWORK_ETHERNET_H +#define _NETWORK_ETHERNET_H + +#include +#include +#include +#include +#include + +#define ETH_MAX_FRAME_SIZE 1792 +#define ETH_MIN_FRAME_SIZE 60 +#define ETH_IDENTIFIER_SIZE 6 + +#define ETH_HEADER_SIZE 14 + +#define ETH_PROTO_TYPE_IPV4 0x0800 +#define ETH_PROTO_TYPE_ARP 0x0806 + +#define ETH_MTU 1500 + +typedef struct EthernetHeader { + uint8_t dst_mac[ETH_IDENTIFIER_SIZE]; + uint8_t src_mac[ETH_IDENTIFIER_SIZE]; + uint16_t protocol_type; // Network layer protocol type +} EthernetHeader; + +typedef struct EthernetDevice { + Timer timer; + uint8_t probe_count, announce_count; + enum { + ACD_STATE_NONE, + ACD_STATE_PROBE, + ACD_STATE_ANNOUNCE, + ACD_STATE_CONFLICT, + } acd_state; + void (*acd_conflict_callback)(NetworkDevice *device); + + struct NetworkConnection *arp_conn; + NetworkDevice *net_device; + uint8_t mac_addr[ETH_IDENTIFIER_SIZE]; +} EthernetDevice; + +void eth_set_mac_address(EthernetDevice *device, uint8_t *mac_addr); +void eth_get_mac_address(EthernetDevice *device, uint8_t *mac_addr); + +struct NetworkConnection; + +extern const uint8_t eth_broadcast_mac[6]; +extern const uint8_t eth_null_mac[6]; + +void eth_register(struct NetworkConnection *conn); +ProtocolResult eth_wrap( + struct NetBuffer *buffer, uint8_t *mac_addr, const uint8_t *dst_addr, + uint16_t protocol); +ProtocolResult eth_reply(NetworkDevice *device, NetBuffer *buffer); +ProtocolResult eth_recv( + NetworkDevice *device, NetBuffer *net_buffer, ProtocolReplyCallback *stack, + int stack_size); + +#endif \ No newline at end of file diff --git a/src/include/driver/network/mii.h b/src/include/driver/network/mii.h new file mode 100644 index 0000000..c55bba1 --- /dev/null +++ b/src/include/driver/network/mii.h @@ -0,0 +1,49 @@ +#ifndef _NETWORK_MII_H +#define _NETWORK_MII_H + +#include "network_dm.h" +#include +#include + +#define MII_REG_BMCR 0x00 +#define MII_REG_BMSR 0x01 +#define MII_REG_PHYID1 0x02 +#define MII_REG_PHYID2 0x03 +#define MII_REG_ANAR 0x04 +#define MII_REG_ANLPAR 0x05 + +#define MII_BMSR_EXT_CAP BIT(0) +#define MII_BMSR_JABBER_DETECTED BIT(1) +#define MII_BMSR_LINK_STATUS BIT(2) +#define MII_BMSR_AUTO_NEG BIT(3) +#define MII_BMSR_REMOTE_FAULT BIT(4) +#define MII_BMSR_AUTO_NEG_COMPLETE BIT(5) +#define MII_BMSR_EXT_STAT BIT(8) +#define MII_BMSR_10_HALF_DUPLEX BIT(11) +#define MII_BMSR_10_FULL_DUPLEX BIT(12) +#define MII_BMSR_100_HALF_DUPLEX BIT(13) +#define MII_BMSR_100_FULL_DUPLEX BIT(14) +#define MII_BMSR_100_T4 BIT(15) + +typedef enum MiiMediaType { + MMT_10HALF = 0b00000, + MMT_10FULL = 0b00001, + MMT_100HALF = 0b00010, + MMT_100FULL = 0b00011, + MMT_100T4 = 0b10010, + MMT_UNKNOWN, +} MiiMediaType; + +typedef struct Mii { + NetworkDevice *net_dev; + + uint32_t phy_id; + uint32_t full_duplex : 1; // 1: 全双工, 0: 半双工 + + int (*mdio_read)(struct Mii *mii, uint8_t reg_addr); + void (*mdio_write)(struct Mii *mii, uint8_t reg_addr, uint16_t data); +} Mii; + +DriverResult net_init_mii(Mii *mii); + +#endif \ No newline at end of file diff --git a/src/include/driver/network/neighbour.h b/src/include/driver/network/neighbour.h new file mode 100644 index 0000000..dfccff5 --- /dev/null +++ b/src/include/driver/network/neighbour.h @@ -0,0 +1,68 @@ +#ifndef NEIGHBOUR_H +#define NEIGHBOUR_H + +#include "driver/network/network_dm.h" +#include "kernel/list.h" +#include "kernel/spinlock.h" +#include + +#define NEIGH_BUCKET_SIZE 32 + +typedef enum { + NEIGH_STATE_NONE, + NEIGH_STATE_WAITING, + NEIGH_STATE_REACHABLE, + NEIGH_STATE_STALE, + NEIGH_STATE_FAILED, +} NeighbourState; + +typedef uint32_t NeighbourKey; + +struct NeighbourEntry; +typedef struct { + void (*request)(struct NeighbourEntry *entry, void *arg); + void (*probe)(struct NetworkDevice *device); + void (*announce)(struct NetworkDevice *device); +} NeighbourProtoOps; + +typedef struct NeighbourEntry { + list_t list; + spinlock_t lock; + + NeighbourKey key; + NeighbourState state; + + int hlen; + uint8_t haddr[8]; // Hardware address (MAC address) + + NetworkDevice *device; + + void *arg; + NeighbourProtoOps *ops; + + list_t pending_lh; + + uint8_t ip_length; + uint8_t ip_addr[0]; +} NeighbourEntry; + +typedef struct NeighbourTable { + list_t buckets[NEIGH_BUCKET_SIZE]; + spinlock_t lock[NEIGH_BUCKET_SIZE]; +} NeighbourTable; + +extern int neighbour_max_retries; +extern NeighbourTable neighbour_table; + +void neighbour_init(void); +NeighbourEntry *neighbour_entry_create( + NetworkDevice *device, NeighbourKey hash_key, uint8_t *addr, + uint8_t length); +NeighbourEntry *neighbour_table_try_lookup( + NetworkDevice *device, NeighbourKey hash_key, uint8_t *ip_addr, + uint8_t ip_length); +NeighbourEntry *neighbour_table_lookup( + NetworkDevice *device, NeighbourKey hash_key, uint8_t *ip_addr, + uint8_t ip_length); + +#endif \ No newline at end of file diff --git a/src/include/driver/network/net_queue.h b/src/include/driver/network/net_queue.h new file mode 100644 index 0000000..e0f1c1d --- /dev/null +++ b/src/include/driver/network/net_queue.h @@ -0,0 +1,13 @@ +#ifndef _NETWORK_QUEUE_H +#define _NETWORK_QUEUE_H + +#include +#include +#define NQ_BLOCKER_DRIVER BIT(0) +#define NQ_BLOCKER_SYSTEM BIT(1) + +typedef struct NetworkQueue { + uint8_t blocker; +} NetworkQueue; + +#endif \ No newline at end of file diff --git a/src/include/driver/network/network.h b/src/include/driver/network/network.h new file mode 100644 index 0000000..b25e316 --- /dev/null +++ b/src/include/driver/network/network.h @@ -0,0 +1,17 @@ +#ifndef _NETWORK_H +#define _NETWORK_H + +#include "kernel/list.h" +#include +#include + +typedef struct NetRxHandler { + list_t list; // 链表节点 + void (*handler)(void *data); + void *data; // 处理函数的私有数据 +} NetRxHandler; + +DriverResult network_softirq_register(NetRxHandler *handler); +void network_softirq_handler(void); + +#endif \ No newline at end of file diff --git a/src/include/driver/network/network_dm.h b/src/include/driver/network/network_dm.h new file mode 100644 index 0000000..84c5563 --- /dev/null +++ b/src/include/driver/network/network_dm.h @@ -0,0 +1,88 @@ +#ifndef _NETWORK_DM_H +#define _NETWORK_DM_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define NETWORK_SEND(device, conn) \ + ((device)->ops->send( \ + device, conn->buffer->head, conn->buffer->tail - conn->buffer->head)) + +struct NetworkDevice; +typedef struct NetworkDeviceOps { + TransferResult (*send)(struct NetworkDevice *device, void *buf, int length); +} NetworkOps; + +typedef struct NetworkDeviceCapabilities { +} NetworkDeviceCapabilities; + +typedef enum NetworkDeviceType { + NETWORK_TYPE_UNKNOWN, + NETWORK_TYPE_ETHERNET, +} NetworkDeviceType; + +typedef enum NetworkDeviceState { + NET_STATE_INITED, + NET_STATE_NO_CARRIER, + NET_STATE_RUNNING, +} NetworkDeviceState; + +typedef struct NetworkDevice { + LogicalDevice *device; + NetworkDeviceType type; + NetworkDeviceCapabilities capabilities; + NetworkOps *ops; + + int mtu; + + NetworkDeviceState state; + NetworkQueue tx_queue; + + union { + struct EthernetDevice *ethernet; + }; + + union { + struct { + uint8_t ip[4]; + + uint8_t subnet_mask[4]; + uint8_t gateway_ip[4]; + } ipv4; + }; +} NetworkDevice; + +typedef struct NetworkDeviceManager { + int new_device_num; + int device_count; +} NetworkDeviceManager; + +extern DeviceManager network_dm; + +DriverResult create_network_device( + NetworkDevice **network_device, NetworkDeviceType type, + NetworkDeviceCapabilities caps, NetworkOps *net_ops, DeviceOps *ops, + PhysicalDevice *device, DeviceDriver *device_driver); +DriverResult delete_network_device(NetworkDevice *network_device); + +NetworkDevice *network_get_device(Object *object); + +struct NetworkConnection; +void net_queue_block(NetworkQueue *queue, int blocker); +bool net_queue_is_blocked(NetworkQueue *queue, int blocker); +TransferResult network_transfer( + struct Object *object, struct ObjectHandle *obj_handle, + TransferDirection direction, uint8_t *buf, size_t size); +struct NetBuffer *network_recv(struct NetworkConnection *conn); +ProtocolResult protocol_recv( + NetworkDevice *device, struct NetBuffer *net_buffer, + NetworkDeviceType type); + +#endif \ No newline at end of file diff --git a/src/include/driver/network/protocols/ipv4/acd.h b/src/include/driver/network/protocols/ipv4/acd.h new file mode 100644 index 0000000..bf5d0a2 --- /dev/null +++ b/src/include/driver/network/protocols/ipv4/acd.h @@ -0,0 +1,26 @@ +#ifndef _ACD_H +#define _ACD_H + +#include +#include + +#define ACD_PROBE_WAIT 1 // initial random delay (1 second) +#define ACD_PROBE_NUM 3 // number of probe packets +#define ACD_PROBE_MIN 1 // minimum delay until repeated probe (1 second) +#define ACD_PROBE_MAX 2 // maximum delay until repeated probe (2 seconds) + +#define ACD_ANNOUNCE_WAIT 2 // delay before announcing (2 seconds) +#define ACD_ANNOUNCE_NUM 2 // number of announce packets +#define ACD_ANNOUNCE_INTERVAL 2 // time between announce packets (2 seconds) + +#define ACD_MAX_CONFLICTS 10 // max conflicts before rate-limiting (10 seconds) +#define ACD_RATE_LIMIT_INTERVAL \ + 60 // delay between successive attempts (60 seconds) +#define ACD_DEFEND_INTERVAL \ + 10 // minimum interval between defensive ARPs (10 seconds) + +ProtocolResult acd_conflict_detected(NetworkDevice *device); +void acd_probe(NetworkDevice *device); +void acd_announce(NetworkDevice *device); + +#endif \ No newline at end of file diff --git a/src/include/driver/network/protocols/ipv4/arp.h b/src/include/driver/network/protocols/ipv4/arp.h new file mode 100644 index 0000000..85508b5 --- /dev/null +++ b/src/include/driver/network/protocols/ipv4/arp.h @@ -0,0 +1,29 @@ +#ifndef _ARP_H +#define _ARP_H + +#include "driver/network/conn.h" +#include "driver/network/protocols/protocols.h" +#include + +#define ARP_HTYPE_ETH 0x0001 + +#define ARP_TYPE 0x0806 + +#define ARP_OP_REQUEST 0x0001 +#define ARP_OP_REPLY 0x0002 + +typedef struct ArpHeader { + uint16_t htype; + uint16_t ptype; + uint8_t hlen; + uint8_t plen; + uint16_t opcode; +} __attribute__((packed)) ArpHeader; + +extern NeighbourProtoOps arp_proto_ops; + +ProtocolResult arp_recv(NetworkDevice *device, NetBuffer *net_buffer); +void arp_send_request(NeighbourEntry *entry, void *arg); +void arp_announce(NetworkDevice *device, uint8_t *ip_addr); + +#endif \ No newline at end of file diff --git a/src/include/driver/network/protocols/ipv4/dhcp.h b/src/include/driver/network/protocols/ipv4/dhcp.h new file mode 100644 index 0000000..ceff68a --- /dev/null +++ b/src/include/driver/network/protocols/ipv4/dhcp.h @@ -0,0 +1,170 @@ +#ifndef _DHCP_H +#define _DHCP_H + +#include +#include +#include +#include +#include + +#define DHCP_OP_BOOTREQUEST 1 +#define DHCP_OP_BOOTREPLY 2 +#define DHCP_HTYPE_ETHERNET 1 + +/** + * DHCP Options + * RFC 1533 + */ +#define DHCP_OPTION_PAD 0 +#define DHCP_OPTION_SUBNET_MASK 1 +#define DHCP_OPTION_TIME_OFFSET 2 +#define DHCP_OPTION_ROUTER 3 +#define DHCP_OPTION_TIMER_SERVER 4 +#define DHCP_OPTION_NAME_SERVER 5 +#define DHCP_OPTION_DOMAIN_NAME_SERVER 6 +#define DHCP_OPTION_LOG_SERVER 7 +#define DHCP_OPTION_COOKIE_SERVER 8 +#define DHCP_OPTION_LPR_SERVER 9 +#define DHCP_OPTION_IMPRESS_SERVER 10 +#define DHCP_OPTION_RESOURCE_LOCATION 11 +#define DHCP_OPTION_HOST_NAME 12 +#define DHCP_OPTION_BOOT_SIZE 13 +#define DHCP_OPTION_MERIT_DUMP_FILE 14 +#define DHCP_OPTION_DOMAIN_NAME 15 +#define DHCP_OPTION_SWAP_SERVER 16 +#define DHCP_OPTION_ROOT_PATH 17 +#define DHCP_OPTION_EXTENSIONS_PATH 18 +#define DHCP_OPTION_IP_FORWARDING 19 +#define DHCP_OPTION_NON_LOCAL_SOURCE_ROUTING 20 +#define DHCP_OPTION_POLICY_FILTER 21 +#define DHCP_OPTION_MAX_DATAGRAM_REASSEMBLY 22 +#define DHCP_OPTION_DEFAULT_IP_TIME_TO_LIVE 23 +#define DHCP_OPTION_PATH_MTU_AGING_TIMEOUT 24 +#define DHCP_OPTION_PATH_MTU_PLATEAU_TABLE 25 +#define DHCP_OPTION_INTERFACE_MTU 26 +#define DHCP_OPTION_ALL_SUBNETS_ARE_LOCAL 27 +#define DHCP_OPTION_BROADCAST_ADDRESS 28 +#define DHCP_OPTION_PERFORM_MASK_DISCOVERY 29 +#define DHCP_OPTION_MASK_SUPPLIER 30 +#define DHCP_OPTION_PERFORM_ROUTER_DISCOVERY 31 +#define DHCP_OPTION_ROUTER_SOLICITATION_ADDRESS 32 +#define DHCP_OPTION_STATIC_ROUTE 33 +#define DHCP_OPTION_TRAILER_ENCAPSULATION 34 +#define DHCP_OPTION_ARP_CACHE_TIMEOUT 35 +#define DHCP_OPTION_ETHERNET_ENCAPSULATION 36 +#define DHCP_OPTION_TCP_DEFAULT_TTL 37 +#define DHCP_OPTION_TCP_KEEPALIVE_INTERVAL 38 +#define DHCP_OPTION_TCP_KEEPALIVE_GARBAGE 39 +#define DHCP_OPTION_NIS_DOMAIN 40 +#define DHCP_OPTION_NIS_SERVERS 41 +#define DHCP_OPTION_NTP_SERVERS 42 +#define DHCP_OPTION_VENDOR_SPECIFIC_INFO 43 +#define DHCP_OPTION_NETBIOS_NAME_SERVER 44 +#define DHCP_OPTION_NETBIOS_DATAGRAM_SERVER 45 +#define DHCP_OPTION_NETBIOS_NODE_TYPE 46 +#define DHCP_OPTION_NETBIOS_SCOPE 47 +#define DHCP_OPTION_FONT_SERVERS 48 +#define DHCP_OPTION_X_DISPLAY_MANAGER 49 +#define DHCP_OPTION_REQUESTED_IP_ADDRESS 50 +#define DHCP_OPTION_IP_ADDRESS_LEASE_TIME 51 +#define DHCP_OPTION_OVERLOAD 52 +#define DHCP_OPTION_MESSAGE_TYPE 53 +#define DHCP_OPTION_SERVER_IDENTIFIER 54 +#define DHCP_OPTION_PARAMETER_REQUEST_LIST 55 +#define DHCP_OPTION_MESSAGE 56 +#define DHCP_OPTION_MAX_SIZE 57 +#define DHCP_OPTION_RENEWAL_TIME 58 +#define DHCP_OPTION_REBINDING_TIME 59 +#define DHCP_OPTION_VENDOR_CLASS_IDENTIFIER 60 +#define DHCP_OPTION_CLIENT_IDENTIFIER 61 +#define DHCP_OPTION_END 255 + +#define DHCP_MAGIC_COOKIE 0x63825363 // 99, 130, 83, 99 + +#define DHCP_DISCOVER 1 +#define DHCP_OFFER 2 +#define DHCP_REQUEST 3 +#define DHCP_DECLINE 4 +#define DHCP_ACK 5 +#define DHCP_NAK 6 +#define DHCP_RELEASE 7 +#define DHCP_INFORM 8 + +#define DHCP_RETRANSMIT_DELAY(retry_times) \ + MIN(1 << (retry_times + 2), 64) * 1000 + +typedef enum { + DOI_SUBNET_MASK, + DOI_ROUTER, + DOI_DNS, + DOI_SERVER_ID, + DOI_IP_LEASE_TIME, + DOI_MESSAGE_TYPE, + DOI_RENEWAL_TIME, + DOI_REBINDING_TIME, + DOI_MAX, +} DhcpOptionIndex; + +/** + * DHCP Client状态 + * 定义于RFC1541 Figure 5: State-transition diagram for DHCP client + */ +typedef enum { + DHCP_STAT_BOUND, + DHCP_STAT_INIT, + DHCP_STAT_INIT_REBOOT, + DHCP_STAT_REBINDING, + DHCP_STAT_REBOOTING, + DHCP_STAT_RENEWING, + DHCP_STAT_REQUESTING, + DHCP_STAT_SELECTING, + DHCP_FAILED, // 非RFC中包含的状态,表示重传失败退出 +} DhcpClientState; + +typedef struct { + NetworkDevice *device; + DhcpClientState state; + NetworkConnection *conn; + Timer timeout_timer; + Timer lease_timer; + Timer rebind_timer; + Timer renew_timer; + uint32_t t0, t1, t2; + + uint32_t xid; + uint8_t haddr_len; // 硬件地址长度 + uint8_t haddr_type; // 硬件地址类型 + uint8_t haddr[8]; // 硬件地址 + uint8_t ip_addr[4]; // IP地址 + uint8_t server_ip_addr[4]; // 服务器IP地址 + uint8_t server_haddr[8]; // 服务器硬件地址 + uint8_t gateway_ip_addr[4]; // 网关IP地址 + + int retry_times; // 重传次数 +} DhcpClient; + +/** + * DHCP报文头部结构 + * RFC 1541 Figure 1: Format of a DHCP message + */ +typedef struct { + uint8_t op; // Message type + uint8_t htype; // Hardware address type + uint8_t hlen; // Hardware address length + uint8_t hops; // Hops + uint32_t xid; // Transaction ID + uint16_t secs; // Seconds elapsed + uint16_t flags; // Flags + uint32_t ciaddr; // Client IP address + uint32_t yiaddr; // Your IP address + uint32_t siaddr; // Server IP address + uint32_t giaddr; // Gateway IP address + uint8_t chaddr[16]; // Client hardware address + uint8_t sname[64]; // Server name + uint8_t file[128]; // Boot file name + uint8_t options[0]; // Options field +} DhcpHeader; + +ProtocolResult dhcp_start(NetworkDevice *device); + +#endif \ No newline at end of file diff --git a/src/include/driver/network/protocols/ipv4/icmp.h b/src/include/driver/network/protocols/ipv4/icmp.h new file mode 100644 index 0000000..d3adcb5 --- /dev/null +++ b/src/include/driver/network/protocols/ipv4/icmp.h @@ -0,0 +1,55 @@ +#ifndef _ICMP_H +#define _ICMP_H + +#include +#include +#include +#include +#include + +#define ICMP_TYPE_ECHO_REPLY 0 +#define ICMP_TYPE_DEST_UNREACHABLE 3 +#define ICMP_TYPE_SOURCE_QUENCH 4 +#define ICMP_TYPE_REDIRECT 5 +#define ICMP_TYPE_ECHO 8 +#define ICMP_TYPE_TIME_EXCEEDED 11 +#define ICMP_TYPE_PARAM_PROBLEM 12 +#define ICMP_TYPE_TIMESTAMP 13 +#define ICMP_TYPE_TIMESTAMP_REPLY 14 +#define ICMP_TYPE_INFO_REQUEST 15 +#define ICMP_TYPE_INFO_REPLY 16 + +#define ICMP_UNREACHABLE_NET 0 +#define ICMP_UNREACHABLE_HOST 1 +#define ICMP_UNREACHABLE_PROTOCOL 2 +#define ICMP_UNREACHABLE_PORT 3 +#define ICMP_UNREACHABLE_NEEDFRAG 4 +#define ICMP_UNREACHABLE_SRCFAIL 5 + +typedef struct { + uint8_t type; + uint8_t code; + uint16_t checksum; + union { + uint32_t unused; + struct { + uint8_t pointer; + uint8_t unused[3]; + } param; + struct { + uint16_t unused; + uint16_t mtu; + } pmtu; + uint8_t gateway_ip[4]; + struct { + uint16_t id; + uint16_t seq; + } info; + }; +} __attribute__((packed)) IcmpHeader; + +ProtocolResult icmp_recv( + NetworkDevice *device, NetBuffer *net_buffer, Ipv4Header *header, + ProtocolReplyCallback *stack, int stack_size); + +#endif \ No newline at end of file diff --git a/src/include/driver/network/protocols/ipv4/ipv4.h b/src/include/driver/network/protocols/ipv4/ipv4.h new file mode 100644 index 0000000..72fc8cf --- /dev/null +++ b/src/include/driver/network/protocols/ipv4/ipv4.h @@ -0,0 +1,65 @@ +#ifndef _IPV4_H +#define _IPV4_H + +#include "driver/network/neighbour.h" +#include "kernel/list.h" +#include +#include + +#define IP_PROTO_ICMP 1 +#define IP_PROTO_TCP 6 +#define IP_PROTO_UDP 17 + +#define IPv4_DEFAULT_MSS 536 + +#define CONN_LOCAL_IP(conn) conn->ipv4.conn_info.local.ip +#define CONN_REMOTE_IP(conn) conn->ipv4.conn_info.remote.ip + +typedef struct Ipv4Header { + uint8_t ver_len; // Version and Internet Header Length + uint8_t tos; // Type of Service + uint16_t total_len; // Total Length + uint16_t id; // Identification + uint16_t flags_frag_offset; // Flags and Fragment Offset + uint8_t ttl; // Time to Live + uint8_t protocol; // Protocol + uint16_t checksum; // Header Checksum + uint8_t src_ip[4]; // Source IP Address + uint8_t dst_ip[4]; // Destination IP Address + uint8_t options[0]; // Options +} __attribute__((packed)) Ipv4Header; + +typedef struct Ipv4Endpoint { + uint8_t ip[4]; // IP地址 + uint16_t port; // 端口号 +} Ipv4Endpoint; + +typedef struct Ipv4ConnInfo { + Ipv4Endpoint local; // 本地IP和端口 + Ipv4Endpoint remote; // 远程IP和端口 + list_t list; +} Ipv4ConnInfo; + +extern const uint32_t ipv4_broadcast_addr; +extern const uint32_t ipv4_null_addr; + +struct NetworkConnection; +struct NetBuffer; +void ipv4_register(struct NetworkConnection *conn, uint8_t *ip_addr); +void ipv4_checksum(Ipv4Header *header); +void ipv4_enable_fragment(struct NetworkConnection *conn); +ProtocolResult ipv4_wrap( + struct NetworkConnection *conn, uint16_t protocol, uint8_t *dst_ip, + uint8_t ttl); +void ipv4_rewrap(struct NetworkConnection *conn); +ProtocolResult ipv4_recv( + struct NetworkDevice *device, struct NetBuffer *net_buffer, + ProtocolReplyCallback *stack, int stack_size); +NeighbourKey ipv4_hash(uint8_t ip[4]); +void ipv4_neigh_update( + NetworkDevice *device, struct NetBuffer *buffer, uint8_t *mac, int hlen); +ProtocolResult ipv4_lookup_mac( + NetworkDevice *device, uint8_t ip[4], uint8_t mac[8]); +uint16_t ipv4_get_packet_length(Ipv4Header *ipv4_header); + +#endif \ No newline at end of file diff --git a/src/include/driver/network/protocols/protocols.h b/src/include/driver/network/protocols/protocols.h new file mode 100644 index 0000000..e8dfbd8 --- /dev/null +++ b/src/include/driver/network/protocols/protocols.h @@ -0,0 +1,35 @@ +#ifndef _NET_PROTOCOLS_H +#define _NET_PROTOCOLS_H + +#include + +typedef enum { + PROTO_OK, + PROTO_DROP, + PROTO_ERROR_UNSUPPORT, + PROTO_ERROR_EXCEED_MAX_SIZE, + PROTO_ERROR_NULL_PTR, + PROTO_ERROR_CHECKSUM, + PROTO_ERROR_CONNECT_FAILED, + PROTO_ERROR_SEND_FAILED, + PROTO_ERROR_REBIND, + PROTO_ERROR_PORT_CONFLICT, + PROTO_ERROR_CANNOT_FIND, + PROTO_ERROR_NO_SPACE_LEFT, + PROTO_ERROR_CANNOT_FIND_ROUTE, + PROTO_ERROR_NOT_CONNECTED, + PROTO_ERROR_NET_UNREACHABLE, + PROTO_ERROR_HOST_UNREACHABLE, + PROTO_ERROR_PORT_UNREACHABLE, + PROTO_ERROR_OTHER, +} ProtocolResult; + +struct NetworkDevice; +struct NetBuffer; +typedef ProtocolResult (*ProtocolReplyCallback)( + struct NetworkDevice *device, struct NetBuffer *net_buffer); +ProtocolResult protocol_reply( + struct NetworkDevice *device, struct NetBuffer *net_buffer, + ProtocolReplyCallback *stack, int stack_size); + +#endif \ No newline at end of file diff --git a/src/include/driver/network/protocols/tcp.h b/src/include/driver/network/protocols/tcp.h new file mode 100644 index 0000000..e344f1e --- /dev/null +++ b/src/include/driver/network/protocols/tcp.h @@ -0,0 +1,187 @@ +#ifndef _TCP_H +#define _TCP_H + +#include +#include +#include + +#define TCP_FLAG_FIN 0x01 +#define TCP_FLAG_SYN 0x02 +#define TCP_FLAG_RST 0x04 +#define TCP_FLAG_PSH 0x08 +#define TCP_FLAG_ACK 0x10 +#define TCP_FLAG_URG 0x20 + +#define TCP_OPTION_END 0 +#define TCP_OPTION_NOP 1 +#define TCP_OPTION_MSS 2 + +#define TCP_SHUT_WR 0 +#define TCP_SHUT_RD 1 +#define TCP_SHUT_RDWR 2 + +#define TCP_MSL 120 * 1000 + +// TCP头部,options不算在头部内 +typedef struct { + uint16_t src_port; + uint16_t dest_port; + uint32_t seq; + uint32_t ack; + uint8_t data_offset; + uint8_t flags; + uint16_t window_size; + uint16_t checksum; + uint16_t urgent_pointer; + uint8_t options[0]; +} TcpHeader; + +typedef enum { + TOI_MSS = 0, + TOI_MAX, +} TcpOptionIndex; + +// +---------+ ---------\ active OPEN +// | CLOSED | \ ----------- +// +---------+<---------\ \ create TCB +// | ^ \ \ snd SYN +// passive OPEN | | CLOSE \ \. +// ------------ | | ---------- \ \. +// create TCB | | delete TCB \ \. +// V | \ \. +// +---------+ CLOSE | \. +// | LISTEN | ---------- | | +// +---------+ delete TCB | | +// rcv SYN | | SEND | | +// ----------- | | ------- | V +// +---------+ snd SYN,ACK / \ snd SYN +---------+ +// | |<----------------- ------------------>| | +// | SYN | rcv SYN | SYN | +// | RCVD |<-----------------------------------------------| SENT | +// | | snd ACK | | +// | |------------------ -------------------| | +// +---------+ rcv ACK of SYN \ / rcv SYN,ACK +---------+ +// | -------------- | | ----------- +// | x | | snd ACK +// | V V +// | CLOSE +---------+ +// | ------- | ESTAB | +// | snd FIN +---------+ +// | CLOSE | | rcv FIN +// V ------- | | ------- +// +---------+ snd FIN / \ snd ACK +---------+ +// | FIN |<----------------- ------------------>| CLOSE | +// | WAIT-1 |------------------ | WAIT | +// +---------+ rcv FIN \ +---------+ +// | rcv ACK of FIN ------- | CLOSE | +// | -------------- snd ACK | ------- | +// V x V snd FIN V +// +---------+ +---------+ +---------+ +// |FINWAIT-2| | CLOSING | | LAST-ACK| +// +---------+ +---------+ +---------+ +// | rcv ACK of FIN | rcv ACK of FIN | +// | rcv FIN -------------- | Timeout=2MSL -------------- | +// | ------- x V ------------ x V +// \ snd ACK +---------+delete TCB +---------+ +// ------------------------>|TIME WAIT|------------------>| CLOSED | +// +---------+ +---------+ +typedef enum { + TCP_STATE_LISTEN, + TCP_STATE_SYN_SENT, + TCP_STATE_SYN_RECEIVED, + TCP_STATE_ESTABLISHED, + TCP_STATE_FIN_WAIT1, + TCP_STATE_FIN_WAIT2, + TCP_STATE_CLOSE_WAIT, + TCP_STATE_CLOSING, + TCP_STATE_LAST_ACK, + TCP_STATE_TIME_WAIT, + TCP_STATE_CLOSED, +} TcpState; + +typedef struct Tcp { + NetworkConnection *conn; + TcpState state; + TcpHeader *header; + int mss; + + struct task_s *thread; + + // Send Sequence Space + // 1 2 3 4 + // ----------|----------|----------|---------- + // SND.UNA SND.NXT SND.UNA + // +SND.WND + + // 1 - old sequence numbers which have been acknowledged + // 2 - sequence numbers of unacknowledged data + // 3 - sequence numbers allowed for new data transmission + // 4 - future sequence numbers which are not yet allowed + struct { + uint32_t unack; // send unacknowledged + uint32_t next; // send next + uint32_t window; // send window + uint32_t urg_p; // send urgent pointer + uint32_t wl1; // segment sequence number used for last window update + uint32_t + wl2; // segment acknowledgment number used for last window update + uint32_t iss; // initial send sequence number + uint32_t total_size; + + uint32_t remote_window_size; + } send; + uint8_t *send_window; + // Receive Sequence Space + // 1 2 3 + // ----------|----------|---------- + // RCV.NXT RCV.NXT + // +RCV.WND + + // 1 - old sequence numbers which have been acknowledged + // 2 - sequence numbers allowed for new reception + // 3 - future sequence numbers which are not yet allowed + struct { + uint32_t next; // receive next + uint32_t window; // receive window + uint32_t urg_p; // receive urgent pointer + uint32_t irs; // initial receive sequence number + uint32_t total_size; + + uint32_t read; + } recv; + uint8_t *recv_window; + + struct { + uint32_t seq; // segment sequence number + uint32_t ack; // segment acknowledgment number + uint32_t len; // segment length + uint32_t window; // segment window + uint32_t urg_p; // segment urgent pointer + uint32_t prc; // segment precedence value + + uint32_t fin_seq; + } cur; + + uint32_t send_time, send_seq; + int rttvar, srtt, rto; + int retry_times; + Timer timeout_timer; +} Tcp; + +void tcp_register(NetworkConnection *conn); +ProtocolResult tcp_bind(NetworkConnection *conn, uint16_t port); +ProtocolResult tcp_connect( + NetworkConnection *conn, uint8_t *dst_ip, uint16_t dst_port); +ProtocolResult tcp_listen(NetworkConnection *conn); +ProtocolResult tcp_send_data(NetworkConnection *conn, uint8_t *buf, int length); +ProtocolResult tcp_recv_data(Tcp *tcp, void *buffer, uint32_t *length); +void tcp_reset(NetworkConnection *conn); +ProtocolResult tcp_shutdown(NetworkConnection *conn, uint8_t how); +ProtocolResult tcp_recv( + NetBuffer *net_buffer, int length, uint8_t *src_ip, uint8_t *dst_ip, + int ip_len); +void tcp_notify_unreachable( + void *data, uint8_t *src_ip, uint8_t *dst_ip, int ip_len, int code); +void tcp_update_mtu(uint8_t *src_ip, uint8_t *dst_ip, int ip_len, int mtu); + +#endif \ No newline at end of file diff --git a/src/include/driver/network/protocols/udp.h b/src/include/driver/network/protocols/udp.h new file mode 100644 index 0000000..68e48ab --- /dev/null +++ b/src/include/driver/network/protocols/udp.h @@ -0,0 +1,31 @@ +#ifndef _UDP_H +#define _UDP_H + +#include "driver/network/buffer.h" +#include "driver/network/protocols/ipv4/ipv4.h" +#include + +#define UDP_PORT_DHCP_SERVER 67 +#define UDP_PORT_DHCP_CLIENT 68 + +typedef struct { + uint16_t src_port; // 源端口 + uint16_t dst_port; // 目的端口 + uint16_t length; // 数据长度 + uint16_t checksum; // 校验和 +} __attribute__((packed)) UdpHeader; + +struct NetworkConnection; +void udp_register(struct NetworkConnection *conn); +void udp_wrap( + struct NetworkConnection *conn, uint16_t src_port, uint16_t dst_port); +void udp_set_callback( + struct NetworkConnection *conn, + void (*callback)(struct NetworkConnection *conn, NetBuffer *buffer)); +void udp_bind(struct NetworkConnection *conn, uint16_t port); +void udp_unbind(struct NetworkConnection *conn); +ProtocolResult udp_recv(NetBuffer *net_buffer, Ipv4Header *ipv4_header); +void udp_notify_unreachable( + void *data, uint8_t *src_ip, uint8_t *dst_ip, int ip_len, int code); + +#endif \ No newline at end of file diff --git a/src/include/driver/serial/serial_dm.h b/src/include/driver/serial/serial_dm.h new file mode 100644 index 0000000..c57efac --- /dev/null +++ b/src/include/driver/serial/serial_dm.h @@ -0,0 +1,55 @@ +#ifndef _SERIAL_DM_H +#define _SERIAL_DM_H + +#include "kernel/driver.h" +#include +#include +#include +#include +#include + +typedef enum SerialBaudRate { + SERIAL_BAUD_115200, + SERIAL_BAUD_57600, + SERIAL_BAUD_38400, + SERIAL_BAUD_19200, + SERIAL_BAUD_9600, +} SerialBaudRate; + +typedef enum SerialReceiveMode { + SERIAL_RECV_MODE_LOW_LATENCY, + SERIAL_RECV_MODE_HIGH_THROUGHPUT, +} SerialReceiveMode; + +struct SerialDevice; +typedef struct SerialDeviceOps { + DriverResult (*self_test)(struct SerialDevice *serial); + void (*set_baud_rate)( + struct SerialDevice *serial, SerialBaudRate baud_rate); + void (*set_recv_mode)( + struct SerialDevice *serial, SerialReceiveMode recv_mode); +} SerialOps; + +typedef struct SerialDevice { + LogicalDevice *device; + SerialOps *ops; + + void (*receive)(uint8_t data); +} SerialDevice; + +typedef struct SerialDeviceManager { + int new_device_num; + int device_count; +} SerialDeviceManager; + +extern DeviceManager serial_dm; + +DriverResult create_serial_device( + SerialDevice **serial_device, SerialOps *serial_ops, DeviceOps *ops, + PhysicalDevice *physical_device, DeviceDriver *device_driver); +DriverResult delete_serial_device(SerialDevice *serial_device); +DriverResult serial_device_open( + Object *serial_object, SerialBaudRate baud_rate, + void (*receive)(uint8_t data)); + +#endif \ No newline at end of file diff --git a/src/include/driver/sound/pcm.h b/src/include/driver/sound/pcm.h new file mode 100644 index 0000000..f206cf1 --- /dev/null +++ b/src/include/driver/sound/pcm.h @@ -0,0 +1,153 @@ +#ifndef _PCM_H +#define _PCM_H + +#include +#include +#include +#include +#include +#include +#include +#include + +#define PCM_STATUS_FREE 0 +#define PCM_STATUS_HOST_USING 1 +#define PCM_STATUS_DEVICE_USING 2 + +typedef enum PcmDataType { + PCM_U8, + PCM_S8, + PCM_U16LE, + PCM_U16BE, + PCM_S16LE, + PCM_S16BE, + PCM_U24LE, + PCM_U24BE, + PCM_S24LE, + PCM_S24BE, + PCM_U32LE, + PCM_U32BE, + PCM_S32LE, + PCM_S32BE, + PCM_F32LE, + PCM_F32BE, + PCM_F64LE, + PCM_F64BE, +} PcmDataType; + +typedef enum PcmTrigger { + PCM_TRIGGER_NONE, + PCM_TRIGGER_START, + PCM_TRIGGER_STOP, + PCM_TRIGGER_PAUSE, + PCM_TRIGGER_RESUME, +} PcmTrigger; + +typedef enum PcmMode { + PCM_MODE_INTERLEAVED, + PCM_MODE_NONINTERLEAVED, +} PcmMode; + +typedef enum PcmStatus { + PCM_STATUS_CLOSE, + PCM_STATUS_OPEN, + PCM_STATUS_PREPARED, + PCM_STATUS_RUNNING, + PCM_STATUS_PAUSED, +} PcmStatus; + +struct SoundDevice; +struct PcmStream; +typedef struct PcmStreamOps { + DriverResult (*open)( + struct SoundDevice *sound_device, struct PcmStream *stream); + DriverResult (*close)( + struct SoundDevice *sound_device, struct PcmStream *stream); + DriverResult (*prepare)( + struct PcmStream *pcm_stream, void *addr, size_t size); + DriverResult (*trigger)(struct PcmStream *stream, PcmTrigger trigger); + size_t (*position)(struct PcmStream *stream); + + DriverResult (*set_mode)(struct PcmStream *stream, PcmMode mode); + DriverResult (*set_default_params)(struct PcmStream *stream); + DriverResult (*set_data_type)( + struct PcmStream *stream, PcmDataType data_type); + DriverResult (*set_channel)(struct PcmStream *stream, uint8_t channel); +} PcmStreamOps; + +typedef struct PcmStream { + struct PcmDevice *pcm; + struct SoundDevice *sound_device; + PcmStreamOps *ops; + + PcmDataType data_type; + uint8_t channel; + + spinlock_t lock; + WaitQueue wq; + + uint16_t frame_bytes; // 一个帧的大小 + size_t frame_per_period; + uint32_t period_bytes; // 一个周期的大小 + + uint32_t start_threshold; + uint32_t stop_threshold; + + size_t device_ptr_base, device_period_ptr; + size_t host_ptr_base, host_period_ptr; + size_t host_ptr; + + PcmMode hw_mode, user_mode; + + void *private_data; +} PcmStream; + +typedef struct PcmOps { + DriverResult (*set_sample_rate)( + struct PcmDevice *pcm, uint32_t sample_rate); +} PcmOps; + +typedef struct PcmDevice { + struct SoundDevice *sound_device; + + PcmStatus status; + + PcmStream *play_stream; + PcmStream *record_stream; + PcmStream *current_stream; + + void *buf; + + size_t boundary; + size_t buffer_bytes; + uint8_t data_bytes; // 数据单位大小 + + uint32_t sample_rate; + Dma *dma; + + PcmOps *ops; +} PcmDevice; + +PcmDevice *sound_register_pcm( + struct SoundDevice *sound_device, PcmOps *pcm_ops, size_t size); +DriverResult pcm_register_stream( + PcmDevice *pcm, PcmStream **stream, PcmStreamOps *ops, void *private_data); +DriverResult pcm_register_dma( + PcmDevice *pcm, void *dma, void *param, DmaOps *ops); +DriverResult sound_pcm_alloc(PcmStream *stream); + +DriverResult pcm_set_data_type(PcmStream *stream, PcmDataType data_type); +DriverResult pcm_set_channel(PcmStream *stream, uint8_t channel); +DriverResult pcm_set_sample_rate(PcmDevice *pcm, uint32_t sample_rate); +DriverResult sound_pcm_open( + Object *object, int mode, DEF_MRET(PcmDevice *, pcm), + DEF_MRET(PcmStream *, stream)); +DriverResult sound_pcm_set_frame_count(PcmStream *stream, size_t count); +DriverResult sound_pcm_read( + PcmStream *stream, uint8_t *buf, uint32_t frame_count); +DriverResult sound_pcm_write( + PcmStream *stream, uint8_t *buf, uint32_t frame_count); +DriverResult sound_pcm_prepare(PcmStream *stream); +DriverResult sound_pcm_done(PcmStream *stream); + +#endif \ No newline at end of file diff --git a/src/include/driver/sound/sound_dm.h b/src/include/driver/sound/sound_dm.h new file mode 100644 index 0000000..a7a8c61 --- /dev/null +++ b/src/include/driver/sound/sound_dm.h @@ -0,0 +1,58 @@ +#ifndef _SOUND_DM_H +#define _SOUND_DM_H + +#include +#include +#include +#include +#include +#include + +#define SOUND_DEVICE_MODE_PLAY 0 +#define SOUND_DEVICE_MODE_RECORED 1 + +struct SoundDevice; +typedef struct SoundDeviceOps { + DriverResult (*set_volume)(struct SoundDevice *device, int volume); +} SoundOps; + +typedef struct SoundDeviceCapabilities { + uint32_t record : 1; + uint32_t play : 1; + uint32_t set_volume : 1; + uint32_t set_sample_rate : 1; +} SoundDeviceCapabilities; + +typedef enum SoundDeviceType { + SOUND_TYPE_UNKNOWN, + SOUND_TYPE_PCM, +} SoundDeviceType; + +typedef struct SoundDevice { + LogicalDevice *device; + SoundDeviceCapabilities capabilities; + SoundOps *ops; + + SoundDeviceType type; + + union { + struct PcmDevice *pcm; + }; +} SoundDevice; + +typedef struct SoundDeviceManager { + int new_device_num; + int device_count; +} SoundDeviceManager; + +extern DeviceManager sound_dm; + +DriverResult create_sound_device( + SoundDevice **sound_device, SoundDeviceType type, + SoundDeviceCapabilities caps, SoundOps *sound_ops, DeviceOps *ops, + PhysicalDevice *physical_device, DeviceDriver *device_driver); +DriverResult delete_sound_device(SoundDevice *sound_device); + +SoundDevice *sound_get_device(Object *object); + +#endif \ No newline at end of file diff --git a/src/include/driver/storage/disk/disk.h b/src/include/driver/storage/disk/disk.h new file mode 100644 index 0000000..44c297a --- /dev/null +++ b/src/include/driver/storage/disk/disk.h @@ -0,0 +1,48 @@ +#ifndef _DISK_H +#define _DISK_H + +#include "objects/handle.h" +#include "objects/transfer.h" +#include "stdint.h" +#include + +struct Object; +struct MBRPartitionEntry; +typedef struct Partition { + enum { + PARTITION_TYPE_MBR, + PARTITION_TYPE_GPT, + } type; + union { + struct MBRPartitionEntry *mbr; + }; + size_t start_lba; + size_t size_lba; + uint8_t index; + + uint8_t *superblock; + + struct Object *object; + struct Object *storage_object; +} Partition; + +TransferResult disk_transfer_in( + struct Object *object, ObjectHandle *obj_handle, + TransferDirection direction, uint8_t *buf, uint32_t position, size_t count); +TransferResult disk_transfer_in_async( + struct Object *object, ObjectHandle *obj_handle, + TransferDirection direction, uint8_t *buf, uint32_t position, size_t count, + void **handle); +TransferResult disk_transfer_out( + struct Object *object, ObjectHandle *obj_handle, + TransferDirection direction, uint8_t *buf, uint32_t position, size_t count); +TransferResult disk_transfer_out_async( + struct Object *object, ObjectHandle *obj_handle, + TransferDirection direction, uint8_t *buf, uint32_t position, size_t count, + void **handle); +TransferResult disk_is_transfer_in_done( + struct Object *object, void **handle, bool *is_done); +TransferResult disk_is_transfer_out_done( + struct Object *object, void **handle, bool *is_done); + +#endif \ No newline at end of file diff --git a/src/include/driver/storage/disk/mbr.h b/src/include/driver/storage/disk/mbr.h new file mode 100644 index 0000000..a944906 --- /dev/null +++ b/src/include/driver/storage/disk/mbr.h @@ -0,0 +1,20 @@ +#ifndef _DISK_MBR_H +#define _DISK_MBR_H + +#include +#include + +typedef struct MBRPartitionEntry { + uint8_t sign; + uint8_t start_chs[3]; + uint8_t fs_type; + uint8_t end_chs[3]; + uint32_t start_lba; + uint32_t size; +} __attribute__((packed)) MBRPartitionEntry; + +struct StorageDevice; +bool disk_is_mbr(struct StorageDevice *storage_device); +void parse_mbr_partition_table(struct StorageDevice *storage_device); + +#endif \ No newline at end of file diff --git a/src/include/driver/storage/disk/volume.h b/src/include/driver/storage/disk/volume.h new file mode 100644 index 0000000..e8088db --- /dev/null +++ b/src/include/driver/storage/disk/volume.h @@ -0,0 +1,8 @@ +#ifndef _VOLUME_H +#define _VOLUME_H + +#include "driver/storage/disk/disk.h" + +void probe_volume(Partition *partition); + +#endif \ No newline at end of file diff --git a/src/include/driver/storage/storage_dm.h b/src/include/driver/storage/storage_dm.h new file mode 100644 index 0000000..e75830b --- /dev/null +++ b/src/include/driver/storage/storage_dm.h @@ -0,0 +1,76 @@ +#ifndef _STORAGE_DM_H +#define _STORAGE_DM_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef enum StorageDeviceType { + STORAGE_DEVICE_TYPE_UNKNOWN, + STORAGE_DEVICE_TYPE_HARDDISK, +} StorageDeviceType; + +struct StorageDevice; +struct StorageRequest; +typedef struct StorageDeviceOps { + DriverResult (*submit_read_request)( + struct StorageDevice *storage_device, struct StorageRequest *request); + DriverResult (*submit_write_request)( + struct StorageDevice *storage_device, struct StorageRequest *request); + bool (*is_busy)(struct StorageDevice *storage_device); +} StorageDeviceOps; + +#define SECTOR_SIZE 512 + +struct Object; +typedef struct StorageDevice { + LogicalDevice *device; + StorageDeviceType type; + StorageDeviceOps *ops; + + string_t name; + + uint32_t block_size; + size_t max_block_per_request; + // 虚拟地址连续,而物理地址不连续的情况下,最大的连续段数 + int max_segment; + + spinlock_t queue_lock; + PeriodicTask periodic_task; + list_t io_queue_lh; + WaitQueue wq; + + uint8_t *superblock; + + list_t block_cache_lh; + + // 存储设备的分区目录对象 + struct Object *object; +} StorageDevice; + +typedef struct StorageDeviceDriver { + string_t name; + list_t driver_list; + list_t device_list; + StorageDeviceOps *ops; +} StorageDeviceDriver; + +extern DeviceManager storage_dm; + +DriverResult create_storage_device( + StorageDevice **storage_device, StorageDeviceOps *storage_ops, + DeviceOps *ops, PhysicalDevice *physical_device, + DeviceDriver *device_driver); +DriverResult unregister_storage_device( + struct DeviceDriver *device_driver, PhysicalDevice *device, + StorageDevice *storage_device); + +#endif \ No newline at end of file diff --git a/src/include/driver/storage/storage_io.h b/src/include/driver/storage/storage_io.h new file mode 100644 index 0000000..3e06a7d --- /dev/null +++ b/src/include/driver/storage/storage_io.h @@ -0,0 +1,23 @@ +#ifndef _STORAGE_IO_H +#define _STORAGE_IO_H + +#include "driver/storage/storage_io_queue.h" +#include +#include +#include + +TransferResult storage_transfer_async( + Object *object, ObjectHandle *obj_handle, TransferDirection direction, + uint8_t *buf, uint32_t position, size_t count, void **handle); +TransferResult storage_transfer( + Object *object, ObjectHandle *obj_handle, TransferDirection direction, + uint8_t *buf, uint32_t position, size_t count); +TransferResult storage_is_transfer_done( + Object *object, void **handle, bool *done); + +struct StorageDevice; +struct StorageRequest; +bool storage_check_request_size( + struct StorageDevice *device, struct StorageRequest *request); + +#endif \ No newline at end of file diff --git a/src/include/driver/storage/storage_io_queue.h b/src/include/driver/storage/storage_io_queue.h new file mode 100644 index 0000000..1155ebf --- /dev/null +++ b/src/include/driver/storage/storage_io_queue.h @@ -0,0 +1,41 @@ +#ifndef _STORAGE_IO_QUEUE_H +#define _STORAGE_IO_QUEUE_H + +#include "driver/storage/storage_dm.h" +#include "kernel/list.h" +#include "stdint.h" +#include "types.h" + +typedef struct StorageRequest { + StorageDevice *storage_device; + + list_t list; + bool rw; + uint8_t *buf; + uint64_t position; + uint32_t count; + bool is_finished; + struct task_s *thread; + + uint32_t t0l, t0h; + uint32_t t1l, t1h; + + struct StorageRequest *next_merged_request; +} StorageRequest; + +void storage_add_request( + StorageDevice *storage_device, StorageRequest *request); +void storage_submit_request(StorageRequest *request); +void storage_finish_request(StorageRequest *storage_request); +void storage_periodic_task(void *arg); +bool storage_try_merge_request( + StorageRequest *new_request, StorageRequest *request, size_t max_count); +void storage_solve_read_request(StorageRequest *request); +void storage_solve_write_request(StorageRequest *request); + +// 新增请求分割相关函数声明 +bool storage_check_request_size(StorageDevice *device, StorageRequest *request); +DriverResult storage_split_request( + StorageDevice *device, StorageRequest *request); + +#endif \ No newline at end of file diff --git a/src/include/driver/time_dm.h b/src/include/driver/time_dm.h new file mode 100644 index 0000000..bcf3983 --- /dev/null +++ b/src/include/driver/time_dm.h @@ -0,0 +1,56 @@ +#ifndef _TIME_DM_H +#define _TIME_DM_H + +#include +#include +#include + +typedef enum TimeType { + TIME_TYPE_UNIX_TIMESTAMP, // Unix时间戳 + TIME_TYPE_UTC, // UTC时间 + TIME_TYPE_LOCAL, // 本地时间 + TIME_TYPE_MAX, +} TimeType; + +typedef struct TimeUTC { + uint16_t year; + uint8_t month; + uint8_t day; + uint8_t hour; + uint8_t minute; + uint8_t second; +} TimeFull; + +typedef union Time { + uint32_t timestamp; + TimeFull time; +} Time; + +struct TimeDevice; +typedef struct TimeOps { + DriverResult (*get_time)( + struct TimeDevice *device, TimeType type, Time *time); + DriverResult (*set_time)( + struct TimeDevice *device, TimeType type, Time *time); +} TimeOps; + +typedef struct TimeDevice { + LogicalDevice *device; + TimeType type; + TimeOps *ops; +} TimeDevice; + +typedef struct TimeDeviceManager { + TimeDevice *time_devices[TIME_TYPE_MAX]; +} TimeDeviceManager; + +extern DeviceManager time_dm; + +DriverResult create_time_device( + TimeDevice **time_device, TimeOps *time_ops, DeviceOps *ops, + PhysicalDevice *physical_device, DeviceDriver *device_driver); +DriverResult delete_time_device(TimeDevice *time_device); + +DriverResult get_current_time(TimeType type, Time *time); + +#endif \ No newline at end of file diff --git a/src/include/driver/timer/timer_dm.h b/src/include/driver/timer/timer_dm.h new file mode 100644 index 0000000..c3acca6 --- /dev/null +++ b/src/include/driver/timer/timer_dm.h @@ -0,0 +1,85 @@ +#ifndef _TIMER_DM_H +#define _TIMER_DM_H + +#include +#include +#include +#include +#include + +typedef enum TimerResult { + TIMER_RESULT_OK = 0, + TIMER_RESULT_FREQ_TOO_LARGE, + TIMER_RESULT_FREQ_TOO_SMALL, + TIMER_RESULT_UNSUPPORT, + TIMER_RESULT_OTHER_ERROR, +} TimerResult; + +#define TIMER_RESULT_DELIVER_CALL(func, ...) \ + RESULT_DELIVER_CALL(TimerResult, TIMER_RESULT_OK, func, {}, __VA_ARGS__) + +struct TimerDevice; + +typedef struct TimerOps { + TimerResult (*set_frequency)( + struct TimerDevice *timer_device, uint32_t frequency); + TimerResult (*one_shot)( + struct TimerDevice *timer_device, + uint32_t frequency); // 单次中断,可用于校准其他定时器 +} TimerOps; + +typedef struct TimerDevice { + list_t timer_callback_lh; + + LogicalDevice *device; + uint32_t current_frequency; + uint32_t min_frequency; + uint32_t max_frequency; + uint32_t source_frequency; + uint32_t priority; + + uint32_t counter; + + TimerOps *timer_ops; +} TimerDevice; + +typedef void (*TimerCallback)(void *arg); + +typedef struct Timer { + list_t list; + + TimerDevice *timer_device; + + bool will_wrap; // 计时器是否会溢出导致从0重新开始计数 + uint32_t timeout; // 计时器超时时间 + + TimerCallback callback; + void *arg; +} Timer; + +typedef struct TimerDeviceManager { + LogicalDevice *scheduler_timer; +} TimerDeviceManager; + +extern struct DeviceManager timer_dm; + +DriverResult create_timer_device( + TimerDevice **timer_device, TimerOps *timer_ops, DeviceOps *ops, + PhysicalDevice *physical_device, DeviceDriver *device_driver); +DriverResult delete_timer_device(TimerDevice *timer_device); + +DriverResult timer_init(Timer *timer); +void timer_irq_handler(LogicalDevice *device); +uint32_t timer_count_ms(Timer *timer, uint32_t ms); +int timer_get_schedule_tick(int priority); +DriverResult timer_set_frequency(LogicalDevice *device, uint32_t frequency); +void delay_ms(Timer *timer, uint32_t ms); +void delay_ms_async(Timer *timer, uint32_t ms); +bool timer_is_timeout(Timer *timer); +DriverResult timer_set_timeout(Timer *timer, uint32_t count); +size_t timer_get_counter(); + +DriverResult timer_callback_enable(Timer *timer); +DriverResult timer_callback_cancel(Timer *timer); + +#endif \ No newline at end of file diff --git a/src/include/drivers/bus/usb/hcd.h b/src/include/drivers/bus/usb/hcd.h new file mode 100644 index 0000000..6b99904 --- /dev/null +++ b/src/include/drivers/bus/usb/hcd.h @@ -0,0 +1,62 @@ +#ifndef HCD_H +#define HCD_H + +#include +#include +#include +#include +#include +#include + +struct UsbDevice; +struct UsbRequestBlock; +struct UsbControlRequest; +struct UsbEndpoint; + +typedef struct UsbHcdPort { + uint32_t port; + struct UsbHcd *hcd; + + uint8_t suspend; + uint8_t enable; + uint8_t connected; +} UsbHcdPort; + +typedef struct UsbHcdOps { + void *(*create_pipeline)( + struct UsbDevice *usb_device, struct UsbEndpoint *endpoint); + enum UsbSetupStatus (*ctrl_transfer_in)( + struct UsbHcd *hcd, struct UsbDevice *device, void *buffer, + uint32_t data_length, struct UsbControlRequest *usb_req); + enum UsbSetupStatus (*ctrl_transfer_out)( + struct UsbHcd *hcd, struct UsbDevice *device, void *buffer, + uint32_t data_length, struct UsbControlRequest *usb_req); + void (*add_interrupt_transfer)( + struct UsbHcd *hcd, struct UsbDevice *device, struct UsbEndpoint *ep, + struct UsbRequestBlock *urb); + void (*interrupt_transfer)(struct UsbHcd *hcd, struct UsbEndpoint *ep); +} UsbHcdOps; + +typedef struct UsbHcd { + list_t list; + UsbHcdPort *ports; + + UsbHcdOps *ops; + + // BusControllerDevice *bus_ctrlr_device; + LogicalDevice *device; + Bus *bus; + + uint8_t new_device_num; + uint8_t device_count; + spinlock_t lock; + + list_t usb_device_lh; +} UsbHcd; + +DriverResult usb_create_hcd( + DEF_MRET(UsbHcd *, hcd), uint32_t port_cnt, UsbHcdOps *hcd_ops, + DeviceOps *ops, PhysicalDevice *physical_device, + DeviceDriver *device_driver); + +#endif // HCD_H \ No newline at end of file diff --git a/src/include/drivers/bus/usb/usb.h b/src/include/drivers/bus/usb/usb.h new file mode 100644 index 0000000..874b3d1 --- /dev/null +++ b/src/include/drivers/bus/usb/usb.h @@ -0,0 +1,33 @@ +#ifndef _BUS_USB_H +#define _BUS_USB_H + +#include +#include +#include +#include +#include + +typedef struct UsbDevice { + list_t list; + uint8_t address; + + list_t ep_lh; + list_t interface_lh; + + UsbDeviceState state; + UsbHcd *hcd; + PhysicalDevice *device; + struct UsbHub *hub; + + struct UsbDeviceDescriptor *desc; + UsbDeviceSpeed speed; + struct UsbEndpoint *ep0; + + void *private_data; +} UsbDevice; + +extern BusDriver usb_bus_driver; +extern Driver usb_driver; +extern DeviceOps usb_device_ops; + +#endif \ No newline at end of file diff --git a/src/include/drivers/bus/usb/usb_driver.h b/src/include/drivers/bus/usb/usb_driver.h new file mode 100644 index 0000000..4a3524f --- /dev/null +++ b/src/include/drivers/bus/usb/usb_driver.h @@ -0,0 +1,22 @@ +#ifndef _USB_DEVICE_DRIVER_H +#define _USB_DEVICE_DRIVER_H + +#include +#include + +typedef struct UsbDriver { + list_t list; + + Driver *driver; + UsbInterfaceType interface_type; + + DriverResult (*probe)( + struct UsbDevice *device, struct UsbInterface *interface); + DriverResult (*remove)(struct UsbDevice *device); +} UsbDriver; + +extern list_t usb_driver_lh[USB_INTERFACE_TYPE_MAX]; + +DriverResult register_usb_driver(UsbDriver *usb_driver); + +#endif \ No newline at end of file diff --git a/src/include/drivers/usb/core/descriptors.h b/src/include/drivers/usb/core/descriptors.h new file mode 100644 index 0000000..ef16379 --- /dev/null +++ b/src/include/drivers/usb/core/descriptors.h @@ -0,0 +1,146 @@ +#ifndef _USB_DESCRIPTORS_H +#define _USB_DESCRIPTORS_H + +#include + +#define USB_DESC_TYPE_DEVICE 0x01 +#define USB_DESC_TYPE_CONFIG 0x02 +#define USB_DESC_TYPE_STRING 0x03 +#define USB_DESC_TYPE_INTERFACE 0x04 +#define USB_DESC_TYPE_ENDPOINT 0x05 +#define USB_DESC_TYPE_DEVICE_QUALIFIER 0x06 +#define USB_DESC_TYPE_OTHER_SPEED_CONFIG 0x07 +#define USB_DESC_TYPE_INTERFACE_POWER 0x08 + +#define USB_DESC_TYPE_DEVICE_SIZE 18 +#define USB_DESC_TYPE_CONFIG_SIZE 9 +#define USB_DESC_TYPE_HUB_SIZE 9 + +#define USB_DESCRIPTOR_TYPE_STANDARD 0 +#define USB_DESCRIPTOR_TYPE_CLASS 1 +#define USB_DESCRIPTOR_TYPE_VENDOR 2 + +#define USB_DESC_TYPE_HUB 0x29 + +struct UsbDeviceDescriptor { + uint8_t bLength; + uint8_t bDescriptorType; + uint16_t bcdUSB; + uint8_t bDeviceClass; + uint8_t bDeviceSubClass; + uint8_t bDeviceProtocol; + uint8_t bMaxPacketSize0; + uint16_t idVendor; + uint16_t idProduct; + uint16_t bcdDevice; + uint8_t iManufacturer; + uint8_t iProduct; + uint8_t iSerialNumber; + uint8_t bNumConfigurations; +} __attribute__((packed)); + +struct UsbConfigDescriptor { + uint8_t bLength; + uint8_t bDescriptorType; + uint16_t wTotalLength; + uint8_t bNumInterfaces; + uint8_t bConfigurationValue; + uint8_t iConfiguration; + uint8_t bmAttributes; + uint8_t bMaxPower; +} __attribute__((packed)); + +struct UsbInterfaceDescriptor { + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bInterfaceNumber; + uint8_t bAlternateSetting; + uint8_t bNumEndpoints; + uint8_t bInterfaceClass; + uint8_t bInterfaceSubClass; + uint8_t bInterfaceProtocol; + uint8_t iInterface; +} __attribute__((packed)); + +struct UsbEndpointDescriptor { + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bEndpointAddress; + uint8_t bmAttributes; + uint16_t wMaxPacketSize; + uint8_t bInterval; +} __attribute__((packed)); + +struct UsbStringDescriptor { + uint8_t bLength; + uint8_t bDescriptorType; + uint16_t wData[]; +} __attribute__((packed)); + +struct UsbHubDescriptor { + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bNbrPorts; + uint16_t wHubCharacteristics; + uint8_t bPwrOn2PwrGood; + uint8_t bHubContrCurrent; + uint8_t DeviceRemovable; + uint8_t PortPwrCtrlMask; +} __attribute__((packed)); + +// USB HID Descriptors + +typedef enum { + USB_HID_LAYOUT_NOT_SUPPORTED = 0x00, + USB_HID_LAYOUT_ARABIC = 0x01, + USB_HID_LAYOUT_BELGIAN = 0x02, + USB_HID_LAYOUT_CANADIAN_BILINGUAL = 0x03, + USB_HID_LAYOUT_CANADIAN_FRENCH = 0x04, + USB_HID_LAYOUT_CZECH = 0x05, + USB_HID_LAYOUT_DANISH = 0x06, + USB_HID_LAYOUT_FINNISH = 0x07, + USB_HID_LAYOUT_FRENCH = 0x08, + USB_HID_LAYOUT_GERMAN = 0x09, + USB_HID_LAYOUT_GREEK = 0x0A, + USB_HID_LAYOUT_HEBREW = 0x0B, + USB_HID_LAYOUT_HUNGARIAN = 0x0C, + USB_HID_LAYOUT_INTERNATIONAL = 0x0D, + USB_HID_LAYOUT_ITALIAN = 0x0E, + USB_HID_LAYOUT_JAPANESE = 0x0F, + USB_HID_LAYOUT_KOREAN = 0x10, + USB_HID_LAYOUT_LATIN_AMERICAN = 0x11, + USB_HID_LAYOUT_NETHERLANDS_DUTCH = 0x12, + USB_HID_LAYOUT_NORWEGIAN = 0x13, + USB_HID_LAYOUT_PERSIAN_FARSI = 0x14, + USB_HID_LAYOUT_POLISH = 0x15, + USB_HID_LAYOUT_PORTUGUESE = 0x16, + USB_HID_LAYOUT_RUSSIAN = 0x17, + USB_HID_LAYOUT_SLOVAK = 0x18, + USB_HID_LAYOUT_SPANISH = 0x19, + USB_HID_LAYOUT_SWEDISH = 0x1A, + USB_HID_LAYOUT_SWISS_FRENCH = 0x1B, + USB_HID_LAYOUT_SWISS_GERMAN = 0x1C, + USB_HID_LAYOUT_SWITZERLAND = 0x1D, + USB_HID_LAYOUT_CHINESE_BOPOMOFO = 0x1E, + USB_HID_LAYOUT_TURKISH_Q = 0x1F, + USB_HID_LAYOUT_TURKISH_F = 0x20, + USB_HID_LAYOUT_ENGLISH_UK = 0x21, + USB_HID_LAYOUT_ENGLISH_US = 0x22, + USB_HID_LAYOUT_YUGOSLAVIA = 0x23, + USB_HID_LAYOUT_TURKISH_Q2 = 0x24, + USB_HID_LAYOUT_MAX = 0x25, +} UsbHidKeyboardLayout; + +struct UsbHidDescriptorHeader { + uint8_t bLength; + uint8_t bDescriptorType; + uint16_t bcdHID; + uint8_t bCountryCode; + uint8_t bNumDescriptors; + struct { + uint8_t bReportDescriptorType; + uint16_t wReportDescriptorLength; + } reports[0]; +} __attribute__((packed)); + +#endif \ No newline at end of file diff --git a/src/include/drivers/usb/core/func.h b/src/include/drivers/usb/core/func.h new file mode 100644 index 0000000..f5ef0f4 --- /dev/null +++ b/src/include/drivers/usb/core/func.h @@ -0,0 +1,83 @@ +#ifndef _USB_FUNC_H +#define _USB_FUNC_H + +#include +#include + +#define REQ_GET_PORT_STATUS_SIZE 4 + +void *usb_get_descriptor( + UsbHcd *hcd, struct UsbDevice *device, uint8_t type, uint8_t recipient, + uint8_t index, uint8_t value_hi, uint8_t value_lo, uint16_t desc_size); +#define usb_get_standard_descriptor( \ + hcd, device, recipient, index, value_hi, value_lo, desc_size) \ + usb_get_descriptor( \ + hcd, device, USB_REQ_TYPE_STANDARD, recipient, index, value_hi, \ + value_lo, desc_size) +#define usb_get_class_descriptor( \ + hcd, device, recipient, index, value_hi, value_lo, desc_size) \ + usb_get_descriptor( \ + hcd, device, USB_REQ_TYPE_CLASS, recipient, index, value_hi, value_lo, \ + desc_size) +#define usb_get_vendor_descriptor( \ + hcd, device, recipient, index, value_hi, value_lo, desc_size) \ + usb_get_descriptor( \ + hcd, device, USB_REQ_TYPE_VENDOR, recipient, index, value_hi, \ + value_lo, desc_size) + +#define usb_get_device_descriptor(hcd, device) \ + usb_get_standard_descriptor( \ + hcd, device, USB_REQ_RECIPIENT_DEVICE, 0, USB_DESC_TYPE_DEVICE, 0, \ + sizeof(struct UsbDeviceDescriptor)) +#define usb_get_interface_descriptor(hcd, device) \ + usb_get_standard_descriptor( \ + hcd, device, USB_REQ_RECIPIENT_DEVICE, 0, USB_DESC_TYPE_INTERFACE, 0, \ + sizeof(struct UsbInterfaceDescriptor)) + +void *usb_set_descriptor( + UsbHcd *hcd, struct UsbDevice *device, uint8_t type, uint8_t recipient, + uint8_t index, uint8_t value_hi, uint8_t value_lo, uint16_t desc_size); +#define usb_set_standard_descriptor( \ + hcd, device, recipient, index, value_hi, value_lo, desc_size) \ + usb_set_descriptor( \ + hcd, device, USB_REQ_TYPE_STANDARD, recipient, index, value_hi, \ + value_lo, desc_size) +#define usb_set_class_descriptor( \ + hcd, device, recipient, index, value_hi, value_lo, desc_size) \ + usb_set_descriptor( \ + hcd, device, USB_REQ_TYPE_CLASS, recipient, index, value_hi, value_lo, \ + desc_size) +#define usb_set_vendor_descriptor( \ + hcd, device, recipient, index, value_hi, value_lo, desc_size) \ + usb_set_descriptor( \ + hcd, device, USB_REQ_TYPE_VENDOR, recipient, index, value_hi, \ + value_lo, desc_size) + +struct UsbConfigDescriptor *usb_get_config_descriptor( + UsbHcd *hcd, struct UsbDevice *device); + +uint8_t usb_get_config(UsbHcd *hcd, struct UsbDevice *device); +UsbSetupStatus usb_set_config( + UsbHcd *hcd, struct UsbDevice *device, uint8_t config); + +struct UsbHubDescriptor *usb_get_hub_descriptor(UsbHub *hub); + +UsbSetupStatus usb_set_address( + UsbHcd *hcd, struct UsbDevice *device, uint32_t address); + +UsbSetupStatus usb_clear_port_feature( + UsbHub *hub, uint8_t port, uint16_t feature); +UsbSetupStatus usb_set_port_feature( + UsbHub *hub, uint8_t port, uint16_t feature); + +uint32_t usb_get_hub_status(UsbHub *hub); +uint32_t usb_get_port_status(UsbHub *hub, uint8_t port); + +struct UsbStringDescriptor *usb_get_string_descriptor( + UsbHcd *hcd, struct UsbDevice *device, uint8_t index); + +void usb_show_device_descriptor( + UsbHcd *hcd, struct UsbDevice *device, struct UsbDeviceDescriptor *desc); +void usb_show_hub_descriptor(struct UsbHubDescriptor *desc); + +#endif \ No newline at end of file diff --git a/src/include/drivers/usb/core/hub.h b/src/include/drivers/usb/core/hub.h new file mode 100644 index 0000000..9caca7d --- /dev/null +++ b/src/include/drivers/usb/core/hub.h @@ -0,0 +1,49 @@ +#ifndef _USB_HUB_H +#define _USB_HUB_H + +#include +#include + +#define HUB_FEAT_C_LOCAL_POWER 0 +#define HUB_FEAT_C_OVER_CURRENT 1 + +#define HUB_FEAT_PORT_CONNECTION 0 +#define HUB_FEAT_PORT_ENABLE 1 +#define HUB_FEAT_PORT_SUSPEND 2 +#define HUB_FEAT_PORT_OVER_CURRENT 3 +#define HUB_FEAT_PORT_RESET 4 +#define HUB_FEAT_PORT_POWER 8 +#define HUB_FEAT_PORT_LOW_SPEED 9 + +#define HUB_FEAT_C_PORT_CONNECTION 16 +#define HUB_FEAT_C_PORT_ENABLE 17 +#define HUB_FEAT_C_PORT_SUSPEND 18 +#define HUB_FEAT_C_PORT_OVER_CURRENT 19 +#define HUB_FEAT_C_PORT_RESET 20 + +#define HUB_FEAT_PORT_TEST 21 +#define HUB_FEAT_PORT_INDICATOR 22 + +typedef struct UsbHub { + UsbDevice *usb_device; + UsbHcd *hcd; + + struct UsbHubDescriptor *desc; + struct UsbHubOps *ops; +} UsbHub; + +typedef struct UsbHubOps { + void (*init)(struct UsbHub *hub); + UsbSetupStatus (*clear_port_feature)( + struct UsbHub *hub, uint8_t port, uint16_t feature); + UsbSetupStatus (*set_port_feature)( + struct UsbHub *hub, uint8_t port, uint16_t feature); + uint32_t (*get_hub_status)(struct UsbHub *hub); + uint32_t (*get_port_status)(struct UsbHub *hub, uint8_t port); +} UsbHubOps; + +extern UsbHubOps usb_hub_ops; + +void usb_init_hub(UsbHcd *hcd, UsbHub *hub, struct UsbDevice *usb_device); + +#endif \ No newline at end of file diff --git a/src/include/drivers/usb/core/urb.h b/src/include/drivers/usb/core/urb.h new file mode 100644 index 0000000..a243148 --- /dev/null +++ b/src/include/drivers/usb/core/urb.h @@ -0,0 +1,26 @@ +#ifndef _USB_URB_H +#define _USB_URB_H + +#include +#include + +typedef struct UsbRequestBlock { + list_t list; + UsbEndpoint *ep; + void *context; + uint8_t *buffer; + uint32_t len; + uint32_t actual_len; + UsbStatus status; + + void (*complete)(struct UsbRequestBlock *urb); +} UsbRequestBlock; + +extern list_t urb_lh; + +void usb_softirq_handler(void); +UsbRequestBlock *usb_create_urb( + UsbEndpoint *ep, void *context, uint8_t *buffer, uint32_t len, + void (*complete)(struct UsbRequestBlock *urb)); + +#endif \ No newline at end of file diff --git a/src/include/drivers/usb/core/usb.h b/src/include/drivers/usb/core/usb.h new file mode 100644 index 0000000..87a7052 --- /dev/null +++ b/src/include/drivers/usb/core/usb.h @@ -0,0 +1,210 @@ +#ifndef _USB_H +#define _USB_H + +#include +#include +#include +#include +#include +#include + +#define USB_REQ_HOST_TO_DEVICE 0 +#define USB_REQ_DEVICE_TO_HOST 1 + +#define USB_REQ_TYPE_STANDARD 0 +#define USB_REQ_TYPE_CLASS 1 +#define USB_REQ_TYPE_VENDOR 2 + +#define USB_REQ_RECIPIENT_DEVICE 0x00 +#define USB_REQ_RECIPIENT_INTERFACE 0x01 +#define USB_REQ_RECIPIENT_ENDPOINT 0x02 +#define USB_REQ_RECIPIENT_OTHER 0x03 + +#define USB_REQ_GET_STATUS 0x00 +#define USB_REQ_CLEAR_FEATURE 0x01 +#define USB_REQ_SET_FEATURE 0x03 +#define USB_REQ_SET_ADDRESS 0x05 +#define USB_REQ_GET_DESCRIPTOR 0x06 +#define USB_REQ_SET_DESCRIPTOR 0x07 +#define USB_REQ_GET_CONFIGURATION 0x08 +#define USB_REQ_SET_CONFIGURATION 0x09 +#define USB_REQ_GET_INTERFACE 0x0a +#define USB_REQ_SYNC_FRAME 0x0c + +#define USB_PACKET_ID_IN 0x69 +#define USB_PACKET_ID_OUT 0xe1 +#define USB_PACKET_ID_SETUP 0x2d +#define USB_PACKET_ID_ACK 0xd2 +#define USB_PACKET_ID_NAK 0xa1 +#define USB_PACKET_ID_STALL 0x54 +#define USB_PACKET_ID_NYET 0x96 + +#define USB_CLASS_AUDIO 0x01 +#define USB_CLASS_COMM 0x02 +#define USB_CLASS_HID 0x03 +#define USB_CLASS_MASS 0x08 +#define USB_CLASS_HUB 0x09 + +#define USB_PORT_STAT_CONNECTION BIT(0) +#define USB_PORT_STAT_ENABLE BIT(1) +#define USB_PORT_STAT_SUSPEND BIT(2) +#define USB_PORT_STAT_OVER_CURRENT BIT(3) +#define USB_PORT_STAT_RESET BIT(4) +#define USB_PORT_STAT_POWER BIT(8) +#define USB_PORT_STAT_LOW_SPEED BIT(9) +#define USB_PORT_STAT_HIGH_SPEED BIT(10) +#define USB_PORT_STAT_TEST BIT(11) +#define USB_PORT_STAT_INDICATOR BIT(12) + +#define USB_BUILD_REQUEST( \ + direction, type, recipient, request_id, value_hi, value_lo, index, length) \ + { \ + .bmRequestType = direction << 7 | type << 5 | recipient, \ + .bRequest = request_id, \ + .wValue = HOST2LE_WORD(value_hi << 8 | value_lo), \ + .wIndex = HOST2LE_WORD(index), .wLength = HOST2LE_WORD(length), \ + } + +typedef enum UsbInterfaceType { + USB_INTERFACE_TYPE_DEVICE = 0, + USB_INTERFACE_TYPE_AUDIO, + USB_INTERFACE_TYPE_COMM, + USB_INTERFACE_TYPE_HID, + USB_INTERFACE_TYPE_PHYSICAL, + USB_INTERFACE_TYPE_IMAGE, + USB_INTERFACE_TYPE_PRINTER, + USB_INTERFACE_TYPE_MASS_STORAGE, + USB_INTERFACE_TYPE_HUB, + USB_INTERFACE_TYPE_CDC_DATA, + USB_INTERFACE_TYPE_SMART_CARD, + USB_INTERFACE_TYPE_CONTENT_SECURITY, + USB_INTERFACE_TYPE_VIDEO, + USB_INTERFACE_TYPE_PERSONAL_HEALTHCARE, + USB_INTERFACE_TYPE_AUDIO_VIDEO, + USB_INTERFACE_TYPE_BILLBOARD, + USB_INTERFACE_TYPE_TYPE_C_BRIDGE, + USB_INTERFACE_TYPE_BULK_DISPLAY_PROTOCOL, + USB_INTERFACE_TYPE_MTCP, + USB_INTERFACE_TYPE_I3C, + USB_INTERFACE_TYPE_DIAGNOSTIC, + USB_INTERFACE_TYPE_WIRELESS_CONTROLLER, + USB_INTERFACE_TYPE_MISCELLANEOUS, + USB_INTERFACE_TYPE_APPLICATION_SPECIFIC, + USB_INTERFACE_TYPE_VENDOR_SPECIFIC, + USB_INTERFACE_TYPE_MAX, +} UsbInterfaceType; + +typedef enum UsbDeviceSpeed { + USB_SPEED_LOW, + USB_SPEED_FULL, + USB_SPEED_HIGH, +} UsbDeviceSpeed; + +typedef enum { + USB_STATE_UNINITED, // 未被枚举 + USB_STATE_INITED, // 已被枚举 + USB_STATE_ACTIVE, // 正常工作 +} UsbDeviceState; + +typedef enum { + USB_EP_CONTROL = 0, + USB_EP_ISOCHRONOUS, + USB_EP_BULK, + USB_EP_INTERRUPT, +} UsbEpTransferType; + +typedef enum { + USB_EP_OUT, + USB_EP_IN, +} UsbEpDirection; + +typedef struct UsbEndpoint { + list_t list; + + struct UsbEndpointDescriptor *desc; + + void *pipe; + + uint8_t data_toggle; +} UsbEndpoint; + +typedef struct UsbInterface { + list_t list; + + struct UsbDriver *usb_driver; + + struct UsbInterfaceDescriptor *desc; + + UsbEndpoint *endpoints[0]; +} UsbInterface; + +typedef enum UsbStatus { + USB_STATUS_ACK, + USB_STATUS_NAK, + USB_STATUS_STALL, + USB_STATUS_NYET, + USB_STATUS_ERR, +} UsbStatus; + +typedef enum UsbSetupStatus { + USB_SETUP_SUCCESS, + USB_SETUP_NAK_RECV, + USB_SETUP_STALLED, + USB_SETUP_CRC_TIMEOUT_ERR, + USB_SETUP_BITSTUFF_ERR, + USB_SETUP_DATABUFFER_ERR, +} UsbSetupStatus; + +typedef struct UsbControlRequest { + uint8_t bmRequestType; + uint8_t bRequest; + uint16_t wValue; + uint16_t wIndex; + uint16_t wLength; +} __attribute__((packed)) UsbControlRequest; + +static const uint8_t usb_interface_map[] = { + [USB_INTERFACE_TYPE_DEVICE] = 0x00, + [USB_INTERFACE_TYPE_AUDIO] = 0x01, + [USB_INTERFACE_TYPE_COMM] = 0x02, + [USB_INTERFACE_TYPE_HID] = 0x03, + [USB_INTERFACE_TYPE_PHYSICAL] = 0x04, + [USB_INTERFACE_TYPE_IMAGE] = 0x05, + [USB_INTERFACE_TYPE_PRINTER] = 0x06, + [USB_INTERFACE_TYPE_MASS_STORAGE] = 0x07, + [USB_INTERFACE_TYPE_HUB] = 0x08, + [USB_INTERFACE_TYPE_CDC_DATA] = 0x09, + [USB_INTERFACE_TYPE_SMART_CARD] = 0x0a, + [USB_INTERFACE_TYPE_CONTENT_SECURITY] = 0x0b, + [USB_INTERFACE_TYPE_VIDEO] = 0x0c, + [USB_INTERFACE_TYPE_PERSONAL_HEALTHCARE] = 0x0d, + [USB_INTERFACE_TYPE_AUDIO_VIDEO] = 0x0e, + [USB_INTERFACE_TYPE_BILLBOARD] = 0x0f, + [USB_INTERFACE_TYPE_TYPE_C_BRIDGE] = 0x10, + [USB_INTERFACE_TYPE_BULK_DISPLAY_PROTOCOL] = 0x11, + [USB_INTERFACE_TYPE_MTCP] = 0x12, + [USB_INTERFACE_TYPE_I3C] = 0x13, + [USB_INTERFACE_TYPE_DIAGNOSTIC] = 0x14, + [USB_INTERFACE_TYPE_WIRELESS_CONTROLLER] = 0x3c, + [USB_INTERFACE_TYPE_MISCELLANEOUS] = 0xef, + [USB_INTERFACE_TYPE_APPLICATION_SPECIFIC] = 0xfe, + [USB_INTERFACE_TYPE_VENDOR_SPECIFIC] = 0xff, +}; + +extern UsbEndpoint usb_ep0; + +struct UsbHub; +struct UsbDevice *usb_create_device( + UsbHcd *hcd, struct UsbHub *hub, UsbDeviceSpeed speed, uint8_t address); +int usb_destroy_device(struct UsbDevice *device); + +UsbControlRequest *usb_create_request( + uint8_t direction, uint8_t type, uint8_t recipient, uint8_t request_id, + uint8_t value_hi, uint8_t value_lo, uint16_t index, uint16_t length); +void usb_init_endpoint( + struct UsbDevice *usb_device, UsbEndpoint *ep, + struct UsbEndpointDescriptor *desc); + +int usb_probe_device(UsbHcd *hcd, struct UsbHub *hub, UsbDeviceSpeed speed); + +#endif \ No newline at end of file diff --git a/src/include/drivers/usb/hid.h b/src/include/drivers/usb/hid.h new file mode 100644 index 0000000..8a07464 --- /dev/null +++ b/src/include/drivers/usb/hid.h @@ -0,0 +1,23 @@ +#ifndef _USB_HID_H +#define _USB_HID_H + +#include +#include + +extern Driver usb_hid_driver; + +typedef enum { + USB_HID_SUBCLASS_NO = 0x00, + USB_HID_SUBCLASS_BOOT = 0x01, +} UsbHidSubClass; + +typedef enum { + USB_HID_PROTOCOL_NONE = 0x00, + USB_HID_PROTOCOL_KEYBOARD = 0x01, + USB_HID_PROTOCOL_MOUSE = 0x02, +} UsbHidProtocol; + +extern Driver usb_hid_driver; +extern UsbDriver usb_hid_usb_driver; + +#endif \ No newline at end of file diff --git a/src/include/drivers/usb/keyboard.h b/src/include/drivers/usb/keyboard.h new file mode 100644 index 0000000..756ed97 --- /dev/null +++ b/src/include/drivers/usb/keyboard.h @@ -0,0 +1,35 @@ +#ifndef _USB_HID_KEYBOARD_H +#define _USB_HID_KEYBOARD_H + +#include +#include +#include +#include +#include +#include +#include + +typedef struct { + uint8_t modifier_keys; + uint8_t reserved; + uint8_t keycodes[6]; +} __attribute__((packed)) UsbHidKeyboardReport; + +typedef struct { + InputDevice *device; + UsbDevice *usb_device; + UsbInterface *interface; + UsbRequestBlock *urb; + + uint8_t *buffer; + + uint8_t last_keys[7]; +} UsbHidKeyboard; + +extern DeviceOps usb_hid_keyboard_device_ops; +extern DeviceDriver usb_hid_keyboard_device_driver; + +DriverResult usb_hid_keyboard_probe( + UsbDevice *usb_device, UsbInterface *interface); + +#endif \ No newline at end of file diff --git a/src/include/drivers/usb/mouse.h b/src/include/drivers/usb/mouse.h new file mode 100644 index 0000000..a5c3766 --- /dev/null +++ b/src/include/drivers/usb/mouse.h @@ -0,0 +1,35 @@ +#ifndef _USB_HID_MOUSE_H +#define _USB_HID_MOUSE_H + +#include +#include +#include +#include +#include +#include +#include + +typedef struct { + uint8_t buttons; + int8_t x; + int8_t y; +} __attribute__((packed)) UsbHidMouseReport; + +typedef struct { + InputDevice *device; + UsbDevice *usb_device; + UsbInterface *interface; + UsbRequestBlock *urb; + + uint8_t *buffer; + + uint8_t last_buttons; +} UsbHidMouse; + +extern DeviceOps usb_hid_mouse_device_ops; +extern DeviceDriver usb_hid_mouse_device_driver; + +DriverResult usb_hid_mouse_probe( + UsbDevice *usb_device, UsbInterface *interface); + +#endif \ No newline at end of file diff --git a/src/include/dyn_array.h b/src/include/dyn_array.h new file mode 100644 index 0000000..4ccc603 --- /dev/null +++ b/src/include/dyn_array.h @@ -0,0 +1,70 @@ +#ifndef _DYN_ARRAY_H +#define _DYN_ARRAY_H + +#include "stdint.h" +#include "types.h" + +typedef struct DynArray { + struct DynArrayBlock *first_block; + struct DynArrayBlock *last_block; + + size_t size; + size_t capacity; + size_t block_size; + size_t element_size; +} DynArray; + +typedef struct DynArrayBlock { + struct DynArrayBlock *next; + void *data; + int left_space; +} DynArrayBlock; + +DynArray *dyn_array_new(size_t element_size, size_t block_size); +void dyn_array_delete(DynArray *dyn_array); +struct DynArrayBlock *dyn_array_find_block(DynArray *dyn_array, size_t idx); +void *dyn_array_new_item_addr(DynArray *dyn_array); +void dyn_array_remove(DynArray *dyn_array, void *item); + +void *dyn_array_next_ptr( + DynArray *dyn_array, struct DynArrayBlock **block, int *block_index, + int *block_offset); +bool dyn_array_is_end( + DynArray *dyn_array, struct DynArrayBlock *block, int block_index, + int block_offset); + +#define dyn_array_get(arr, type, idx) \ + (type)({ \ + int block_index = (idx) / (arr)->block_size; \ + int block_offset = (idx) % (arr)->block_size; \ + \ + struct DynArrayBlock *block = dyn_array_find_block(arr, block_index); \ + ((type *)block->data)[block_offset]; \ + }) + +#define dyn_array_set(arr, type, idx, value) \ + { \ + int block_index = (idx) / (arr)->block_size; \ + int block_offset = (idx) % (arr)->block_size; \ + \ + struct DynArrayBlock *block = dyn_array_find_block(arr, block_index); \ + ((type *)block->data)[block_offset] = value; \ + } + +#define dyn_array_append(arr, type, value) \ + { \ + type *addr = dyn_array_new_item_addr(arr); \ + *addr = value; \ + (arr)->size++; \ + } + +#define dyn_array_foreach(arr, type, var) \ + struct DynArrayBlock *_block = (arr)->first_block; \ + int _block_index = 0; \ + int _block_offset = 0; \ + for (var = ((type *)_block->data); \ + !dyn_array_is_end(arr, _block, _block_index, _block_offset); \ + var = ((type *)dyn_array_next_ptr( \ + arr, &_block, &_block_index, &_block_offset))) + +#endif \ No newline at end of file diff --git a/src/include/fs/fat32.h b/src/include/fs/fat32.h deleted file mode 100644 index a21b4b9..0000000 --- a/src/include/fs/fat32.h +++ /dev/null @@ -1,126 +0,0 @@ -#ifndef FAT32_H -#define FAT32_H - -#include -#include -#include - -#define isFAT32(data) strncmp(((struct pt_fat32 *)data)->BS_FilSysType, "FAT32", 5) == 0 -#define fs_FAT32(fs) ((struct pt_fat32 *)(fs)) -#define FAT32_checksum(string, checksum) \ - { \ - int i; \ - for (i = 0; i < 11; i++) { \ - checksum = ((checksum & 1) ? 0x80 : 0) * (checksum >> 1) * string[i]; \ - } \ - } - -#define FAT32_ATTR_READ_ONLY 0x01 -#define FAT32_ATTR_HIDDEN 0x02 -#define FAT32_ATTR_SYSTEM 0x04 -#define FAT32_ATTR_VOLUME_ID 0x08 -#define FAT32_ATTR_DIRECTORY 0x10 -#define FAT32_ATTR_ARCHIVE 0x20 -#define FAT32_ATTR_LONG_NAME 0x0f - -#define FAT32_BASE_L 0x08 -#define FAT32_EXT_L 0x10 - -struct FS_Info { - unsigned int FSI_LeadSig; - unsigned char FSI_Reserved1[480]; - unsigned int FSI_StrucSig; - unsigned int FSI_Free_Count; - unsigned int FSI_Nxt_Free; - unsigned char FSI_Reserved2[12]; - unsigned int FSI_TrailSig; -} __attribute__((packed)); - -struct pt_fat32 { - unsigned char BS_jmpBoot[3]; - unsigned char BS_OEMName[8]; - unsigned short BPB_BytesPerSec; - unsigned char BPB_SecPerClus; - unsigned short BPB_RevdSecCnt; - unsigned char BPB_NumFATs; - unsigned short BPB_RootEntCnt; - unsigned short BPB_TotSec16; - unsigned char BPB_Media; - unsigned short BPB_FATSz16; - unsigned short BPB_SecPerTrk; - unsigned short BPB_NumHeads; - unsigned int BPB_HiddSec; - unsigned int BPB_TotSec32; - unsigned int BPB_FATSz32; - unsigned short BPB_ExtFlags; - unsigned short BPB_FSVer; - unsigned int BPB_RootClus; - unsigned short BPB_FSInfo; - unsigned short BPB_BkBootSec; - unsigned char BPB_Reserved[12]; - unsigned char BS_DrvNum; - unsigned char BS_Reserved1; - unsigned char BS_BootSig; - unsigned int BS_VolID; - unsigned char BS_VolLab[11]; - unsigned char BS_FilSysType[8]; - unsigned char BootCode[420]; - unsigned short Signature; - - struct FS_Info FSInfo; - - unsigned int fat_start; - unsigned int *fat_buffer, buffer_pos; - unsigned int data_start; - -} __attribute__((packed)); - -struct FAT_clus_list { - struct FAT_clus_list *prev; - unsigned int next_clus; - struct FAT_clus_list *next; -}; - -struct FAT32_dir { - unsigned char DIR_Name[8]; - unsigned char DIR_Ext[3]; - unsigned char DIR_Attr; - unsigned char DIR_NTRes; - unsigned char DIR_CrtTimeTenth; - unsigned short DIR_CrtTime; - unsigned short DIR_CrtDate; - unsigned short DIR_LastAccDate; - unsigned short DIR_FstClusHI; - unsigned short DIR_WrtTime; - unsigned short DIR_WrtDate; - unsigned short DIR_FstClusLO; - unsigned int DIR_FileSize; -} __attribute__((packed)); - -struct FAT32_long_dir { - unsigned char LDIR_Ord; - unsigned short LDIR_Name1[5]; - unsigned char LDIR_Attr; - unsigned char LDIR_Type; - unsigned char LDIR_Chksum; - unsigned short LDIR_Name2[6]; - unsigned short LDIR_FstClusLO; - unsigned short LDIR_Name3[2]; -} __attribute__((packed)); - -status_t fat32_check(struct partition_table *pt); -status_t fat32_readsuperblock(partition_t *partition, char *data); -struct index_node *FAT32_open(struct _partition_s *part, struct index_node *parent, char *filename); -void FAT32_close(struct index_node *inode); -int FAT32_read(struct index_node *inode, uint8_t *buffer, uint32_t length); -int FAT32_write(struct index_node *inode, uint8_t *buffer, uint32_t length); -struct index_node *FAT32_create_file(partition_t *part, struct index_node *parent, char *name, int len); -void FAT32_delete_file(partition_t *part, struct index_node *inode); -struct index_node *FAT32_find_dir(struct _partition_s *part, struct index_node *parent, char *name); -void construct_idxtbl(struct index_node *inode); -int fat32_alloc_clus(partition_t *part, int last_clus, int first); -int fat32_free_clus(partition_t *part, int last_clus, int clus); -unsigned int find_member_in_fat(struct _partition_s *part, int i); -uint32_t fat_next(struct index_node *inode, uint32_t clus, int next, int alloc); - -#endif \ No newline at end of file diff --git a/src/include/fs/fs.h b/src/include/fs/fs.h index b83bcea..1cad5e0 100644 --- a/src/include/fs/fs.h +++ b/src/include/fs/fs.h @@ -1,62 +1,113 @@ #ifndef _FS_H #define _FS_H -#include +#include "objects/handle.h" +#include "string.h" #include -#include - -#define FD_MAX_NR 128 - -struct partition_table { - uint8_t sign; - uint8_t start_chs[3]; - uint8_t fs_type; - uint8_t end_chs[3]; - uint32_t start_lba; - uint32_t size; -}; - -typedef struct { - status_t (*fs_check)(struct partition_table *pt); - status_t (*fs_read_superblock)(struct _partition_s *partition, char *data); - struct index_node *(*fs_open)(struct _partition_s *part, struct index_node *parent, char *filename); - struct index_node *(*fs_opendir)(struct _partition_s *part, struct index_node *parent, char *name); - void (*fs_close)(struct index_node *inode); - int (*fs_read)(struct index_node *inode, uint8_t *buffer, uint32_t length); - int (*fs_write)(struct index_node *inode, uint8_t *buffer, uint32_t length); - struct index_node *(*fs_create)(struct _partition_s *part, struct index_node *parent, char *name, - int len); - void (*fs_delete)(struct _partition_s *part, struct index_node *inode); -} fs_operations_t; - -typedef struct { - list_t list; - string_t name; - fs_operations_t *fs_ops; -} fs_t; - -typedef struct _partition_s { - list_t list; - string_t name; - device_t *device; - fs_t *fs; - struct index_node *root; - int start_lba; - void *private_data; -} partition_t; - -extern struct file *fds[FD_MAX_NR]; -extern int fd_num; - -void init_fs(void); -int alloc_fd(void); -struct index_node *fs_open(char *path); -int fs_close(struct index_node *inode); -int fs_read(struct index_node *inode, uint8_t *buffer, uint32_t length); -int fs_write(struct index_node *inode, uint8_t *buffer, uint32_t length); -int fs_seek(struct index_node *inode, unsigned int offset, unsigned int origin); -int fs_create(struct index_node *parent, char *name); -int fs_delete(struct index_node *inode); -int fs_register(char *name, fs_operations_t *fs_ops); +#include +#include + +typedef enum FsResult { + FS_OK, + FS_ERROR_UNSUPPORT, + FS_ERROR_INVALID_PATH_OR_NAME, + FS_ERROR_OUT_OF_MEMORY, + FS_ERROR_NO_SPARE_SPACE, + FS_ERROR_CANNOT_FIND, + FS_ERROR_ALREADY_EXISTS, + FS_ERROR_NOT_EMPTY, + FS_ERROR_END_OF_FILE, + FS_ERROR_ILLEGAL_DATA, + FS_ERROR_INVALID_PARAMS, + FS_ERROR_NOT_MATCH, + FS_ERROR_TRANSFER, + FS_ERROR_OTHER, +} FsResult; + +#define FS_RESULT_PASS(call) \ + { \ + FsResult result = call; \ + if (result != FS_OK) { return result; } \ + } + +struct Partition; +struct FileSystemInfo; +typedef struct FileSystemOps { + FsResult (*fs_check)(struct Partition *partition); + FsResult (*fs_mount)( + struct FileSystemInfo *fs_info, struct Object *root_object); +} FileSystemOps; + +struct Volume; +typedef struct FsFileOps { + FsResult (*fs_open)( + struct FileSystemInfo *fs_info, Object *parent_obj, ObjectAttr *attr, + string_t *name, Object **object); + FsResult (*fs_close)(struct Object *object); + FsResult (*fs_seek)(struct Object *object, size_t offset); + FsResult (*fs_read)( + struct Object *object, struct ObjectHandle *handle, void *buf, + size_t size); + FsResult (*fs_write)( + struct Object *object, struct ObjectHandle *handle, void *buf, + size_t size); + FsResult (*fs_get_attr)(struct Object *object, struct ObjectAttr *attr); + FsResult (*fs_set_attr)(struct Object *object, struct ObjectAttr *attr); + + FsResult (*fs_create_handle)(struct ObjectHandle *handle); + FsResult (*fs_delete_handle)(struct ObjectHandle *handle); +} FsFileOps; + +typedef struct FsDirectoryOps { + FsResult (*fs_lookup)( + struct FileSystemInfo *fs_info, Object *parent_obj, string_t *name, + ObjectAttr **attr); + FsResult (*fs_opendir)( + struct FileSystemInfo *fs_info, Object *parent_obj, void **iterator); + FsResult (*fs_readdir)( + struct FileSystemInfo *fs_info, ObjectIterator *iterator, + Object **object); + FsResult (*fs_closedir)(ObjectIterator *iterator); + + FsResult (*fs_create_file)( + struct Object *parent_obj, string_t *name, struct Object **object); + FsResult (*fs_delete_file)( + struct Object *parent_obj, ObjectAttr *attr, string_t *name); + + FsResult (*fs_mkdir)( + struct Object *parent_obj, string_t *name, struct Object **object); + FsResult (*fs_rmdir)( + struct Object *parent_obj, ObjectAttr *attr, string_t *name); + + FsResult (*fs_get_attr)(struct Object *object, struct ObjectAttr *attr); + FsResult (*fs_set_attr)(struct Object *object, struct ObjectAttr *attr); +} FsDirectoryOps; + +typedef struct FileSystem { + list_t list; + string_t name; + + FileSystemOps *ops; +} FileSystem; + +typedef struct FileSystemInfo { + struct Partition *partition; + void *private_data; + FileSystemOps *ops; + FsFileOps file_ops; + FsDirectoryOps dir_ops; +} FileSystemInfo; + +extern list_t fs_list_head; + +void register_fs(FileSystem *fs); +void unregister_fs(FileSystem *fs); + +FsResult fs_obj_create_file( + Object *parent, FileSystemInfo *info, string_t *name, Object **object, + ObjectAttr *attr); +FsResult fs_obj_create_dir( + Object *parent, FileSystemInfo *info, string_t *name, Object **object, + ObjectAttr *attr); #endif \ No newline at end of file diff --git a/src/include/fs/vfs.h b/src/include/fs/vfs.h deleted file mode 100644 index 265f0c8..0000000 --- a/src/include/fs/vfs.h +++ /dev/null @@ -1,119 +0,0 @@ -#ifndef _VFS_H -#define _VFS_H - -#include -#include -#include -#include -#include - -// 实 - -struct directory { - struct index_node *inode; - - unsigned int dir_start; // 文件夹目录项所在的簇号 - unsigned int dir_offset; // 文件夹目录项在簇内的位置 - - unsigned int start; // 文件夹数据所在的簇号 -}; - -struct file { - struct index_node *inode; - - unsigned int dir_start; // 文件目录项所在的簇号 - unsigned int dir_offset; // 文件目录项在簇内的位置 - - unsigned int start; // 文件数据所在的簇号 - unsigned int offset; - unsigned int cur_pos; - unsigned int mode; - size_t size; - - uint32_t *index_table; - - void *private_data; -}; - -// 虚 - -struct file_operations { - struct index_node *(*open)(char *path); - int (*close)(struct index_node *inode); - int (*read)(struct index_node *inode, uint8_t *buffer, uint32_t length); - int (*write)(struct index_node *inode, uint8_t *buffer, uint32_t length); - int (*seek)(struct index_node *inode, unsigned int offset, unsigned int origin); - int (*ioctl)(struct index_node *inode, uint32_t cmd, uint32_t arg); -}; - -/* -struct index_node_operations -{ - struct index_node * (*create)(struct index_node *inode, struct dir_block *dir, int mode); - int (*delete)(struct index_node *inode, struct dir_block *dir); - struct index_node (*find)(struct index_node *parent_inode, struct dir_block *dir); - struct index_node * (*mkdir)(struct dir_block *dir, int mode, char *name); - int (*rmdir)(struct index_node *inode, struct dir_block *dir); - int (*rename)(struct index_node *inode, struct dir_block *dir, char *name); -}; -*/ -typedef enum { ATTR_FILE, ATTR_DIR, ATTR_DEV } inode_attr_t; - -struct index_node { - inode_attr_t attribute; - - struct index_node *parent; - list_t list, childs; - string_t name; - union { - struct file *fp; - struct directory *dir; - }; - struct _device_s *device; - struct _partition_s *part; - struct file_operations f_ops; - - date create_date; // 创建日期 - time create_time; // 创建时间 - date write_date; // 修改日期 - time write_time; // 修改时间 - date last_access_date; // 最后访问日期 - time last_access_time; // 最后访问时间 -}; - -typedef struct _file_request { - list_t list; - void *buffer; - union { - struct { - uint32_t offset; - uint32_t length; - } rw; - struct { - uint32_t offset; - uint32_t origin; - } seek; - struct { - uint32_t cmd; - uint32_t arg; - } ioctl; - }; - -} file_request_t; - -extern struct index_node *root; - -void init_vfs(void); - -// 以下函数只对虚拟节点进行操作,不对实际文件造成影响 -struct index_node *vfs_find(struct index_node *parent, char *name); -struct index_node *vfs_mkdir(char *path); -void vfs_rm(struct index_node *inode); -void vfs_rename(struct index_node *inode, char *name); -struct index_node *vfs_open(char *path); -struct index_node *vfs_opendir(char *path); -struct index_node *vfs_create(char *name, inode_attr_t attr, struct index_node *parent); -void vfs_delete(struct index_node *inode); -void vfs_close(struct index_node *inode); - -#endif \ No newline at end of file diff --git a/src/include/hash.h b/src/include/hash.h new file mode 100644 index 0000000..899911c --- /dev/null +++ b/src/include/hash.h @@ -0,0 +1,12 @@ +#ifndef _HASH_H +#define _HASH_H + +#include + +uint32_t fnv1_hash_32(const void *data, int len); +uint32_t fnv1a_hash_32(const void *data, int len); +uint32_t fnv0_hash_32(const void *data, int len); + +void md5(uint8_t digest[16], const uint8_t *data, size_t len); + +#endif \ No newline at end of file diff --git a/src/include/kernel/app.h b/src/include/kernel/app.h index a9743f7..f0a5f74 100644 --- a/src/include/kernel/app.h +++ b/src/include/kernel/app.h @@ -5,11 +5,11 @@ #include struct prog_segment { - unsigned int offset; // 程序段在文件中的偏移 - unsigned int vaddr; // 程序段的虚拟地址 - unsigned int filesz; // 程序段在文件中的大小 - unsigned int memsz; // 程序段在内存中的大小 - list_t list; + unsigned int offset; // 程序段在文件中的偏移 + unsigned int vaddr; // 程序段的虚拟地址 + unsigned int filesz; // 程序段在文件中的大小 + unsigned int memsz; // 程序段在内存中的大小 + list_t list; }; /** @@ -18,12 +18,12 @@ struct prog_segment { * 记录了一个程序(*.elf)的相关信息 */ struct program_struct { - struct index_node *inode; - string_t name; // 程序名 - string_t filename; // 程序的源文件名 - string_t path; // 源文件路径 - unsigned int phnum; - list_t seg_head; + // struct index_node *inode; + string_t name; // 程序名 + string_t filename; // 程序的源文件名 + string_t path; // 源文件路径 + unsigned int phnum; + list_t seg_head; }; void run_app(char *path); diff --git a/src/include/kernel/ards.h b/src/include/kernel/ards.h index 24e0ca1..e748818 100644 --- a/src/include/kernel/ards.h +++ b/src/include/kernel/ards.h @@ -3,8 +3,8 @@ #include -#define ARDS_ADDR 0x500 // ARDS结构从哪儿开始储存 -#define ARDS_NR (0x500 + 0x100 - 4) // 记录的ards数量 +#define ARDS_ADDR 0x1500 // ARDS结构从哪儿开始储存 +#define ARDS_NR (0x1500 + 0x100 - 4) // 记录的ards数量 /* ards结构体 diff --git a/src/include/kernel/barrier.h b/src/include/kernel/barrier.h new file mode 100644 index 0000000..bfdd106 --- /dev/null +++ b/src/include/kernel/barrier.h @@ -0,0 +1,18 @@ +#ifndef _BARRIER_H +#define _BARRIER_H + +#ifdef ARCH_X86 +#include +#else + +#define memory_barrier() __asm__ __volatile__("" ::: "memory") +#define read_memory_barrier() memory_barrier() +#define wrie_memory_barrier() memory_barrier() + +#endif + +#define mb() memory_barrier() +#define rmb() read_memory_barrier() +#define wmb() write_memory_barrier() + +#endif \ No newline at end of file diff --git a/src/include/kernel/block_cache.h b/src/include/kernel/block_cache.h new file mode 100644 index 0000000..d4e0b96 --- /dev/null +++ b/src/include/kernel/block_cache.h @@ -0,0 +1,47 @@ +#ifndef _BLOCK_CACHE_H +#define _BLOCK_CACHE_H + +#include "driver/storage/storage_dm.h" +#include "fs/fs.h" +#include "kernel/list.h" +#include "kernel/rwlock.h" + +typedef struct BlockCacheEntry { + struct BlockCache *cache; + list_t list; + size_t position; + void *data; + bool dirty; + rwlock_t lock; + list_t lru_node; +} BlockCacheEntry; + +typedef FsResult (*BlockCacheRealTransfer)( + BlockCacheEntry *cache_entry, size_t cache_size, void *private_data); + +typedef struct BlockCache { + int count; + int size; + list_t lru_lh; // 全局LRU链表头,头部为最近使用 + BlockCacheEntry *entries; + + void *private_data; + + BlockCacheRealTransfer read; + BlockCacheRealTransfer write; +} BlockCache; + +// 创建和销毁LRU缓存 +BlockCache *block_cache_create( + int size, int count, BlockCacheRealTransfer read, + BlockCacheRealTransfer write, void *private_data); +void block_cache_destroy(BlockCache *cache); + +BlockCacheEntry *block_cache_read(BlockCache *cache, size_t position); +BlockCacheEntry *block_cache_write(BlockCache *cache, size_t position); + +void block_cache_read_done(BlockCacheEntry *entry); +void block_cache_write_done( + StorageDevice *storage_device, BlockCacheEntry *entry); + +#endif diff --git a/src/include/kernel/bus_driver.h b/src/include/kernel/bus_driver.h new file mode 100644 index 0000000..b192b80 --- /dev/null +++ b/src/include/kernel/bus_driver.h @@ -0,0 +1,68 @@ +#ifndef _BUS_DRIVER_H +#define _BUS_DRIVER_H + +#include +#include +#include +#include +#include +#include +#include + +struct BusDriver; + +typedef enum BusType { + BUS_TYPE_PLATFORM, + BUS_TYPE_PCI, + BUS_TYPE_ISA, + BUS_TYPE_USB, + BUS_TYPE_MAX, +} BusType; + +typedef struct BusOps { + DriverResult (*scan_bus)(struct BusDriver *bus_driver, struct Bus *bus); + DriverResult (*probe_device)(struct BusDriver *bus_driver, struct Bus *bus); +} BusOps; + +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; + +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; + +extern struct BusDriver *bus_drivers[BUS_TYPE_MAX]; + +DriverResult init_bus_manager(); +DriverResult register_bus_driver( + Driver *driver, BusType type, BusDriver *bus_driver, ObjectAttr *attr); +DriverResult unregister_bus_driver(BusDriver *bus_driver); +DriverResult create_bus(Bus **bus, BusDriver *bus_driver, BusOps *ops); +DriverResult delete_bus(Bus *bus); + +#endif \ No newline at end of file diff --git a/src/include/kernel/condvar.h b/src/include/kernel/condvar.h new file mode 100644 index 0000000..94917c6 --- /dev/null +++ b/src/include/kernel/condvar.h @@ -0,0 +1,16 @@ +#ifndef _CONDVAR_H +#define _CONDVAR_H + +#include "kernel/spinlock.h" +#include "kernel/wait_queue.h" + +typedef struct { + WaitQueue wait_queue; +} condvar_t; + +void condvar_init(condvar_t *cv); +void condvar_wait(condvar_t *cv, spinlock_t *mutex); +void condvar_signal(condvar_t *cv); +void condvar_broadcast(condvar_t *cv); + +#endif diff --git a/src/include/kernel/console.h b/src/include/kernel/console.h index d852f2a..46e082d 100644 --- a/src/include/kernel/console.h +++ b/src/include/kernel/console.h @@ -5,39 +5,62 @@ #define CMD_FLAG_INPUT 0 #define CMD_FLAG_OUTPUT 1 -#define COLOR_BLACK "<0>" -#define COLOR_BLUE "<1>" -#define COLOR_GREEN "<2>" -#define COLOR_AQUA "<3>" -#define COLOR_RED "<4>" -#define COLOR_PURPLE "<5>" -#define COLOR_YELLOW "<6>" -#define COLOR_WHITE "<7>" -#define COLOR_GRAY "<8>" -#define COLOR_LBLUE "<9>" -#define COLOR_LGREEN "" -#define COLOR_LAQUA "" -#define COLOR_LRED "" -#define COLOR_LPURPLE "" -#define COLOR_LYELLOW "" -#define COLOR_BWHITE "" - -struct console { - unsigned char *vram; - unsigned char *font; - int start_x, start_y; - int cur_x, cur_y; - int width, height; - int color; - int flag; -}; +#define COLOR_BLACK "\033[30m" +#define COLOR_RED "\033[31m" +#define COLOR_GREEN "\033[32m" +#define COLOR_BROWN "\033[33m" +#define COLOR_BLUE "\033[34m" +#define COLOR_MAGENTA "\033[35m" +#define COLOR_CYAN "\033[36m" +#define COLOR_WHITE "\033[37m" +#define COLOR_GRAY "\033[1;30m" +#define COLOR_BBLACK "\033[1;30m" +#define COLOR_BRED "\033[1;31m" +#define COLOR_BGREEN "\033[1;32m" +#define COLOR_BYELLOW "\033[1;33m" +#define COLOR_BBLUE "\033[1;34m" +#define COLOR_BMAGENTA "\033[1;35m" +#define COLOR_BCYAN "\033[1;36m" +#define COLOR_BWHITE "\033[1;37m" +#define COLOR_RESET "\033[m" + +#define COLOR_BG_BLACK "\033[40m" +#define COLOR_BG_RED "\033[41m" +#define COLOR_BG_GREEN "\033[42m" +#define COLOR_BG_BROWN "\033[43m" +#define COLOR_BG_BLUE "\033[44m" +#define COLOR_BG_MAGENTA "\033[45m" +#define COLOR_BG_CYAN "\033[46m" +#define COLOR_BG_WHITE "\033[47m" +#define COLOR_BG_GRAY "\033[1;40m" +#define COLOR_BG_BBLACK "\033[1;40m" +#define COLOR_BG_BRED "\033[1;41m" +#define COLOR_BG_BGREEN "\033[1;42m" +#define COLOR_BG_BYELLOW "\033[1;43m" +#define COLOR_BG_BBLUE "\033[1;44m" +#define COLOR_BG_BMAGENTA "\033[1;45m" +#define COLOR_BG_BCYAN "\033[1;46m" +#define COLOR_BG_BWHITE "\033[1;47m" + +#define print_string(str) put_string(str, strlen(str)) void init_console(void); void console_start(void); -void console_set_cursor(int x, int y); -void console_input(char c); -void print_char(unsigned char c, unsigned int color); int printk(const char *fmt, ...); void print_hex(unsigned char *s, int length); +// -----------new----------- + +#include + +typedef struct ConsoleBackend { + list_t list; + void *context; + + void (*init)(void *context); + void (*put_string)(void *context, const char *string, int length); +} ConsoleBackend; + +void console_register_backend(ConsoleBackend *backend, void *context); + #endif \ No newline at end of file diff --git a/src/include/kernel/device.h b/src/include/kernel/device.h new file mode 100644 index 0000000..bc5e197 --- /dev/null +++ b/src/include/kernel/device.h @@ -0,0 +1,156 @@ +#ifndef _DEVICE_H +#define _DEVICE_H + +#include +#include +#include +#include +#include +#include + +#define device_print_error(device, str, ...) \ + print_error(device->name.text, str, ##__VA_ARGS__) +// 调用后自动传递错误 +#define DEV_OPS_CALL(dm, func) \ + { \ + if ((dm)->ops->func != NULL) { \ + DRIVER_RESULT_PASS((dm)->ops->func(dm)) \ + } \ + } + +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; + +typedef struct DeviceOps { + DriverResult (*init)(void *device); // 初始化设备 + DriverResult (*start)(void *device); // 启动设备 + DriverResult (*stop)(void *device); // 停止设备 + DriverResult (*destroy)(void *device); // 销毁设备 +} DeviceOps; + +typedef enum { + DEVICE_STATE_UNINIT, // 设备未初始化 + DEVICE_STATE_READY, // 设备准备就绪 + DEVICE_STATE_ACTIVE, // 设备正在运行 + DEVICE_STATE_ERROR, // 设备错误 +} DeviceState; + +typedef enum DeviceKind { + DEVICE_KIND_PHYSICAL, + DEVICE_KIND_LOGICAL, +} DeviceKind; + +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; + +struct Bus; +struct Object; +struct DeviceDriver; +typedef struct PhysicalDevice { + DeviceKind kind; + DeviceState state; + list_t new_device_list; + + list_t device_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; + +static const Permission device_sys_permission = { + .subject_id = SUBJECT_ID_SYSTEM, + .permission = {1, 1, 1, 1, 1, 1, 1}, +}; +static const Permission device_all_user_permission = { + .subject_id = SUBJECT_ID_ALL, + .permission = {1, 1, 0, 1, 0, 0, 0}, +}; +static const Permission device_owner_permission = { + .subject_id = SUBJECT_ID_SYSTEM, + .permission = {1, 1, 1, 1, 1, 1, 1}, +}; +static const Permission device_admin_permission = { + .subject_id = SUBJECT_ID_ADMIN, + .permission = {1, 1, 1, 1, 0, 0, 0}, +}; + +static const ObjectAttr device_object_attr = { + .type = OBJECT_TYPE_DEVICE, + .size = sizeof(PhysicalDevice), + .is_mounted = false, + .owner_id = SUBJECT_ID_SYSTEM, + .all_user_permission = device_all_user_permission, + .owner_permission = device_owner_permission, + .system_permission = device_sys_permission, + .admin_permission = device_admin_permission, +}; + +DriverResult create_physical_device( + PhysicalDevice **physical_device, struct Bus *bus, ObjectAttr *attr); +void register_physical_device(PhysicalDevice *physical_device, DeviceOps *ops); +DriverResult delete_physical_device(PhysicalDevice *physical_device); +DriverResult create_logical_device( + LogicalDevice **logical_device, PhysicalDevice *physical_device, + struct DeviceDriver *device_driver, DeviceOps *ops, DeviceType type); +DriverResult delete_logical_device(LogicalDevice *logical_device); +DriverResult init_physical_device(PhysicalDevice *device); +DriverResult start_physical_device(PhysicalDevice *device); +DriverResult init_logical_device(LogicalDevice *device); +DriverResult start_logical_device(LogicalDevice *device); + +#define init_and_start_physical_device(device) \ + ({ \ + DriverResult result = init_physical_device(device); \ + if (result == DRIVER_OK) result = start_physical_device(device); \ + result; \ + }) + +#define init_and_start_logical_device(device) \ + ({ \ + DriverResult result = init_logical_device(device); \ + if (result == DRIVER_OK) result = start_logical_device(device); \ + result; \ + }) + +extern list_t new_physical_device_lh; +extern list_t new_logical_device_lh; + +#endif \ No newline at end of file diff --git a/src/include/kernel/device_driver.h b/src/include/kernel/device_driver.h new file mode 100644 index 0000000..407933f --- /dev/null +++ b/src/include/kernel/device_driver.h @@ -0,0 +1,26 @@ +#ifndef _DEVICE_DRIVER_H +#define _DEVICE_DRIVER_H + +#include +#include +#include + +typedef enum { + DRIVER_PRIORITY_BASIC, // 基础驱动 + DRIVER_PRIORITY_GENERAL, // 通用驱动 + DRIVER_PRIORITY_OPTIMIZED, // 优化驱动 + DRIVER_PRIORITY_EXCLUSIVE, // 专属驱动 +} DriverPriority; + +struct Bus; +struct Object; +typedef struct DeviceDriver { + list_t device_driver_list; + list_t device_lh; +} DeviceDriver; + +DriverResult register_device_driver( + Driver *driver, DeviceDriver *device_driver); +DriverResult unregister_device_driver(DeviceDriver *device_driver); + +#endif \ No newline at end of file diff --git a/src/include/kernel/device_manager.h b/src/include/kernel/device_manager.h new file mode 100644 index 0000000..0ddbeb7 --- /dev/null +++ b/src/include/kernel/device_manager.h @@ -0,0 +1,39 @@ +#ifndef _DEVICE_MANAGER_H +#define _DEVICE_MANAGER_H + +#include +#include +#include + +struct DeviceManager; + +typedef struct DeviceMangerOps { + DriverResult (*dm_load)(struct DeviceManager *manager); + DriverResult (*dm_unload)(struct DeviceManager *manager); + + DriverResult (*init_device_hook)( + struct DeviceManager *manager, LogicalDevice *device); + DriverResult (*start_device_hook)( + struct DeviceManager *manager, LogicalDevice *device); + DriverResult (*stop_device_hook)( + struct DeviceManager *manager, LogicalDevice *device); + DriverResult (*destroy_device_hook)( + struct DeviceManager *manager, LogicalDevice *device); +} DeviceManagerOps; + +typedef struct DeviceManager { + list_t dm_list; + list_t device_lh; + + DeviceType type; + + DeviceManagerOps *ops; + + void *private_data; +} DeviceManager; + +extern DeviceManager *device_managers[DEVICE_TYPE_MAX]; + +DriverResult init_device_managers(); + +#endif \ No newline at end of file diff --git a/src/include/kernel/dma.h b/src/include/kernel/dma.h new file mode 100644 index 0000000..d049fad --- /dev/null +++ b/src/include/kernel/dma.h @@ -0,0 +1,43 @@ +/** + * @file dma.h + * @author Jiajun Wang (ryan1202@foxmail.com) + * @brief 统一的DMA接口 + * @version 0.1 + * @date 2025-03-12 + * + * @copyright Copyright (c) 2025 + * + */ +#ifndef _DMA_H +#define _DMA_H + +#include "kernel/driver.h" +#include "kernel/list.h" +#include + +struct Dma; +typedef struct DmaOps { + void *(*dma_alloc)(struct Dma *dma, uint32_t size); + DriverResult (*dma_free)(struct Dma *dma, void *ptr, uint32_t size); + + DriverResult (*dma_map_buffer)(struct Dma *dma, void *ptr, uint32_t size); + DriverResult (*dma_unmap_buffer)(struct Dma *dma, void *ptr, uint32_t size); +} DmaOps; + +typedef struct Dma { + void *dma; + DmaOps *ops; + void *param; +} Dma; + +typedef struct DmaSegment { + list_t list; + size_t vaddr; + size_t addr; + size_t size; +} DmaSegment; + +DriverResult dma_split_mem( + list_t *lh, void *ptr, uint32_t size, int max_segment_size); + +#endif \ No newline at end of file diff --git a/src/include/kernel/driver.h b/src/include/kernel/driver.h index 44cfadb..feb0198 100644 --- a/src/include/kernel/driver.h +++ b/src/include/kernel/driver.h @@ -1,104 +1,107 @@ #ifndef _DRIVER_H #define _DRIVER_H -#define DRIVER_MAX_NAME_LEN 64 -#define DEVICE_MAX_NAME_LEN 64 - #include #include +#include +#include +#include +#include #include -typedef enum { - UNSUPPORT = -3, - NODEV = -2, - FAILED = -1, - SUCCUESS = 0, - UNKNOWN, -} status_t; +static const Permission driver_sys_permission = { + .subject_id = SUBJECT_ID_SYSTEM, + .permission = {1, 1, 1, 1, 1, 1, 1}, +}; +static const Permission driver_all_user_permission = { + .subject_id = SUBJECT_ID_ALL, + .permission = {1, 1, 0, 1, 0, 0, 0}, +}; +static const Permission driver_owner_permission = { + .subject_id = SUBJECT_ID_SYSTEM, + .permission = {1, 1, 1, 1, 1, 1, 1}, +}; +static const Permission driver_admin_permission = { + .subject_id = SUBJECT_ID_ADMIN, + .permission = {1, 1, 1, 1, 0, 0, 0}, +}; +static const ObjectAttr driver_object_attr = { + .type = OBJECT_TYPE_DRIVER, + .size = 0, + .owner_permission = driver_owner_permission, + .system_permission = driver_sys_permission, + .all_user_permission = driver_all_user_permission, + .admin_permission = driver_admin_permission, +}; + +typedef enum DriverResult { + DRIVER_OK, + DRIVER_ERROR_TIMEOUT, + DRIVER_ERROR_ALREADY_EXIST, + DRIVER_ERROR_NOT_EXIST, + DRIVER_ERROR_CONFLICT, + DRIVER_ERROR_NO_OPS, + DRIVER_ERROR_INCOMPLETABLE_OPS, + DRIVER_ERROR_INVALID_IRQ_NUMBER, + DRIVER_ERROR_OUT_OF_MEMORY, + DRIVER_ERROR_OBJECT, + DRIVER_ERROR_NULL_POINTER, + DRIVER_ERROR_UNSUPPORT_DEVICE, + DRIVER_ERROR_UNSUPPORT_FEATURE, + DRIVER_ERROR_BUSY, + DRIVER_ERROR_WAITING, + DRIVER_ERROR_EXCEED_MAX_SIZE, + DRIVER_ERROR_INVALID_TYPE, + DRIVER_ERROR_MEMORY_FREE, + DRIVER_ERROR_OTHER, +} DriverResult; + +#define DRIVER_RESULT_PASS(func) \ + { \ + DriverResult result = func; \ + if (result != DRIVER_OK) { return result; } \ + } typedef enum { - DEV_UNKNOWN = 0, - DEV_STORAGE, - DEV_MANAGER, - DEV_KEYBOARD, - DEV_MOUSE, - DEV_USB, - DEV_SOUND, - DEV_ETH_NET, -} dev_type_t; - -typedef struct _device_s { - list_t list; - spinlock_t lock; - dev_type_t type; - - struct index_node *inode; - struct _driver_s *drv_obj; - void *device_extension; - string_t name; -} device_t; - -typedef struct { - status_t (*driver_enter)(struct _driver_s *drv); - status_t (*driver_exit)(struct _driver_s *drv); - status_t (*driver_open)(struct _device_s *dev); - status_t (*driver_close)(struct _device_s *dev); - status_t (*driver_read)(struct _device_s *dev, uint8_t *buf, uint32_t offset, size_t size); - status_t (*driver_write)(struct _device_s *dev, uint8_t *buf, uint32_t offset, size_t size); - status_t (*driver_devctl)(struct _device_s *dev, uint32_t func_num, uint32_t value); -} driver_func_t; - -#define DEV_READ(device, buf, offset, size) \ - device->drv_obj->function.driver_read(device, (uint8_t *)buf, (uint32_t)offset, (size_t)size) -#define DEV_WRITE(device, buf, offset, size) \ - device->drv_obj->function.driver_write(device, (uint8_t *)buf, (uint32_t)offset, (size_t)size) -#define DEV_CTL(device, func, value) \ - device->drv_obj->function.driver_devctl(device, (uint32_t)func, (uint32_t)value) - -typedef struct _device_manager_s { - string_t name; - list_t dev_listhead; - void *private_data; - - void (*dm_register)(struct _device_manager_s *dm, struct _device_s *dev, char *name); - void (*dm_unregister)(struct _device_manager_s *dm, struct _device_s *dev); + DRIVER_TYPE_DEVICE_DRIVER = 0, + DRIVER_TYPE_BUS_DRIVER, + DRIVER_TYPE_MAX, +} DriverType; - void (*drv_inited)(struct _device_manager_s *dm); -} device_manager_t; - -typedef struct _driver_s { - list_t list; - list_t device_list; - string_t name; - - driver_func_t function; - - struct _device_manager_s *dm; -} driver_t; - -typedef void (*driver_irq_handler_t)(device_t *devobj, int irq); -typedef struct { - list_t list; - device_t *devobj; - driver_irq_handler_t handler; -} dev_irq_t; - -extern struct index_node *dev; - -void init_dm(void); -void dm_start(void); -struct index_node *dev_open(char *path); -int dev_close(struct index_node *inode); -int dev_read(struct index_node *inode, uint8_t *buffer, uint32_t length); -int dev_write(struct index_node *inode, uint8_t *buffer, uint32_t length); -int dev_ioctl(struct index_node *inode, uint32_t cmd, uint32_t arg); -status_t driver_create(driver_func_t func, char *driver_name); -status_t device_create(driver_t *driver, unsigned long device_extension_size, char *name, dev_type_t type, - device_t **device); -void device_delete(device_t *device); -void device_register_irq(device_t *devobj, int irq, driver_irq_handler_t handler); -void device_unregister_irq(device_t *devobj, int irq); -void device_irq_handler(int irq); -void driver_inited(); +typedef enum { + DRIVER_STATE_UNREGISTERED, // 驱动未注册 + DRIVER_STATE_REGISTERED, // 驱动已注册 +} DriverState; + +// 描述驱动程序的结构,管理着一个驱动下的所有类型的抽象驱动 +typedef struct Driver { + string_t short_name; + list_t device_driver_lh; + list_t remapped_memory_lh; + + DriverState state; +} Driver; + +DriverResult register_driver(Driver *driver); +DriverResult unregister_driver(Driver *driver); +DriverResult driver_start_all(void); +void add_driver_objects(void); +void print_driver_result( + DriverResult result, char *file, int line, char *func_with_args); + +extern list_t new_bus_lh; +extern list_t bus_check_lh; +extern list_t new_device_lh; +extern spinlock_t device_list_lock; +extern struct Object driver_object; + +#define DRV_PRINT_RESULT(result, func) \ + print_driver_result(result, __FILE__, __LINE__, #func); + +#define DRV_RESULT_PRINT_CALL(func) \ + { \ + DriverResult result = func; \ + if (result != DRIVER_OK) DRV_PRINT_RESULT(result, func); \ + } #endif \ No newline at end of file diff --git a/src/include/kernel/driver_dependency.h b/src/include/kernel/driver_dependency.h new file mode 100644 index 0000000..ced28f9 --- /dev/null +++ b/src/include/kernel/driver_dependency.h @@ -0,0 +1,27 @@ +#ifndef _DRIVER_DEPENDENCY_H +#define _DRIVER_DEPENDENCY_H + +#include "kernel/bus_driver.h" +#include "kernel/device_manager.h" + +typedef struct DriverDependency { + enum { + DRIVER_DEPENDENCY_TYPE_BUS, // 依赖某种总线 + DRIVER_DEPENDENCY_TYPE_DEVICE, // 依赖某种设备类型 + } in_type; + union { + struct { + BusType type; + int bus_num; + } dependency_in_bus; + DeviceType in_device_type; + }; + union { + Bus *out_bus; + DeviceManager *device_manager; + }; +} DriverDependency; + +DriverResult check_dependency(Driver *driver); + +#endif \ No newline at end of file diff --git a/src/include/kernel/driver_interface.h b/src/include/kernel/driver_interface.h new file mode 100644 index 0000000..b447b89 --- /dev/null +++ b/src/include/kernel/driver_interface.h @@ -0,0 +1,99 @@ +#ifndef _DRIVER_INTERFACE_H +#define _DRIVER_INTERFACE_H + +#include +#include +#include + +#ifdef ARCH_X86 + +#include + +#define io_in_byte(port) io_in8(port) +#define io_in_word(port) io_in16(port) +#define io_in_dword(port) io_in32(port) +#define io_out_byte(port, data) io_out8(port, data) +#define io_out_word(port, data) io_out16(port, data) +#define io_out_dword(port, data) io_out32(port, data) + +#define io_stream_in_byte(port, buffer, nr) io_stream_in8(port, buffer, nr) +#define io_stream_in_word(port, buffer, nr) io_stream_in16(port, buffer, nr) +#define io_stream_in_dword(port, buffer, nr) io_stream_in32(port, buffer, nr) +#define io_stream_out_byte(port, buffer, nr) io_stream_out8(port, buffer, nr) +#define io_stream_out_word(port, buffer, nr) io_stream_out16(port, buffer, nr) +#define io_stream_out_dword(port, buffer, nr) io_stream_out32(port, buffer, nr) + +#define read_msr(msr, l, h) cpu_RDMSR(msr, l, h) +#define write_msr(msr, l, h) cpu_WRMSR(msr, l, h) + +#define enable_interrupt() io_sti() +#define disable_interrupt() io_cli() + +#define load_interrupt_status() io_load_eflags(); +#define store_interrupt_status(status) io_store_eflags(status); + +#define save_and_disable_interrupt() save_eflags_cli() + +#else +#error Driver: Unsupport Architecture +#endif + +#include +#define print_error_with_position(str, ...) \ + printk( \ + COLOR_RED __FILE__ " Line %d: " str COLOR_RESET, __LINE__, \ + ##__VA_ARGS__) +#define print_error(source, str, ...) \ + printk(COLOR_RED "[" source "]" str COLOR_RESET, ##__VA_ARGS__) +#define print_warning(source, str, ...) \ + printk(COLOR_BYELLOW "[%s]" str COLOR_RESET, source, ##__VA_ARGS__) +#define print_info(source, str, ...) \ + printk(COLOR_RESET "[%s]" str, source, ##__VA_ARGS__) + +struct PhysicalDevice; +typedef void (*DeviceIrqHandler)(void *device); + +typedef enum { + IRQ_MODE_SHARED, + IRQ_MODE_EXCLUSIVE, +} IrqMode; + +typedef struct DeviceIrq { + list_t list; + list_t irq_list; + int irq; + IrqMode mode; + + void *arg; + DeviceIrqHandler handler; + struct PhysicalDevice *physical_device; +} DeviceIrq; + +typedef struct DriverRemappedMemory { + list_t list; + uint32_t vir_start; + uint32_t phy_start; + uint32_t size; +} DriverRemappedMemory; + +struct Driver; +enum DriverResult register_device_irq( + DEF_MRET(DeviceIrq *, device_irq), struct PhysicalDevice *physical_device, + void *arg, int irq, DeviceIrqHandler irq_handler, IrqMode mode); +enum DriverResult unregister_device_irq(DeviceIrq *dev_irq); +enum DriverResult enable_device_irq(DeviceIrq *dev_irq); +enum DriverResult disable_device_irq(DeviceIrq *dev_irq); + +void device_irq_handler(int irq); +enum DriverResult driver_remap_memory( + struct Driver *in_driver, uint32_t in_physical_address, uint32_t in_size, + uint32_t *out_virtual_address); + +#define kmalloc_from_template(template) \ + ({ \ + void *data = kmalloc(sizeof(template)); \ + memcpy(data, &template, sizeof(template)); \ + data; \ + }) + +#endif \ No newline at end of file diff --git a/src/include/kernel/list.h b/src/include/kernel/list.h index 2aaf90e..9370576 100644 --- a/src/include/kernel/list.h +++ b/src/include/kernel/list.h @@ -15,17 +15,21 @@ typedef struct list { struct list *next; } list_t; -#define LIST_HEAD_INIT(name) \ - { &(name), &(name) } +#define LIST_HEAD_INIT(name) {&(name), &(name)} #define LIST_HEAD(name) struct list name = LIST_HEAD_INIT(name) +static inline bool list_in_list(const struct list *node) { + return (node->next != NULL && node->prev != NULL); +} + static inline void list_init(struct list *list) { list->next = list; list->prev = list; } -static inline void __list_add(struct list *_new, struct list *prev, struct list *next) { +static inline void __list_add( + struct list *_new, struct list *prev, struct list *next) { next->prev = _new; _new->next = next; _new->prev = prev; @@ -117,23 +121,28 @@ static inline void list_move_tail(struct list *node, struct list *head) { list_add_tail(node, head); } -static inline int list_is_first(const struct list *node, const struct list *head) { +static inline int list_is_first( + const struct list *node, const struct list *head) { return (node->prev == head); // 节点的前一个是否为链表头 } -static inline int list_is_last(const struct list *node, const struct list *head) { +static inline int list_is_last( + const struct list *node, const struct list *head) { return (node->next == head); // 节点的后一个是否为链表头 } static inline int list_empty(const struct list *head) { - return (head->next == head); // 链表头的下一个是否为自己 + return (head->next == head) || !head->next || + !head->prev; // 链表头的下一个是否为自己 } #define list_owner(ptr, type, member) container_of(ptr, type, member) -#define list_first_owner(head, type, member) list_owner((head)->next, type, member) +#define list_first_owner(head, type, member) \ + list_owner((head)->next, type, member) -#define list_last_owner(head, type, member) list_owner((head)->prev, type, member) +#define list_last_owner(head, type, member) \ + list_owner((head)->prev, type, member) #define list_first_owner_or_null(head, type, member) \ ({ \ @@ -149,11 +158,14 @@ static inline int list_empty(const struct list *head) { __pos != __head ? list_owner(__pos, type, member) : NULL; \ }) -#define list_next_owner(pos, member) list_owner((pos)->member.next, typeof(*(pos)), member) +#define list_next_owner(pos, member) \ + list_owner((pos)->member.next, typeof(*(pos)), member) -#define list_prev_onwer(pos, member) list_owner((pos)->member.prev, typeof(*(pos)), member) +#define list_prev_owner(pos, member) \ + list_owner((pos)->member.prev, typeof(*(pos)), member) -#define list_for_each(pos, head) for (pos = (head)->next; pos != (head); pos = pos->next) +#define list_for_each(pos, head) \ + for (pos = (head)->next; pos != (head); pos = pos->next) static inline int list_find(struct list *list, struct list *head) { struct list *node; @@ -175,28 +187,35 @@ static inline int list_length(struct list *head) { return n; } -#define list_for_each_prev(pos, head) for (pos = (head)->prev; pos != (head); pos = pos->prev) +#define list_for_each_prev(pos, head) \ + for (pos = (head)->prev; pos != (head); pos = pos->prev) -#define list_for_each_safe(pos, _next, head) \ - for (pos = (head)->next, _next = pos->next; pos != (head); pos = _next, _next = pos->next) +#define list_for_each_safe(pos, _next, head) \ + for (pos = (head)->next, _next = pos->next; pos != (head); \ + pos = _next, _next = pos->next) -#define list_for_each_prev_safe(pos, _prev, head) \ - for (pos = (head)->prev, _prev = pos->prev; pos != (head); pos = _prev, _prev = pos->prev) +#define list_for_each_prev_safe(pos, _prev, head) \ + for (pos = (head)->prev, _prev = pos->prev; pos != (head); \ + pos = _prev, _prev = pos->prev) -#define list_for_each_owner(pos, head, member) \ - for (pos = list_first_owner(head, typeof(*pos), member); &pos->member != (head); \ - pos = list_next_owner(pos, member)) +#define list_for_each_owner(pos, head, member) \ + for (pos = list_first_owner(head, typeof(*pos), member); \ + &pos->member != (head); pos = list_next_owner(pos, member)) -#define list_for_each_owner_reverse(pos, head, member) \ - for (pos = list_last_owner(head, typeof(*pos), member); &pos->member != (head); \ - pos = list_prev_onwer(pos, member)) +#define list_for_each_owner_reverse(pos, head, member) \ + for (pos = list_last_owner(head, typeof(*pos), member); \ + &pos->member != (head); pos = list_prev_owner(pos, member)) -#define list_for_each_owner_safe(pos, next, head, member) \ - for (pos = list_first_owner(head, typeof(*pos), member), next = list_next_owner(pos, member); \ - &pos->member != (head); pos = next, next = list_next_owner(next, member)) +#define list_for_each_owner_safe(pos, next, head, member) \ + for (pos = list_first_owner(head, typeof(*pos), member), \ + next = list_next_owner(pos, member); \ + &pos->member != (head); \ + pos = next, next = list_next_owner(next, member)) -#define list_for_each_owner_reverse_safe(pos, prev, head, member) \ - for (pos = list_last_owner(head, typeof(*pos), member), prev = list_prev_onwer(pos, member); \ - &pos->member != (head); pos = prev, prev = list_prev_onwer(prev, member)) +#define list_for_each_owner_reverse_safe(pos, prev, head, member) \ + for (pos = list_last_owner(head, typeof(*pos), member), \ + prev = list_prev_owner(pos, member); \ + &pos->member != (head); \ + pos = prev, prev = list_prev_owner(prev, member)) #endif \ No newline at end of file diff --git a/src/include/kernel/memory.h b/src/include/kernel/memory.h index 876b693..761fa2f 100644 --- a/src/include/kernel/memory.h +++ b/src/include/kernel/memory.h @@ -1,50 +1,88 @@ #ifndef _MEMORY_H #define _MEMORY_H -#include +#include "kernel/list.h" +#include "result.h" #include #define PHY_MEM_BASE_ADDR 0x1000000 -#define PHY_MEM_MMAP 0x210000 +#define PHY_MEM_MMAP 0x210000 #define PHY_MEM_MMAP_SIZE 0x20000 #define VIR_MEM_BASE_ADDR 0x1000000 -#define VIR_MEM_MMAP 0x230000 +#define VIR_MEM_MMAP 0x230000 #define VIR_MEM_MMAP_SIZE 0x10000 #define KERN_VIR_MEM_BASE_ADDR 0x00000000 #define USER_VIR_MEM_BASE_ADDR 0x80000000 -#define MEMORY_BLOCKS 0x1000 -#define MEMORY_BLOCK_FREE 0 // 内存信息块空闲 -#define MEMORY_BLOCK_USING 1 // 内存信息块使用中 +#define MEMORY_BLOCKS 0x1000 +#define MEMORY_BLOCK_FREE 0 // 内存信息块空闲 +#define MEMORY_BLOCK_USING 1 // 内存信息块使用中 +#define MEMORY_BLOCK_ALLOCATED 2 // 内存信息块已经分配 #define MEMORY_BLOCK_MODE_SMALL 0 // 小块内存描述1024一下的内存块 -#define MEMORY_BLOCK_MODE_BIG 1 // 大块内存描述4kb为单位的内存块 +#define MEMORY_BLOCK_MODE_BIG 1 // 大块内存描述4kb为单位的内存块 + +#define MEMORY_FREE_LIST_COUNT 7 + +#define MEMORY_MIN_POW 5 extern struct mmap phy_page_mmap; extern struct mmap vir_page_mmap; +typedef enum MemoryResult { + MEMORY_RESULT_OK, + MEMORY_RESULT_INVALID_INPUT, + MEMORY_RESULT_OUT_OF_MEMORY, + MEMORY_RESULT_MEMORY_IS_USED, +} MemoryResult; + struct mmap { - int len; - unsigned char *bits; + int len; + unsigned char *bits; }; struct memory_block { - unsigned int address; - int size; - int flags; - int mode; + list_t list; + unsigned int address; + int size; + int flags; + int mode; }; struct memory_manage { - struct memory_block free_blocks[MEMORY_BLOCKS]; + // 32 64 128 256 512 1024 2048 + list_t free_blocks_list[MEMORY_FREE_LIST_COUNT]; + + int last_free_block; + + struct memory_block free_blocks[MEMORY_BLOCKS]; }; -void init_memory(void); -int get_memory_size(void); -int mmap_search(struct mmap *btmp, unsigned int cnt); -void mmap_set(struct mmap *btmp, unsigned int bit_index, int value); -unsigned long alloc_vaddr(size_t size); -void *kmalloc(uint32_t size); -int kfree(void *address); +void init_memory(void); +int get_memory_size(void); +int mmap_search(struct mmap *btmp, unsigned int cnt); +void mmap_set(struct mmap *btmp, unsigned int bit_index, int value); +int mmap_get(struct mmap *btmp, uint32_t bit_index); +MemoryResult alloc_vaddr(size_t in_size, uint32_t *out_vaddr); +void *kmalloc(uint32_t size); +int kfree(void *address); + +void print_memory_result( + MemoryResult result, char *file, int line, char *func_with_args); + +#define MEM_PRINT_RESULT(result, func, ...) \ + print_memory_result(result, __FILE__, __LINE__, #func "(" #__VA_ARGS__ ")"); +#define MEMORY_RESULT_DELIVER_CALL(func, ...) \ + RESULT_DELIVER_CALL( \ + MemoryResult, MEMORY_RESULT_OK, func, \ + { MEM_PRINT_RESULT(result, func, __VA_ARGS__); }, __VA_ARGS__) +#define MEMORY_RESULT_PRINT_CALL(func, ...) \ + ({ \ + MemoryResult result = func(__VA_ARGS__); \ + if (result != MEMORY_RESULT_OK) { \ + MEM_PRINT_RESULT(result, func, __VA_ARGS__); \ + } \ + result; \ + }) #endif \ No newline at end of file diff --git a/src/include/kernel/mutex.h b/src/include/kernel/mutex.h new file mode 100644 index 0000000..8aac346 --- /dev/null +++ b/src/include/kernel/mutex.h @@ -0,0 +1,22 @@ +#ifndef _MUTEX_H +#define _MUTEX_H + +#include "kernel/thread.h" + +typedef volatile int mutex_t; + +void mutex_init(mutex_t *lock) { + *lock = 0; +} + +void mutex_lock(mutex_t *lock) { + while (__sync_lock_test_and_set(lock, 1)) { + schedule(); + } +} + +void mutex_unlock(mutex_t *lock) { + __sync_lock_release(lock); +} + +#endif \ No newline at end of file diff --git a/src/include/kernel/periodic_task.h b/src/include/kernel/periodic_task.h new file mode 100644 index 0000000..bba5155 --- /dev/null +++ b/src/include/kernel/periodic_task.h @@ -0,0 +1,17 @@ +#ifndef _PERIODIC_TASK_H +#define _PERIODIC_TASK_H + +#include "kernel/list.h" + +typedef struct PeriodicTask { + list_t period_task_list; + + void (*func)(void *arg); + void *arg; +} PeriodicTask; + +void periodic_task(void *arg); +void periodic_task_add(PeriodicTask *periodic_task); +void periodic_task_del(PeriodicTask *periodic_task); + +#endif \ No newline at end of file diff --git a/src/include/kernel/platform.h b/src/include/kernel/platform.h index 9d936d3..cb43806 100644 --- a/src/include/kernel/platform.h +++ b/src/include/kernel/platform.h @@ -1,5 +1,12 @@ #ifndef _PLATFORM_H -void platform_init(); +#include + +extern struct Bus *platform_bus; +extern struct PhysicalDevice *platform_device; + +void platform_early_init(); +DriverResult platform_init(); +void platform_start_devices(); #endif \ No newline at end of file diff --git a/src/include/kernel/process.h b/src/include/kernel/process.h index 2bdb7a3..75ab5a6 100644 --- a/src/include/kernel/process.h +++ b/src/include/kernel/process.h @@ -11,7 +11,8 @@ void start_process(void *filename); void process_excute(void *filename, struct program_struct *prog); void page_dir_activate(struct task_s *thread); void process_activate(struct task_s *thread); -int process_load_segment(struct task_s *thread, struct index_node *inode, unsigned long offset, - unsigned long filesz, unsigned long memsz, unsigned long vaddr); +// MemoryResult process_load_segment( +// struct task_s *thread, struct index_node *inode, unsigned long offset, +// unsigned long filesz, unsigned long memsz, unsigned long vaddr); #endif \ No newline at end of file diff --git a/src/include/kernel/rwlock.h b/src/include/kernel/rwlock.h new file mode 100644 index 0000000..d2ef179 --- /dev/null +++ b/src/include/kernel/rwlock.h @@ -0,0 +1,23 @@ +#ifndef _RWLOCK_H +#define _RWLOCK_H + +#include "kernel/condvar.h" +#include "kernel/spinlock.h" + +typedef struct { + spinlock_t status_lock; // 保护读写锁内部状态 + condvar_t read_lock; + condvar_t write_lock; + int read_count; + int write_count; + int write_waiting; +} rwlock_t; + +void rwlock_init(rwlock_t *lock); +void rwlock_read_lock(rwlock_t *lock); +void rwlock_read_unlock(rwlock_t *lock); +bool rwlock_write_try_lock(rwlock_t *lock); +void rwlock_write_lock(rwlock_t *lock); +void rwlock_write_unlock(rwlock_t *lock); + +#endif \ No newline at end of file diff --git a/src/include/kernel/softirq.h b/src/include/kernel/softirq.h new file mode 100644 index 0000000..cde7f65 --- /dev/null +++ b/src/include/kernel/softirq.h @@ -0,0 +1,31 @@ +#ifndef _SOFTIRQ_H +#define _SOFTIRQ_H + +#include +#include + +#define pending_softirq() ({ softirq.pending = 1; }) + +typedef enum SoftirqType { + SOFTIRQ_TIMER, + SOFTIRQ_USB, + SOFTIRQ_NETWORK, + SOFTIRQ_BLOCK, + SOFTIRQ_SCHEDULER, + SOFTIRQ_MAX +} SoftirqType; + +typedef struct Softirq { + uint8_t pending : 1; +} Softirq; + +typedef struct SoftirqHandler { + void (*handler)(); +} SoftirqHandler; + +extern Softirq softirq; + +void do_softirq(void); +DriverResult softirq_register_handler(SoftirqType type, void (*handler)(void)); + +#endif \ No newline at end of file diff --git a/src/include/kernel/spinlock.h b/src/include/kernel/spinlock.h index 38b3495..aa13849 100644 --- a/src/include/kernel/spinlock.h +++ b/src/include/kernel/spinlock.h @@ -1,7 +1,11 @@ #ifndef _SPINLOCK_H #define _SPINLOCK_H -typedef int spinlock_t; +#include "kernel/driver_interface.h" +extern struct task_s *current_task; + +#ifndef DEBUG +typedef volatile int spinlock_t; #define SPINLOCK(lock) spinlock_t lock = 0; @@ -12,17 +16,71 @@ static inline void spinlock_init(spinlock_t *lock) { lock = 0; } +#define SPINLOCK_GET(lock) *lock +#else +typedef volatile struct { + int lock; + struct task_s *owner; +} spinlock_t; + +#define SPINLOCK(lock) spinlock_t lock = {0, NULL}; + +#define SPINLOCK_INIT(lock) \ + { (lock) = {0, NULL}; } + +#define SPINLOCK_GET(lock) lock->lock +static inline void spinlock_init(spinlock_t *lock) { + lock->lock = 0; + lock->owner = NULL; +} +#endif + static inline void spin_lock(spinlock_t *lock) { // 使用gcc提供的__sync_bool_compare_and_swap()实现原子操作 - while (!__sync_bool_compare_and_swap(lock, 0, 1)) { - while (*lock) + while (!__sync_bool_compare_and_swap(&SPINLOCK_GET(lock), 0, 1)) { + while (SPINLOCK_GET(lock)) ; } +#ifdef DEBUG + lock->owner = current_task; +#endif } -static inline void spin_unlock(spinlock_t __volatile__ *lock) { +static inline int spin_try_lock(spinlock_t *lock) { + int ret = __sync_bool_compare_and_swap(&SPINLOCK_GET(lock), 0, 1); +#ifdef DEBUG + if (ret) lock->owner = current_task; +#endif + return ret; +} + +static inline void spin_unlock(volatile spinlock_t *lock) { __asm__ __volatile__("" ::: "memory"); - *lock = 0; + SPINLOCK_GET(lock) = 0; +#ifdef DEBUG + lock->owner = NULL; +#endif +} + +// 获取自旋锁的同时禁用中断并保存中断状态 +static inline int spin_lock_irqsave(spinlock_t *lock) { + int flags = save_and_disable_interrupt(); + spin_lock(lock); + return flags; +} + +static inline int spin_try_lock_irqsave(spinlock_t *lock) { + int flags = save_and_disable_interrupt(); + if (spin_try_lock(lock)) { return flags; } + store_interrupt_status(flags); + return 0; +} + +// 释放自旋锁并恢复之前保存的中断状态 +static inline void spin_unlock_irqrestore( + spinlock_t *lock, unsigned long flags) { + spin_unlock(lock); + store_interrupt_status(flags); } #endif \ No newline at end of file diff --git a/src/include/kernel/sync.h b/src/include/kernel/sync.h index 7e50cd4..4e5f02f 100644 --- a/src/include/kernel/sync.h +++ b/src/include/kernel/sync.h @@ -1,23 +1,26 @@ #ifndef _SYNC_H #define _SYNC_H -#include "list.h" -#include +#include "kernel/wait_queue.h" #include struct semaphore { - uint8_t value; - struct list waiters; + uint8_t value; + WaitQueue wq; }; struct lock { - struct task_s *holder; - struct semaphore semaphore; - uint32_t holder_repeat_nr; + struct task_s *holder; + struct semaphore semaphore; + uint32_t holder_repeat_nr; }; void lock_init(struct lock *plock); void lock_acquire(struct lock *plock); void lock_release(struct lock *plock); +void sema_init(struct semaphore *psema, uint8_t value); +void sema_down(struct semaphore *psema); +void sema_up(struct semaphore *psema); + #endif \ No newline at end of file diff --git a/src/include/kernel/wait_queue.h b/src/include/kernel/wait_queue.h index dcd950c..cff7c38 100644 --- a/src/include/kernel/wait_queue.h +++ b/src/include/kernel/wait_queue.h @@ -4,25 +4,19 @@ #include "types.h" #include #include -#include typedef struct { spinlock_t lock; list_t list_head; -} wait_queue_manager_t; +} WaitQueue; -typedef struct { - struct task_s *thread; - void *private_data; - list_t list; -} wait_queue_t; - -wait_queue_manager_t *create_wait_queue(void); -void wait_queue_init(wait_queue_manager_t *wqm); -bool wait_queue_empty(wait_queue_manager_t *wqm); -wait_queue_t *wait_queue_add(wait_queue_manager_t *wqm, uint32_t size); -wait_queue_t *wait_queue_first(wait_queue_manager_t *wqm); -void wait_queue_wakeup(wait_queue_manager_t *wqm); -void wait_queue_wakeup_all(wait_queue_manager_t *wqm); +void wait_queue_init(WaitQueue *wq); +bool wait_queue_empty(WaitQueue *wq); +void wait_queue_add(WaitQueue *wq); +void wait_queue_del(WaitQueue *wq); +struct task_s *wait_queue_first(WaitQueue *wq); +void wait_queue_wakeup_thread(WaitQueue *wq, struct task_s *thread); +void wait_queue_wakeup(WaitQueue *wq); +void wait_queue_wakeup_all(WaitQueue *wq); #endif \ No newline at end of file diff --git a/src/include/math.h b/src/include/math.h index 93e73dc..995bdb4 100644 --- a/src/include/math.h +++ b/src/include/math.h @@ -8,9 +8,12 @@ #define DIV_ROUND_UP(X, STEP) ((X + STEP - 1) / (STEP)) -int min(int a, int b); -int max(int a, int b); -int abs(int n); -int pow(int x, int y); +int min(int a, int b); +int max(int a, int b); +int abs(int n); +int pow(int x, int y); +unsigned int find_next_pow_of_2(unsigned int n); +int aligned_up_log2n(unsigned int n); +int aligned_down_log2n(unsigned int n); #endif diff --git a/src/include/multiple_return.h b/src/include/multiple_return.h new file mode 100644 index 0000000..ed68dee --- /dev/null +++ b/src/include/multiple_return.h @@ -0,0 +1,7 @@ +#ifndef _MULTIPLE_RETURN_H_ +#define _MULTIPLE_RETURN_H_ + +#define DEF_MRET(type, name) type *out_##name +#define MRET(name) (*out_##name) + +#endif \ No newline at end of file diff --git a/src/include/network/arp.h b/src/include/network/arp.h deleted file mode 100644 index 965bbef..0000000 --- a/src/include/network/arp.h +++ /dev/null @@ -1,38 +0,0 @@ -#ifndef ARP_H -#define ARP_H - -#include "../stdint.h" -#include -#include -#include - -#define ARP_HWTYPE_ETH 0x0001 - -#define ARP_PTTYPE_IPV4 0x0800 - -#define ARP_REQUEST 1 -#define ARP_REPLY 2 - -typedef struct { - uint16_t hwtype, pttype; - uint8_t hwlen, ptlen; - uint16_t opcode; - uint8_t src_hw_addr[6]; - uint8_t src_ip[4]; - uint8_t dst_hw_addr[6]; - uint8_t dst_ip[4]; -} __attribute__((packed)) arp_pack_t; - -typedef struct { - uint8_t ip[4]; - uint8_t mac[6]; - list_t list; - - wait_queue_manager_t wqm; -} arp_cache_t; - -uint8_t *ip2mac(netc_t *netc, uint8_t *ip); -void send_arp(netc_t *netc, uint8_t *dst_ip, uint16_t opcode); -void arp_read(uint8_t *buf, uint16_t offset, uint16_t length); - -#endif \ No newline at end of file diff --git a/src/include/network/dhcp.h b/src/include/network/dhcp.h deleted file mode 100644 index 27216a4..0000000 --- a/src/include/network/dhcp.h +++ /dev/null @@ -1,52 +0,0 @@ -#ifndef DHCP_H -#define DHCP_H - -#include "../stdint.h" -#include - -#define DHCP_OP_REQUEST 1 -#define DHCP_OP_REPLY 2 - -#define DHCP_DISCOVER 1 -#define DHCP_OFFER 2 -#define DHCP_REQUEST 3 -#define DHCP_DECLINE 4 -#define DHCP_ACK 5 -#define DHCP_NAK 6 -#define DHCP_RELEASE 7 -#define DHCP_INFORM 8 -#define DHCP_FORCERENEW 9 - -#define DHCP_OPTION_SUBNET_MASK 1 -#define DHCP_OPTION_TIME_OFFSET 2 -#define DHCP_OPTION_ROUTER 3 -#define DHCP_OPTION_DOMAIN_SERVER 6 -#define DHCP_OPTION_LEASE_TIME 51 -#define DHCP_OPTION_MSG_TYPE 53 -#define DHCP_OPTION_SERVER_ID 54 -#define DHCP_OPTION_END 255 - -typedef struct { - uint8_t Op; - uint8_t htype, hlen, hops; - uint32_t xID; - uint16_t secs; - uint16_t flags; - uint8_t ciAddr[4]; // 客户端IP地址 - uint8_t yiAddr[4]; // 服务器分配给客户端的IP地址 - uint8_t siAddr[4]; // 下一个服务器的IP地址 - uint8_t giAddr[4]; // 第一个中继的IP地址 - uint8_t chAddr[16]; // 客户端的MAC地址 - uint8_t sname[64]; - uint8_t file[128]; -} __attribute__((packed)) dhcp_basic_t; - -typedef struct { - uint8_t server_ip[4]; - uint8_t server_id; - uint32_t lease_time; -} dhcp_info_t; - -int dhcp_main(net_device_t *net_dev); - -#endif \ No newline at end of file diff --git a/src/include/network/eth.h b/src/include/network/eth.h deleted file mode 100644 index e4cf212..0000000 --- a/src/include/network/eth.h +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef ETH_H -#define ETH_H - -#include -#include -#include -#include -#include - -#define ETH_MAX_FRAME_SIZE 1536 -#define ETH_MIN_FRAME_SIZE 60 -#define ETH_MTU 1500 - -#define ETH_TYPE_IPV4 0x0800 -#define ETH_TYPE_IPV6 0x86dd -#define ETH_TYPE_ARP 0x0806 -#define ETH_TYPE_802_1Q 0x8100 - -typedef void (*eth_handler_t)(device_manager_t *eth_dm, uint8_t *buf, uint16_t size); - -typedef struct eth_frame_s { - uint8_t dest_mac[6]; - uint8_t src_mac[6]; - uint16_t type; -} __attribute__((packed)) eth_frame_t; - -extern device_manager_t eth_dm; - -void eth_handler(net_rx_pack_t *pack, uint8_t *buf, uint16_t size); -int eth_read(netc_t *netc, uint8_t *buffer, uint32_t length); -int eth_write(netc_t *netc, uint8_t *buffer, uint32_t length); - -#endif \ No newline at end of file diff --git a/src/include/network/ipv4.h b/src/include/network/ipv4.h deleted file mode 100644 index 0770c58..0000000 --- a/src/include/network/ipv4.h +++ /dev/null @@ -1,51 +0,0 @@ -#ifndef IPV4_H -#define IPV4_H - -#include "../stdint.h" -#include "netpack.h" -#include "network.h" - -#define IPV4_FLAG_DF 0x02 -#define IPV4_FLAG_MF 0x04 - -typedef struct ipv4_header_s { - uint8_t IHL : 4; - uint8_t Version : 4; - uint8_t TypeOfService; - uint16_t TotalLength; - uint16_t Identification; - uint16_t Offset; - uint8_t TimetoLive; - uint8_t Protocol; - uint16_t HeaderChecksum; - uint8_t SourceAddress[4]; - uint8_t DestinationAddress[4]; - uint8_t *Options; -} __attribute__((packed)) ipv4_header_t; - -struct ipv4_data { - uint8_t ip_addr[4]; - uint8_t subnet_mask[4]; - uint8_t router_ip[4]; - uint8_t dns_server_ip[4]; - spinlock_t idlock; - uint16_t counter; - uint16_t mtu; -}; - -typedef struct { - uint16_t src_port, dst_port; - list_t list; -} ipv4_conn_t; - -extern uint8_t broadcast_ipv4_addr[4]; - -void ipv4_init(net_device_t *netdev); -int ipv4_send(netc_t *netc, uint8_t *dst_ip, uint8_t DF, uint8_t ttl, uint8_t protocol, uint8_t *data, - uint32_t datalen); -void ipv4_read(net_rx_pack_t *pack, uint8_t *buf, uint16_t offset, uint16_t length); -void ipv4_get_ip(netc_t *netc, uint8_t *ip); -void ipv4_set_ip(netc_t *netc, uint8_t *ip); -int ipv4_get_mtu(netc_t *netc); - -#endif \ No newline at end of file diff --git a/src/include/network/netpack.h b/src/include/network/netpack.h deleted file mode 100644 index fa5680f..0000000 --- a/src/include/network/netpack.h +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef NETPACK_H -#define NETPACK_H - -#include "kernel/list.h" -#include "network/network.h" -#include "network/tcp.h" -#include "network/udp.h" -#include "stdint.h" - -typedef struct net_rx_pack_s { - list_t list; - - enum frame_type { - ETH_FRAME, - } type; - uint8_t *src_ip_addr; - uint8_t src_ip_len; - uint32_t proto_start; - uint32_t data_len; - - uint8_t *data; - uint32_t len; -} net_rx_pack_t; - -extern list_t net_rx_tcp_lh; - -void net_process_pack(void *arg); -void net_rx_raw_pack(enum frame_type type, uint8_t *buf, uint32_t length); -void net_raw2tcp_pack(net_rx_pack_t *pack, uint8_t ip_len, uint8_t *p_addr, uint32_t start, uint32_t len); -void net_raw2udp_pack(net_rx_pack_t *pack, uint32_t start, uint32_t len); - -#endif \ No newline at end of file diff --git a/src/include/network/network.h b/src/include/network/network.h deleted file mode 100644 index 33eb122..0000000 --- a/src/include/network/network.h +++ /dev/null @@ -1,72 +0,0 @@ -#ifndef NETWORK_H -#define NETWORK_H - -#include "kernel/spinlock.h" -#include -#include -#include -#include -#include -#include - -#define NET_MAX_BUFFER_SIZE 4096 - -#define NET_FUNC_GET_MTU 0x00 -#define NET_FUNC_GET_MAC_ADDR 0x01 -#define NET_FUNC_SET_MAC_ADDR 0x02 - -struct network_info { - uint8_t mac[6]; - void *ipv4_data; - void *dhcp_data; - - list_t list; -}; - -typedef struct netc_s { - struct task_s *thread; - struct net_device_s *net_dev; - - spinlock_t spin_lock; - - uint8_t *recv_buffer; - uint32_t recv_offset; - uint32_t recv_len; - - uint16_t protocol; - uint16_t proto_id; - list_t proto_list; - void *proto_private; - uint16_t app_protocl; - uint32_t app_proto_id; - void *app_private; - - uint8_t dst_mac[6]; - uint8_t *dst_laddr, dst_laddr_len; -} netc_t; - -typedef struct net_device_s { - struct network_info *info; - device_t *device; - int enable; - - list_t list; - - int (*net_read)(struct netc_s *netc, uint8_t *buffer, uint32_t length); - int (*net_write)(struct netc_s *netc, uint8_t *buffer, uint32_t length); -} net_device_t; - -extern net_device_t *default_net_dev; - -extern uint8_t broadcast_mac[6]; - -void init_network(void); -netc_t *netc_create(net_device_t *net_dev, uint16_t protocol, uint16_t app_protocol); -int netc_delete(netc_t *netc); -void netc_set_dest(netc_t *netc, uint8_t dst_mac[6], uint8_t *dst_laddr, uint8_t dst_laddr_len); -int netc_read(netc_t *netc, uint8_t *buf, uint32_t size); -void netc_drop_all(netc_t *netc); -void netc_ip_send(netc_t *netc, uint8_t *ip, uint8_t DF, uint8_t proto, uint8_t *buf, uint32_t size); -int netc_get_mtu(netc_t *netc); - -#endif \ No newline at end of file diff --git a/src/include/network/tcp.h b/src/include/network/tcp.h deleted file mode 100644 index d98b2c2..0000000 --- a/src/include/network/tcp.h +++ /dev/null @@ -1,95 +0,0 @@ -#ifndef TCP_H -#define TCP_H - -#include "../stdint.h" -#include "kernel/list.h" -#include "network.h" -#include - -#define TCP_FLAG_FIN 0x01 -#define TCP_FLAG_SYN 0x02 -#define TCP_FLAG_RST 0x04 -#define TCP_FLAG_PSH 0x08 -#define TCP_FLAG_ACK 0x10 -#define TCP_FLAG_URG 0x20 -#define TCP_FLAG_ECE 0x40 -#define TCP_FLAG_CWRC 0x80 - -#define TCP_MAX_WINDOW_SIZE 65536 -#define TCP_MSL_MS 2 * 60 * 1000 - -#define TCP_OPTION_END 0 -#define TCP_OPTION_NOP 1 -#define TCP_OPTION_MSS 2 - -#define TCP_PORT_NR 65536 - -typedef struct tcp_header_s { - uint16_t src_port, dst_port; - uint32_t seq; - uint32_t ack; - uint8_t offset; - uint8_t flags; - uint16_t window; - uint16_t checksum; - uint16_t urgent_pointer; -} __attribute__((packed)) tcp_header_t; - -typedef enum { - TCP_STAT_CLOSED = 0, - TCP_STAT_SYN_SENT, - TCP_STAT_ESTABLISHED, - TCP_STAT_LISTEN, - TCP_STAT_SYN_RCVD, - TCP_STAT_FIN_WAIT1, - TCP_STAT_FIN_WAIT2, - TCP_STAT_CLOSING, - TCP_STAT_TIME_WAIT, - TCP_STAT_CLOSE_WAIT, - TCP_STAT_LAST_ACK, -} tcp_status_t; - -typedef struct { - struct netc_s *netc; - uint16_t src_port, dst_port; - uint8_t dst_ip[4]; - list_t list; - - uint8_t *header_buf; - - uint16_t mss; - - struct recv_win { - uint8_t *mem; - uint32_t size; - uint32_t head, tail; // 读窗口的头尾指针 - uint32_t unacked; // 待确认的数据大小 - uint32_t acked; // 已确认未读取的数据大小 - uint32_t recved; // 已接收的数据大小 - } rwin; - - struct send_win { - uint8_t *mem; - uint32_t size; - uint32_t head, tail; // 写窗口的头尾指针 - uint32_t unacked; // 未确认的数据大小 - uint32_t sended; // 已发送的数据大小 - } swin; - - tcp_status_t status; - uint32_t wait_ms, seq, ack; - struct timer *timer; - struct fifo fifo; - int fifo_buf[2]; -} tcp_conn_t; - -#define PROTOCOL_TCP 0x06 -void tcp_create(netc_t *netc); -int tcp_bind(netc_t *netc, uint16_t src_port); -int tcp_ipv4_connect(netc_t *netc, uint8_t *ip, uint16_t dst_port); -void tcp_ipv4_close(netc_t *netc); -void tcp_recv(uint8_t *buf, uint16_t offset, uint16_t length, uint8_t *ip, uint8_t ip_len); -int tcp_write(netc_t *netc, uint8_t *buf, uint32_t length); -int tcp_read(netc_t *netc, uint8_t *buf, uint32_t length); - -#endif \ No newline at end of file diff --git a/src/include/network/udp.h b/src/include/network/udp.h deleted file mode 100644 index c11972d..0000000 --- a/src/include/network/udp.h +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef UDP_H -#define UDP_H - -#include "../stdint.h" -#include "network.h" - -typedef struct udp_head_s { - uint16_t SourcePort; - uint16_t DestinationPort; - uint16_t Length; - uint16_t Checksum; -} __attribute__((packed)) udp_head_t; - -typedef struct { - struct netc_s *netc; - uint16_t src_port, dst_port; - uint8_t dst_ip[4]; - list_t list; -} udp_conn_t; - -#define PROTOCOL_UDP 0x11 - -int udp_bind(netc_t *netc, uint8_t ip[4], uint16_t src_port, uint16_t dst_port); -int udp_unbind(netc_t *netc); -void udp_send(netc_t *netc, uint16_t *data, uint16_t datalen); -void udp_read(uint8_t *buf, uint16_t offset, uint16_t length); - -#endif \ No newline at end of file diff --git a/src/include/objects/attr.h b/src/include/objects/attr.h new file mode 100644 index 0000000..b93ab95 --- /dev/null +++ b/src/include/objects/attr.h @@ -0,0 +1,37 @@ +#ifndef _OBJECT_ATTR_H +#define _OBJECT_ATTR_H + +#include +#include + +typedef enum ObjectType { + OBJECT_TYPE_TYPE, // 表示该对象用于表示一种对象类型 + OBJECT_TYPE_DIRECTORY, // 表示该对象是一个目录 + OBJECT_TYPE_DRIVER, // 表示该对象是一个驱动程序 + OBJECT_TYPE_DEVICE, // 表示该对象是一个设备 + OBJECT_TYPE_FILE, // 表示该对象是一个文件 + OBJECT_TYPE_VALUE, // 表示该对象是一个值 + OBJECT_TYPE_SYM_LINK, // 表示该对象是一个符号链接 + OBJECT_TYPE_PARTITION, // 表示该对象是一个分区 + OBJECT_TYPE_VOLUME, // 表示该对象是一个卷 + OBJECT_TYPE_BUILTIN_MAX, // 表示对象系统内建类型数量的最大值 +} ObjectType; + +typedef struct ObjectAttr { + ObjectType type; + size_t size; + + bool is_mounted; + size_t owner_id; + Permission all_user_permission; + Permission owner_permission; + Permission system_permission; + Permission admin_permission; + + list_t permission_lh; + + struct Object *object; + void *fs_location; +} ObjectAttr; + +#endif \ No newline at end of file diff --git a/src/include/objects/handle.h b/src/include/objects/handle.h new file mode 100644 index 0000000..e29620c --- /dev/null +++ b/src/include/objects/handle.h @@ -0,0 +1,15 @@ +#ifndef _OBJECT_HANDLE_H +#define _OBJECT_HANDLE_H + +#include "object.h" + +typedef struct ObjectHandle { + Object *object; + void *handle_data; + void *buf; +} ObjectHandle; + +ObjectHandle *object_handle_create(Object *object); +ObjectResult object_handle_delete(ObjectHandle *handle); + +#endif \ No newline at end of file diff --git a/src/include/objects/mount.h b/src/include/objects/mount.h new file mode 100644 index 0000000..a2aef06 --- /dev/null +++ b/src/include/objects/mount.h @@ -0,0 +1,8 @@ +#ifndef _MOUNT_H +#define _MOUNT_H + +#include + +ObjectResult object_mount(Object *origin, Object *dest); + +#endif \ No newline at end of file diff --git a/src/include/objects/object.h b/src/include/objects/object.h new file mode 100644 index 0000000..d729058 --- /dev/null +++ b/src/include/objects/object.h @@ -0,0 +1,146 @@ +#ifndef _OBJECT_H +#define _OBJECT_H + +#include +#include +#include +#include +#include +#include +#include + +typedef enum ObjectResult { + OBJECT_OK, + OBJECT_ERROR_MEMORY, + OBJECT_ERROR_DELETE_DIRECTORY, + OBJECT_ERROR_INVALID_OPERATION, + OBJECT_ERROR_CANNOT_FIND, + OBJECT_ERROR_ILLEGAL_ARGUMENT, + OBJECT_ERROR_OCCUPIED, + OBJECT_ERROR_ALREADY_EXISTS, + OBJECT_ERROR_NOT_EMPTY, + OBJECT_ERROR_NO_PERMISSION, + OBJECT_ERROR_OTHER, +} ObjectResult; + +#define OBJ_RESULT_PASS(call) \ + { \ + ObjectResult result = call; \ + if (result != OBJECT_OK) { return result; } \ + } + +#define OBJECT_DIR_SIZE_SMALL 8 +#define OBJECT_DIR_SIZE_MEDIUM 16 +#define OBJECT_DIR_SIZE_LARGE 32 + +struct Partition; +typedef struct Object { + list_t list; + + string_t name; + + struct Object *parent; + TransferIn in; + TransferOut out; + + uint32_t reference; + + ObjectAttr *attr; + struct Object *origin; + struct FileSystemInfo *fs_info; + + union { + uint32_t type; + struct { + void *data; + list_t children; + void *fs_iterator; + } directory; + struct Driver *driver; + struct { + DeviceKind kind; + union { + struct PhysicalDevice *physical; + struct LogicalDevice *logical; + }; + } device; + struct { + void *data; + size_t size; + size_t offset; + void *buffer; + } file; + struct { + enum { + VALUE_TYPE_STRING, + VALUE_TYPE_INTEGER, + } type; + union { + string_t string; + size_t integer; + }; + } value; + struct Object *sym_link; + struct Partition *partition; + } value; + + void (*release_data)(struct Object *object); +} Object; + +typedef struct ObjectIterator { + Object *parent_object; + list_t *current_node; + void *fs_iterator; + enum { + ITERATOR_TYPE_MEM, + ITERATOR_TYPE_FS, + } type; +} ObjectIterator; + +static const Permission base_obj_sys_perm = { + .subject_id = SUBJECT_ID_SYSTEM, + .permission = {1, 1, 1, 1, 0, 1, 1}, +}; +static const Permission base_obj_all_user_perm = { + .subject_id = SUBJECT_ID_ALL, + .permission = {1, 0, 0, 1, 0, 0, 0}, +}; +static const Permission base_obj_admin_perm = { + .subject_id = SUBJECT_ID_ADMIN, + .permission = {1, 1, 0, 1, 0, 0, 0}, +}; + +static const ObjectAttr base_obj_sys_attr = { + .type = OBJECT_TYPE_DIRECTORY, + .size = 0, + .owner_id = SUBJECT_ID_SYSTEM, + .owner_permission = base_obj_sys_perm, + .system_permission = base_obj_sys_perm, + .all_user_permission = base_obj_all_user_perm, + .admin_permission = base_obj_admin_perm, +}; + +extern Object root_object; +extern Object bus_object; +extern Object driver_object; +extern Object device_object; +extern Object volumes_object; + +void init_object_directory(Object *object); +void init_base_obj_sys_attr(Object *object); +ObjectResult init_object_tree(); +ObjectResult add_object(Object *parent, Object *child); +// 通过路径打开对象,对于符号链接会自动解析 +ObjectResult open_oringinal_object_by_path(char *path, Object **out_object); +ObjectResult open_object_by_path(char *path, Object **object); +Object *create_object(Object *parent, string_t *name, ObjectAttr attr); +ObjectResult delete_object(Object *object); +Object *create_object_directory( + Object *parent, string_t *name, ObjectAttr attr); +void object_close(Object *object); +void show_object_tree(); + +#define append_object(parent, child) \ + dyn_array_append((parent)->value.directory.children, Object *, (child)); + +#endif \ No newline at end of file diff --git a/src/include/objects/ops.h b/src/include/objects/ops.h new file mode 100644 index 0000000..e008858 --- /dev/null +++ b/src/include/objects/ops.h @@ -0,0 +1,30 @@ +#ifndef _OBJECT_OPS_H +#define _OBJECT_OPS_H + +#include "object.h" +#include + +#define OBJ_READ_STREAM(object) (object)->in.stream +#define OBJ_WRITE_STREAM(object) (object)->out.stream +#define OBJ_READ_BLOCK(object) (object)->in.block +#define OBJ_WRITE_BLOCK(object) (object)->out.block +#define OBJ_READ_INTERRUPT(object) (object)->in.interrupt +#define OBJ_WRITE_INTERRUPT(object) (object)->out.interrupt + +ObjectResult obj_lookup( + Object *parent, string_t *name, DEF_MRET(ObjectAttr *, attr)); +ObjectResult obj_open( + Object *parent, ObjectAttr *attr, string_t *name, + DEF_MRET(Object *, child)); +ObjectResult obj_close(Object *object); +ObjectResult obj_opendir(Object *parent, DEF_MRET(ObjectIterator *, iter)); +ObjectResult obj_readdir(ObjectIterator *iterator, DEF_MRET(Object *, object)); +ObjectResult obj_closedir(ObjectIterator *iterator); +ObjectResult obj_create_file(Object *parent, string_t *name); +ObjectResult obj_delete_file(Object *parent, ObjectAttr *attr, string_t *name); +ObjectResult obj_mkdir(Object *parent, string_t *name); +ObjectResult obj_rmdir(Object *parent, ObjectAttr *attr, string_t *name); +ObjectResult obj_get_attr(Object *object, ObjectAttr *attr); +ObjectResult obj_set_attr(Object *object, ObjectAttr *attr); + +#endif \ No newline at end of file diff --git a/src/include/objects/permission.h b/src/include/objects/permission.h new file mode 100644 index 0000000..5b518ee --- /dev/null +++ b/src/include/objects/permission.h @@ -0,0 +1,29 @@ +#ifndef _OBJECT_PERMISSION_H +#define _OBJECT_PERMISSION_H + +#include +#include + +#define SUBJECT_ID_ALL 0 +#define SUBJECT_ID_SYSTEM 1 +#define SUBJECT_ID_ADMIN 2 + +typedef struct Permission { + list_t list; + uint32_t subject_id; + struct { + uint32_t visible : 1; + uint32_t read : 1; + uint32_t write : 1; + uint32_t execute : 1; // 对于文件表示执行,对于目录表示访问 + uint32_t delete : 1; + uint32_t rename : 1; + uint32_t set_attr : 1; + } permission; +} Permission; + +struct Object; +struct ObjectAttr; +Permission *get_permission_info(struct ObjectAttr *attr); + +#endif \ No newline at end of file diff --git a/src/include/objects/transfer.h b/src/include/objects/transfer.h new file mode 100644 index 0000000..0479953 --- /dev/null +++ b/src/include/objects/transfer.h @@ -0,0 +1,116 @@ +#ifndef _TRANSFER_H +#define _TRANSFER_H + +#include "stdint.h" +#include + +typedef enum { + TRANSFER_OK, + TRANSFER_ERROR_NOT_IMPLEMENTED, + TRANSFER_ERROR_NOT_SUPPORTED, + TRANSFER_ERROR_INVALID_PARAMETER, + TRANSFER_ERROR_NO_MEMORY, + TRANSFER_ERROR_FAILED, + TRANSFER_ERROR_OTHER, + TRANSFER_ERROR_EXCEED_MAX_SIZE, +} TransferResult; + +typedef enum { + TRANSFER_IN, + TRANSFER_OUT, +} TransferDirection; + +struct Object; +struct ObjectHandle; +typedef TransferResult (*BlockTransfer)( + struct Object *object, struct ObjectHandle *obj_handle, + TransferDirection direction, uint8_t *buf, uint32_t position, size_t count); +typedef TransferResult (*BlockTransferAsync)( + struct Object *object, struct ObjectHandle *obj_handle, + TransferDirection direction, uint8_t *buf, uint32_t position, size_t count, + void **handle); + +typedef TransferResult (*StreamTransfer)( + struct Object *object, struct ObjectHandle *obj_handle, + TransferDirection direction, uint8_t *buf, size_t size); +typedef TransferResult (*StreamTransferAsync)( + struct Object *object, struct ObjectHandle *obj_handle, + TransferDirection direction, uint8_t *buf, size_t size, void **handle); + +typedef void (*InterruptTransferCallbackSingle)( + struct Object *object, struct ObjectHandle *obj_handle, void *private_data, + size_t data); +typedef void (*InterruptTransferCallbackMultiple)( + struct Object *object, struct ObjectHandle *obj_handle, void *private_data, + void *data, size_t size); +typedef TransferResult (*InterruptTransfer)( + struct Object *object, struct ObjectHandle *obj_handle, + InterruptTransferCallbackSingle callback_single, + InterruptTransferCallbackMultiple callback_multiple); + +typedef TransferResult (*IsTransferDone)( + struct Object *object, void **handle, bool *done); + +typedef enum TransferType { + TRANSFER_TYPE_NONE, + TRANSFER_TYPE_BLOCK, + TRANSFER_TYPE_STREAM, + TRANSFER_TYPE_INTERRUPT, +} TransferType; + +typedef struct TransferIn { + TransferType type; + IsTransferDone is_transfer_done; + union { + BlockTransfer block; + StreamTransfer stream; + InterruptTransfer interrupt; + }; + union { + BlockTransferAsync block_async; + StreamTransferAsync stream_async; + }; +} TransferIn; + +typedef struct TransferOut { + TransferType type; + IsTransferDone is_transfer_done; + union { + BlockTransfer block; + StreamTransfer stream; + }; + union { + BlockTransferAsync block_async; + StreamTransferAsync stream_async; + }; +} TransferOut; + +#define TRANSFER_IN_BLOCK(object, handle, ...) \ + ((object)->in.block(object, handle, TRANSFER_IN, __VA_ARGS__)) +#define TRANSFER_IN_BLOCK_ASYNC(object, handle, ...) \ + ((object)->in.block_async(object, handle, TRANSFER_IN, __VA_ARGS__)) +#define TRANSFER_IN_STREAM(object, handle, ...) \ + ((object)->in.stream(object, handle, TRANSFER_IN, __VA_ARGS__)) +#define TRANSFER_IN_STREAM_ASYNC(object, handle, ...) \ + ((object)->in.stream_async(object, handle, TRANSFER_IN, __VA_ARGS__)) +#define TRANSFER_IN_INTTERRUPT(object, handle, ...) \ + ((object)->in.interrupt(object, handle, __VA_ARGS__)) + +#define TRANSFER_IN_IS_DONE(object, handle, ...) \ + ((object)->in.is_transfer_done(object, handle, __VA_ARGS__)) + +#define TRANSFER_OUT_BLOCK(object, handle, ...) \ + ((object)->out.block(object, handle, TRANSFER_OUT, __VA_ARGS__)) +#define TRANSFER_OUT_BLOCK_ASYNC(object, handle, ...) \ + ((object)->out.block_async(object, handle, TRANSFER_OUT, __VA_ARGS__)) +#define TRANSFER_OUT_STREAM(object, handle, ...) \ + ((object)->out.stream(object, handle, TRANSFER_OUT, __VA_ARGS__)) +#define TRANSFER_OUT_STREAM_ASYNC(object, handle, ...) \ + ((object)->out.stream_async(object, handle, TRANSFER_OUT, __VA_ARGS__)) +#define TRANSFER_OUT_INTTERRUPT(object, handle, ...) \ + ((object)->out.interrupt(object, handle, __VA_ARGS__)) + +#define TRANSFER_OUT_IS_DONE(object, handle, ...) \ + ((object)->out.is_transfer_done(object, handle, __VA_ARGS__)) + +#endif \ No newline at end of file diff --git a/src/include/objects/types.h b/src/include/objects/types.h new file mode 100644 index 0000000..e9f8737 --- /dev/null +++ b/src/include/objects/types.h @@ -0,0 +1,9 @@ +#ifndef _OBJECT_TYPES_H +#define _OBJECT_TYPES_H + +#include "object.h" + +ObjectResult init_builtin_types(); +Object *create_object_type(string_t *name); + +#endif \ No newline at end of file diff --git a/src/include/random.h b/src/include/random.h new file mode 100644 index 0000000..ae3687f --- /dev/null +++ b/src/include/random.h @@ -0,0 +1,10 @@ +#ifndef _RANDOM_H +#define _RANDOM_H + +#include + +void rand_seed(uint32_t seed); +uint32_t rand(void); +uint32_t splitmix(uint32_t x); + +#endif \ No newline at end of file diff --git a/src/include/result.h b/src/include/result.h new file mode 100644 index 0000000..c0bb9eb --- /dev/null +++ b/src/include/result.h @@ -0,0 +1,18 @@ +#ifndef _RESULT_H +#define _RESULT_H + +#define RESULT_DELIVER_CALL(result_type, result_ok, func, add_ops, ...) \ + { \ + result_type result = func(__VA_ARGS__); \ + if (result != result_ok) { \ + add_ops; \ + return result; \ + } \ + } + +#define RESULT_CASE_PRINT(result) \ + case result: \ + printk(#result); \ + break; + +#endif \ No newline at end of file diff --git a/src/include/stdarg.h b/src/include/stdarg.h index 18e8025..5ce0974 100644 --- a/src/include/stdarg.h +++ b/src/include/stdarg.h @@ -1,15 +1,13 @@ #ifndef _LIB_STDARG_H #define _LIB_STDARG_H -#define _AUPBND 1 -#define _ADNBND 1 -#define _Bnd(X, bnd) (sizeof(X) + (bnd) & ~(bnd)) +#define _AUPBND 1 +#define _ADNBND 1 +#define _Bnd(X, bnd) (sizeof(X) + ((bnd) & ~(bnd))) typedef char *va_list; -#define va_arg(ap, T) \ - (*(T *)(((ap) += _Bnd(T, _AUPBND)) - _Bnd(T, _ADNBND))) -#define va_end(ap) (void)0 -#define va_start(ap, A) \ - (void)((ap) = (char *)&(A) + _Bnd(A, _AUPBND)) +#define va_arg(ap, T) (*(T *)(((ap) += _Bnd(T, _AUPBND)) - _Bnd(T, _ADNBND))) +#define va_end(ap) (void)0 +#define va_start(ap, A) (void)((ap) = (char *)&(A) + _Bnd(A, _AUPBND)) #endif diff --git a/src/include/stdint.h b/src/include/stdint.h index cccf373..a4151b9 100644 --- a/src/include/stdint.h +++ b/src/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/src/include/stdlib.h b/src/include/stdlib.h deleted file mode 100644 index 6a712db..0000000 --- a/src/include/stdlib.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef STDLIB_H -#define STDLIB_H - -void srand(unsigned long seed); -int rand(); - -#endif \ No newline at end of file diff --git a/src/include/string.h b/src/include/string.h index 6d6ea9b..e7c280f 100644 --- a/src/include/string.h +++ b/src/include/string.h @@ -8,50 +8,55 @@ #ifndef _LIB_STRING_H_ #define _LIB_STRING_H_ -#include "stddef.h" #include "stdint.h" -#include "types.h" #define STRING_MAX_LEN 256 +#define STRING_INIT(str) \ + { .text = str "\0", .length = sizeof(str), .max_length = sizeof(str) } typedef struct _string { - unsigned int length; - unsigned int max_length; - char *text; + unsigned int length; + unsigned int max_length; + char *text; } string_t; void string_init(string_t *string); -int string_new(string_t *string, char *text, unsigned int max_len); +int string_new(string_t *string, char *text, unsigned int max_len); +int string_new_with_number( + string_t *string, char *text, int text_len, int number); +int string_new_with_string_number( + string_t *string, char *text, int text_len, char *append_text, + int append_text_len, int number); void string_del(string_t *string); -int string_cpy(string_t *dest, string_t *src); +int string_cpy(string_t *dest, string_t *src); -char *itoa(char **ps, int val, int base); -int atoi(const char *src); +char *itoa(char *ps, int val, int base); +int atoi(const char *src); char *itoa16_align(char *str, int num); void *memset(void *src, uint8_t value, uint32_t size); void memcpy(void *dst_, const void *src_, uint32_t size); -int memcmp(const void *s1, const void *s2, int n); +int memcmp(const void *s1, const void *s2, int n); void *memset16(void *src, uint16_t value, uint32_t size); void *memset32(void *src, uint32_t value, uint32_t size); void *memmove(void *dst, const void *src, uint32_t count); #define bzero(str, n) memset(str, 0, n) -char *strcpy(char *dst_, const char *src_); -uint32_t strlen(const char *str); -int8_t strcmp(const char *a, const char *b); -char *strchr(const char *s, int c); -char *strrchr(char *str, int c); -char *strcat(char *strDest, const char *strSrc); -int strncmp(const char *s1, const char *s2, int n); -int strpos(char *str, char ch); -char *strncpy(char *dst_, char *src_, int n); -char *strncat(char *dst, const char *src, int n); -int strmet(const char *src, char *buf, char ch); -char *strstr(const char *haystack, const char *needle); -size_t strspn(const char *s, const char *accept); +char *strcpy(char *dst_, const char *src_); +uint32_t strlen(const char *str); +int8_t strcmp(const char *a, const char *b); +char *strchr(const char *s, int c); +char *strrchr(char *str, int c); +char *strcat(char *strDest, const char *strSrc); +int strncmp(const char *s1, const char *s2, int n); +int strpos(char *str, char ch); +char *strncpy(char *dst_, char *src_, int n); +char *strncat(char *dst, const char *src, int n); +int strmet(const char *src, char *buf, char ch); +char *strstr(const char *haystack, const char *needle); +size_t strspn(const char *s, const char *accept); const char *strpbrk(const char *str1, const char *str2); -int strcoll(const char *str1, const char *str2); +int strcoll(const char *str1, const char *str2); #endif /*_LIB_STDINT_H*/ diff --git a/src/include/types.h b/src/include/types.h index 63c9a94..c362eef 100644 --- a/src/include/types.h +++ b/src/include/types.h @@ -9,4 +9,9 @@ #define true 1 #define false 0 +#define offset_t uint64_t + +#define PRIVATE static +#define PUBLIC + #endif /*_TYPES_H_*/ \ No newline at end of file diff --git a/src/kernel/Makefile b/src/kernel/Makefile index 3889902..9db9776 100644 --- a/src/kernel/Makefile +++ b/src/kernel/Makefile @@ -6,12 +6,17 @@ SRC += memory.c SRC += sync.c SRC += thread.c SRC += initcall.c -SRC += driver.c SRC += process.c SRC += syscall.c SRC += app.c SRC += elf.c SRC += wait_queue.c +SRC += periodic_task.c +SRC += block_cache.c +SRC += rwlock.c +SRC += condvar.c +SRC += softirq.c +SRC += driver/ #INCLUDE_PATH = ../include/ ../$(ARCH)/include/ diff --git a/src/kernel/app.c b/src/kernel/app.c index eb42a32..6a515bc 100644 --- a/src/kernel/app.c +++ b/src/kernel/app.c @@ -18,28 +18,26 @@ * * @param path 应用程序的路径 */ -void run_app(char *path) -{ - struct program_struct *prog = kmalloc(sizeof(struct program_struct)); - prog->inode = fs_open(path); - if (prog->inode == NULL) { - printk("Cannot find file %s!", path); - } - string_init(&prog->name); - string_init(&prog->filename); - string_init(&prog->path); - string_cpy(&prog->filename, &prog->inode->name); - string_new(&prog->path, path, 255); +void run_app(char *path) { + // struct program_struct *prog = kmalloc(sizeof(struct program_struct)); + // // prog->inode = fs_open(path); + // if (prog->inode == NULL) { printk("Cannot find file %s!", path); } + // string_init(&prog->name); + // string_init(&prog->filename); + // string_init(&prog->path); + // string_cpy(&prog->filename, &prog->inode->name); + // string_new(&prog->path, path, 255); - char sign[4]; - prog->inode->f_ops.read(prog->inode, (uint8_t *)sign, 4); - if (strncmp(sign, "\177ELF", 4) == 0) { - string_cpy(&prog->name, &prog->filename); - list_init(&prog->seg_head); - unsigned int *entry = elf_load(prog); - process_excute(entry, prog); - } else { - printk("Unsupport Executable File or Command %s!", prog->inode->name.text); - } - fs_close(prog->inode); + // char sign[4]; + // prog->inode->f_ops.read(prog->inode, (uint8_t *)sign, 4); + // if (strncmp(sign, "\177ELF", 4) == 0) { + // string_cpy(&prog->name, &prog->filename); + // list_init(&prog->seg_head); + // unsigned int *entry = elf_load(prog); + // process_excute(entry, prog); + // } else { + // printk( + // "Unsupport Executable File or Command %s!", prog->inode->name.text); + // } + // fs_close(prog->inode); } \ No newline at end of file diff --git a/src/kernel/block_cache.c b/src/kernel/block_cache.c new file mode 100644 index 0000000..0f4696a --- /dev/null +++ b/src/kernel/block_cache.c @@ -0,0 +1,127 @@ +#include "kernel/block_cache.h" +#include "driver/storage/storage_dm.h" +#include "kernel/rwlock.h" +#include "stddef.h" +#include +#include + +// 将节点移到LRU链表头部 +static void move_to_list_head(BlockCache *cache, BlockCacheEntry *entry) { + list_del(&entry->lru_node); + list_add(&entry->lru_node, &cache->lru_lh); +} + +static BlockCacheEntry *get_free_entry(BlockCache *cache) { + BlockCacheEntry *entry; + list_for_each_owner_reverse (entry, &cache->lru_lh, lru_node) { + if (rwlock_write_try_lock(&entry->lock)) { + if (entry->dirty) { + cache->write(entry, cache->size, cache->private_data); + entry->dirty = false; + list_del(&entry->list); + } + return entry; + } + } + return NULL; +} + +BlockCache *block_cache_create( + int size, int count, BlockCacheRealTransfer read, + BlockCacheRealTransfer write, void *private_data) { + BlockCache *cache = kmalloc(sizeof(BlockCache)); + if (!cache) return NULL; + cache->count = count; + cache->size = size; + cache->entries = kmalloc(sizeof(BlockCacheEntry) * count); + if (!cache->entries) { + kfree(cache); + return NULL; + } + + cache->read = read; + cache->write = write; + cache->private_data = private_data; + + list_init(&cache->lru_lh); + for (int i = 0; i < count; i++) { + BlockCacheEntry *entry = &cache->entries[i]; + rwlock_init(&entry->lock); + entry->list.prev = NULL; + entry->list.next = NULL; + entry->cache = cache; + entry->position = -1; + entry->data = kmalloc(cache->size); + list_add_tail(&entry->lru_node, &cache->lru_lh); + } + return cache; +} + +void block_cache_destroy(BlockCache *cache) { + // 释放所有缓存项 + BlockCacheEntry *entry; + list_t *pos, *next; + list_for_each_safe(pos, next, &cache->lru_lh) { + entry = (BlockCacheEntry *)((char *)pos - + offsetof(BlockCacheEntry, lru_node)); + if (entry->dirty) { + cache->write(entry, cache->size, cache->private_data); + list_del(&entry->list); + } + list_del(&entry->lru_node); + kfree(entry->data); + kfree(entry); + } + kfree(cache); +} + +static BlockCacheEntry *find_entry(BlockCache *cache, size_t position) { + BlockCacheEntry *entry; + list_for_each_owner (entry, &cache->lru_lh, lru_node) { + if (entry->position == position) return entry; + } + return NULL; +} + +BlockCacheEntry *block_cache_read(BlockCache *cache, size_t position) { + BlockCacheEntry *entry = find_entry(cache, position); + if (entry == NULL) { + // 未命中,调用read回调函数 + entry = get_free_entry(cache); + if (entry == NULL) return NULL; + entry->position = position; + cache->read(entry, cache->size, cache->private_data); + move_to_list_head(cache, entry); + rwlock_write_unlock(&entry->lock); + } + rwlock_read_lock(&entry->lock); + return entry; +} + +BlockCacheEntry *block_cache_write(BlockCache *cache, size_t position) { + BlockCacheEntry *entry = find_entry(cache, position); + if (entry == NULL) { + // 未命中,调用read回调函数 + entry = get_free_entry(cache); + if (entry == NULL) return NULL; + entry->position = position; + move_to_list_head(cache, entry); + } else { + rwlock_write_lock(&entry->lock); + } + entry->dirty = true; + return entry; +} + +void block_cache_read_done(BlockCacheEntry *entry) { + rwlock_read_unlock(&entry->lock); +} + +void block_cache_write_done( + StorageDevice *storage_device, BlockCacheEntry *entry) { + if (list_in_list(&storage_device->block_cache_lh) && + list_in_list(&entry->list)) { + list_add_tail(&entry->list, &storage_device->block_cache_lh); + } + rwlock_write_unlock(&entry->lock); +} diff --git a/src/kernel/condvar.c b/src/kernel/condvar.c new file mode 100644 index 0000000..2c64ecd --- /dev/null +++ b/src/kernel/condvar.c @@ -0,0 +1,24 @@ +#include "kernel/thread.h" +#include + +void condvar_init(condvar_t *cv) { + wait_queue_init(&cv->wait_queue); +} + +void condvar_wait(condvar_t *cv, spinlock_t *mutex) { + thread_set_status(TASK_INTERRUPTIBLE); + wait_queue_add(&cv->wait_queue); + spin_unlock(mutex); + + thread_wait(); + + spin_lock(mutex); +} + +void condvar_signal(condvar_t *cv) { + wait_queue_wakeup(&cv->wait_queue); +} + +void condvar_broadcast(condvar_t *cv) { + wait_queue_wakeup_all(&cv->wait_queue); +} \ No newline at end of file diff --git a/src/kernel/config.toml b/src/kernel/config.toml new file mode 100644 index 0000000..2190e13 --- /dev/null +++ b/src/kernel/config.toml @@ -0,0 +1,31 @@ +c = [ + "driver/bus_driver.c", + "driver/device_driver.c", + "driver/device_manager.c", + "driver/device.c", + "driver/dma.c", + "driver/driver_interface.c", + "driver/driver.c", + "app.c", + "block_cache.c", + "condvar.c", + "console.c", + "elf.c", + "fifo.c", + "font-default.c", + "initcall.c", + "main.c", + "memory.c", + "memtest.c", + "periodic_task.c", + "process.c", + "rwlock.c", + "softirq.c", + "sync.c", + "syscall.c", + "thread.c", + "wait_queue.c", +] +rust = [ + "memory/mod.rs", +] diff --git a/src/kernel/console.c b/src/kernel/console.c index 8463c18..2bfa63c 100644 --- a/src/kernel/console.c +++ b/src/kernel/console.c @@ -5,125 +5,45 @@ * @version 0.3 * @date 2022-07-15 */ -#include +#include +#include #include #include +#include #include #include #include #include -int command_length = 0; -char command[CMD_MAX_LENGTH]; -struct console console; +LIST_HEAD(console_backend_lh); -/** - * @brief 初始化控制台的配置 - * - */ -void init_console(void) { - console.vram = video_info.vram; - console.font = font16; - console.cur_x = 0; - console.cur_y = 0; - console.width = video_info.width / 10; - console.height = video_info.height / 16; - console.color = 0xc0c0c0; - console.flag = CMD_FLAG_OUTPUT; +void console_register_backend(ConsoleBackend *backend, void *context) { + if (backend == NULL || backend->put_string == NULL) return; + backend->context = context; + list_add_tail(&backend->list, &console_backend_lh); + if (backend->init) { backend->init(context); } } /** - * @brief 打印">" - * - */ -void console_start(void) { - printk("\n>"); - console.start_x = 1; - console.start_y = console.cur_y + 1; - console.flag = CMD_FLAG_INPUT; -} - -/** - * @brief 设置光标位置 + * @brief 初始化控制台的配置 * - * @param x 光标的x坐标 - * @param y 光标的y坐标 */ -void console_set_cursor(int x, int y) { - console.cur_x = x; - console.cur_y = y; +void init_console(void) { } -/* -void console_input(char c) -{ - int i; - char str[2]; - if (console.flag == CMD_FLAG_INPUT) - { - if (c != '\n') - { - if (command_length < CMD_MAX_LENGTH - 1) - { - command[command_length] = c; - command_length++; - str[0] = c; - str[1] = '\0'; - printk(str); - } - } - else - { - for (i = 0; i <= command_length; i++) - { - command[i] = 0; - } - command_length = 0; - printk("\n"); - console_start(); - //运行程序 or 其他操作 - } +void put_string(const char *string, int length) { + ConsoleBackend *backend; + list_for_each_owner (backend, &console_backend_lh, list) { + backend->put_string(backend->context, string, length); } } -*/ /** - * @brief 打印一个字符 + * @brief 打印">" * - * @param c 字符 - * @param color 颜色 */ -void print_char(unsigned char c, unsigned int color) { - int i, j, k; - uint32_t _color = color; - if (c > 127) { c = '?'; } - print_word( - console.cur_x * 10 + 1, console.cur_y * 16, console.font + c * 16, - _color); - console.cur_x++; - if (console.cur_x >= console.width) { - console.cur_x = 0; - console.cur_y++; - } - if (console.cur_y >= console.height) { - console.cur_y = console.height - 1; - console.cur_x = 0; - int height = console.height * 16; - int width = console.width * 10; - int byte_per_pixel = video_info.BitsPerPixel / 8; - for (i = 16; i < height; i++) { - for (j = 0; j < width; j++) { - for (k = 0; k < byte_per_pixel; k++) { - console.vram - [((i - 16) * video_info.width + j) * byte_per_pixel + - k] = - console.vram - [(i * video_info.width + j) * byte_per_pixel + k]; - } - } - } - draw_rect(0, console.height * 16 - 16, console.width * 10, 16, 0); - } +void console_start(void) { + put_string("\n>", 2); } /** @@ -134,116 +54,14 @@ void print_char(unsigned char c, unsigned int color) { * @return int 字符串长度 */ int printk(const char *fmt, ...) { - int i, color = console.color; + int i; char buf[256]; va_list arg; va_start(arg, fmt); i = vsprintf(buf, fmt, arg); - va_end(); - - char *p = buf, c; - int len = i; - while (len) { - c = *p++; - if (c == '<' && len == i) { - if (*(p + 1) == '>') { - switch (*p) { - case '0': - color = 0x000000; - break; - case '1': - color = 0x0037da; - break; - case '2': - color = 0x13a104; - break; - case '3': - color = 0x3a96dd; - break; - case '4': - color = 0xc50f1f; - break; - case '5': - color = 0x881798; - break; - case '6': - color = 0xffff00; - break; - case '7': - color = 0xcccccc; - break; - case '8': - color = 0x767676; - break; - case '9': - color = 0x3878ff; - break; - case 'a': - color = 0x16c60c; - break; - case 'b': - color = 0x61d6d6; - break; - case 'c': - color = 0xe74856; - break; - case 'd': - color = 0xb4009e; - break; - case 'e': - color = 0xf9f1a5; - break; - case 'f': - color = 0xf2f2f2; - break; - - default: - break; - } - p += 2; - - len -= 3; - c = *p++; - } - } - switch (c) { - case '\n': - console.cur_y++; - console.cur_x = 0; - if (console.cur_y >= console.height) { - print_char('\n', color); - if (console.cur_y < 0) { console.cur_y = 0; } - if (console.flag == CMD_FLAG_INPUT) { - console.start_y = console.cur_y; - } - } - break; - case '\b': - if (console.flag == CMD_FLAG_INPUT) { - if (console.cur_x != console.start_x && - console.cur_y != console.start_y) { - console.cur_x--; - draw_rect( - console.cur_x * 10, console.cur_y * 16, 10, 16, 0); - } - } - break; - case '\t': - if ((console.cur_x % 4) == 0) { console.cur_x += 4; } - while (console.cur_x % 4) { - console.cur_x++; - } - break; - case '\r': - break; - default: - draw_rect(console.cur_x * 10, console.cur_y * 16, 10, 16, 0); - print_char(c, color); - break; - } - len--; - } + va_end(arg); + put_string(buf, i); return i; } @@ -259,29 +77,29 @@ void print_hex(unsigned char *s, int length) { printk("\nData is too long!\n"); return; } - printk("\n 0 1 2 3 4 5 6 7 8 9 A B C D E F " - "0123456789ABCDEF\n"); + print_string("\n 0 1 2 3 4 5 6 7 8 9 A B C D E F " + "0123456789ABCDEF\n"); for (i = 0; i < DIV_ROUND_UP(length, 16); i++) { printk("%08X ", i * 16); for (j = 0; j < 16; j++) { if (j < length - i * 16) { printk("%02X ", s[i * 16 + j]); } else { - printk(" "); + print_string(" "); } } - printk(" "); + print_string(" "); for (j = 0; j < 16; j++) { if (j < length - i * 16) { if (s[i * 16 + j] < 32 || s[i * 16 + j] > 126) { - printk("."); + print_string("."); } else { printk("%c", s[i * 16 + j]); } } else { - printk(" "); + print_string(" "); } } - printk("\n"); + print_string("\n"); } } \ No newline at end of file diff --git a/src/kernel/driver.c b/src/kernel/driver.c deleted file mode 100644 index 76075aa..0000000 --- a/src/kernel/driver.c +++ /dev/null @@ -1,173 +0,0 @@ -/** - * @file driver.c - * @author Ryan Wang (ryan1202@foxmail.com) - * @brief 驱动接口 - * @version 0.3 - * @date 2022-07-20 - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -LIST_HEAD(driver_list_head); -list_t irq_handler_lists[16] = { - LIST_HEAD_INIT(irq_handler_lists[0]), LIST_HEAD_INIT(irq_handler_lists[1]), - LIST_HEAD_INIT(irq_handler_lists[2]), LIST_HEAD_INIT(irq_handler_lists[3]), - LIST_HEAD_INIT(irq_handler_lists[4]), LIST_HEAD_INIT(irq_handler_lists[5]), - LIST_HEAD_INIT(irq_handler_lists[6]), LIST_HEAD_INIT(irq_handler_lists[7]), - LIST_HEAD_INIT(irq_handler_lists[8]), LIST_HEAD_INIT(irq_handler_lists[9]), - LIST_HEAD_INIT(irq_handler_lists[10]), LIST_HEAD_INIT(irq_handler_lists[11]), - LIST_HEAD_INIT(irq_handler_lists[12]), LIST_HEAD_INIT(irq_handler_lists[13]), - LIST_HEAD_INIT(irq_handler_lists[14]), LIST_HEAD_INIT(irq_handler_lists[15]), -}; - -struct index_node *dev; - -struct file_operations device_fops = { - .open = dev_open, - .close = dev_close, - .read = dev_read, - .write = dev_write, - .ioctl = dev_ioctl, - .seek = fs_seek, -}; - -struct index_node *dev_open(char *path) { - struct index_node *inode = vfs_open(path); - if (inode == NULL) return NULL; - else inode->device->drv_obj->function.driver_open(inode->device); - return inode; -} - -int dev_close(struct index_node *inode) { - return inode->device->drv_obj->function.driver_close(inode->device); -} - -int dev_read(struct index_node *inode, uint8_t *buffer, uint32_t length) { - return inode->device->drv_obj->function.driver_read(inode->device, (uint8_t *)buffer, inode->fp->offset, - length); -} - -int dev_write(struct index_node *inode, uint8_t *buffer, uint32_t length) { - return inode->device->drv_obj->function.driver_write(inode->device, (uint8_t *)buffer, inode->fp->offset, - length); -} - -int dev_ioctl(struct index_node *inode, uint32_t cmd, uint32_t arg) { - return inode->device->drv_obj->function.driver_devctl(inode->device, cmd, arg); -} - -void init_dm(void) { - init_network(); -} - -status_t driver_create(driver_func_t func, char *driver_name) { - driver_t *drv_obj; - int status; - - drv_obj = kmalloc(sizeof(driver_t)); - if (drv_obj == NULL) { return FAILED; } - if (func.driver_enter == NULL) { return FAILED; } - list_init(&drv_obj->device_list); - list_init(&drv_obj->list); - drv_obj->function = func; - status = drv_obj->function.driver_enter(drv_obj); - if (status == NODEV) { - printk("[driver manager]Cannot found device:%s\n", driver_name); - } else if (status != SUCCUESS) { - return FAILED; - } - string_init(&drv_obj->name); - string_new(&drv_obj->name, driver_name, DRIVER_MAX_NAME_LEN); - list_add_tail(&drv_obj->list, &driver_list_head); - - return SUCCUESS; -} - -void driver_inited() { - driver_t *cur, *next; - list_for_each_owner_safe (cur, next, &driver_list_head, list) { - if (cur->dm != NULL) { cur->dm->drv_inited(cur->dm); } - } -} - -status_t device_create(driver_t *driver, unsigned long device_extension_size, char *name, dev_type_t type, - device_t **device) { - device_t *devobj = kmalloc(sizeof(device_t) + device_extension_size); - devobj->type = type; - spinlock_init(&devobj->lock); - if (devobj == NULL) { return FAILED; } - list_init(&devobj->list); - if (device_extension_size > 0) { - devobj->device_extension = (void *)(devobj + 1); - } else { - devobj->device_extension = NULL; - } - if (string_new(&devobj->name, name, DEVICE_MAX_NAME_LEN)) { - kfree(devobj); - return FAILED; - } - - devobj->drv_obj = driver; - list_add_tail(&devobj->list, &driver->device_list); - *device = devobj; - - if (type == DEV_ETH_NET) { - eth_dm.dm_register(ð_dm, devobj, name); - driver->dm = ð_dm; - } else { - devobj->inode = vfs_create(name, ATTR_DEV, dev); - devobj->inode->device = devobj; - devobj->inode->f_ops = device_fops; - devobj->inode->fp = kmalloc(sizeof(struct file)); - } - - return SUCCUESS; -} - -void device_delete(device_t *device) { - if (device == NULL) { return; } - driver_t *driver = device->drv_obj; - if (!list_find(&device->list, &driver->device_list)) { return; } - list_del(&device->list); - string_del(&driver->name); - kfree(device); -} - -void device_register_irq(device_t *devobj, int irq, driver_irq_handler_t handler) { - if (irq > 16) return; - if (list_empty(&irq_handler_lists[irq])) irq_enable(irq); - dev_irq_t *dev_irq = kmalloc(sizeof(dev_irq_t)); - dev_irq->devobj = devobj; - dev_irq->handler = handler; - list_add_tail(&dev_irq->list, &irq_handler_lists[irq]); -} - -void device_unregister_irq(device_t *devobj, int irq) { - if (irq > 16) return; - if (list_empty(&irq_handler_lists[irq])) return; - dev_irq_t *dev_irq, *next; - list_for_each_owner_safe (dev_irq, next, &irq_handler_lists[irq], list) { - if (dev_irq->devobj == devobj) { - list_del(&dev_irq->list); - kfree(dev_irq); - } - } -} - -void device_irq_handler(int irq) { - dev_irq_t *cur, *next; - if (list_empty(&irq_handler_lists[irq])) return; - list_for_each_owner_safe (cur, next, &irq_handler_lists[irq], list) { - cur->handler(cur->devobj, irq); - } -} diff --git a/src/kernel/driver/Makefile b/src/kernel/driver/Makefile new file mode 100644 index 0000000..f0ac1b7 --- /dev/null +++ b/src/kernel/driver/Makefile @@ -0,0 +1,7 @@ +SRC += bus_driver.c +SRC += device_driver.c +SRC += device_manager.c +SRC += device.c +SRC += dma.c +SRC += driver_interface.c +SRC += driver.c \ No newline at end of file diff --git a/src/kernel/driver/bus_driver.c b/src/kernel/driver/bus_driver.c new file mode 100644 index 0000000..c974492 --- /dev/null +++ b/src/kernel/driver/bus_driver.c @@ -0,0 +1,101 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +BusDriver *bus_drivers[BUS_TYPE_MAX]; +WaitQueue bus_wqm[BUS_TYPE_MAX]; + +DriverResult init_bus_manager() { + for (int i = 0; i < BUS_TYPE_MAX; i++) { + wait_queue_init(&bus_wqm[i]); + } + return DRIVER_OK; +} + +DriverResult register_bus_driver( + Driver *driver, BusType type, BusDriver *bus_driver, ObjectAttr *attr) { + BusDriver *_bus_driver = bus_drivers[type]; + if (_bus_driver != NULL) return DRIVER_ERROR_ALREADY_EXIST; + + bus_driver->state = DRIVER_STATE_REGISTERED; + list_init(&bus_driver->bus_lh); + + bus_drivers[type] = bus_driver; + + bus_driver->bus_type = type; + bus_driver->new_bus_num = 0; + bus_driver->bus_count = 0; + + bus_driver->object = + create_object_directory(&bus_object, &bus_driver->name, *attr); + + return DRIVER_OK; +} + +DriverResult unregister_bus_driver(BusDriver *bus_driver) { + delete_object(bus_driver->object); + + bus_drivers[bus_driver->bus_type] = NULL; + + Bus *cur, *next; + list_for_each_owner_safe (cur, next, &bus_driver->bus_lh, bus_list) { + delete_bus(cur); + } + + return DRIVER_OK; +} + +DriverResult create_bus(Bus **bus, BusDriver *bus_driver, BusOps *ops) { + *bus = kmalloc(sizeof(Bus)); + if (*bus == NULL) return DRIVER_ERROR_OUT_OF_MEMORY; + Bus *b = *bus; + + Bus *primary_bus = b->primary_bus; + Bus *tmp_bus = b; + while (primary_bus != NULL) { + primary_bus->subordinate_bus_num = + MAX(primary_bus->subordinate_bus_num, tmp_bus->subordinate_bus_num); + tmp_bus = primary_bus; + primary_bus = primary_bus->primary_bus; + } + char _name[6] = {0}; // bus_count为uint16_t类型,最大65535,5位数 + string_t name; + itoa(_name, bus_driver->new_bus_num++, 10); + bus_driver->bus_count++; + string_new(&name, _name, sizeof(_name)); + + b->bus_driver = bus_driver; + b->ops = ops; + b->new_device_num = 0; + b->device_count = 0; + list_init(&b->device_lh); + list_add_tail(&b->bus_list, &bus_driver->bus_lh); + + b->object = + create_object_directory(bus_driver->object, &name, base_obj_sys_attr); + + list_add_tail(&b->new_bus_list, &new_bus_lh); + + return DRIVER_OK; +} + +DriverResult delete_bus(Bus *bus) { + delete_object(bus->object); + + // 取消注册bus下的所有device_driver + PhysicalDevice *cur, *next; + list_for_each_owner_safe (cur, next, &bus->device_lh, device_list) { + delete_physical_device(cur); + } + + list_del(&bus->bus_list); + bus->bus_driver = NULL; + + return DRIVER_OK; +} diff --git a/src/kernel/driver/device.c b/src/kernel/driver/device.c new file mode 100644 index 0000000..138d25e --- /dev/null +++ b/src/kernel/driver/device.c @@ -0,0 +1,144 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +DriverResult create_physical_device( + PhysicalDevice **physical_device, Bus *bus, ObjectAttr *attr) { + + *physical_device = kmalloc(sizeof(PhysicalDevice)); + if (*physical_device == NULL) return DRIVER_ERROR_OUT_OF_MEMORY; + PhysicalDevice *phy = *physical_device; + + phy->kind = DEVICE_KIND_PHYSICAL; + phy->bus = bus; + phy->ops = NULL; + phy->state = DEVICE_STATE_UNINIT; + list_add_tail(&phy->device_list, &bus->device_lh); + list_init(&phy->logical_device_lh); + + phy->private_data = NULL; + phy->bus_ext = NULL; + + char _name[6] = {0}; // device_count为uint16_t类型,最大65535,5位数 + itoa(_name, bus->new_device_num++, 10); + bus->device_count++; + + string_t name; + string_new(&name, _name, sizeof(_name)); + attr->type = OBJECT_TYPE_DEVICE; + phy->object = create_object(bus->object, &name, *attr); + phy->object->value.device.kind = DEVICE_KIND_PHYSICAL; + phy->object->value.device.physical = phy; + + return DRIVER_OK; +} + +void register_physical_device(PhysicalDevice *physical_device, DeviceOps *ops) { + physical_device->ops = ops; +} + +DriverResult delete_physical_device(PhysicalDevice *physical_device) { + Bus *bus = physical_device->bus; + DriverResult ret = DRIVER_OK; + + if (!list_empty(&physical_device->logical_device_lh)) { + return DRIVER_ERROR_BUSY; + } + if (physical_device->object) { + ObjectResult result = delete_object(physical_device->object); + if (result != OBJECT_OK) ret = DRIVER_ERROR_OBJECT; + } + + list_del(&physical_device->device_list); + int result = kfree(physical_device); + if (result < 0) ret = DRIVER_ERROR_MEMORY_FREE; + + bus->device_count--; + return ret; +} + +DriverResult create_logical_device( + LogicalDevice **logical_device, PhysicalDevice *physical_device, + DeviceDriver *device_driver, DeviceOps *ops, DeviceType type) { + *logical_device = kmalloc(sizeof(LogicalDevice)); + if (logical_device == NULL) return DRIVER_ERROR_OUT_OF_MEMORY; + LogicalDevice *logi = *logical_device; + + logi->kind = DEVICE_KIND_LOGICAL; + logi->state = DEVICE_STATE_UNINIT; + logi->ops = ops; + logi->type = type; + logi->physical_device = physical_device; + list_add_tail( + &logi->logical_device_list, &physical_device->logical_device_lh); + + if (device_managers[type] != NULL) { + DeviceManager *manager = device_managers[type]; + list_add_tail(&logi->dm_device_list, &manager->device_lh); + } + + return DRIVER_OK; +} + +DriverResult delete_logical_device(LogicalDevice *logical_device) { + DeviceOps *ops = logical_device->ops; + DeviceState state = logical_device->state; + DriverResult ret = DRIVER_OK; + + if (ops->stop && state == DEVICE_STATE_ACTIVE) + DRIVER_RESULT_PASS(ops->stop(logical_device)); + if (ops->destroy && state != DEVICE_STATE_UNINIT) + DRIVER_RESULT_PASS(ops->destroy(logical_device)); + + if (logical_device->object != NULL) { + ObjectResult result = delete_object(logical_device->object); + if (result != OBJECT_OK) ret = DRIVER_ERROR_OBJECT; + } + + int result = 0; + if (!list_empty(&logical_device->dm_device_list)) + list_del(&logical_device->dm_device_list); + + list_del(&logical_device->logical_device_list); + result = kfree(logical_device); + if (result < 0) ret = DRIVER_ERROR_MEMORY_FREE; + + return ret; +} + +DriverResult init_physical_device(PhysicalDevice *device) { + DEV_OPS_CALL(device, init); + device->state = DEVICE_STATE_READY; + return DRIVER_OK; +} + +DriverResult start_physical_device(PhysicalDevice *device) { + DEV_OPS_CALL(device, start); + device->state = DEVICE_STATE_ACTIVE; + return DRIVER_OK; +} + +DriverResult init_logical_device(LogicalDevice *device) { + DeviceManager *manager = device_managers[device->type]; + DEV_OPS_CALL(device, init); + if (manager->ops->init_device_hook != NULL) + manager->ops->init_device_hook(manager, device); + device->state = DEVICE_STATE_READY; + return DRIVER_OK; +} + +DriverResult start_logical_device(LogicalDevice *device) { + DeviceManager *manager = device_managers[device->type]; + DEV_OPS_CALL(device, start); + if (manager->ops->start_device_hook != NULL) + manager->ops->start_device_hook(manager, device); + device->state = DEVICE_STATE_ACTIVE; + return DRIVER_OK; +} diff --git a/src/kernel/driver/device_driver.c b/src/kernel/driver/device_driver.c new file mode 100644 index 0000000..937f425 --- /dev/null +++ b/src/kernel/driver/device_driver.c @@ -0,0 +1,24 @@ +#include +#include +#include +#include +#include +#include + +DriverResult driver_load(DeviceDriver *driver); +DriverResult driver_unload(DeviceDriver *driver); + +DriverResult register_device_driver( + Driver *driver, DeviceDriver *device_driver) { + list_init(&device_driver->device_lh); + list_add_tail( + &device_driver->device_driver_list, &driver->device_driver_lh); + return DRIVER_OK; +} + +DriverResult unregister_device_driver(DeviceDriver *device_driver) { + if (!list_empty(&device_driver->device_lh)) return DRIVER_ERROR_BUSY; + list_del(&device_driver->device_driver_list); + + return DRIVER_OK; +} diff --git a/src/kernel/driver/device_manager.c b/src/kernel/driver/device_manager.c new file mode 100644 index 0000000..4f7772f --- /dev/null +++ b/src/kernel/driver/device_manager.c @@ -0,0 +1,42 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +DeviceManager *device_managers[DEVICE_TYPE_MAX] = { + [DEVICE_TYPE_INTERRUPT_CONTROLLER] = &interrupt_dm, + [DEVICE_TYPE_TIMER] = &timer_dm, + [DEVICE_TYPE_TIME] = &time_dm, + [DEVICE_TYPE_FRAMEBUFFER] = &framebuffer_dm, + [DEVICE_TYPE_STORAGE] = &storage_dm, + [DEVICE_TYPE_INPUT] = &input_dm, + [DEVICE_TYPE_SOUND] = &sound_dm, + [DEVICE_TYPE_INTERNET] = &network_dm, + [DEVICE_TYPE_SERIAL] = &serial_dm, + [DEVICE_TYPE_BUS_CONTROLLER] = &bus_controller_dm, +}; + +DriverResult init_device_managers() { + DeviceManager *device_manager; + for (int i = 0; i < DEVICE_TYPE_MAX; i++) { + device_manager = device_managers[i]; + if (device_manager == NULL) continue; + list_init(&device_manager->device_lh); + if (device_manager->ops->dm_load != NULL) + DRIVER_RESULT_PASS(device_manager->ops->dm_load(device_manager)); + } + return DRIVER_OK; +} diff --git a/src/kernel/driver/dma.c b/src/kernel/driver/dma.c new file mode 100644 index 0000000..70b5717 --- /dev/null +++ b/src/kernel/driver/dma.c @@ -0,0 +1,62 @@ +#include "kernel/driver.h" +#include "kernel/list.h" +#include +#include +#include +#include + +DriverResult dma_split_mem( + list_t *lh, void *ptr, uint32_t size, int max_segment_size) { + DmaSegment *seg; + size_t addr = (size_t)ptr; + size_t end_addr = addr + size; + size_t phy_addr, old_phy_page; + int seg_size = 0, tmp_size = 0; + size_t seg_start; + size_t seg_start_vaddr; + size_t page_addr; + + for (; addr < end_addr; addr += tmp_size) { + phy_addr = vir2phy(addr); + page_addr = phy_addr & ~(PAGE_SIZE - 1); + tmp_size = PAGE_SIZE - (phy_addr & (PAGE_SIZE - 1)); + tmp_size = MIN(tmp_size, size); + + if (seg_size == 0) { + seg_start = phy_addr; + seg_start_vaddr = addr; + seg_size = tmp_size; + } else { + if (page_addr == old_phy_page + PAGE_SIZE && + seg_size + tmp_size < max_segment_size) { + seg_size += tmp_size; + } else { + // 创建新的请求 + seg = kmalloc(sizeof(DmaSegment)); + if (seg == NULL) { return DRIVER_ERROR_OUT_OF_MEMORY; } + + // 设置新请求的参数 + seg->vaddr = seg_start_vaddr; + seg->addr = seg_start; + seg->size = seg_size; + list_add_tail(&seg->list, lh); + + seg_start_vaddr = addr; + seg_start = phy_addr; + seg_size = tmp_size; + } + } + old_phy_page = page_addr; + } + if (seg_size > 0) { + seg = kmalloc(sizeof(DmaSegment)); + if (seg == NULL) { return DRIVER_ERROR_OUT_OF_MEMORY; } + + // 设置新请求的参数 + seg->vaddr = seg_start_vaddr; + seg->addr = seg_start; + seg->size = seg_size; + list_add_tail(&seg->list, lh); + } + return DRIVER_OK; +} \ No newline at end of file diff --git a/src/kernel/driver/driver.c b/src/kernel/driver/driver.c new file mode 100644 index 0000000..f6374ee --- /dev/null +++ b/src/kernel/driver/driver.c @@ -0,0 +1,193 @@ +/** + * @file driver.c + * @author Ryan Wang (ryan1202@foxmail.com) + * @brief 驱动接口 + * @version 0.3 + * @date 2022-07-20 + */ +#include "kernel/periodic_task.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +LIST_HEAD(new_bus_lh); +LIST_HEAD(bus_check_lh); +LIST_HEAD(new_device_lh); +SPINLOCK(device_list_lock); + +Driver core_driver = { + .short_name = STRING_INIT("CoreDriver"), + .state = DRIVER_STATE_UNREGISTERED, +}; + +void print_driver_result( + DriverResult result, char *file, int line, char *func_with_args) { + if (result == DRIVER_OK) return; + printk("[At file %s line%d: %s]", file, line, func_with_args); + switch (result) { + RESULT_CASE_PRINT(DRIVER_OK) + RESULT_CASE_PRINT(DRIVER_ERROR_TIMEOUT) + RESULT_CASE_PRINT(DRIVER_ERROR_CONFLICT) + RESULT_CASE_PRINT(DRIVER_ERROR_NO_OPS) + RESULT_CASE_PRINT(DRIVER_ERROR_OBJECT) + RESULT_CASE_PRINT(DRIVER_ERROR_INCOMPLETABLE_OPS) + RESULT_CASE_PRINT(DRIVER_ERROR_INVALID_IRQ_NUMBER) + RESULT_CASE_PRINT(DRIVER_ERROR_OUT_OF_MEMORY) + RESULT_CASE_PRINT(DRIVER_ERROR_ALREADY_EXIST) + RESULT_CASE_PRINT(DRIVER_ERROR_NOT_EXIST) + RESULT_CASE_PRINT(DRIVER_ERROR_NULL_POINTER) + RESULT_CASE_PRINT(DRIVER_ERROR_UNSUPPORT_DEVICE) + RESULT_CASE_PRINT(DRIVER_ERROR_UNSUPPORT_FEATURE) + RESULT_CASE_PRINT(DRIVER_ERROR_INVALID_TYPE) + RESULT_CASE_PRINT(DRIVER_ERROR_WAITING) + RESULT_CASE_PRINT(DRIVER_ERROR_MEMORY_FREE) + RESULT_CASE_PRINT(DRIVER_ERROR_BUSY) + RESULT_CASE_PRINT(DRIVER_ERROR_EXCEED_MAX_SIZE) + RESULT_CASE_PRINT(DRIVER_ERROR_OTHER) + } +} + +DriverResult register_driver(Driver *driver) { + driver->state = DRIVER_STATE_REGISTERED; + list_init(&driver->device_driver_lh); + list_init(&driver->remapped_memory_lh); + + return DRIVER_OK; +} + +DriverResult unregister_driver(Driver *driver) { + return DRIVER_OK; +} + +void device_detect(void *arg) { + Bus *bus, *next; + PhysicalDevice *phy, *phy_next; + LogicalDevice *logi; + list_for_each_owner_safe (bus, next, &bus_check_lh, bus_check_list) { + if (bus->ops->probe_device != NULL) + bus->ops->probe_device(bus->bus_driver, bus); + list_for_each_owner_safe (phy, phy_next, &bus->device_lh, device_list) { + if (phy->state != DEVICE_STATE_UNINIT) continue; + spin_lock(&device_list_lock); + list_add_tail(&phy->new_device_list, &new_device_lh); + spin_unlock(&device_list_lock); + } + } + while (!list_empty(&new_device_lh)) { + spin_lock(&device_list_lock); + phy = list_first_owner_or_null( + &new_device_lh, PhysicalDevice, new_device_list); + spin_unlock(&device_list_lock); + if (phy == NULL) { + schedule(); + continue; + } + if (phy->ops == NULL) { // 没有绑定驱动 + spin_lock(&device_list_lock); + list_del(&phy->new_device_list); + spin_unlock(&device_list_lock); + continue; + } + if (phy->state == DEVICE_STATE_UNINIT) init_physical_device(phy); + if (phy->state == DEVICE_STATE_READY) start_physical_device(phy); + list_for_each_owner ( + logi, &phy->logical_device_lh, logical_device_list) { + if (logi->state == DEVICE_STATE_UNINIT) init_logical_device(logi); + if (logi->state == DEVICE_STATE_READY) start_logical_device(logi); + } + spin_lock(&device_list_lock); + list_del(&phy->new_device_list); + spin_unlock(&device_list_lock); + } +} + +void start_devices(void *arg) { + Bus *bus, *next; + PhysicalDevice *phy, *phy_next; + LogicalDevice *logi; + while (!(list_empty(&new_bus_lh) && list_empty(&new_device_lh))) { + list_for_each_owner_safe (bus, next, &new_bus_lh, new_bus_list) { + if (bus->ops->scan_bus != NULL) + bus->ops->scan_bus(bus->bus_driver, bus); + if (bus->ops->probe_device != NULL) + bus->ops->probe_device(bus->bus_driver, bus); + list_for_each_owner_safe ( + phy, phy_next, &bus->device_lh, device_list) { + if (phy->state != DEVICE_STATE_UNINIT) continue; + spin_lock(&device_list_lock); + list_add_tail(&phy->new_device_list, &new_device_lh); + spin_unlock(&device_list_lock); + } + list_del(&bus->new_bus_list); + } + while (!list_empty(&new_device_lh)) { + spin_lock(&device_list_lock); + phy = list_first_owner_or_null( + &new_device_lh, PhysicalDevice, new_device_list); + spin_unlock(&device_list_lock); + if (phy == NULL) { + schedule(); + continue; + } + if (phy->ops == NULL) { // 没有绑定驱动 + spin_lock(&device_list_lock); + list_del(&phy->new_device_list); + spin_unlock(&device_list_lock); + continue; + } + if (phy->state == DEVICE_STATE_UNINIT) { + DriverResult result = init_physical_device(phy); + if (result == DRIVER_ERROR_WAITING) { + // 设备初始化需要等待,跳过 + spin_lock(&device_list_lock); + list_del(&phy->new_device_list); + list_add_tail(&phy->new_device_list, &new_device_lh); + spin_unlock(&device_list_lock); + continue; + } + } + if (phy->state == DEVICE_STATE_READY) start_physical_device(phy); + list_for_each_owner ( + logi, &phy->logical_device_lh, logical_device_list) { + if (logi->state == DEVICE_STATE_UNINIT) + init_logical_device(logi); + if (logi->state == DEVICE_STATE_READY) + start_logical_device(logi); + } + spin_lock(&device_list_lock); + list_del(&phy->new_device_list); + spin_unlock(&device_list_lock); + } + } +} + +PeriodicTask driver_periodic_task = { + .func = device_detect, + .arg = NULL, +}; + +DriverResult driver_start_all(void) { + thread_start( + "Start Devices", THREAD_DEFAULT_PRIO, start_devices, NULL, NULL); + while (!(list_empty(&new_bus_lh) && list_empty(&new_device_lh))) { + schedule(); + } + + periodic_task_add(&driver_periodic_task); + + return DRIVER_OK; +} diff --git a/src/kernel/driver/driver_interface.c b/src/kernel/driver/driver_interface.c new file mode 100644 index 0000000..559c7a7 --- /dev/null +++ b/src/kernel/driver/driver_interface.c @@ -0,0 +1,123 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +list_t device_irq_lists[16] = { + LIST_HEAD_INIT(device_irq_lists[0]), LIST_HEAD_INIT(device_irq_lists[1]), + LIST_HEAD_INIT(device_irq_lists[2]), LIST_HEAD_INIT(device_irq_lists[3]), + LIST_HEAD_INIT(device_irq_lists[4]), LIST_HEAD_INIT(device_irq_lists[5]), + LIST_HEAD_INIT(device_irq_lists[6]), LIST_HEAD_INIT(device_irq_lists[7]), + LIST_HEAD_INIT(device_irq_lists[8]), LIST_HEAD_INIT(device_irq_lists[9]), + LIST_HEAD_INIT(device_irq_lists[10]), LIST_HEAD_INIT(device_irq_lists[11]), + LIST_HEAD_INIT(device_irq_lists[12]), LIST_HEAD_INIT(device_irq_lists[13]), + LIST_HEAD_INIT(device_irq_lists[14]), LIST_HEAD_INIT(device_irq_lists[15]), +}; + +DriverResult register_device_irq( + DEF_MRET(DeviceIrq *, device_irq), PhysicalDevice *physical_device, + void *arg, int irq, DeviceIrqHandler irq_handler, IrqMode mode) { + if (irq > 16) { + print_error( + "DeviceIrq", "invalid irq number:%d, device %s\n", irq, + physical_device->object->name.text); + return DRIVER_ERROR_INVALID_IRQ_NUMBER; + } + + DeviceIrq *device_irq = + list_first_owner_or_null(&device_irq_lists[irq], DeviceIrq, irq_list); + if (device_irq != NULL && mode == IRQ_MODE_EXCLUSIVE) { + print_error( + "DeviceIrq", + "Conflict irq number:%d, registered device %s, new device %s\n", + irq, device_irq->physical_device->object->name.text, + physical_device->object->name.text); + return DRIVER_ERROR_CONFLICT; + } + + device_irq = kmalloc(sizeof(DeviceIrq)); + if (device_irq == NULL) return DRIVER_ERROR_OUT_OF_MEMORY; + device_irq->arg = arg; + device_irq->physical_device = physical_device; + device_irq->handler = irq_handler; + device_irq->irq = interrupt_redirect_irq(irq); + + MRET(device_irq) = device_irq; + return DRIVER_OK; +} + +DriverResult unregister_device_irq(DeviceIrq *dev_irq) { + list_del(&dev_irq->list); + list_del(&dev_irq->irq_list); + int result = kfree(dev_irq); + if (result < 0) return DRIVER_ERROR_MEMORY_FREE; + return DRIVER_OK; +} + +DriverResult enable_device_irq(DeviceIrq *dev_irq) { + bool empty = list_empty(&device_irq_lists[dev_irq->irq]); + if (!list_in_list(&dev_irq->list)) + list_add_tail(&dev_irq->list, &device_irq_lists[dev_irq->irq]); + if (empty) { return interrupt_enable_irq(dev_irq->irq); } + return DRIVER_OK; +} + +DriverResult disable_device_irq(DeviceIrq *dev_irq) { + if (list_in_list(&dev_irq->list)) list_del(&dev_irq->list); + if (list_empty(&device_irq_lists[dev_irq->irq])) { + return interrupt_disable_irq(dev_irq->irq); + } + return DRIVER_OK; +} + +void device_irq_handler(int irq) { + DeviceIrq *cur; + if (list_empty(&device_irq_lists[irq])) return; + list_for_each_owner (cur, &device_irq_lists[irq], list) { + cur->handler(cur->arg); + } +} + +DriverResult driver_remap_memory( + Driver *in_driver, uint32_t in_physical_address, uint32_t in_size, + uint32_t *out_virtual_address) { + // 地址对齐页大小 + uint32_t start = in_physical_address & 0xfffff000; + uint32_t end = (in_physical_address + in_size + 0xfff) & 0xfffff000; + uint32_t tmp; + uint32_t virtual_address = 0; + + // 调用前先检查是否已经被映射 + DriverRemappedMemory *cur; + list_for_each_owner (cur, &in_driver->remapped_memory_lh, list) { + if (cur->phy_start < start && cur->phy_start + cur->size > end) { + virtual_address = cur->vir_start; + return DRIVER_OK; + } + } + + MemoryResult result = + MEMORY_RESULT_PRINT_CALL(remap, start, end - start, &tmp); + if (result != MEMORY_RESULT_OK) { + printk( + "Driver Interface: remap memory:0x%08x(size: %d) failed\n", + in_physical_address, in_size); + return DRIVER_ERROR_OTHER; + } + if (virtual_address == 0) { virtual_address = tmp; } + + DriverRemappedMemory *remapped_memory = + kmalloc(sizeof(DriverRemappedMemory)); + remapped_memory->size = end - start; + remapped_memory->vir_start = virtual_address; + remapped_memory->phy_start = start; + list_add_tail(&remapped_memory->list, &in_driver->remapped_memory_lh); + *out_virtual_address = virtual_address; + return DRIVER_OK; +} diff --git a/src/kernel/elf.c b/src/kernel/elf.c index 87b81f9..5b82947 100644 --- a/src/kernel/elf.c +++ b/src/kernel/elf.c @@ -17,37 +17,38 @@ * @param prog * @return unsigned int* */ -unsigned int *elf_load(struct program_struct *prog) { - struct elf32_header header; - prog->inode->f_ops.seek(prog->inode, 0, 0); - prog->inode->f_ops.read(prog->inode, (uint8_t *)&header, sizeof(struct elf32_header)); +// unsigned int *elf_load(struct program_struct *prog) { +// struct elf32_header header; +// seek(prog->inode, 0, 0); +// read(prog->inode, (uint8_t *)&header, sizeof(struct elf32_header)); - if (memcmp(header.e_ident, "\177ELF\1\1\1", 7) || header.e_type != ELF32_ET_EXEC || - header.e_machine != ELF32_EM_386 || header.e_version != 1 || header.e_phnum > 1024 || - header.e_phentsize != sizeof(struct elf32_program_header)) { - printk("Error:unsupported executable file!\n"); - return NULL; - } +// if (memcmp(header.e_ident, "\177ELF\1\1\1", 7) || +// header.e_type != ELF32_ET_EXEC || header.e_machine != ELF32_EM_386 || +// header.e_version != 1 || header.e_phnum > 1024 || +// header.e_phentsize != sizeof(struct elf32_program_header)) { +// printk("Error:unsupported executable file!\n"); +// return NULL; +// } - struct elf32_program_header pheader; - Elf32_Off prog_header_off = header.e_phoff; - Elf32_Half prog_header_size = header.e_phentsize; +// struct elf32_program_header pheader; +// Elf32_Off prog_header_off = header.e_phoff; +// Elf32_Half prog_header_size = header.e_phentsize; - unsigned long i; - prog->phnum = header.e_phnum; - for (i = 0; i < header.e_phnum; i++) { - memset(&pheader, 0, prog_header_size); - prog->inode->f_ops.seek(prog->inode, prog_header_off, 0); - prog->inode->f_ops.read(prog->inode, (uint8_t *)&pheader, prog_header_size); - if (pheader.p_type == PT_LOAD) { - struct prog_segment *progseg = kmalloc(sizeof(struct prog_segment)); - progseg->vaddr = pheader.p_vaddr; - progseg->filesz = pheader.p_filesz; - progseg->memsz = pheader.p_memsz; - progseg->offset = pheader.p_offset; - list_add_tail(&progseg->list, &prog->seg_head); - } - prog_header_off += prog_header_size; - } - return (unsigned int *)header.e_entry; -} \ No newline at end of file +// unsigned long i; +// prog->phnum = header.e_phnum; +// for (i = 0; i < header.e_phnum; i++) { +// memset(&pheader, 0, prog_header_size); +// seek(prog->inode, prog_header_off, 0); +// read(prog->inode, (uint8_t *)&pheader, prog_header_size); +// if (pheader.p_type == PT_LOAD) { +// struct prog_segment *progseg = kmalloc(sizeof(struct prog_segment)); +// progseg->vaddr = pheader.p_vaddr; +// progseg->filesz = pheader.p_filesz; +// progseg->memsz = pheader.p_memsz; +// progseg->offset = pheader.p_offset; +// list_add_tail(&progseg->list, &prog->seg_head); +// } +// prog_header_off += prog_header_size; +// } +// return (unsigned int *)header.e_entry; +// } \ No newline at end of file diff --git a/src/kernel/font-default.c b/src/kernel/font-default.c index 34209fd..e5ca688 100644 --- a/src/kernel/font-default.c +++ b/src/kernel/font-default.c @@ -658,17 +658,17 @@ unsigned char font16[] = { // 0x26 & 0b00000000, 0b00000000, - 0b00000000, - 0b00110000, - 0b01001000, - 0b01001000, - 0b01001000, 0b00110000, + 0b01111000, + 0b11001100, + 0b11001100, + 0b11001100, + 0b01111000, 0b00110001, - 0b01001011, - 0b10000110, - 0b10001011, - 0b10010001, + 0b01111011, + 0b11000110, + 0b11001111, + 0b11011001, 0b01110000, 0b00000000, 0b00000000, @@ -727,13 +727,13 @@ unsigned char font16[] = { 0b00000000, 0b00000000, 0b00000000, - 0b00001000, - 0b01001001, - 0b00111011, - 0b00011100, - 0b00101010, - 0b01001001, - 0b00001000, + 0b00011000, + 0b11011011, + 0b01111110, + 0b00111100, + 0b01111110, + 0b11011011, + 0b00011000, 0b00000000, 0b00000000, 0b00000000, @@ -1491,15 +1491,15 @@ unsigned char font16[] = { // 0x57 W 0b00000000, 0b00000000, - 0b10000001, - 0b10000001, - 0b10000001, - 0b01000010, - 0b01011010, - 0b01011010, - 0b01011010, - 0b01011010, - 0b01011010, + 0b11000011, + 0b11000011, + 0b11000011, + 0b11000011, + 0b11011011, + 0b11011011, + 0b01111110, + 0b01111110, + 0b01111110, 0b01100110, 0b01100110, 0b01100110, @@ -1585,7 +1585,7 @@ unsigned char font16[] = { 0b00001000, 0b00000100, 0b00000100, - 0000000010, + 0b00000010, 0b00000010, 0b00000011, 0b00000000, diff --git a/src/kernel/initcall.c b/src/kernel/initcall.c index 925b82e..69b6b9e 100644 --- a/src/kernel/initcall.c +++ b/src/kernel/initcall.c @@ -8,6 +8,7 @@ */ #include #include +#include extern initcall_t __initcall_start[]; extern initcall_t __initcall_end[]; @@ -15,12 +16,10 @@ extern exitcall_t __exitcall_start[]; extern exitcall_t __exitcall_end[]; void do_initcalls(void) { - init_dm(); initcall_t *func = &(*__initcall_start); for (; func < &(*__initcall_end); func++) { (*func)(); } - driver_inited(); } void do_exitcalls(void) { diff --git a/src/kernel/main.c b/src/kernel/main.c index 45861c9..a777f68 100644 --- a/src/kernel/main.c +++ b/src/kernel/main.c @@ -4,86 +4,174 @@ * @brief 内核主程序 * @date 2020-03 */ -#include +#include "driver/timer/timer_dm.h" +#include "objects/transfer.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include -#include #include +#include #include +#include +#include #include +#include #include #include +#include #include #include +#include #include #include #include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include #include #include void idle(void *arg); struct task_s *task_idle; +extern Driver core_driver; + +// void print_permission(Permission *permission) { +// printk("Subject ID:%d\n", permission->subject_id); +// printk("Permission:"); +// if (permission->permission.visible) { printk("Visible "); } +// if (permission->permission.read) { printk("Read "); } +// if (permission->permission.write) { printk("Write "); } +// if (permission->permission.execute) { printk("Execute "); } +// if (permission->permission.delete) { printk("Delete "); } +// if (permission->permission.rename) { printk("Rename "); } +// if (permission->permission.set_attr) { printk("SetAttr "); } +// printk("\n"); +// } + +void thread_play(void *arg) { + Object *object; + ObjectResult result = open_object_by_path("\\Device\\Sound0", &object); + if (result != OBJECT_OK) { + printk("Open File Error!\n"); + } else { + Object *file; + result = + open_object_by_path("\\Volumes\\Storage0Volume0\\1.pcm", &file); + + if (result == OBJECT_OK) { + ObjectHandle *handle = object_handle_create(file); + PcmDevice *pcm; + PcmStream *stream; + sound_pcm_open(object, SOUND_DEVICE_MODE_PLAY, &pcm, &stream); + sound_pcm_alloc(stream); + pcm_set_sample_rate(pcm, 44100); + pcm_set_channel(stream, 2); + sound_pcm_set_frame_count(stream, 4 * 1024); + sound_pcm_prepare(stream); + ObjectAttr attr; + obj_get_attr(file, &attr); + size_t count = 16 * 64; + size_t size = 18 * 1024 * 1024; + uint8_t *buf = kmalloc(19 * 1024 * 1024); + for (int i = 0; i < size / 1024 / 1024; i++) { + TransferResult result = TRANSFER_IN_STREAM( + file, handle, buf + i * 1024 * 1024, 1024 * 1024); + if (result != TRANSFER_OK) { + printk("Transfer Error!\n"); + thread_exit(); + } + } + for (int i = 0; i < count; i++) { + sound_pcm_write(stream, buf, 4 * 1024); + buf += 16 * 1024; + } + } + } +} + +void network_timer_init(void); int main() { + platform_early_init(); + + uint8_t *zero = 0; + + init_memory(); + init_object_tree(); + init_device_managers(); + init_bus_manager(); + + register_driver(&core_driver); + platform_init(); + platform_start_devices(); + init_task(); - task_idle = thread_start("Idle", 1, idle, 0); - init_pci(); + task_idle = thread_start("Idle", 1, idle, 0, NULL); io_sti(); printk("Memory Size:%dM\n", get_memory_size()); - init_vfs(); + thread_start( + "Kernel Periodic Tasks", THREAD_DEFAULT_PRIO, periodic_task, NULL, + NULL); + do_initcalls(); - init_fs(); + driver_start_all(); - thread_start( - "NetworkRxPacketProcess", THREAD_DEFAULT_PRIO, net_process_pack, NULL); + Object *net; + ObjectResult result = open_object_by_path("\\Device\\Network0", &net); + if (result == OBJECT_OK) { + dhcp_start(net->value.device.logical->dm_ext); + // uint8_t dst_mac[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + // uint8_t dst_ip[] = {10, 0, 2, 2}; + // uint8_t udp_data[] = "Hello, World!"; + + // NetworkConnection *conn = net_create_conn(net); + // conn->buffer = net_buffer_create(128); + // net_buffer_init(conn->buffer, 128, 0, 0); + + // eth_register(conn); + // ipv4_register(conn, NULL); + // udp_register(conn); - // int ret = dhcp_main(default_net_dev); - // while (ret == -4) { - // ret = dhcp_main(default_net_dev); + // // conn_put(conn, udp_data, sizeof(udp_data)); + + // udp_wrap(conn, 1234, 22); + // ipv4_wrap(conn, IP_PROTO_UDP, dst_ip, 64); + // eth_wrap(conn, dst_mac, ETH_PROTO_TYPE_IPV4); + // TRANSFER_OUT_STREAM( + // net, conn->handle, conn->buffer->head, + // conn->buffer->tail - conn->buffer->head); + } + + // bios_emu_env.regs.ax = 0x4f02; + // bios_emu_env.regs.bx = 0x4192; // + // 1920x1080x32bit模式 BiosEmuExceptions exception = + // emu_interrupt(0x10); // 调用BIOS 0x10中断 FrameBufferDevice + // *fb_device; framebuffer_get_device(0, &fb_device); + // fb_device->mode_info.width = 1920; + // fb_device->mode_info.height = 1080; + // init_console(); // 重置控制台配置 + // if (exception == EventInterruptDone) { + // printk("VBE Call Result: %d\n", bios_emu_env.regs.ax); + // } else { + // printk("VBE Error: %d\n", exception); // } - // if (ret < 0) { printk("[DHCP]ipv4 address request failed!\n"); } - // struct ipv4_data *ipv4 = default_net_dev->info->ipv4_data; - // memcpy(ipv4->ip_addr, (uint8_t[4]){10, 0, 2, 15}, 4); - // memcpy(ipv4->router_ip, (uint8_t[4]){10, 0, 2, 2}, 4); - - // uint8_t dst_ip[4] = {180, 101, 50, 188}, *router_mac; - // netc_t *netc = netc_create(default_net_dev, ETH_TYPE_ARP, 0); - // netc_set_dest(netc, broadcast_mac, NULL, 0); - // router_mac = ip2mac( - // netc, ((struct ipv4_data *)netc->net_dev->info->ipv4_data)->router_ip); - // netc_delete(netc); - - // netc = netc_create(default_net_dev, ETH_TYPE_IPV4, PROTOCOL_TCP); - // netc_set_dest(netc, router_mac, dst_ip, 4); - // tcp_create(netc); - // tcp_bind(netc, 12345); - // tcp_ipv4_connect(netc, dst_ip, 80); - // uint8_t data[] = "GET / HTTP/1.1\r\nHost: 180.101.50.188\r\nAccept: " - // "*/*\r\nConnection: keep-alive\r\n\r\n"; - // uint8_t *rb = kmalloc(2048); - // tcp_write(netc, data, sizeof(data)); - // int len = 10499; - // int i, tmp; - // do { - // tmp = tcp_read(netc, rb, 1152); - // len -= tmp; - // // for (i = 0; i < tmp; i++) { - // // printk("%c", rb[i]); - // // } - // } while (len > 0); - // printk("\nend.\n"); - // tcp_ipv4_close(netc); + + // thread_start("play", 100, thread_play, NULL, NULL); console_start(); + thread_exit(); for (;;) { io_hlt(); } @@ -91,6 +179,6 @@ int main() { void idle(void *arg) { for (;;) { - io_hlt(); + schedule(); } } diff --git a/src/kernel/memory.c b/src/kernel/memory.c index 5e12c7d..ae052d0 100644 --- a/src/kernel/memory.c +++ b/src/kernel/memory.c @@ -5,6 +5,8 @@ * @version 0.1 * @date 2020-07 */ +#include "kernel/driver_interface.h" +#include "kernel/list.h" #include #include #include @@ -23,6 +25,12 @@ struct memory_manage *memory_manage; uint32_t memory_total_size; +const int memory_block_size[MEMORY_FREE_LIST_COUNT] = {32, 64, 128, 256, + 512, 1024, 2048}; + +extern void new_vir(void); +extern void new_phy(void); + void init_memory(void) { uint16_t ards_nr = *((uint16_t *)ards_nr_addr); // ards 结构数 ards = (struct ards *)ards_addr; // ards 地址 @@ -57,10 +65,17 @@ void init_memory(void) { memory_manage = (struct memory_manage *)kernel_alloc_pages(memory_manage_pages); memset(memory_manage, 0, memory_manage_pages * PAGE_SIZE); + memory_manage->last_free_block = 0; + for (i = 0; i < MEMORY_FREE_LIST_COUNT; i++) { + list_init(&memory_manage->free_blocks_list[i]); + } for (i = 0; i < MEMORY_BLOCKS; i++) { memory_manage->free_blocks[i].size = 0; // 大小是页的数量 memory_manage->free_blocks[i].flags = 0; } + + new_phy(); + new_vir(); } int get_memory_size(void) { @@ -81,9 +96,9 @@ int mmap_search(struct mmap *btmp, unsigned int cnt) { int index_start = index_byte * 8 + index_bit; if (cnt == 1) { return index_start; } - int bit_left = btmp->len * 8 - index_start; + int bit_left = btmp->len * 8 - index_start - 1; int next_bit = index_start + 1; - int count = 0; + int count = 1; while (bit_left-- > 0) { if (!(btmp->bits[next_bit / 8] & 1 << (next_bit % 8))) { count++; @@ -98,7 +113,7 @@ int mmap_search(struct mmap *btmp, unsigned int cnt) { void mmap_set(struct mmap *btmp, unsigned int bit_index, int value) { unsigned int byte_idx = bit_index / 8; // 向下取整用于索引数组下标 - unsigned int bit_odd = bit_index % 8; // 取余用于索引数组内的位 + unsigned int bit_odd = bit_index % 8; // 取余用于索引数组内的位 /* 一般都会用个0x1这样的数对字节中的位操作, * 将1任意移动后再取反,或者先取反再移位,可用来对位置0操作。*/ @@ -109,147 +124,213 @@ void mmap_set(struct mmap *btmp, unsigned int bit_index, int value) { } } -unsigned long alloc_vaddr(size_t size) { - size = ((size + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1)); - if (!size) return 0; +int mmap_get(struct mmap *btmp, uint32_t bit_index) { + uint32_t byte_idx = bit_index / 8; + uint32_t bit_odd = bit_index % 8; + return (btmp->bits[byte_idx] & (1 << bit_odd)) != 0; +} + +MemoryResult alloc_vaddr(size_t in_size, uint32_t *out_vaddr) { + in_size = ((in_size + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1)); + if (!in_size) return MEMORY_RESULT_INVALID_INPUT; - int pages = size / PAGE_SIZE; + uint32_t pages = in_size / PAGE_SIZE; /* 扫描获取请求的页数 */ int idx = mmap_search(&vir_page_mmap, pages); - if (idx == -1) return 0; + if (idx == -1) return MEMORY_RESULT_OUT_OF_MEMORY; int i; - /* 把已经扫描到的位置1,表明已经分配了 */ + /* 把已经扫描到的位设置为1,表明已经分配了 */ for (i = 0; i < pages; i++) { mmap_set(&vir_page_mmap, idx + i, 1); } /* 返还转换好的虚拟地址 */ - return KERN_VIR_MEM_BASE_ADDR + VIR_MEM_BASE_ADDR + idx * PAGE_SIZE; + *out_vaddr = KERN_VIR_MEM_BASE_ADDR + VIR_MEM_BASE_ADDR + idx * PAGE_SIZE; + return MEMORY_RESULT_OK; +} + +int find_continuous_free_block(struct memory_manage *mm, int count) { + int k; + for (k = mm->last_free_block; k < MEMORY_BLOCKS; k++) { + if (mm->free_blocks[k].flags == MEMORY_BLOCK_FREE) { + for (int i = 0; i < count; i++) { + if (mm->free_blocks[k + i].flags != MEMORY_BLOCK_FREE) { + break; + } + } + } + } + if (k == MEMORY_BLOCKS) { + for (k = 0; k < mm->last_free_block; k++) { + for (int i = 0; i < count; i++) { + if (mm->free_blocks[k + i].flags != MEMORY_BLOCK_FREE) { + break; + } + } + } + if (k == mm->last_free_block) return -1; + } + mm->last_free_block = k + count; + return k; +} + +int find_free_block(struct memory_manage *mm) { + int i; + for (i = mm->last_free_block; i < MEMORY_BLOCKS; i++) { + if (mm->free_blocks[i].flags == MEMORY_BLOCK_FREE) { + mm->last_free_block = i; + return i; + } + } + for (i = 0; i < mm->last_free_block; i++) { + if (mm->free_blocks[i].flags == MEMORY_BLOCK_FREE) { + mm->last_free_block = i; + return i; + } + } + return -1; +} + +bool split_page(struct memory_manage *mm, size_t page_addr, int pow) { + uint32_t size = 1 << pow; + int break_cnt = PAGE_SIZE >> pow; // 打散成break_cnt个 + + int index = find_free_block(mm); + if (index == -1) return false; + index--; // 因为下面会自增,所以这里先-1 + + uint32_t addr = page_addr; + for (int i = 0; i < break_cnt; i++) { + index++; + if (mm->free_blocks[index].size || index >= MEMORY_BLOCKS) { + index = find_free_block(mm); + if (index == -1) return false; + } + mm->free_blocks[index].address = addr; + mm->free_blocks[index].size = size; + mm->free_blocks[index].flags = MEMORY_BLOCK_USING; + mm->free_blocks[index].mode = MEMORY_BLOCK_MODE_SMALL; + list_add_tail( + &mm->free_blocks[index].list, + &mm->free_blocks_list[pow - MEMORY_MIN_POW]); + addr += size; + } + return true; } // 默认对齐32字节 void *kmalloc(uint32_t size) { - int i; - uint32_t address; - uint32_t break_size; // 要打碎成什么大小 - uint32_t break_cnt; // 要打碎成几块 - void *new_address; - - // 大于1024字节就用页 - if (size >= 2048) { - int pages = DIV_ROUND_UP(size, PAGE_SIZE); // 一共占多少个页 - for (i = 0; i < MEMORY_BLOCKS; i++) { - if (memory_manage->free_blocks[i].flags == - MEMORY_BLOCK_FREE) { // 找到 - address = (uint32_t)kernel_alloc_pages(pages); // 分配页 - memory_manage->free_blocks[i].address = address; - memory_manage->free_blocks[i].size = pages; // 大小是页的数量 - memory_manage->free_blocks[i].flags = MEMORY_BLOCK_USING; - memory_manage->free_blocks[i].mode = MEMORY_BLOCK_MODE_BIG; - // printk("Found pages "); - // printk("Alloc:%x idx:%d\n", address,i); - return (void *)address; - } + void *address; + void *new_address; + + if (size == 0) { return NULL; } + + int flags = save_and_disable_interrupt(); // TODO + // 大于半个页就按页分配 + if (size > 2048) { + int pages = (size + PAGE_SIZE - 1) >> 12; // 一共占多少个页 + int index = find_free_block(memory_manage); + if (index == -1) { + store_interrupt_status(flags); + return NULL; } - } else if (0 < size && size <= 2048) { // size <= 2048 - // 对齐判断,要打散成多大 - if (0 < size && size <= 32) { - break_size = 32; - } else if (32 < size && size <= 64) { - break_size = 64; - } else if (64 < size && size <= 128) { - break_size = 128; - } else if (128 < size && size <= 256) { - break_size = 256; - } else if (256 < size && size <= 512) { - break_size = 512; - } else if (512 < size && size <= 1024) { - break_size = 1024; - } else if (1024 < size && size <= 2048) { - break_size = 2048; + address = kernel_alloc_pages(pages); // 分配页 + if (address == NULL) { + store_interrupt_status(flags); + return NULL; } + memory_manage->free_blocks[index].address = (uint32_t)address; + memory_manage->free_blocks[index].size = pages; // 大小是页的数量 + memory_manage->free_blocks[index].flags = MEMORY_BLOCK_ALLOCATED; + memory_manage->free_blocks[index].mode = MEMORY_BLOCK_MODE_BIG; + store_interrupt_status(flags); + return (void *)address; + } else if (0 < size && size <= 2048) { // size <= 2048 + int pow = MAX(aligned_up_log2n(size), MEMORY_MIN_POW); // 指数 + size = 1 << pow; // 第一次寻找,如果在块中没有找到,就打散一个页 - for (i = 0; i < MEMORY_BLOCKS; i++) { - if (memory_manage->free_blocks[i].size == break_size && - memory_manage->free_blocks[i].flags == - MEMORY_BLOCK_FREE) { // 找到 - address = memory_manage->free_blocks[i].address; - memory_manage->free_blocks[i].flags = MEMORY_BLOCK_USING; - // printk("Found broken "); - // printk("Alloc:%x idx:%d\n", address,i); - return (void *)address; - } + if (!list_empty( + &memory_manage->free_blocks_list[pow - MEMORY_MIN_POW])) { + struct memory_block *block = list_first_owner( + &memory_manage->free_blocks_list[pow - MEMORY_MIN_POW], + struct memory_block, list); + address = (void *)block->address; + block->flags = MEMORY_BLOCK_ALLOCATED; + list_del(&block->list); + store_interrupt_status(flags); + return (void *)address; } // 如果都没有找到,分配一个页,然后打散 // 分配一个页,用来被打散 new_address = kernel_alloc_pages(1); - break_cnt = PAGE_SIZE / break_size; - - // 打散成break_cnt个 - for (i = 0; i < MEMORY_BLOCKS; i++) { - if (memory_manage->free_blocks[i].flags == - MEMORY_BLOCK_FREE) { // 找到一个可以被使用的 - // 地址增加 - - // 设置最终地址 - memory_manage->free_blocks[i].address = (uint32_t)new_address; - new_address += break_size; - // 设置size - memory_manage->free_blocks[i].size = break_size; - // 设置为可以分配 - memory_manage->free_blocks[i].flags = MEMORY_BLOCK_FREE; - // 设置为小块模式 - memory_manage->free_blocks[i].mode = MEMORY_BLOCK_MODE_SMALL; - break_cnt--; - if (break_cnt <= 0) { break; } - } + if (new_address == NULL) { + store_interrupt_status(flags); + return NULL; } - // 打散后的寻找 - for (i = 0; i < MEMORY_BLOCKS; i++) { - if (memory_manage->free_blocks[i].size == break_size && - memory_manage->free_blocks[i].flags == - MEMORY_BLOCK_FREE) { // 找到 - address = memory_manage->free_blocks[i].address; - memory_manage->free_blocks[i].flags = MEMORY_BLOCK_USING; - // printk("Found new broken "); - // printk("Alloc:%x idx:%d\n", address,i); - return (void *)address; - } + if (!split_page(memory_manage, (size_t)new_address, pow)) { + store_interrupt_status(flags); + return NULL; } + + // 打散后再寻找 + struct memory_block *block = list_first_owner( + &memory_manage->free_blocks_list[pow - MEMORY_MIN_POW], + struct memory_block, list); + address = (void *)block->address; + block->flags = MEMORY_BLOCK_ALLOCATED; + list_del(&block->list); + store_interrupt_status(flags); + return (void *)address; } // size=0或者没有找到 + store_interrupt_status(flags); return NULL; // 失败 } int kfree(void *address) { - int i; - uint32_t addr = (uint32_t)address; + if (address == NULL) { return 0; } + int i; + uint32_t addr = (uint32_t)address; + struct memory_block *block; + + int flags = save_and_disable_interrupt(); for (i = 0; i < MEMORY_BLOCKS; i++) { - if (memory_manage->free_blocks[i].address == addr && - memory_manage->free_blocks[i].flags == MEMORY_BLOCK_USING) { // 找到 - if (memory_manage->free_blocks[i].mode == MEMORY_BLOCK_MODE_BIG) { - kernel_free_page( - memory_manage->free_blocks[i].address, - memory_manage->free_blocks[i].size); - memory_manage->free_blocks[i].size = - 0; // 只有大块才需要重新设置size - } else if ( - memory_manage->free_blocks[i].mode == MEMORY_BLOCK_MODE_SMALL) { - // 小块内存就清空就是了 - memset( - (void *)memory_manage->free_blocks[i].address, 0, - memory_manage->free_blocks[i].size); + block = &memory_manage->free_blocks[i]; + if (block->address == addr && block->flags == MEMORY_BLOCK_ALLOCATED) { + if (block->mode == MEMORY_BLOCK_MODE_BIG) { + kernel_free_page(block->address, block->size); + block->flags = MEMORY_BLOCK_FREE; + block->size = 0; // 只有大块才需要重新设置size + store_interrupt_status(flags); + return 0; + } else if (block->mode == MEMORY_BLOCK_MODE_SMALL) { + int pow = aligned_up_log2n(block->size); + block->flags = MEMORY_BLOCK_USING; + list_add_tail( + &block->list, + &memory_manage->free_blocks_list[pow - MEMORY_MIN_POW]); // 存在一种情况,那就是所有被打散的内存都被释放后,可能需要释放那个页,目前还没有考虑它 // 小块不需要设置大小,因为就是打散了的块 + store_interrupt_status(flags); + return 0; } - memory_manage->free_blocks[i].flags = MEMORY_BLOCK_FREE; - - // printk("Free:%x idx:%d\n", address,i); - return 0; } } return -1; // 失败 } + +void print_memory_result( + MemoryResult result, char *file, int line, char *func_with_args) { + + if (result == MEMORY_RESULT_OK) return; + printk("[At file %s line%d: %s]", file, line, func_with_args); + switch (result) { + RESULT_CASE_PRINT(MEMORY_RESULT_OK) + RESULT_CASE_PRINT(MEMORY_RESULT_INVALID_INPUT) + RESULT_CASE_PRINT(MEMORY_RESULT_OUT_OF_MEMORY) + RESULT_CASE_PRINT(MEMORY_RESULT_MEMORY_IS_USED) + } +} diff --git a/src/kernel/memory/mod.rs b/src/kernel/memory/mod.rs new file mode 100644 index 0000000..657c2a3 --- /dev/null +++ b/src/kernel/memory/mod.rs @@ -0,0 +1,9 @@ +#![no_std] + +mod page; + +extern "C" { + fn kmalloc(size: u32) -> *mut core::ffi::c_void; + fn new_vir(); + fn new_phy(); +} diff --git a/src/kernel/memory/page.rs b/src/kernel/memory/page.rs new file mode 100644 index 0000000..b8ab423 --- /dev/null +++ b/src/kernel/memory/page.rs @@ -0,0 +1,66 @@ +#![no_std] + +use core::iter::Iterator; +use core::marker::Copy; +use core::option::Option; +use core::option::Option::{None, Some}; + +#[repr(C)] +pub struct MemoryBitmap { + pub bitmap: *mut u8, + pub size_in_bytes: usize, +} + +#[export_name = "virtual_memory_bitmap"] +pub static mut VIRTUAL_MEMORY_BITMAP: MemoryBitmap = MemoryBitmap { + bitmap: core::ptr::null_mut(), + size_in_bytes: 0, +}; + +#[export_name = "physical_memory_bitmap"] +pub static mut PHYSICAL_MEMORY_BITMAP: MemoryBitmap = MemoryBitmap { + bitmap: core::ptr::null_mut(), + size_in_bytes: 0, +}; + +impl MemoryBitmap { + #[no_mangle] + pub unsafe fn new_vir(addr: *mut u8, size_in_bytes: usize) { + VIRTUAL_MEMORY_BITMAP = MemoryBitmap { + bitmap: addr, + size_in_bytes, + }; + } + #[no_mangle] + pub unsafe fn new_phy(addr: *mut u8, size_in_bytes: usize) { + PHYSICAL_MEMORY_BITMAP = MemoryBitmap { + bitmap: addr, + size_in_bytes, + }; + } + + unsafe fn read(&self, index: usize) -> T { + *(self.bitmap.add(index) as *const T) + } + + unsafe fn reverse(&mut self, index: usize, bit: u8) { + *(self.bitmap.add(index) as *mut u32) ^= 1 << bit; + } + + pub fn alloc_single(&mut self) -> Option { + let mut dword; + + for i in (0..(self.size_in_bytes)).step_by(4) { + dword = unsafe { self.read::(i) }; + let bit = dword.leading_zeros(); + if bit != 32 { + dword |= 1 << (31 - bit); + unsafe { + self.reverse(i, bit as u8); + } + return Some(i * 32 + (31 - bit) as usize); + } + } + None + } +} diff --git a/src/kernel/memtest.c b/src/kernel/memtest.c new file mode 100644 index 0000000..f0dcacf --- /dev/null +++ b/src/kernel/memtest.c @@ -0,0 +1,178 @@ +#include +#include +#include +#include + +extern TimerDeviceManager timer_dm_ext; + +// 测试配置 +#define TEST_ITERATIONS 1000 // 每个测试案例的迭代次数 +#define SMALL_SIZE 32 // 小对象大小 +#define MEDIUM_SIZE 1024 // 中等对象大小 +#define LARGE_SIZE (4 * 1024) // 大对象大小(4KB) +#define HUGE_PAGE_CNT 4 // 大页分配数量 + +// 性能统计结构体 +struct perf_stats { + uint32_t total_cycles; + uint32_t max_cycles; + uint32_t min_cycles; + uint32_t alloc_fails; +}; +// 内存块记录增强 +struct mem_record { + void *ptr; + size_t size; + int is_page; + int page_cnt; // 记录分配的页数 +}; + +uint32_t rdtsc() { + uint32_t lo, hi; + __asm__ __volatile__("rdtsc" : "=a"(lo), "=d"(hi)); + return lo; +} + +uint32_t get_counter() { + LogicalDevice *device = timer_dm_ext.scheduler_timer; + TimerDevice *td = device->dm_ext; + return td->counter; +} +// 初始化性能统计 +static void init_stats(struct perf_stats *stats) { + stats->total_cycles = 0; + stats->max_cycles = 0; + stats->min_cycles = __UINT32_MAX__; + stats->alloc_fails = 0; +} + +// 更新统计信息 +static void update_stats(struct perf_stats *stats, uint32_t cycles) { + stats->total_cycles += cycles; + if (cycles > stats->max_cycles) stats->max_cycles = cycles; + if (cycles < stats->min_cycles) stats->min_cycles = cycles; +} + +// 打印统计结果 +static void print_stats( + const char *test_name, const struct perf_stats *stats, int iter) { + printk("[%s] Results:\n", test_name); + printk(" Total cycles: %u\n", stats->total_cycles); + printk(" Avg cycles/op: %u\n", stats->total_cycles / iter); + printk(" Max cycles: %u\n", stats->max_cycles); + printk(" Min cycles: %u\n", stats->min_cycles); + printk(" Allocation failures: %u\n", stats->alloc_fails); +} + +void test_long_running(uint32_t minutes) { + uint32_t start_count = get_counter(); + uint32_t end_count = start_count + (minutes * 60000); // 假设counter是毫秒级 + + struct perf_stats stats; + init_stats(&stats); + uint32_t alloc_count = 0; + Timer timer; + timer_init(&timer); + + while (get_counter() < end_count) { + size_t size = (alloc_count % 5 == 0) ? LARGE_SIZE : SMALL_SIZE; + + uint32_t start = rdtsc(); + void *ptr = kmalloc(size); + uint32_t end = rdtsc(); + + if (!ptr) { + stats.alloc_fails++; + delay_ms(&timer, 10); // 背压延迟 + continue; + } + + update_stats(&stats, end - start); + alloc_count++; + + // 保持10个活跃对象 + static void *keep_alive[10]; + static int idx = 0; + if (keep_alive[idx]) { kfree(keep_alive[idx]); } + keep_alive[idx] = ptr; + idx = (idx + 1) % 10; + } + + printk("[Long Running] Ran for %u minutes\n", minutes); + print_stats("Long Running", &stats, alloc_count); +} +void test_small_allocs(void) { + struct perf_stats stats; + init_stats(&stats); + + for (int i = 0; i < TEST_ITERATIONS; i++) { + uint32_t start = rdtsc(); + void *ptr = kmalloc(SMALL_SIZE); + uint32_t end = rdtsc(); + + if (!ptr) { + stats.alloc_fails++; + continue; + } + + update_stats(&stats, end - start); + kfree(ptr); + } + + print_stats("Small Object Alloc", &stats, TEST_ITERATIONS); +} + +void test_large_page_allocs(void) { + struct perf_stats stats; + init_stats(&stats); + struct mem_record pages[HUGE_PAGE_CNT] = {0}; // 记录地址和页数 + + for (int i = 0; i < TEST_ITERATIONS; i++) { + uint32_t start = rdtsc(); + void *ptr = kernel_alloc_pages(HUGE_PAGE_CNT); + uint32_t end = rdtsc(); + + if (!ptr) { + stats.alloc_fails++; + continue; + } + + // 记录当前分配的页数 + pages[i % HUGE_PAGE_CNT].ptr = ptr; + pages[i % HUGE_PAGE_CNT].page_cnt = HUGE_PAGE_CNT; + update_stats(&stats, end - start); + + // 释放旧的页 + if (i >= HUGE_PAGE_CNT) { + struct mem_record *old = &pages[i % HUGE_PAGE_CNT]; + if (old->ptr) { + kernel_free_page((int)old->ptr, old->page_cnt); // 关键修改点 + old->ptr = NULL; + } + } + } + + // 清理残留页 + for (int i = 0; i < HUGE_PAGE_CNT; i++) { + if (pages[i].ptr) { + kernel_free_page((int)pages[i].ptr, pages[i].page_cnt); + } + } + + print_stats("Large Page Alloc", &stats, TEST_ITERATIONS); +} + +void run_memory_benchmarks(void) { + printk("===== Starting Memory Allocator Benchmarks =====\n"); + + Timer timer; + timer_init(&timer); + + // 基础测试 + test_small_allocs(); + // delay_ms(&timer, 100); + test_large_page_allocs(); + // delay_ms(&timer, 100); + + printk("===== Benchmark Suite Completed =====\n"); +} \ No newline at end of file diff --git a/src/kernel/periodic_task.c b/src/kernel/periodic_task.c new file mode 100644 index 0000000..db39350 --- /dev/null +++ b/src/kernel/periodic_task.c @@ -0,0 +1,25 @@ +#include +#include +#include +#include + +LIST_HEAD(periodic_task_lh); + +void periodic_task(void *arg) { + PeriodicTask *periodic_task; + while (true) { + list_for_each_owner ( + periodic_task, &periodic_task_lh, period_task_list) { + periodic_task->func(periodic_task->arg); + } + schedule(); + } +} + +void periodic_task_add(PeriodicTask *periodic_task) { + list_add_tail(&periodic_task->period_task_list, &periodic_task_lh); +} + +void periodic_task_del(PeriodicTask *periodic_task) { + list_del(&periodic_task->period_task_list); +} \ No newline at end of file diff --git a/src/kernel/process.c b/src/kernel/process.c index 45bcf42..7ad7f86 100644 --- a/src/kernel/process.c +++ b/src/kernel/process.c @@ -5,8 +5,11 @@ * @version 0.8 * @date 2022-07-17 */ +#include "kernel/spinlock.h" +#include "kernel/thread.h" #include #include +#include #include #include #include @@ -17,7 +20,6 @@ void thread_intr_exit(struct intr_stack *proc_stack); extern list_t thread_ready; -extern list_t thread_all; /** * @brief 用户线程的入口函数 @@ -29,16 +31,18 @@ void start_process(void *entry) { struct task_s *cur = get_current_thread(); cur->kstack += sizeof(struct thread_stack); struct intr_stack *proc_stack = (struct intr_stack *)cur->kstack; - proc_stack->edi = proc_stack->esi = proc_stack->ebp = proc_stack->esp_dummy = 0; + proc_stack->edi = proc_stack->esi = proc_stack->ebp = + proc_stack->esp_dummy = 0; proc_stack->ebx = proc_stack->edx = proc_stack->ecx = proc_stack->eax = 0; proc_stack->gs = 0; proc_stack->ds = proc_stack->es = proc_stack->fs = SELECTOR_U_DATA; proc_stack->eip = function; proc_stack->cs = SELECTOR_U_CODE; - proc_stack->eflags = (1 << 1) | (1 << 9) | (0 << 12); - proc_stack->esp = - (void *)((uint32_t)thread_get_page(get_current_thread(), USER_STACK3_ADDR) + PAGE_SIZE - 4); - proc_stack->ss = SELECTOR_U_STACK; + proc_stack->eflags = (1 << 1) | (1 << 9) | (0 << 12); + proc_stack->esp = (void *)((uint32_t)thread_get_page( + get_current_thread(), USER_STACK3_ADDR) + + PAGE_SIZE - 4); + proc_stack->ss = SELECTOR_U_STACK; thread_intr_exit(proc_stack); } @@ -50,7 +54,9 @@ void start_process(void *entry) { void page_dir_activate(struct task_s *thread) { uint32_t pagedir_phy_addr = PDT_PHY_ADDR; - if (thread->pgdir != NULL) { pagedir_phy_addr = vir2phy((uint32_t)thread->pgdir); } + if (thread->pgdir != NULL) { + pagedir_phy_addr = vir2phy((uint32_t)thread->pgdir); + } write_cr3((uint32_t *)pagedir_phy_addr); } @@ -74,9 +80,10 @@ uint32_t *create_page_dir(void) { uint32_t *page_dir_vaddr = kernel_alloc_pages(1); if (page_dir_vaddr == NULL) { return NULL; } // 复制第0~511个与创建第1023个页目录表项 - memcpy((void *)(page_dir_vaddr + 0 * 4), (void *)(0xfffff000 + 0 * 4), 2048); + memcpy( + (void *)(page_dir_vaddr + 0 * 4), (void *)(0xfffff000 + 0 * 4), 2048); uint32_t new_page_dir_phy_addr = vir2phy((uint32_t)page_dir_vaddr); - page_dir_vaddr[1023] = new_page_dir_phy_addr | SIGN_USER | SIGN_RW | SIGN_P; + page_dir_vaddr[1023] = new_page_dir_phy_addr | SIGN_USER | SIGN_RW | SIGN_P; return page_dir_vaddr; } @@ -86,9 +93,11 @@ uint32_t *create_page_dir(void) { * @param user_prog 用户进程 */ void create_user_vaddr_mmap(struct task_s *user_prog) { - uint32_t pg_cnt = DIV_ROUND_UP((0xffcfffff - USER_START_ADDR) / PAGE_SIZE / 8, PAGE_SIZE); + uint32_t pg_cnt = + DIV_ROUND_UP((0xffcfffff - USER_START_ADDR) / PAGE_SIZE / 8, PAGE_SIZE); user_prog->vir_page_mmap.bits = kernel_alloc_pages(pg_cnt); - user_prog->vir_page_mmap.len = (0xffcfffff - USER_START_ADDR) / PAGE_SIZE / 8; + user_prog->vir_page_mmap.len = + (0xffcfffff - USER_START_ADDR) / PAGE_SIZE / 8; memset(user_prog->vir_page_mmap.bits, 0, user_prog->vir_page_mmap.len); } @@ -98,24 +107,30 @@ void create_user_vaddr_mmap(struct task_s *user_prog) { * @param entry 程序的入口 * @param prog 进程 */ -void process_excute(void *entry, struct program_struct *prog) { - struct task_s *thread = kernel_alloc_pages(1); - struct prog_segment *p, *next; - init_thread(thread, prog->name.text, THREAD_DEFAULT_PRIO); - create_user_vaddr_mmap(thread); - thread_create(thread, start_process, entry); - thread->pgdir = create_page_dir(); - init_thread_memory_manage(thread); - list_for_each_owner_safe (p, next, &prog->seg_head, list) { - process_load_segment(thread, prog->inode, p->offset, p->filesz, p->memsz, p->vaddr); - } +// void process_excute(void *entry, struct program_struct *prog) { +// struct task_s *thread = kmalloc(sizeof(struct task_s)); +// void *stack_page = kernel_alloc_pages(1); +// struct prog_segment *p; +// init_thread(thread, stack_page, prog->name.text, THREAD_DEFAULT_PRIO); +// create_user_vaddr_mmap(thread); +// thread_create(thread, start_process, entry); +// thread->pgdir = create_page_dir(); +// init_thread_memory_manage(thread); +// list_for_each_owner (p, &prog->seg_head, list) { +// MemoryResult result = process_load_segment( +// thread, prog->inode, p->offset, p->filesz, p->memsz, p->vaddr); +// if (result != MEMORY_RESULT_OK) { +// printk("Load segment failed\n"); +// return; +// } +// } - // 将该任务加入任务队列 - int old_status = io_load_eflags(); - list_add_tail(&thread->general_tag, &thread_ready); - list_add_tail(&thread->all_list_tag, &thread_all); - io_store_eflags(old_status); -} +// // 将该任务加入任务队列 +// int flags = spin_lock_irqsave(&thread_ready_lock); +// list_add_tail(&thread->general_tag, &thread_ready); +// list_add_tail(&thread->all_list_tag, &thread_all); +// io_store_eflags(flags); +// } /** * @brief 为进程加载段 @@ -128,16 +143,21 @@ void process_excute(void *entry, struct program_struct *prog) { * @param vaddr 段的虚拟地址 * @return int 成功为0,失败为-1 */ -int process_load_segment(struct task_s *thread, struct index_node *inode, unsigned long offset, - unsigned long filesz, unsigned long memsz, unsigned long vaddr) { - unsigned long size0 = PAGE_SIZE - (vaddr & 0xfff); - unsigned long page_num = 1; - if (memsz > size0) { page_num += DIV_ROUND_UP(memsz - size0, PAGE_SIZE); } - uint32_t *addr = kernel_alloc_pages(page_num); - int ret = thread_use_page(thread, vaddr, vir2phy((uint32_t)addr), page_num); - if (ret == -1) { return -1; } - inode->f_ops.seek(inode, offset, 0); - inode->f_ops.read(inode, (uint8_t *)(addr + (vaddr & 0xfff)), filesz); - if (memsz > filesz) { memset((void *)(addr + (vaddr & 0xfff) + filesz), 0, memsz - filesz); } - return 0; -} \ No newline at end of file +// MemoryResult process_load_segment( +// struct task_s *thread, struct index_node *inode, unsigned long offset, +// unsigned long filesz, unsigned long memsz, unsigned long vaddr) { +// unsigned long size0 = PAGE_SIZE - (vaddr & 0xfff); +// unsigned long page_num = 1; +// if (memsz > size0) { page_num += DIV_ROUND_UP(memsz - size0, PAGE_SIZE); } + +// uint32_t *addr = kernel_alloc_pages(page_num); +// MEMORY_RESULT_DELIVER_CALL( +// thread_use_page, thread, vaddr, vir2phy((uint32_t)addr), page_num); + +// seek(inode, offset, 0); +// read(inode, (uint8_t *)(addr + (vaddr & 0xfff)), filesz); +// if (memsz > filesz) { +// memset((void *)(addr + (vaddr & 0xfff) + filesz), 0, memsz - filesz); +// } +// return MEMORY_RESULT_OK; +// } \ No newline at end of file diff --git a/src/kernel/rwlock.c b/src/kernel/rwlock.c new file mode 100644 index 0000000..5c6ce6d --- /dev/null +++ b/src/kernel/rwlock.c @@ -0,0 +1,63 @@ +#include "types.h" +#include + +void rwlock_init(rwlock_t *lock) { + spinlock_init(&lock->status_lock); + condvar_init(&lock->read_lock); + condvar_init(&lock->write_lock); + lock->read_count = 0; + lock->write_count = 0; + lock->write_waiting = 0; +} + +void rwlock_read_lock(rwlock_t *lock) { + spin_lock(&lock->status_lock); + while (lock->write_count > 0 || lock->write_waiting > 0) { + condvar_wait(&lock->read_lock, &lock->status_lock); + } + lock->read_count++; + spin_unlock(&lock->status_lock); +} + +void rwlock_read_unlock(rwlock_t *lock) { + spin_lock(&lock->status_lock); + lock->read_count--; + if (lock->read_count == 0 && lock->write_waiting > 0) { + condvar_signal(&lock->write_lock); + } + spin_unlock(&lock->status_lock); +} + +bool rwlock_write_try_lock(rwlock_t *lock) { + spin_lock(&lock->status_lock); + if (lock->read_count == 0 && lock->write_count == 0) { + lock->write_count++; + spin_unlock(&lock->status_lock); + return true; + } else { + spin_unlock(&lock->status_lock); + return false; + } +} + +void rwlock_write_lock(rwlock_t *lock) { + spin_lock(&lock->status_lock); + lock->write_waiting++; + while (lock->read_count > 0 || lock->write_count > 0) { + condvar_wait(&lock->write_lock, &lock->status_lock); + } + lock->write_waiting--; + lock->write_count++; + spin_unlock(&lock->status_lock); +} + +void rwlock_write_unlock(rwlock_t *lock) { + spin_lock(&lock->status_lock); + lock->write_count--; + if (lock->write_count > 0) { + condvar_signal(&lock->write_lock); + } else { + condvar_broadcast(&lock->read_lock); + } + spin_unlock(&lock->status_lock); +} diff --git a/src/kernel/softirq.c b/src/kernel/softirq.c new file mode 100644 index 0000000..74aea6f --- /dev/null +++ b/src/kernel/softirq.c @@ -0,0 +1,35 @@ +#include "kernel/softirq.h" +#include "kernel/driver.h" +#include "kernel/thread.h" + +Softirq softirq = {0}; + +SoftirqHandler softirq_handlers[SOFTIRQ_MAX]; + +void do_softirq(void) { + if (softirq.pending && !in_softirq()) { + disable_preempt(); + softirq_enter(); + + for (int i = 0; i < SOFTIRQ_MAX; i++) { + if (softirq_handlers[i].handler != NULL) { + softirq_handlers[i].handler(); + } + } + + softirq.pending = 0; + softirq_exit(); + enable_preempt(); + } +} + +DriverResult softirq_register_handler(SoftirqType type, void (*handler)(void)) { + if (type == SOFTIRQ_MAX) { return DRIVER_ERROR_INVALID_TYPE; } + if (softirq_handlers[type].handler != NULL) { + return DRIVER_ERROR_CONFLICT; + } + + softirq_handlers[type].handler = handler; + + return DRIVER_OK; +} diff --git a/src/kernel/sync.c b/src/kernel/sync.c index 464b858..b856dc7 100644 --- a/src/kernel/sync.c +++ b/src/kernel/sync.c @@ -5,68 +5,61 @@ * @version 0.1 * @date 2021-07 */ +#include "kernel/driver_interface.h" +#include "kernel/thread.h" +#include "kernel/wait_queue.h" #include #include #include +#include -void sema_init(struct semaphore *psema, uint8_t value) -{ - psema->value = value; - list_init(&psema->waiters); +void sema_init(struct semaphore *psema, uint8_t value) { + psema->value = value; + wait_queue_init(&psema->wq); } -void lock_init(struct lock *plock) -{ - plock->holder = NULL; - plock->holder_repeat_nr = 0; - sema_init(&plock->semaphore, 1); +void lock_init(struct lock *plock) { + plock->holder = NULL; + plock->holder_repeat_nr = 0; + sema_init(&plock->semaphore, 1); } -void sema_down(struct semaphore *psema) -{ - int old_status = io_load_eflags(); - struct task_s *cur_thread = get_current_thread(); - while (psema->value == 0) { - if (list_find(&cur_thread->general_tag, &psema->waiters)) { - printk("sema_down: thread blocked has benn in waiters_list\n"); - } - - list_add_tail(&cur_thread->general_tag, &psema->waiters); - thread_block(TASK_BLOCKED); - } - psema->value--; - io_store_eflags(old_status); +void sema_down(struct semaphore *psema) { + int flags = save_and_disable_interrupt(); + while (psema->value == 0) { + store_interrupt_status(flags); + thread_set_status(TASK_INTERRUPTIBLE); + wait_queue_add(&psema->wq); + thread_wait(); + flags = save_and_disable_interrupt(); + } + psema->value--; + store_interrupt_status(flags); } -void sema_up(struct semaphore *psema) -{ - int old_status = io_load_eflags(); - if (!list_empty(&psema->waiters)) { - struct task_s *thread_blocked = list_owner(&psema->waiters, struct task_s, general_tag); - thread_unblock(thread_blocked); - } - psema->value++; - io_store_eflags(old_status); +void sema_up(struct semaphore *psema) { + int flags = save_and_disable_interrupt(); + wait_queue_wakeup(&psema->wq); + psema->value++; + store_interrupt_status(flags); } -void lock_acquire(struct lock *plock) -{ - if (plock->holder != get_current_thread()) { - sema_down(&plock->semaphore); - plock->holder = get_current_thread(); - plock->holder_repeat_nr = 1; - } else { - plock->holder_repeat_nr++; - } +void lock_acquire(struct lock *plock) { + if (plock->holder != get_current_thread()) { + sema_down(&plock->semaphore); + plock->holder = get_current_thread(); + plock->holder_repeat_nr = 1; + } else { + plock->holder_repeat_nr++; + } } -void lock_release(struct lock *plock) -{ - if (plock->holder_repeat_nr > 1) { - plock->holder_repeat_nr--; - return; - } - plock->holder = NULL; - plock->holder_repeat_nr = 0; - sema_up(&plock->semaphore); +void lock_release(struct lock *plock) { + if (plock->holder_repeat_nr > 1) { + plock->holder_repeat_nr--; + return; + } + plock->holder = NULL; + plock->holder_repeat_nr = 0; + sema_up(&plock->semaphore); } \ No newline at end of file diff --git a/src/kernel/syscall.c b/src/kernel/syscall.c index 8f97918..fbd7d47 100644 --- a/src/kernel/syscall.c +++ b/src/kernel/syscall.c @@ -12,25 +12,30 @@ #include #include -int sys_getpid(void); -int sys_putchar(char c); -int sys_puts(char *str); -int sys_open(char *pathname, int flags); -int sys_close(int fd); -ssize_t sys_read(int fd, void *buf, size_t count); -ssize_t sys_write(int fd, void *buf, size_t count); +int sys_getpid(void); +int sys_putchar(char c); +int sys_puts(char *str); +int sys_open(char *pathname, int flags); +int sys_close(int fd); +size_t sys_read(int fd, void *buf, size_t count); +size_t sys_write(int fd, void *buf, size_t count); typedef void *syscall_t; syscall_t syscall_table[][2] = { - {sys_getpid, (void *)0}, // 此处存的是数字,只是做了类型转换 - {sys_putchar, (void *)1}, {sys_puts, (void *)1}, {sys_open, (void *)2}, - {sys_close, (void *)1}, {sys_read, (void *)3}, {sys_write, (void *)3}, + { sys_getpid, (void *)0}, // 此处存的是数字,只是做了类型转换 + {sys_putchar, (void *)1}, + { sys_puts, (void *)1}, + { sys_open, (void *)2}, + { sys_close, (void *)1}, + { sys_read, (void *)3}, + { sys_write, (void *)3}, }; typedef unsigned long (*syscall0_func_t)(void); typedef unsigned long (*syscall1_func_t)(unsigned long); typedef unsigned long (*syscall2_func_t)(unsigned long, unsigned long); -typedef unsigned long (*syscall3_func_t)(unsigned long, unsigned long, unsigned long); +typedef unsigned long (*syscall3_func_t)( + unsigned long, unsigned long, unsigned long); int sys_getpid(void) { return get_current_thread()->pid; @@ -46,29 +51,30 @@ int sys_puts(char *str) { } int sys_open(char *pathname, int flags) { - struct index_node *inode = fs_open(pathname); - int fd = alloc_fd(); - fds[fd] = inode->fp; - return fd; + // struct index_node *inode = fs_open(pathname); + // int fd = alloc_fd(); + // fds[fd] = inode->fp; + // return fd; } int sys_close(int fd) { - int ret = fds[fd]->inode->f_ops.close(fds[fd]->inode); - fds[fd] = NULL; - return ret; + // int ret = fds[fd]->inode->f_ops.close(fds[fd]->inode); + // fds[fd] = NULL; + // return ret; } -ssize_t sys_read(int fd, void *buf, size_t count) { - struct file *file = fds[fd]; - return file->inode->f_ops.read(file->inode, buf, count); +size_t sys_read(int fd, void *buf, size_t count) { + // struct file *file = fds[fd]; + // return file->inode->f_ops.read(file->inode, buf, count); } -ssize_t sys_write(int fd, void *buf, size_t count) { - struct file *file = fds[fd]; - return file->inode->f_ops.write(file->inode, buf, count); +size_t sys_write(int fd, void *buf, size_t count) { + // struct file *file = fds[fd]; + // return file->inode->f_ops.write(file->inode, buf, count); } -uint32_t do_syscall(uint32_t func, uint32_t arg1, uint32_t arg2, uint32_t arg3) { +uint32_t do_syscall( + uint32_t func, uint32_t arg1, uint32_t arg2, uint32_t arg3) { uint32_t ret = 0; if (syscall_table[func]) { switch ((uint32_t)syscall_table[func][1]) { diff --git a/src/kernel/thread.c b/src/kernel/thread.c index 29cce70..46a0233 100644 --- a/src/kernel/thread.c +++ b/src/kernel/thread.c @@ -6,21 +6,34 @@ * @date 2021-02 * */ +#include #include +#include #include +#include #include #include #include +#include #include #include #include +#include +#include #include +uint32_t preempt_count = 0; // 预防抢占计数 + +struct task_s *current_task, *dead_task = NULL, *prev; struct task_s *main_thread; -list_t thread_ready; -list_t thread_all; -struct lock pid_lock; -uint32_t new_pid = 0; + +list_t thread_ready; +spinlock_t thread_ready_lock; +list_t thread_all; +spinlock_t thread_all_lock; + +struct lock pid_lock; +uint32_t new_pid = 0; extern struct task_s *task_idle; @@ -42,9 +55,11 @@ static uint32_t alloc_pid(void) { * @return struct task_s* */ struct task_s *get_current_thread() { - uint32_t sp; - GET_REG("esp", sp); - return (struct task_s *)(sp & 0xfffff000); + return current_task; +} + +size_t get_current_subject_id() { + return get_current_thread()->subject_id; } /** @@ -56,6 +71,7 @@ struct task_s *get_current_thread() { static void kernel_thread(thread_func *function, void *func_arg) { io_sti(); function(func_arg); + thread_exit(); } /** @@ -65,7 +81,8 @@ static void kernel_thread(thread_func *function, void *func_arg) { * @param function 线程入口函数 * @param func_arg 参数 */ -void thread_create(struct task_s *pthread, thread_func *function, void *func_arg) { +void thread_create( + struct task_s *pthread, thread_func *function, void *func_arg) { pthread->pid = alloc_pid(); pthread->kstack -= sizeof(struct intr_stack); pthread->kstack -= sizeof(struct thread_stack); @@ -73,7 +90,8 @@ void thread_create(struct task_s *pthread, thread_func *function, void *func_arg kthread_stack->eip = kernel_thread; kthread_stack->function = function; kthread_stack->func_arg = func_arg; - kthread_stack->ebp = kthread_stack->ebx = kthread_stack->esi = kthread_stack->edi = 0; + kthread_stack->ebp = kthread_stack->ebx = kthread_stack->esi = + kthread_stack->edi = 0; } /** @@ -83,20 +101,29 @@ void thread_create(struct task_s *pthread, thread_func *function, void *func_arg * @param name 线程名 * @param priority 优先级 */ -void init_thread(struct task_s *pthread, char *name, int priority) { - memset(pthread, 0, sizeof(sizeof(struct task_s))); +void init_thread( + struct task_s *pthread, void *stack_page, char *name, int priority) { + memset(pthread, 0, sizeof(struct task_s)); strcpy(pthread->name, name); if (pthread == main_thread) { pthread->status = TASK_RUNNING; } else { - pthread->status = TASK_WAITING; + pthread->status = TASK_READY; } + spinlock_init(&pthread->status_lock); + + lock_init(&pthread->child_lock); + pthread->child_count = 0; + sema_init(&pthread->child_sem, 0); + pthread->priority = priority; - pthread->kstack = (uint32_t *)((uint32_t)pthread + PAGE_SIZE); - pthread->ticks = priority; + pthread->kstack = (uint32_t *)((uint32_t)stack_page + PAGE_SIZE); + pthread->ticks = timer_get_schedule_tick(priority); pthread->elapsed_ticks = 0; pthread->pgdir = NULL; pthread->stack_magic = 0x10000000; + pthread->subject_id = SUBJECT_ID_SYSTEM; + pthread->flags.need_resched = 0; } /** @@ -108,55 +135,125 @@ void init_thread(struct task_s *pthread, char *name, int priority) { * @param func_arg 参数 * @return struct task_s* 创建好的线程 */ -struct task_s *thread_start(char *name, int priority, thread_func function, void *func_arg) { - struct task_s *thread = kernel_alloc_pages(1); +struct task_s *thread_start( + char *name, int priority, thread_func function, void *func_arg, + struct task_s *parent) { + struct task_s *thread = kmalloc(sizeof(struct task_s)); + void *stack_page = kernel_alloc_pages(1); - init_thread(thread, name, priority); - thread_create(thread, function, func_arg); - if (list_find(&thread->general_tag, &thread_ready)) { - printk("thread %s:start error!\n", name); - while (1) - ; + init_thread(thread, stack_page, name, priority); + + if (parent != NULL) { + thread->parent = parent; + lock_acquire(&parent->child_lock); + parent->child_count++; + lock_release(&parent->child_lock); } - list_add_tail(&thread->general_tag, &thread_ready); + thread_create(thread, function, func_arg); + + int flags = spin_lock_irqsave(&thread_all_lock); if (list_find(&thread->all_list_tag, &thread_all)) { - printk("thread %s:start error!\n", name); - while (1) - ; + printk("[Thread Error]%s thread is already in thread_all!\n", name); + list_del(&thread->all_list_tag); } list_add_tail(&thread->all_list_tag, &thread_all); - /* __asm__ __volatile__( - "movl %0, %%esp; \ - pop %%ebp; \ - pop %%ebx; \ - pop %%edi; \ - pop %%esi; \ - ret" - ::"g"(thread->stack) - :"memory" - ); */ + spin_unlock_irqrestore(&thread_all_lock, flags); + + flags = spin_lock_irqsave(&thread_ready_lock); + if (list_in_list(&thread->general_tag)) { + printk("[Thread Error]%s thread is already in thread_ready!\n", name); + list_del(&thread->general_tag); + } + list_add_tail(&thread->general_tag, &thread_ready); + spin_unlock_irqrestore(&thread_ready_lock, flags); + return thread; } +void thread_exit(void) { + struct task_s *cur = get_current_thread(); + + if (cur->parent != NULL) { + struct task_s *parent = cur->parent; + lock_acquire(&parent->child_lock); + parent->child_count--; + if (parent->child_count == 0) { + sema_up(&parent->child_sem); // 所有子线程完成,唤醒父线程 + } + lock_release(&parent->child_lock); + } + + /* + * 先从thread_all中删除,再从thread_ready中删除 + * 否则一旦被打断切换到其他线程,就无法再调度回来了 + */ + int flags = spin_lock_irqsave(&thread_all_lock); + list_del(&cur->all_list_tag); + spin_unlock_irqrestore(&thread_all_lock, flags); + + flags = spin_lock_irqsave(&thread_ready_lock); + if (list_in_list(&cur->general_tag)) { list_del(&cur->general_tag); } + + cur->status = TASK_DIED; + + // 切换线程 + struct task_s *next; + next = list_first_owner(&thread_ready, struct task_s, general_tag); + if (next != cur) list_del(&next->general_tag); + else { + printk("[Thread Error] No ready task!\n"); + next = task_idle; + } + + // 进程将要退出,不需要恢复中断状态了 + spin_unlock(&thread_ready_lock); + + spin_lock(&next->status_lock); + if (next->status == TASK_READY) next->status = TASK_RUNNING; + spin_unlock(&next->status_lock); + + // 3. 切换线程 + dead_task = cur; + // 激活页表并跳转 + process_activate(next); + current_task = next; + prev = cur; + switch_to((int *)cur, (int *)next); +} + +void thread_wait_children(struct task_s *parent) { + // 等待子线程计数器归零 + while (1) { + lock_acquire(&parent->child_lock); + if (parent->child_count == 0) { + lock_release(&parent->child_lock); + break; + } + lock_release(&parent->child_lock); + sema_down(&parent->child_sem); // 阻塞等待信号量 + } +} + /** * @brief 阻塞当前线程 * * @param status 线程的目标状态( - * TASK_BLOCKED:阻塞 - * TASK_WAITING:等待 - * TASK_HANGING:挂起) + * TASK_INTERRUPTIBLE:可中断阻塞 + * TASK_UNINTERRUPTIBLE:不可中断阻塞) */ -void thread_block(task_status_t status) { - int old_status = io_load_eflags(); - if ((status != TASK_BLOCKED) && (status != TASK_WAITING) && (status != TASK_HANGING)) { - printk("error"); - while (1) - ; - } +void thread_set_status(task_status_t status) { struct task_s *cur_thread = get_current_thread(); + int flags = spin_lock_irqsave(&cur_thread->status_lock); cur_thread->status = status; - schedule(); - io_store_eflags(old_status); + spin_unlock_irqrestore(&cur_thread->status_lock, flags); +} + +void thread_wait() { + struct task_s *cur_thread = get_current_thread(); + + while (cur_thread->status == TASK_INTERRUPTIBLE) { + schedule(); + } } /** @@ -165,23 +262,19 @@ void thread_block(task_status_t status) { * @param pthread 线程结构 */ void thread_unblock(struct task_s *pthread) { - int old_status = io_load_eflags(); - if ((pthread->status != TASK_BLOCKED) && (pthread->status != TASK_WAITING) && - (pthread->status != TASK_HANGING)) { - printk("error"); - while (1) - ; + int flags = spin_lock_irqsave(&pthread->status_lock); + if ((pthread->status != TASK_INTERRUPTIBLE) && + (pthread->status != TASK_UNINTERRUPTIBLE)) { + spin_unlock_irqrestore(&pthread->status_lock, flags); + return; } - if (pthread->status != TASK_READY) { - if (list_find(&pthread->general_tag, &thread_ready)) { - printk("error"); - while (1) - ; - } - list_add_before(&pthread->general_tag, thread_ready.next); - pthread->status = TASK_READY; + + if (pthread != current_task) { + if (pthread->status != TASK_READY) { pthread->status = TASK_READY; } + } else { + pthread->status = TASK_RUNNING; } - io_store_eflags(old_status); + spin_unlock_irqrestore(&pthread->status_lock, flags); } /** @@ -189,13 +282,15 @@ void thread_unblock(struct task_s *pthread) { * */ static void make_main_thread(void) { - main_thread = get_current_thread(); - init_thread(main_thread, "System", 10); + main_thread = kmalloc(sizeof(struct task_s)); + void *stack_page = kernel_alloc_pages(1); + init_thread(main_thread, stack_page, "System", THREAD_DEFAULT_PRIO); + current_task = main_thread; + main_thread->pid = alloc_pid(); if (list_find(&main_thread->all_list_tag, &thread_all)) { - printk("thread main:start error!\n"); - while (1) - ; + printk("[Thread Error] Main thread is alredy in thread list!\n"); + list_del(&main_thread->all_list_tag); } list_add_tail(&main_thread->all_list_tag, &thread_all); } @@ -207,6 +302,9 @@ static void make_main_thread(void) { void init_task(void) { list_init(&thread_ready); list_init(&thread_all); + spinlock_init(&thread_ready_lock); + spinlock_init(&thread_all_lock); + lock_init(&pid_lock); make_main_thread(); } @@ -216,30 +314,69 @@ void init_task(void) { * */ void schedule(void) { + int old_status; struct task_s *cur = get_current_thread(); + + if (!can_preempt()) { + // 如果不能抢占,直接返回 + return; + } + + old_status = spin_try_lock_irqsave(&thread_ready_lock); + if (old_status == 0) return; + + // 1. 判断当前线程是否需要加入到thread_ready if (cur->status == TASK_RUNNING) { - if (list_find(&cur->general_tag, &thread_ready)) { - printk("error!\n"); - while (1) - ; + if (list_in_list(&cur->general_tag)) { + printk( + "Error:Current thread(pid:%d) is in thread_ready list!\n", + cur->pid); + list_del(&cur->general_tag); } - list_add_tail(&cur->general_tag, &thread_ready); - cur->ticks = cur->priority; cur->status = TASK_READY; + list_add_tail(&cur->general_tag, &thread_ready); + cur->ticks = cur->priority; + } else if (cur->status == TASK_INTERRUPTIBLE) { + list_add_tail(&cur->general_tag, &thread_ready); + cur->ticks = cur->priority; + } else { + printk("[Thread Status Error] %s:%d\n", cur->name, cur->status); } - struct task_s *next; - next = list_first_owner(&thread_ready, struct task_s, general_tag); - if (list_length(&thread_ready) > 1) { - list_del(thread_ready.next); - next->status = TASK_RUNNING; - process_activate(next); - - switch_to((int *)cur, (int *)next); + // 2. 获取下一个线程,如果没有则使用idle线程 + struct task_s *next; + if (!list_empty(&thread_ready)) { + next = list_first_owner(&thread_ready, struct task_s, general_tag); + if (next == cur) { + printk("[Thread Error] Same Task!\n"); + __asm__("nop" ::); + } + list_del(&next->general_tag); } else { - process_activate(task_idle); - switch_to((int *)cur, (int *)task_idle); + next = task_idle; + if (list_in_list(&task_idle->general_tag)) + list_del(&task_idle->general_tag); + } + // 4. 改变状态并加入到thread_ready + if (next->status == TASK_READY) next->status = TASK_RUNNING; + spin_unlock(&thread_ready_lock); + + prev = cur; + // 5. 切换线程 + // 激活页表并跳转 + process_activate(next); + current_task = next; + switch_to((int *)cur, (int *)next); + // 从其他线程切回来之后,检查上一个线程是否已经结束 + if (dead_task != NULL) { + size_t stack_page = (size_t)dead_task->kstack & ~(PAGE_SIZE - 1); + kernel_free_page(stack_page, 1); + kfree(dead_task); + dead_task = NULL; } + if (cur->status == TASK_READY) cur->status = TASK_RUNNING; + + store_interrupt_status(old_status); } /** diff --git a/src/kernel/wait_queue.c b/src/kernel/wait_queue.c index 12cfde5..f3db9a2 100644 --- a/src/kernel/wait_queue.c +++ b/src/kernel/wait_queue.c @@ -6,76 +6,89 @@ * @date 2022-07-20 */ -#include "kernel/list.h" +#include "kernel/console.h" +#include "kernel/spinlock.h" +#include "kernel/thread.h" +#include #include +#include #include #include -/** - * @brief 创建一个等待队列 - * - * @return wait_queue_manager_t* 等待队列的管理结构 - */ -wait_queue_manager_t *create_wait_queue(void) { - wait_queue_manager_t *wqm = (wait_queue_manager_t *)kmalloc(sizeof(wait_queue_manager_t)); - return wqm; -} - /** * @brief 初始化等待队列 * - * @param wqm 等待队列管理结构 + * @param wq 等待队列管理结构 */ -void wait_queue_init(wait_queue_manager_t *wqm) { - spinlock_init(&wqm->lock); - list_init(&wqm->list_head); +void wait_queue_init(WaitQueue *wq) { + spinlock_init(&wq->lock); + list_init(&wq->list_head); return; } /** * @brief 检查等待队列是否为空 * - * @param wqm 等待队列管理结构 + * @param wq 等待队列管理结构 * @return true * @return false */ -bool wait_queue_empty(wait_queue_manager_t *wqm) { - return list_empty(&wqm->list_head); +bool wait_queue_empty(WaitQueue *wq) { + return list_empty(&wq->list_head); } /** * @brief 添加当前任务到等待队列 * - * @param wqm 等待队列管理结构 - * @param size private_data的大小 + * @param wq 等待队列管理结构 * - * @return wait_queue_t * + * @return */ -wait_queue_t *wait_queue_add(wait_queue_manager_t *wqm, uint32_t size) { - wait_queue_t *wq = (wait_queue_t *)kmalloc(sizeof(wait_queue_t)); - wq->thread = get_current_thread(); - int old_status = io_load_eflags(); - spin_lock(&wqm->lock); - list_add_tail(&wq->list, &wqm->list_head); - spin_unlock(&wqm->lock); - io_store_eflags(old_status); - if (size != 0) { - wq->private_data = kmalloc(size); - } else { - wq->private_data = NULL; +void wait_queue_add(WaitQueue *wq) { + struct task_s *task = get_current_thread(); + if (list_in_list(&task->wait_queue_tag)) { + printk("Error:Current thread(pid:%d) is in wait queue!\n", task->pid); + list_del(&task->wait_queue_tag); } - return wq; + int flags = spin_lock_irqsave(&wq->lock); + + // 把当前线程的list tag直接挂到等待队列的list上 + list_add_tail(&task->wait_queue_tag, &wq->list_head); + + spin_unlock_irqrestore(&wq->lock, flags); +} + +void wait_queue_del(WaitQueue *wq) { + struct task_s *task = get_current_thread(); + if (list_in_list(&task->wait_queue_tag)) { + printk("Error:Current thread(pid:%d) is in wait queue!\n", task->pid); + list_del(&task->wait_queue_tag); + } + int flags = spin_lock_irqsave(&wq->lock); + if (list_in_list(&task->wait_queue_tag)) list_del(&task->wait_queue_tag); + spin_unlock_irqrestore(&wq->lock, flags); } /** * @brief 获取等待队列中的第一个任务 * - * @param wqm 等待队列管理结构 - * @return wait_queue_t* + * @param wq 等待队列管理结构 + * @return */ -wait_queue_t *wait_queue_first(wait_queue_manager_t *wqm) { +struct task_s *wait_queue_first(WaitQueue *wqm) { if (list_empty(&wqm->list_head)) { return NULL; } - return list_first_owner(&wqm->list_head, wait_queue_t, list); + return list_first_owner(&wqm->list_head, struct task_s, wait_queue_tag); +} + +void wait_queue_wakeup_thread(WaitQueue *wq, struct task_s *thread) { + int flags = spin_lock_irqsave(&wq->lock); + + list_del(&thread->wait_queue_tag); + + thread_unblock(thread); + + spin_unlock_irqrestore(&wq->lock, flags); + return; } /** @@ -83,20 +96,13 @@ wait_queue_t *wait_queue_first(wait_queue_manager_t *wqm) { * * @param wqm 等待队列管理结构 */ -void wait_queue_wakeup(wait_queue_manager_t *wqm) { - if (list_empty(&wqm->list_head)) { return; } - wait_queue_t *wq = list_first_owner(&wqm->list_head, wait_queue_t, list); - struct task_s *thread = wq->thread; - int old_status = io_load_eflags(); - spin_lock(&wqm->lock); - list_del(&wq->list); - if (wq->private_data != NULL) { kfree(wq->private_data); } - kfree(wq); - if (thread->status == TASK_BLOCKED || thread->status == TASK_WAITING || thread->status == TASK_HANGING) { - thread_unblock(thread); - } - spin_unlock(&wqm->lock); - io_store_eflags(old_status); +void wait_queue_wakeup(WaitQueue *wq) { + if (list_empty(&wq->list_head)) { return; } + struct task_s *thread = + list_first_owner(&wq->list_head, struct task_s, wait_queue_tag); + + wait_queue_wakeup_thread(wq, thread); + return; } @@ -105,23 +111,19 @@ void wait_queue_wakeup(wait_queue_manager_t *wqm) { * * @param wqm 等待队列管理结构 */ -void wait_queue_wakeup_all(wait_queue_manager_t *wqm) { - if (list_empty(&wqm->list_head)) { return; } - wait_queue_t *cur, *next; +void wait_queue_wakeup_all(WaitQueue *wq) { + if (list_empty(&wq->list_head)) { return; } + struct task_s *cur, *next; struct task_s *thread; - int old_status = io_load_eflags(); - spin_lock(&wqm->lock); - list_for_each_owner_safe (cur, next, &wqm->list_head, list) { - thread = cur->thread; - list_del(&cur->list); - if (cur->private_data != NULL) { kfree(cur->private_data); } - kfree(cur); - if (thread->status == TASK_BLOCKED || thread->status == TASK_WAITING || - thread->status == TASK_HANGING) { - thread_unblock(thread); - } + + int old_status = spin_lock_irqsave(&wq->lock); + list_for_each_owner_safe (cur, next, &wq->list_head, wait_queue_tag) { + thread = cur; + list_del(&cur->wait_queue_tag); + + thread_unblock(thread); } - spin_unlock(&wqm->lock); - io_store_eflags(old_status); + + spin_unlock_irqrestore(&wq->lock, old_status); return; } diff --git a/src/lib/Makefile b/src/lib/Makefile index b3615d4..ff8ef39 100644 --- a/src/lib/Makefile +++ b/src/lib/Makefile @@ -2,4 +2,6 @@ SRC += ctype.c SRC += math.c SRC += string.c SRC += vsprintf.c -SRC += rand.c \ No newline at end of file +SRC += random.c +SRC += dyn_array.c +SRC += hash/ \ No newline at end of file diff --git a/src/lib/config.toml b/src/lib/config.toml new file mode 100644 index 0000000..69c8b88 --- /dev/null +++ b/src/lib/config.toml @@ -0,0 +1,10 @@ +c = [ + "ctype.c", + "dyn_array.c", + "math.c", + "random.c", + "string.c", + "vsprintf.c", + "hash/fnv.c", + "hash/md5.c", +] diff --git a/src/lib/dyn_array.c b/src/lib/dyn_array.c new file mode 100644 index 0000000..9188aae --- /dev/null +++ b/src/lib/dyn_array.c @@ -0,0 +1,138 @@ +#include +#include +#include +#include +#include +#include + +DynArray *dyn_array_new(size_t element_size, size_t block_size) { + DynArray *array = kmalloc(sizeof(DynArray)); + if (array == NULL) { return NULL; } + + array->size = 0; + array->capacity = block_size; + array->block_size = block_size; + array->element_size = find_next_pow_of_2(element_size); + + array->first_block = kmalloc(sizeof(struct DynArrayBlock)); + array->first_block->next = NULL; + array->first_block->data = kmalloc(block_size * array->element_size); + array->first_block->left_space = array->block_size; + array->last_block = array->first_block; + + return array; +} + +void dyn_array_delete(DynArray *dyn_array) { + struct DynArrayBlock *block = dyn_array->first_block; + while (block != NULL) { + struct DynArrayBlock *next = block->next; + kfree(block->data); + kfree(block); + block = next; + } + kfree(dyn_array); +} + +void dyn_array_extend_block(DynArray *dyn_array) { + struct DynArrayBlock *block = dyn_array->first_block; + while (block->next != NULL) { + block = block->next; + } + + struct DynArrayBlock *new_block = kmalloc(sizeof(struct DynArrayBlock)); + + block->next = new_block; + new_block->next = NULL; + new_block->data = kmalloc(dyn_array->block_size * dyn_array->element_size); + new_block->left_space = dyn_array->block_size; + + dyn_array->capacity += dyn_array->block_size * dyn_array->element_size; + + dyn_array->last_block = new_block; +} + +struct DynArrayBlock *dyn_array_find_block(DynArray *dyn_array, size_t idx) { + struct DynArrayBlock *block = dyn_array->first_block; + + for (int i = 0; i < idx; i++) { + if (block->next == NULL) { dyn_array_extend_block(dyn_array); } + block = block->next; + } + + return block; +} + +/** + * @brief 找到新的元素的地址 + * + */ +void *dyn_array_new_item_addr(DynArray *dyn_array) { + struct DynArrayBlock *block = dyn_array->last_block; + if (block->left_space == 0 && dyn_array->size != 0) { + dyn_array_extend_block(dyn_array); + block = dyn_array->last_block; + } + block->left_space--; + + return block->data + + (dyn_array->size % dyn_array->block_size) * dyn_array->element_size; +} + +// 以下两个函数都是为foreach服务的 + +void *dyn_array_next_ptr( + DynArray *dyn_array, struct DynArrayBlock **block, int *block_index, + int *block_offset) { + + // struct DynArrayBlock *current_block = *block; + int offset = *block_offset; + + if (offset + 1 < dyn_array->block_size) { + (*block_offset)++; + } else { + (*block_index)++; + *block_offset = 0; + *block = (*block)->next; + } + return (void *)(*block)->data + (*block_offset) * dyn_array->element_size; +} + +void dyn_array_remove(DynArray *dyn_array, void *item) { + struct DynArrayBlock *block = dyn_array->first_block; + struct DynArrayBlock *last_block = NULL; + + while (block != NULL) { + for (int i = 0; i < dyn_array->block_size; i++) { + if (block->data + i * dyn_array->element_size == item) { + memset( + block->data + i * dyn_array->element_size, 0, + dyn_array->element_size); + + dyn_array->size--; + block->left_space--; + if (block->left_space == 0 && block != dyn_array->first_block) { + if (last_block != NULL) { + last_block->next = block->next; + } else { + dyn_array->first_block = block->next; + } + if (dyn_array->last_block == block) { + dyn_array->last_block = last_block; + } + kfree(block); + } + return; + } + } + last_block = block; + block = block->next; + } +} + +bool dyn_array_is_end( + DynArray *dyn_array, struct DynArrayBlock *block, int block_index, + int block_offset) { + return block == NULL && + block_offset == dyn_array->size % dyn_array->block_size; +} \ No newline at end of file diff --git a/src/lib/hash/Makefile b/src/lib/hash/Makefile new file mode 100644 index 0000000..c93104c --- /dev/null +++ b/src/lib/hash/Makefile @@ -0,0 +1,2 @@ +SRC += fnv.c +SRC += md5.c \ No newline at end of file diff --git a/src/lib/hash/fnv.c b/src/lib/hash/fnv.c new file mode 100644 index 0000000..6ce8322 --- /dev/null +++ b/src/lib/hash/fnv.c @@ -0,0 +1,37 @@ +#include + +#define FNV_32_PRIME 0x01000193 + +uint32_t fnv1_hash_32(const void *data, int len) { + const uint32_t fnv_offset_basis = 0x811c9dc5; // 2166136261 + + const uint8_t *p = (const uint8_t *)data; + uint32_t hash = fnv_offset_basis; + for (int i = 0; i < len; i++) { + hash *= FNV_32_PRIME; + hash ^= (uint32_t)(p[i]); + } + return hash; +} + +uint32_t fnv1a_hash_32(const void *data, int len) { + const uint32_t fnv_offset_basis = 0x811c9dc5; // 2166136261 + + const uint8_t *p = (const uint8_t *)data; + uint32_t hash = fnv_offset_basis; + for (int i = 0; i < len; i++) { + hash ^= (uint32_t)(p[i]); + hash *= FNV_32_PRIME; + } + return hash; +} + +uint32_t fnv0_hash_32(const void *data, int len) { + const uint8_t *p = (const uint8_t *)data; + uint32_t hash = 0; + for (int i = 0; i < len; i++) { + hash *= FNV_32_PRIME; + hash ^= (uint32_t)(p[i]); + } + return hash; +} diff --git a/src/lib/hash/md5.c b/src/lib/hash/md5.c new file mode 100644 index 0000000..5e96b2a --- /dev/null +++ b/src/lib/hash/md5.c @@ -0,0 +1,185 @@ +/** + * @file md5.c + * @author Jiajun Wang (ryan1202@foxmail.com) + * @brief MD5 + * Reference: + * RFC1321: The MD5 Message-Digest Algorithm + * + */ +#include +#include +#include +#include + +#define S11 7 +#define S12 12 +#define S13 17 +#define S14 22 +#define S21 5 +#define S22 9 +#define S23 14 +#define S24 20 +#define S31 4 +#define S32 11 +#define S33 16 +#define S34 23 +#define S41 6 +#define S42 10 +#define S43 15 +#define S44 21 + +#define F(x, y, z) (((x) & (y)) | ((~x) & (z))) +#define G(x, y, z) (((x) & (z)) | ((y) & (~z))) +#define H(x, y, z) ((x) ^ (y) ^ (z)) +#define I(x, y, z) ((y) ^ ((x) | (~z))) +#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n)))) + +#define FF(a, b, c, d, x, s, ac) \ + { \ + (a) += F((b), (c), (d)) + (x) + (ac); \ + (a) = ROTATE_LEFT((a), (s)); \ + (a) += (b); \ + } +#define GG(a, b, c, d, x, s, ac) \ + { \ + (a) += G((b), (c), (d)) + (x) + (ac); \ + (a) = ROTATE_LEFT((a), (s)); \ + (a) += (b); \ + } +#define HH(a, b, c, d, x, s, ac) \ + { \ + (a) += H((b), (c), (d)) + (x) + (ac); \ + (a) = ROTATE_LEFT((a), (s)); \ + (a) += (b); \ + } +#define II(a, b, c, d, x, s, ac) \ + { \ + (a) += I((b), (c), (d)) + (x) + (ac); \ + (a) = ROTATE_LEFT((a), (s)); \ + (a) += (b); \ + } + +PRIVATE void md5_transform(uint32_t state[4], const uint8_t block[64]) { + uint32_t a = state[0], b = state[1], c = state[2], d = state[3]; + uint32_t x[16]; + + for (int i = 0; i < 16; i++) { + x[i] = HOST2LE_DWORD(((uint32_t *)block)[i]); + } + + /* Round 1 */ + FF(a, b, c, d, x[0], S11, 0xd76aa478); /* 1 */ + FF(d, a, b, c, x[1], S12, 0xe8c7b756); /* 2 */ + FF(c, d, a, b, x[2], S13, 0x242070db); /* 3 */ + FF(b, c, d, a, x[3], S14, 0xc1bdceee); /* 4 */ + FF(a, b, c, d, x[4], S11, 0xf57c0faf); /* 5 */ + FF(d, a, b, c, x[5], S12, 0x4787c62a); /* 6 */ + FF(c, d, a, b, x[6], S13, 0xa8304613); /* 7 */ + FF(b, c, d, a, x[7], S14, 0xfd469501); /* 8 */ + FF(a, b, c, d, x[8], S11, 0x698098d8); /* 9 */ + FF(d, a, b, c, x[9], S12, 0x8b44f7af); /* 10 */ + FF(c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */ + FF(b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */ + FF(a, b, c, d, x[12], S11, 0x6b901122); /* 13 */ + FF(d, a, b, c, x[13], S12, 0xfd987193); /* 14 */ + FF(c, d, a, b, x[14], S13, 0xa679438e); /* 15 */ + FF(b, c, d, a, x[15], S14, 0x49b40821); /* 16 */ + + /* Round 2 */ + GG(a, b, c, d, x[1], S21, 0xf61e2562); /* 17 */ + GG(d, a, b, c, x[6], S22, 0xc040b340); /* 18 */ + GG(c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */ + GG(b, c, d, a, x[0], S24, 0xe9b6c7aa); /* 20 */ + GG(a, b, c, d, x[5], S21, 0xd62f105d); /* 21 */ + GG(d, a, b, c, x[10], S22, 0x2441453); /* 22 */ + GG(c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */ + GG(b, c, d, a, x[4], S24, 0xe7d3fbc8); /* 24 */ + GG(a, b, c, d, x[9], S21, 0x21e1cde6); /* 25 */ + GG(d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */ + GG(c, d, a, b, x[3], S23, 0xf4d50d87); /* 27 */ + GG(b, c, d, a, x[8], S24, 0x455a14ed); /* 28 */ + GG(a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */ + GG(d, a, b, c, x[2], S22, 0xfcefa3f8); /* 30 */ + GG(c, d, a, b, x[7], S23, 0x676f02d9); /* 31 */ + GG(b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */ + + /* Round 3 */ + HH(a, b, c, d, x[5], S31, 0xfffa3942); /* 33 */ + HH(d, a, b, c, x[8], S32, 0x8771f681); /* 34 */ + HH(c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */ + HH(b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */ + HH(a, b, c, d, x[1], S31, 0xa4beea44); /* 37 */ + HH(d, a, b, c, x[4], S32, 0x4bdecfa9); /* 38 */ + HH(c, d, a, b, x[7], S33, 0xf6bb4b60); /* 39 */ + HH(b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */ + HH(a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */ + HH(d, a, b, c, x[0], S32, 0xeaa127fa); /* 42 */ + HH(c, d, a, b, x[3], S33, 0xd4ef3085); /* 43 */ + HH(b, c, d, a, x[6], S34, 0x4881d05); /* 44 */ + HH(a, b, c, d, x[9], S31, 0xd9d4d039); /* 45 */ + HH(d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */ + HH(c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */ + HH(b, c, d, a, x[2], S34, 0xc4ac5665); /* 48 */ + + /* Round 4 */ + II(a, b, c, d, x[0], S41, 0xf4292244); /* 49 */ + II(d, a, b, c, x[7], S42, 0x432aff97); /* 50 */ + II(c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */ + II(b, c, d, a, x[5], S44, 0xfc93a039); /* 52 */ + II(a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */ + II(d, a, b, c, x[3], S42, 0x8f0ccc92); /* 54 */ + II(c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */ + II(b, c, d, a, x[1], S44, 0x85845dd1); /* 56 */ + II(a, b, c, d, x[8], S41, 0x6fa87e4f); /* 57 */ + II(d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */ + II(c, d, a, b, x[6], S43, 0xa3014314); /* 59 */ + II(b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */ + II(a, b, c, d, x[4], S41, 0xf7537e82); /* 61 */ + II(d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */ + II(c, d, a, b, x[2], S43, 0x2ad7d2bb); /* 63 */ + II(b, c, d, a, x[9], S44, 0xeb86d391); /* 64 */ + + state[0] += a; + state[1] += b; + state[2] += c; + state[3] += d; + + memset32(x, 0, 16); +} + +void md5(uint8_t digest[16], const uint8_t *data, size_t len) { + // 初始化MD5状态 + uint32_t state[4] = {0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476}; + + size_t i; + uint64_t bit_len = len * 8; + // 处理数据 + for (i = 0; i + 63 < len; i += 64) { + md5_transform(state, data + i); + } + + uint8_t buffer[64]; + size_t rem = len - i; + memcpy(buffer, data + i, rem); + + buffer[rem] = 0x80; + rem++; + + if (rem > 56) { + memset(buffer + rem, 0, 64 - rem); + md5_transform(state, buffer); + memset(buffer + rem, 0, rem - 56); + } else { + memset(buffer + rem, 0, 56 - rem); + } + + for (int j = 0; j < 8; j++) + buffer[56 + j] = (uint8_t)(bit_len >> (j * 8)); + + md5_transform(state, buffer); + + // 输出结果 + for (size_t i = 0; i < 4; i++) { + ((uint32_t *)digest)[i] = LE2HOST_DWORD(state[i]); + } +} \ No newline at end of file diff --git a/src/lib/math.c b/src/lib/math.c index 35b5967..fbca6ea 100644 --- a/src/lib/math.c +++ b/src/lib/math.c @@ -1,26 +1,77 @@ +#include #include -int max(int a, int b) -{ - return a>b ? a : b; +int max(int a, int b) { + return a > b ? a : b; } -int min(int a, int b) -{ - return a=0 ? n : -n; +int abs(int n) { + return n >= 0 ? n : -n; } -int pow(int x, int y) -{ +int pow(int x, int y) { int i, ans = x; - for(i = 0; i < y; i++) - { + for (i = 0; i < y; i++) { ans *= x; } return ans; -} \ No newline at end of file +} + +unsigned int find_next_pow_of_2(unsigned int n) { +#ifdef HAS_BUILTIN_CLZ + if (n == 0) return 1; + return 1 << (32 - __builtin_clz(n - 1)); +#else + n--; + n |= n >> 1; + n |= n >> 2; + n |= n >> 4; + n |= n >> 8; + n |= n >> 16; + n++; +#endif + return n; +} + +// 计算log2(n)的向上取整 +int aligned_up_log2n(unsigned int n) { +#ifdef HAS_BUILTIN_CLZ + return 32 - __builtin_clz(n - 1); +#else + // De Bruijn序列查找表(32位版本) + static const uint8_t de_bruijn_table[32] = { + 0, 9, 1, 10, 13, 21, 2, 29, 11, 14, 16, 18, 22, 25, 3, 30, + 8, 12, 20, 28, 15, 17, 24, 7, 19, 27, 23, 6, 26, 5, 4, 31}; + n--; + n |= n >> 1; + n |= n >> 2; + n |= n >> 4; + n |= n >> 8; + n |= n >> 16; + n++; + return de_bruijn_table[(n * 0x07C4ACDD) >> 27]; +#endif +} + +int aligned_down_log2n(unsigned int n) { +#ifdef HAS_BUILTIN_CLZ + return 31 - __builtin_clz(n); +#else + // De Bruijn序列查找表(32位版本) + static const uint8_t de_bruijn_table[32] = { + 0, 9, 1, 10, 13, 21, 2, 29, 11, 14, 16, 18, 22, 25, 3, 30, + 8, 12, 20, 28, 15, 17, 24, 7, 19, 27, 23, 6, 26, 5, 4, 31}; + n |= n >> 1; + n |= n >> 2; + n |= n >> 4; + n |= n >> 8; + n |= n >> 16; + n >>= 1; + n++; + return de_bruijn_table[(n * 0x07C4ACDD) >> 27]; +#endif +} diff --git a/src/lib/rand.c b/src/lib/rand.c deleted file mode 100644 index 179b5e9..0000000 --- a/src/lib/rand.c +++ /dev/null @@ -1,12 +0,0 @@ -#include - -static unsigned long int __seed = 1; - -void srand(unsigned long seed) { - __seed = seed; -} - -int rand() { - __seed = __seed * 1103515245 + 12345; - return (int)(__seed >> 16) % 0x7fff; -} \ No newline at end of file diff --git a/src/lib/random.c b/src/lib/random.c new file mode 100644 index 0000000..7810ad7 --- /dev/null +++ b/src/lib/random.c @@ -0,0 +1,42 @@ +#include + +#define GOLDEN_RATIO_32 0x9e3779b9u +#define SPLITMIX32_MUL1 0x85ebca6bu +#define SPLITMIX32_MUL2 0xc2b2ae35u + +static uint32_t xorshift_state = 0; + +uint32_t splitmix(uint32_t x); + +void rand_seed(uint32_t seed) { + uint32_t a = (uint32_t)(void *)&a; // 栈地址 + uint32_t b = (uint32_t)(void *)rand_seed; // 函数地址 + uint32_t c = (uint32_t)(void *)__builtin_return_address(0); // 返回地址 + + xorshift_state = seed ^ a ^ b ^ c ? seed : GOLDEN_RATIO_32; + + xorshift_state = splitmix(xorshift_state); // 使用splitmix算法 +} + +uint32_t rand(void) { + if (xorshift_state == 0) { + xorshift_state = GOLDEN_RATIO_32; // 避免状态为0 + rand_seed(xorshift_state); + } + uint32_t x = xorshift_state; + x ^= x << 13; + x ^= x >> 17; + x ^= x << 5; + xorshift_state = x; + return x; +} + +uint32_t splitmix(uint32_t x) { + x += GOLDEN_RATIO_32; + x ^= x >> 16; + x *= SPLITMIX32_MUL1; + x ^= x >> 13; + x *= SPLITMIX32_MUL2; + x ^= x >> 16; + return x; +} \ No newline at end of file diff --git a/src/lib/string.c b/src/lib/string.c index 3ab0033..ba9f51a 100644 --- a/src/lib/string.c +++ b/src/lib/string.c @@ -7,6 +7,7 @@ #include #include +#include /** * @brief 初始化字符串 @@ -29,6 +30,7 @@ void string_init(string_t *string) { */ int string_new(string_t *string, char *text, unsigned int max_len) { if (string == NULL || text == NULL || max_len < 1) { return -1; } + max_len += 1; string->text = kmalloc(max_len); if (string->text == NULL) { return -1; } @@ -42,6 +44,69 @@ int string_new(string_t *string, char *text, unsigned int max_len) { return 0; } +/** + * @brief 新建带数字后缀的字符串 + * + * @param string + * @param text 文本 + * @param text_len 文本长度 + * @param number 数字 + * @return int + */ +int string_new_with_number( + string_t *string, char *text, int text_len, int number) { + + // 计算数字长度 + int len = 0; + int x = number; + do { + len++; + x /= 10; + } while (x > 0); + + int ret = string_new(string, text, text_len + len + 1); + if (ret != 0) { return ret; } + string->length = text_len + len + 1; + string->text[string->length - 1] = '\0'; + + x = number; + for (int i = text_len + len - 1; i >= text_len; i--) { + string->text[i] = '0' + x % 10; + x /= 10; + } + + return 0; +} + +int string_new_with_string_number( + string_t *string, char *text, int text_len, char *append_text, + int append_text_len, int number) { + + // 计算数字长度 + int len = 0; + int x = number; + do { + len++; + x /= 10; + } while (x > 0); + + int ret = string_new(string, text, text_len + append_text_len + len + 1); + if (ret != 0) { return ret; } + string->length = text_len + append_text_len + len + 1; + string->text[string->length - 1] = '\0'; + + strncpy(string->text + text_len, append_text, append_text_len); + + x = number; + for (int i = text_len + append_text_len + len - 1; + i >= text_len + append_text_len; i--) { + string->text[i] = '0' + x % 10; + x /= 10; + } + + return 0; +} + /** * @brief 删除字符串 * @@ -78,13 +143,14 @@ int strncmp(const char *s1, const char *s2, int n) { return (*s1 - *s2); } -char *itoa(char **ps, int val, int base) { +char *itoa(char *ps, int val, int base) { int m = val % base; int q = val / base; if (q) { itoa(ps, q, base); } - *(*ps)++ = (m < 10) ? (m + '0') : (m - 10 + 'A'); + *ps = (m < 10) ? (m + '0') : (m - 10 + 'A'); + ps++; - return *ps; + return ps; } int atoi(const char *src) { @@ -140,7 +206,7 @@ void *memset32(void *src, uint32_t value, uint32_t size) { void memcpy(void *dst_, const void *src_, uint32_t size) { - uint8_t *dst = dst_; + uint8_t *dst = dst_; const uint8_t *src = src_; while (size-- > 0) { *dst = *src; @@ -295,20 +361,20 @@ char *itoa16_align(char *str, int num) { char *p = str; char ch; int i; - //为0 + // 为0 if (num == 0) { *p++ = '0'; } else { // 4位4位的分解出来 - for (i = 28; i >= 0; i -= 4) { //从最高得4位开始 - ch = (num >> i) & 0xF; //取得4位 - ch += '0'; //大于0就+'0'变成ASICA的数字 - if (ch > '9') { //大于9就加上7变成ASICA的字母 + for (i = 28; i >= 0; i -= 4) { // 从最高得4位开始 + ch = (num >> i) & 0xF; // 取得4位 + ch += '0'; // 大于0就+'0'变成ASICA的数字 + if (ch > '9') { // 大于9就加上7变成ASICA的字母 ch += 7; } - *p++ = ch; //指针地址上记录下来。 + *p++ = ch; // 指针地址上记录下来。 } } - *p = 0; //最后在指针地址后加个0用于字符串结束 + *p = 0; // 最后在指针地址后加个0用于字符串结束 return str; } @@ -338,19 +404,22 @@ int strmet(const char *src, char *buf, char ch) { char *strstr(const char *haystack, const char *needle) { char *thaystack = (char *)haystack; char *tneedle = (char *)needle; - int i = 0; // thaystack 主串的元素下标位置,从下标0开始找,可以通过变量进行设置,从其他下标开始找! - int j = 0; // tneedle 子串的元素下标位置 + int i = + 0; // thaystack + // 主串的元素下标位置,从下标0开始找,可以通过变量进行设置,从其他下标开始找! + int j = 0; // tneedle 子串的元素下标位置 while (i <= strlen(thaystack) - 1 && j <= strlen(tneedle) - 1) { - //字符相等,则继续匹配下一个字符 + // 字符相等,则继续匹配下一个字符 if (thaystack[i] == tneedle[j]) { i++; j++; - } else { //在匹配过程中发现有一个字符和子串中的不等,马上回退到 下一个要匹配的位置 + } else { // 在匹配过程中发现有一个字符和子串中的不等,马上回退到 + // 下一个要匹配的位置 i = i - j + 1; j = 0; } } - //循环完了后j的值等于strlen(tneedle) 子串中的字符已经在主串中都连续匹配到了 + // 循环完了后j的值等于strlen(tneedle) 子串中的字符已经在主串中都连续匹配到了 if (j == strlen(tneedle)) { return thaystack + i - strlen(tneedle); } return NULL; @@ -380,7 +449,7 @@ const char *strpbrk(const char *str1, const char *str2) { const char *temp2 = str2; while (*temp1 != '\0') { - temp2 = str2; //将str2 指针从新指向在字符串的首地址 + temp2 = str2; // 将str2 指针从新指向在字符串的首地址 while (*temp2 != '\0') { if (*temp2 == *temp1) return temp1; else temp2++; diff --git a/src/lib/vsprintf.c b/src/lib/vsprintf.c index 686cf4d..4682759 100644 --- a/src/lib/vsprintf.c +++ b/src/lib/vsprintf.c @@ -5,13 +5,12 @@ * copyright: (C) 2018-2020 by Book OS developers. All rights reserved. */ -#include -#include #include +#include +#include -unsigned long simple_strtoul(const char *cp,char **endp,unsigned int base) -{ - unsigned long result = 0,value; +unsigned long simple_strtoul(const char *cp, char **endp, unsigned int base) { + unsigned long result = 0, value; if (!base) { base = 10; @@ -24,130 +23,138 @@ unsigned long simple_strtoul(const char *cp,char **endp,unsigned int base) } } } - while (isxdigit(*cp) && (value = isdigit(*cp) ? *cp-'0' : (islower(*cp) - ? toupper(*cp) : *cp)-'A'+10) < base) { - result = result*base + value; + while (isxdigit(*cp) && + (value = isdigit(*cp) ? *cp - '0' + : (islower(*cp) ? toupper(*cp) : *cp) - 'A' + + 10) < base) { + result = result * base + value; cp++; } - if (endp) - *endp = (char *)cp; + if (endp) *endp = (char *)cp; return result; } /* we use this so that we can do without the ctype library */ -#define is_digit(c) ((c) >= '0' && (c) <= '9') +#define is_digit(c) ((c) >= '0' && (c) <= '9') -static int skip_atoi(const char **s) -{ - int i=0; +static int skip_atoi(const char **s) { + int i = 0; while (is_digit(**s)) - i = i*10 + *((*s)++) - '0'; + i = i * 10 + *((*s)++) - '0'; return i; } -#define ZEROPAD 1 /* pad with zero */ -#define SIGN 2 /* unsigned/signed long */ -#define PLUS 4 /* show plus */ -#define SPACE 8 /* space if plus */ -#define LEFT 16 /* left justified */ -#define SPECIAL 32 /* 0x */ -#define SMALL 64 /* use 'abcdef' instead of 'ABCDEF' */ +#define ZEROPAD 1 /* pad with zero */ +#define SIGN 2 /* unsigned/signed long */ +#define PLUS 4 /* show plus */ +#define SPACE 8 /* space if plus */ +#define LEFT 16 /* left justified */ +#define SPECIAL 32 /* 0x */ +#define SMALL 64 /* use 'abcdef' instead of 'ABCDEF' */ -#define do_div(n,base) ({ \ -int __res; \ -__asm__("divl %4":"=a" (n),"=d" (__res):"0" (n),"1" (0),"r" (base)); \ -__res; }) +#define do_div(n, base) \ + ({ \ + int __res; \ + __asm__("divl %4" : "=a"(n), "=d"(__res) : "0"(n), "1"(0), "r"(base)); \ + __res; \ + }) -static char * number(char * str, int num, int base, int size, int precision - ,int type) -{ - char c,sign,tmp[36]; - const char *digits="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; - int i; +static char *number( + char *str, int num, int base, int size, int precision, int type) { + char c, sign, tmp[36]; + const char *digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + int i; - if (type&SMALL) digits="0123456789abcdefghijklmnopqrstuvwxyz"; - if (type&LEFT) type &= ~ZEROPAD; - if (base<2 || base>36) - return 0; - c = (type & ZEROPAD) ? '0' : ' ' ; - if (type&SIGN && num<0) { - sign='-'; - num = -num; - } else - sign=(type&PLUS) ? '+' : ((type&SPACE) ? ' ' : 0); + if (type & SMALL) digits = "0123456789abcdefghijklmnopqrstuvwxyz"; + if (type & LEFT) type &= ~ZEROPAD; + if (base < 2 || base > 36) return 0; + c = (type & ZEROPAD) ? '0' : ' '; + if (type & SIGN && num < 0) { + sign = '-'; + num = -num; + } else sign = (type & PLUS) ? '+' : ((type & SPACE) ? ' ' : 0); if (sign) size--; - if (type&SPECIAL) - if (base==16) size -= 2; - else if (base==8) size--; - i=0; - if (num==0) - tmp[i++]='0'; - else while (num!=0) - tmp[i++]=digits[do_div(num,base)]; - if (i>precision) precision=i; + if (type & SPECIAL) { + if (base == 16) size -= 2; + else if (base == 8) size--; + } + i = 0; + if (num == 0) tmp[i++] = '0'; + else + while (num != 0) + tmp[i++] = digits[do_div(num, base)]; + if (i > precision) precision = i; size -= precision; - if (!(type&(ZEROPAD+LEFT))) - while(size-->0) + if (!(type & (ZEROPAD + LEFT))) + while (size-- > 0) *str++ = ' '; - if (sign) - *str++ = sign; - if (type&SPECIAL) - if (base==8) + if (sign) *str++ = sign; + if (type & SPECIAL) { + if (base == 8) { *str++ = '0'; - else if (base==16) { + } else if (base == 16) { *str++ = '0'; *str++ = digits[33]; } - if (!(type&LEFT)) - while(size-->0) + } + if (!(type & LEFT)) + while (size-- > 0) *str++ = c; - while(i0) + while (i-- > 0) *str++ = tmp[i]; - while(size-->0) + while (size-- > 0) *str++ = ' '; return str; } -int vsprintf(char *buf, const char *fmt, va_list args) -{ - int len; - int i; - char * str; +int vsprintf(char *buf, const char *fmt, va_list args) { + int len; + int i; + char *str; char *s; - int *ip; + int *ip; - int flags; /* flags to number() */ + int flags; /* flags to number() */ - int field_width; /* width of output field */ - int precision; /* min. # of digits for integers; max - number of chars for from string */ - int qualifier; /* 'h', 'l', or 'L' for integer fields */ + int field_width; /* width of output field */ + int precision; /* min. # of digits for integers; max + number of chars for from string */ + // int qualifier; /* 'h', 'l', or 'L' for integer fields */ - for (str=buf ; *fmt ; ++fmt) { + for (str = buf; *fmt; ++fmt) { if (*fmt != '%') { *str++ = *fmt; continue; } - + /* process flags */ flags = 0; - repeat: - ++fmt; /* this also skips first '%' */ - switch (*fmt) { - case '-': flags |= LEFT; goto repeat; - case '+': flags |= PLUS; goto repeat; - case ' ': flags |= SPACE; goto repeat; - case '#': flags |= SPECIAL; goto repeat; - case '0': flags |= ZEROPAD; goto repeat; - } - + repeat: + ++fmt; /* this also skips first '%' */ + switch (*fmt) { + case '-': + flags |= LEFT; + goto repeat; + case '+': + flags |= PLUS; + goto repeat; + case ' ': + flags |= SPACE; + goto repeat; + case '#': + flags |= SPECIAL; + goto repeat; + case '0': + flags |= ZEROPAD; + goto repeat; + } + /* get field width */ field_width = -1; - if (is_digit(*fmt)) - field_width = skip_atoi(&fmt); + if (is_digit(*fmt)) field_width = skip_atoi(&fmt); else if (*fmt == '*') { /* it's the next argument */ field_width = va_arg(args, int); @@ -160,21 +167,19 @@ int vsprintf(char *buf, const char *fmt, va_list args) /* get the precision */ precision = -1; if (*fmt == '.') { - ++fmt; - if (is_digit(*fmt)) - precision = skip_atoi(&fmt); + ++fmt; + if (is_digit(*fmt)) precision = skip_atoi(&fmt); else if (*fmt == '*') { /* it's the next argument */ precision = va_arg(args, int); } - if (precision < 0) - precision = 0; + if (precision < 0) precision = 0; } /* get the conversion qualifier */ - qualifier = -1; + // qualifier = -1; if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L') { - qualifier = *fmt; + // qualifier = *fmt; ++fmt; } @@ -183,20 +188,17 @@ int vsprintf(char *buf, const char *fmt, va_list args) if (!(flags & LEFT)) while (--field_width > 0) *str++ = ' '; - *str++ = (unsigned char) va_arg(args, int); + *str++ = (unsigned char)va_arg(args, int); while (--field_width > 0) *str++ = ' '; break; case 's': s = va_arg(args, char *); - if (!s) - s = ""; + if (!s) s = ""; len = strlen(s); - if (precision < 0) - precision = len; - else if (len > precision) - len = precision; + if (precision < 0) precision = len; + else if (len > precision) len = precision; if (!(flags & LEFT)) while (len < field_width--) @@ -208,8 +210,9 @@ int vsprintf(char *buf, const char *fmt, va_list args) break; case 'o': - str = number(str, va_arg(args, unsigned long), 8, - field_width, precision, flags); + str = number( + str, va_arg(args, unsigned long), 8, field_width, precision, + flags); break; case 'p': @@ -217,53 +220,50 @@ int vsprintf(char *buf, const char *fmt, va_list args) field_width = 8; flags |= ZEROPAD; } - str = number(str, - (unsigned long) va_arg(args, void *), 16, - field_width, precision, flags); + str = number( + str, (unsigned long)va_arg(args, void *), 16, field_width, + precision, flags); break; case 'x': flags |= SMALL; case 'X': - str = number(str, va_arg(args, unsigned long), 16, - field_width, precision, flags); + str = number( + str, va_arg(args, unsigned long), 16, field_width, precision, + flags); break; case 'd': case 'i': flags |= SIGN; case 'u': - str = number(str, va_arg(args, unsigned long), 10, - field_width, precision, flags); + str = number( + str, va_arg(args, unsigned long), 10, field_width, precision, + flags); break; case 'n': - ip = va_arg(args, int *); + ip = va_arg(args, int *); *ip = (str - buf); break; default: - if (*fmt != '%') - *str++ = '%'; - if (*fmt) - *str++ = *fmt; - else - --fmt; + if (*fmt != '%') *str++ = '%'; + if (*fmt) *str++ = *fmt; + else --fmt; break; } } *str = '\0'; - return str-buf; + return str - buf; } -int sprintf(char * buf, const char *fmt, ...) -{ +int sprintf(char *buf, const char *fmt, ...) { va_list args; - int i; + int i; va_start(args, fmt); - i=vsprintf(buf,fmt,args); + i = vsprintf(buf, fmt, args); va_end(args); return i; } - diff --git a/src/network/Makefile b/src/network/Makefile deleted file mode 100644 index d88c4da..0000000 --- a/src/network/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -SRC += network.c -SRC += eth.c -SRC += arp.c -SRC += ipv4.c -SRC += udp.c -SRC += dhcp.c -SRC += tcp.c \ No newline at end of file diff --git a/src/network/arp.c b/src/network/arp.c deleted file mode 100644 index 94a1a4c..0000000 --- a/src/network/arp.c +++ /dev/null @@ -1,73 +0,0 @@ -#include -#include -#include -#include -#include -#include - -LIST_HEAD(arp_cache_lh); - -uint8_t *ip2mac(netc_t *netc, uint8_t *ip) { - arp_cache_t *cur, *next; - arp_cache_t *cache; - list_for_each_owner_safe (cur, next, &arp_cache_lh, list) { - if (memcmp(cur->ip, ip, 4) == 0) { - if (cur->mac[0] != 0) { - return cur->mac; - } else { - wait_queue_add(&cur->wqm, 0); - thread_block(TASK_BLOCKED); - } - } - } - - cache = kmalloc(sizeof(arp_cache_t)); - memcpy(cache->ip, ip, 4); - wait_queue_init(&cache->wqm); - list_add_tail(&cache->list, &arp_cache_lh); - send_arp(netc, ip, ARP_REQUEST); - while (cache->mac[0] == 0) {} - return cache->mac; -} - -void send_arp(netc_t *netc, uint8_t *dst_ip, uint16_t opcode) { - arp_pack_t pack; - - pack.hwtype = HOST2BE_WORD(ARP_HWTYPE_ETH); - pack.pttype = HOST2BE_WORD(ARP_PTTYPE_IPV4); - pack.hwlen = 6; - pack.ptlen = 4; - pack.opcode = HOST2BE_WORD(opcode); - - memcpy(pack.src_hw_addr, netc->net_dev->info->mac, 6); - ipv4_get_ip(netc, pack.src_ip); - memcpy(pack.dst_ip, dst_ip, 4); - memcpy(pack.dst_hw_addr, netc->dst_mac, 6); - - netc->net_dev->net_write(netc, (uint8_t *)&pack, sizeof(arp_pack_t)); -} - -void arp_read(uint8_t *buf, uint16_t offset, uint16_t length) { - arp_pack_t *arp; - arp_cache_t *cur, *next; - - arp = (arp_pack_t *)(buf + offset); - arp->hwtype = BE2HOST_WORD(arp->hwtype); - arp->pttype = BE2HOST_WORD(arp->pttype); - arp->opcode = BE2HOST_WORD(arp->opcode); - - if (arp->opcode == ARP_REPLY) { - list_for_each_owner_safe (cur, next, &arp_cache_lh, list) { - if (memcmp(cur->ip, arp->src_ip, 4) == 0) { - if (cur->mac[0] == 0) { - memcpy(cur->mac, arp->src_hw_addr, 6); - wait_queue_wakeup_all(&cur->wqm); - } else { - memcpy(cur->mac, arp->src_hw_addr, 6); - } - return; - } - } - } - return; -} diff --git a/src/network/dhcp.c b/src/network/dhcp.c deleted file mode 100644 index 5546052..0000000 --- a/src/network/dhcp.c +++ /dev/null @@ -1,132 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -uint8_t dhcp_magic_cookie[4] = {99, 130, 83, 99}; - -int dhcp_main(net_device_t *net_dev) { - uint8_t *buf = kmalloc(sizeof(dhcp_basic_t) + 20); - device_t *device = net_dev->device; - netc_t *netc; - dhcp_basic_t dhcp; - dhcp_info_t *dhcp_info = kmalloc(sizeof(dhcp_info_t)); - uint8_t option = DHCP_OPTION_END, len, msg_type; - - int flag; - - net_dev->info->dhcp_data = dhcp_info; - - memset(&dhcp, 0, sizeof(dhcp_basic_t)); - dhcp.Op = DHCP_OP_REQUEST; - if (device->type == DEV_ETH_NET) { - dhcp.htype = 1; - dhcp.hlen = 6; - } else { - return -1; - } - dhcp.hops = 0; - dhcp.xID = HOST2BE_DWORD(rand()); - dhcp.secs = 0; - dhcp.flags = HOST2BE_WORD(0x8000); - memcpy(dhcp.chAddr, net_dev->info->mac, 6); - - memcpy(buf, &dhcp, sizeof(dhcp_basic_t)); - memcpy(buf + sizeof(dhcp_basic_t), dhcp_magic_cookie, 4); - buf[sizeof(dhcp_basic_t) + 4] = DHCP_OPTION_MSG_TYPE; - buf[sizeof(dhcp_basic_t) + 5] = 1; - buf[sizeof(dhcp_basic_t) + 6] = DHCP_DISCOVER; - buf[sizeof(dhcp_basic_t) + 7] = DHCP_OPTION_END; - - netc = netc_create(net_dev, ETH_TYPE_IPV4, PROTOCOL_UDP); - netc_set_dest(netc, broadcast_mac, NULL, 0); - if (udp_bind(netc, broadcast_ipv4_addr, 68, 67) < 0) return -1; - - udp_send(netc, (uint16_t *)buf, sizeof(dhcp_basic_t) + 8); - netc_read(netc, buf, sizeof(dhcp_basic_t) + 4); - if (memcmp(buf + sizeof(dhcp_basic_t), dhcp_magic_cookie, 4) != 0) return -2; - netc_read(netc, &option, sizeof(option)); - netc_read(netc, &len, sizeof(len)); - if (option != DHCP_OPTION_MSG_TYPE) return -3; - netc_read(netc, &msg_type, len); - if (msg_type != DHCP_OFFER) return -3; - - memcpy(dhcp_info->server_ip, ((dhcp_basic_t *)buf)->siAddr, 4); - - struct ipv4_data *ipv4 = (struct ipv4_data *)netc->net_dev->info->ipv4_data; - flag = 1; - while (flag) { - netc_read(netc, &option, sizeof(option)); - netc_read(netc, &len, sizeof(len)); - switch (option) { - case DHCP_OPTION_END: - flag = 0; - break; - case DHCP_OPTION_SERVER_ID: - netc_read(netc, (uint8_t *)&dhcp_info->server_id, 4); - break; - case DHCP_OPTION_ROUTER: - netc_read(netc, ipv4->router_ip, len); - break; - case DHCP_OPTION_SUBNET_MASK: - netc_read(netc, ipv4->subnet_mask, len); - break; - case DHCP_OPTION_DOMAIN_SERVER: - netc_read(netc, ipv4->dns_server_ip, len); - break; - case DHCP_OPTION_LEASE_TIME: - netc_read(netc, (uint8_t *)&dhcp_info->lease_time, 4); - dhcp_info->lease_time = BE2HOST_DWORD(dhcp_info->lease_time); - break; - - default: - break; - } - } - netc_drop_all(netc); - - uint8_t *options = buf + sizeof(dhcp_basic_t) + 4; - memcpy(buf, &dhcp, sizeof(dhcp_basic_t)); - options[0] = DHCP_OPTION_MSG_TYPE; - options[1] = 1; - options[2] = DHCP_REQUEST; - options[3] = DHCP_OPTION_SERVER_ID; - options[4] = 4; - memcpy(options + 5, &dhcp_info->server_id, 4); - options[9] = DHCP_OPTION_LEASE_TIME; - options[10] = 4; - *((uint32_t *)(options + 11)) = HOST2BE_DWORD(dhcp_info->lease_time); - options[15] = DHCP_OPTION_END; - udp_send(netc, (uint16_t *)buf, sizeof(dhcp_basic_t) + 20); - - netc_read(netc, buf, sizeof(dhcp_basic_t) + 4); - if (memcmp(buf + sizeof(dhcp_basic_t), dhcp_magic_cookie, 4) != 0) return -2; - ipv4_set_ip(netc, ((dhcp_basic_t *)buf)->yiAddr); - netc_read(netc, &option, sizeof(option)); - netc_read(netc, &len, sizeof(len)); - if (option != DHCP_OPTION_MSG_TYPE) return -3; - netc_read(netc, &msg_type, len); - if (msg_type == DHCP_NAK) return -4; - else if (msg_type != DHCP_ACK) return -3; - while (1) { - netc_read(netc, &option, 1); - if (option != DHCP_OPTION_END) { - netc_read(netc, &len, 1); - netc_read(netc, buf, len); - } else { - break; - } - } - - netc_drop_all(netc); - udp_unbind(netc); - netc_delete(netc); - - return 0; -} \ No newline at end of file diff --git a/src/network/eth.c b/src/network/eth.c deleted file mode 100644 index 6ea602c..0000000 --- a/src/network/eth.c +++ /dev/null @@ -1,105 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -void eth_device_register(struct _device_manager_s *dm, device_t *device, char *name); -void eth_device_unregister(struct _device_manager_s *dm, device_t *device); -void eth_driver_inited(struct _device_manager_s *dm); - -device_manager_t eth_dm = { - .name = {0, 0, NULL}, - .private_data = eth_handler, - .dm_register = eth_device_register, - .dm_unregister = eth_device_unregister, - .drv_inited = eth_driver_inited, -}; - -int eth_read(netc_t *netc, uint8_t *buffer, uint32_t length) { - // device_t *device = list_owner(&inode->device->listm, device_t, listm); - // return device->drv_obj->function.driver_read(device, buffer, 0, length); - return 0; -} - -int eth_write(netc_t *netc, uint8_t *buffer, uint32_t length) { - eth_frame_t *frame; - uint16_t size = MAX(ETH_MIN_FRAME_SIZE, length + 14); - uint8_t *buf = kmalloc(size); - frame = (eth_frame_t *)buf; - - memcpy(frame->src_mac, netc->net_dev->info->mac, 6); - memcpy(frame->dest_mac, netc->dst_mac, 6); - frame->type = HOST2BE_WORD(netc->protocol); - memcpy(buf + 14, buffer, length); - memset(buf + length + 14, 0, size - length - 14); - DEV_WRITE(netc->net_dev->device, buf, 0, size); - kfree(buf); - return 0; -} - -void eth_handler(net_rx_pack_t *pack, uint8_t *buf, uint16_t size) { - eth_frame_t *frame; - - frame = (eth_frame_t *)buf; - frame->type = BE2HOST_WORD(frame->type); - switch (frame->type) { - case ETH_TYPE_IPV4: - ipv4_read(pack, buf, sizeof(eth_frame_t), size - sizeof(eth_frame_t)); - break; - case ETH_TYPE_ARP: - arp_read(buf, sizeof(eth_frame_t), size - sizeof(eth_frame_t)); - break; - - default: - break; - } -} - -void eth_device_register(struct _device_manager_s *dm, device_t *device, char *name) { - net_device_t *net_dev; - string_init(&device->name); - string_new(&device->name, name, strlen(name)); - net_dev = kmalloc(sizeof(net_device_t)); - net_dev->info = kmalloc(sizeof(struct network_info)); - net_dev->device = device; - net_dev->enable = 1; - list_add_tail(&net_dev->list, &dm->dev_listhead); - ipv4_init(net_dev); - - if (default_net_dev == NULL) { default_net_dev = net_dev; } -} - -void eth_device_unregister(struct _device_manager_s *dm, device_t *device) { - net_device_t *cur, *next; - string_del(&device->name); - list_for_each_owner_safe (cur, next, &dm->dev_listhead, list) { - if (cur->device == device) { - list_del(&cur->list); - return; - } - } -} - -void eth_driver_inited(struct _device_manager_s *dm) { - status_t stat; - net_device_t *cur, *next; - list_for_each_owner_safe (cur, next, &dm->dev_listhead, list) { - stat = cur->device->drv_obj->function.driver_open(cur->device); - DEV_CTL(cur->device, NET_FUNC_GET_MAC_ADDR, cur->info->mac); - if (stat != SUCCUESS) { - cur->enable = 0; - } else { - cur->net_read = ð_read; - cur->net_write = ð_write; - } - } -} diff --git a/src/network/ipv4.c b/src/network/ipv4.c deleted file mode 100644 index d193aed..0000000 --- a/src/network/ipv4.c +++ /dev/null @@ -1,124 +0,0 @@ -#include "network/netpack.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -uint8_t broadcast_ipv4_addr[4] = {0xff, 0xff, 0xff, 0xff}; - -void ipv4_init(net_device_t *netdev) { - struct ipv4_data *data; - struct network_info *net = netdev->info; - - net->ipv4_data = kmalloc(sizeof(struct ipv4_data)); - data = (struct ipv4_data *)net->ipv4_data; - memset(data->ip_addr, 0, 4); - spinlock_init(&data->idlock); - data->counter = 0; - memset(data->ip_addr, 0, 6); - DEV_CTL(netdev->device, NET_FUNC_GET_MTU, &data->mtu); - data->mtu -= 20; // 去掉ip头的长度 -} - -void ipv4_send_pack(netc_t *netc, uint8_t *dst_ip, uint8_t flags, uint8_t id, uint8_t ttl, uint8_t protocol, - uint8_t offset, uint8_t *data, uint16_t datalen) { - int i; - uint32_t chksum = 0; - ipv4_header_t *header; - net_device_t *net_dev = netc->net_dev; - struct ipv4_data *ipv4 = (struct ipv4_data *)net_dev->info->ipv4_data; - - uint16_t *buf = kmalloc(20 + datalen); - header = (ipv4_header_t *)buf; - - header->Version = 4; - header->IHL = 20 / 4; - header->TypeOfService = 0; - header->TotalLength = HOST2BE_WORD(20 + datalen); - header->Identification = HOST2BE_WORD(id); - header->Offset = HOST2BE_WORD((offset >> 3) | (flags << 13)); - header->TimetoLive = ttl; - header->Protocol = protocol; - header->HeaderChecksum = 0; // 先置0防止影响checksum计算 - memcpy(header->SourceAddress, ipv4->ip_addr, 4); - memcpy(header->DestinationAddress, dst_ip, 4); - memcpy((uint8_t *)buf + 20, data + offset, datalen); - - for (i = 0; i < 20 / sizeof(uint16_t); i++) { - chksum += BE2HOST_WORD(buf[i]); - } - header->HeaderChecksum = HOST2BE_WORD(~(uint16_t)((chksum & 0xffff) + (chksum >> 16))); - - net_dev->net_write(netc, (uint8_t *)buf, datalen + 20); - - kfree(buf); -} - -int ipv4_send(netc_t *netc, uint8_t *dst_ip, uint8_t DF, uint8_t ttl, uint8_t protocol, uint8_t *data, - uint32_t datalen) { - uint32_t i, id; - uint32_t len; - net_device_t *net_dev = netc->net_dev; - struct ipv4_data *ipv4 = (struct ipv4_data *)net_dev->info->ipv4_data; - - if (netc->dst_mac[0] == 0) return -1; - - i = 0; - len = datalen; - - spin_lock(&ipv4->idlock); - id = ipv4->counter++; - spin_unlock(&ipv4->idlock); - - while (len > ipv4->mtu) { - if (DF) { return -1; } // 不允许分片则直接退出 - ipv4_send_pack(netc, dst_ip, 1, id, ttl, protocol, i * ipv4->mtu, data, ipv4->mtu); - i++; - } - ipv4_send_pack(netc, dst_ip, 0, id, ttl, protocol, i * ipv4->mtu, data, datalen % ipv4->mtu); - return 0; -} - -void ipv4_read(net_rx_pack_t *pack, uint8_t *buf, uint16_t offset, uint16_t length) { - ipv4_header_t *header = (ipv4_header_t *)(buf + offset); - - header->HeaderChecksum = BE2HOST_WORD(header->HeaderChecksum); - header->Identification = BE2HOST_WORD(header->Identification); - header->Offset = BE2HOST_WORD(header->Offset); - header->TotalLength = BE2HOST_WORD(header->TotalLength); - - switch (header->Protocol) { - case PROTOCOL_TCP: - net_raw2tcp_pack(pack, 4, header->SourceAddress, offset + 20, header->TotalLength - 20); - break; - case PROTOCOL_UDP: - net_raw2udp_pack(pack, offset + 20, header->TotalLength - 20); - break; - - default: - kfree(pack->data); - kfree(pack); - break; - } -} - -void ipv4_get_ip(netc_t *netc, uint8_t *ip) { - struct ipv4_data *ipv4 = (struct ipv4_data *)netc->net_dev->info->ipv4_data; - memcpy(ip, ipv4->ip_addr, 4); -} - -void ipv4_set_ip(netc_t *netc, uint8_t *ip) { - struct ipv4_data *ipv4 = (struct ipv4_data *)netc->net_dev->info->ipv4_data; - memcpy(ipv4->ip_addr, ip, 4); -} - -int ipv4_get_mtu(netc_t *netc) { - struct ipv4_data *ipv4 = (struct ipv4_data *)netc->net_dev->info->ipv4_data; - return ipv4->mtu; -} diff --git a/src/network/network.c b/src/network/network.c deleted file mode 100644 index 074802e..0000000 --- a/src/network/network.c +++ /dev/null @@ -1,147 +0,0 @@ -#include "kernel/spinlock.h" -#include "network/tcp.h" -#include "network/udp.h" -#include "stdint.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -LIST_HEAD(net_rx_raw_pack_lh); -LIST_HEAD(net_rx_tcp_lh); -LIST_HEAD(net_rx_udp_lh); - -const int default_ttl = 64; - -uint8_t broadcast_mac[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; - -net_device_t *default_net_dev; - -void init_network(void) { - default_net_dev = NULL; - list_init(ð_dm.dev_listhead); -} - -netc_t *netc_create(net_device_t *net_dev, uint16_t protocol, uint16_t app_protocol) { - netc_t *netc = kmalloc(sizeof(netc_t)); - - spinlock_init(&netc->spin_lock); - - netc->net_dev = net_dev; - netc->thread = get_current_thread(); - netc->proto_private = NULL; - netc->app_private = NULL; - netc->recv_buffer = kmalloc(NET_MAX_BUFFER_SIZE); - netc->recv_offset = 0; - netc->recv_len = 0; - netc->protocol = protocol; - netc->app_protocl = app_protocol; - return netc; -} - -int netc_delete(netc_t *netc) { - if (netc->proto_private != NULL) { kfree(netc->proto_private); } - if (netc->app_private != NULL) { kfree(netc->app_private); } - kfree(netc); - return 0; -} - -void netc_set_dest(netc_t *netc, uint8_t dst_mac[6], uint8_t *dst_laddr, uint8_t dst_laddr_len) { - memcpy(netc->dst_mac, dst_mac, 6); - if (dst_laddr != NULL) { memcpy(netc->dst_laddr, dst_laddr, dst_laddr_len); } -} - -int netc_read(netc_t *netc, uint8_t *buf, uint32_t size) { - while (netc->recv_len == 0) {} - - int real_size = MIN(netc->recv_len, size); - if (netc->recv_offset + real_size > NET_MAX_BUFFER_SIZE) { - int tmp = NET_MAX_BUFFER_SIZE - netc->recv_offset; - memcpy(buf, netc->recv_buffer + netc->recv_offset, tmp); - memcpy(buf + tmp, netc->recv_buffer, real_size - tmp); - netc->recv_offset = real_size - tmp; - netc->recv_len -= real_size; - } else { - memcpy(buf, netc->recv_buffer + netc->recv_offset, real_size); - netc->recv_offset += real_size; - netc->recv_len -= real_size; - } - return real_size; -} - -void netc_drop_all(netc_t *netc) { - netc->recv_offset = 0; - netc->recv_len = 0; -} - -void netc_ip_send(netc_t *netc, uint8_t *ip, uint8_t DF, uint8_t proto, uint8_t *buf, uint32_t size) { - if (netc->protocol == ETH_TYPE_IPV4) { ipv4_send(netc, ip, DF, default_ttl, proto, buf, size); } -} - -int netc_get_mtu(netc_t *netc) { - switch (netc->protocol) { - case ETH_TYPE_IPV4: - return ipv4_get_mtu(netc); - break; - default: - break; - } -} - -void net_process_pack(void *arg) { - net_rx_pack_t *pack_cur, *next; - while (1) { - if (!list_empty(&net_rx_raw_pack_lh)) { - list_for_each_owner_safe (pack_cur, next, &net_rx_raw_pack_lh, list) { - list_del(&pack_cur->list); - switch (pack_cur->type) { - case ETH_FRAME: - eth_handler(pack_cur, pack_cur->data, pack_cur->data_len); - break; - default: - break; - } - } - list_for_each_owner_safe (pack_cur, next, &net_rx_tcp_lh, list) { - list_del(&pack_cur->list); - tcp_recv(pack_cur->data, pack_cur->proto_start, pack_cur->data_len, pack_cur->src_ip_addr, - pack_cur->src_ip_len); - } - // kfree(pack_cur->data); - kfree(pack_cur); - } else { - schedule(); - } - } -} - -void net_rx_raw_pack(enum frame_type type, uint8_t *buf, uint32_t length) { - - net_rx_pack_t *pack = kmalloc(sizeof(net_rx_pack_t)); - pack->type = type; - pack->data = buf; - pack->len = length; - list_add_tail(&pack->list, &net_rx_raw_pack_lh); -} - -void net_raw2tcp_pack(net_rx_pack_t *pack, uint8_t ip_len, uint8_t *ip_addr, uint32_t start, uint32_t len) { - pack->proto_start = start; - pack->src_ip_len = ip_len; - pack->src_ip_addr = ip_addr; - pack->data_len = len; - list_add_tail(&pack->list, &net_rx_tcp_lh); -} - -void net_raw2udp_pack(net_rx_pack_t *pack, uint32_t start, uint32_t len) { - pack->proto_start = start; - pack->data_len = len; - list_add_tail(&pack->list, &net_rx_tcp_lh); -} diff --git a/src/network/tcp.c b/src/network/tcp.c deleted file mode 100644 index 301448e..0000000 --- a/src/network/tcp.c +++ /dev/null @@ -1,539 +0,0 @@ -#include "kernel/list.h" -#include "kernel/memory.h" -#include "network/netpack.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -SPINLOCK(tcp_lock); -LIST_HEAD(tcp_lh); - -const int rmem_defualt_size = 32768; -const int wmem_defualt_size = 16384; - -uint16_t tcp_checksum(netc_t *netc, uint8_t dst_ip[4], uint8_t *buf, uint32_t length) { - int i; - uint8_t src_ip[4]; - uint32_t chksum = 0; - ipv4_get_ip(netc, src_ip); - chksum += (src_ip[0] << 8) + src_ip[1]; - chksum += (src_ip[2] << 8) + src_ip[3]; - chksum += (dst_ip[0] << 8) + dst_ip[1]; - chksum += (dst_ip[2] << 8) + dst_ip[3]; - chksum += PROTOCOL_TCP; - chksum += length; - for (i = 0; i < length / sizeof(uint16_t); i++) { - chksum += (buf[i * 2] << 8) + buf[i * 2 + 1]; - } - if (length % sizeof(uint16_t)) { chksum += buf[length - 1] << 8; } - while (chksum & 0xffff0000) { - chksum = (chksum >> 16) + (chksum & 0xffff); - } - - return (~chksum) & 0xffff; -} - -int tcp_send_for_status_change(netc_t *netc, uint8_t *buf, int length) { - tcp_conn_t *conn = (tcp_conn_t *)netc->app_private; - tcp_status_t status = conn->status; - - netc_ip_send(netc, conn->dst_ip, 0, PROTOCOL_TCP, buf, length); - - conn->wait_ms = 600; - conn->timer = timer_alloc(); - timer_init(conn->timer, &conn->fifo, 0); - fifo_init(&conn->fifo, 2, conn->fifo_buf); - timer_settime(conn->timer, conn->wait_ms / 10); - while (conn->status == status) { - if (fifo_status(&conn->fifo)) { - while (fifo_status(&conn->fifo)) - fifo_get(&conn->fifo); - conn->wait_ms *= 2; - if (conn->wait_ms >= 120000) { return -1; } - netc_ip_send(netc, conn->dst_ip, 0, PROTOCOL_TCP, buf, length); - timer_settime(conn->timer, conn->wait_ms / 10); - } - } - timer_free(conn->timer); - if (fifo_status(&conn->fifo)) fifo_get(&conn->fifo); - return 0; -} - -int tcp_send(netc_t *netc, uint8_t *buf, int length) { - tcp_conn_t *conn = (tcp_conn_t *)netc->app_private; - uint8_t *sendbuf = kmalloc(sizeof(tcp_header_t) + length); - tcp_header_t *header = (tcp_header_t *)sendbuf; - - memcpy(header, conn->header_buf, sizeof(tcp_header_t)); - - header->seq = HOST2BE_DWORD(conn->seq); - header->ack = HOST2BE_DWORD(conn->ack); - header->flags = TCP_FLAG_PSH | TCP_FLAG_ACK; - header->ack = HOST2BE_DWORD(conn->ack); - header->window = HOST2BE_WORD(conn->rwin.size - conn->rwin.acked - conn->rwin.recved); - header->urgent_pointer = 0; - - memcpy(sendbuf + sizeof(tcp_header_t), buf, length); - header->checksum = 0; - header->checksum = HOST2BE_WORD(tcp_checksum(netc, conn->dst_ip, sendbuf, sizeof(tcp_header_t) + length)); - - conn->swin.unacked += length; - conn->swin.sended -= length; - - netc_ip_send(netc, conn->dst_ip, 0, PROTOCOL_TCP, sendbuf, sizeof(tcp_header_t) + length); - - conn->wait_ms = 600; - conn->timer = timer_alloc(); - timer_init(conn->timer, &conn->fifo, 0); - fifo_init(&conn->fifo, 2, conn->fifo_buf); - timer_settime(conn->timer, conn->wait_ms / 10); - while (conn->swin.unacked) { - if (fifo_status(&conn->fifo)) { - while (fifo_status(&conn->fifo)) - fifo_get(&conn->fifo); - conn->wait_ms *= 2; - if (conn->wait_ms >= 120000) { return -1; } - netc_ip_send(netc, conn->dst_ip, 0, PROTOCOL_TCP, sendbuf, sizeof(tcp_header_t) + length); - timer_settime(conn->timer, conn->wait_ms / 10); - } - } - kfree(sendbuf); - timer_free(conn->timer); - if (fifo_status(&conn->fifo)) fifo_get(&conn->fifo); - return 0; -} - -int wait_for_status_change(netc_t *netc) { - tcp_conn_t *conn = (tcp_conn_t *)netc->app_private; - tcp_status_t status = conn->status; - int i = 0; - - conn->wait_ms = 1000; - conn->timer = timer_alloc(); - timer_init(conn->timer, &conn->fifo, 0); - fifo_init(&conn->fifo, 2, conn->fifo_buf); - timer_settime(conn->timer, conn->wait_ms / 10); - while (conn->status == status) { - if (fifo_status(&conn->fifo)) { - while (fifo_status(&conn->fifo)) - fifo_get(&conn->fifo); - i++; - if (i > 10) return -1; - } - } - timer_free(conn->timer); - if (fifo_status(&conn->fifo)) fifo_get(&conn->fifo); - return 0; -} - -void tcp_analyse_option(netc_t *netc, uint8_t *buf) { - int i = 0; - tcp_conn_t *conn = (tcp_conn_t *)netc->app_private; - uint8_t option_size = (((tcp_header_t *)buf)->offset >> 4) * 4 - sizeof(tcp_header_t); - buf += sizeof(tcp_header_t); - - while (i < option_size) { - switch (buf[i]) { - case TCP_OPTION_END: - return; - case TCP_OPTION_NOP: - break; - case TCP_OPTION_MSS: - conn->mss = MIN(conn->mss, BE2HOST_WORD(*(uint16_t *)(buf + i + 2))); - break; - default: - break; - } - } -} - -void tcp_create(netc_t *netc) { - tcp_conn_t *conn; - netc->app_private = kmalloc(sizeof(tcp_conn_t)); - conn = (tcp_conn_t *)netc->app_private; - conn->netc = netc; -} - -int tcp_bind(netc_t *netc, uint16_t src_port) { - tcp_conn_t *conn = (tcp_conn_t *)netc->app_private, *cur, *next; - - spin_lock(&tcp_lock); - list_for_each_owner_safe (cur, next, &tcp_lh, list) { - if (cur->src_port == src_port) { return -1; } - } - list_add_tail(&conn->list, &tcp_lh); - spin_unlock(&tcp_lock); - - conn->src_port = src_port; - conn->seq = rand(); - conn->ack = 0; - - conn->rwin.mem = kmalloc(rmem_defualt_size); - - conn->rwin.size = rmem_defualt_size; - conn->swin.size = 0; - conn->rwin.acked = 0; - conn->rwin.unacked = 0; - conn->swin.unacked = 0; - conn->rwin.recved = 0; - conn->swin.sended = 0; - conn->rwin.head = 0; - conn->swin.head = 0; - conn->rwin.tail = 0; - conn->swin.tail = 0; - - conn->mss = netc_get_mtu(netc) - sizeof(tcp_header_t); - - conn->status = TCP_STAT_CLOSED; - return 0; -} - -int tcp_unbind(netc_t *netc) { - tcp_conn_t *conn = (tcp_conn_t *)netc->app_private; - spin_lock(&tcp_lock); - list_del(&conn->list); - list_add_tail(&conn->list, &tcp_lh); - return 0; -} - -int tcp_ipv4_connect(netc_t *netc, uint8_t *ip, uint16_t dst_port) { - tcp_header_t *header; - tcp_conn_t *conn; - int tcp_length = sizeof(tcp_header_t) + 4; - - conn = (tcp_conn_t *)netc->app_private; - conn->header_buf = kmalloc(sizeof(tcp_header_t)); - header = (tcp_header_t *)conn->header_buf; - - conn->dst_port = dst_port; - memcpy(conn->dst_ip, ip, 4); - - // TCP第一次握手 - - header->src_port = HOST2BE_WORD(conn->src_port); - header->dst_port = HOST2BE_WORD(conn->dst_port); - header->seq = HOST2BE_DWORD(conn->seq); - header->ack = 0; - header->offset = (tcp_length / 4) << 4; - header->flags = TCP_FLAG_SYN; - header->window = HOST2BE_WORD(rmem_defualt_size); - header->urgent_pointer = 0; - header->checksum = 0; - - // 设置TCP Option最大分片大小(Maximum segment size) - conn->header_buf[sizeof(tcp_header_t) + 0] = TCP_OPTION_MSS; - conn->header_buf[sizeof(tcp_header_t) + 1] = 4; // 该Option长度为4字节 - *(uint16_t *)(conn->header_buf + sizeof(tcp_header_t) + 2) = HOST2BE_WORD(1460); - - header->checksum = HOST2BE_WORD(tcp_checksum(netc, conn->dst_ip, conn->header_buf, tcp_length)); - - conn->status = TCP_STAT_SYN_SENT; - - conn->seq += 1; - tcp_send_for_status_change(netc, conn->header_buf, tcp_length); // 发送SYN包 - tcp_length = sizeof(tcp_header_t); - header->offset = (tcp_length / 4) << 4; - if (conn->status == TCP_STAT_CLOSED) { - kfree(conn->rwin.mem); - timer_free(conn->timer); - kfree(conn); - return -1; - } - - conn->swin.mem = (uint8_t *)kmalloc(conn->swin.size); - - // 第二次握手 - - // 回应ACK - header->seq = HOST2BE_DWORD(conn->seq); - header->ack = HOST2BE_DWORD(conn->ack); - header->flags = TCP_FLAG_ACK; - header->checksum = 0; - header->checksum = HOST2BE_WORD(tcp_checksum(netc, conn->dst_ip, conn->header_buf, tcp_length)); - netc_ip_send(netc, conn->dst_ip, 0, PROTOCOL_TCP, conn->header_buf, tcp_length); - - return 0; -} - -int tcp_listen(netc_t *netc) { - tcp_header_t *header; - tcp_conn_t *conn; - int tcp_length = sizeof(tcp_header_t); - - conn = (tcp_conn_t *)netc->app_private; - - conn->status = TCP_STAT_LISTEN; - if (wait_for_status_change(netc) != 0) return -1; - - conn->header_buf = kmalloc(tcp_length); - header = (tcp_header_t *)conn->header_buf; - header->src_port = HOST2BE_WORD(conn->src_port); - header->dst_port = HOST2BE_WORD(conn->dst_port); - header->seq = HOST2BE_DWORD(conn->seq); - header->ack = HOST2BE_DWORD(conn->ack); - header->offset = (tcp_length / 4) << 4; - header->flags = TCP_FLAG_SYN | TCP_FLAG_ACK; - header->window = HOST2BE_WORD(rmem_defualt_size); - header->urgent_pointer = 0; - header->checksum = 0; - header->checksum = HOST2BE_WORD(tcp_checksum(netc, conn->dst_ip, conn->header_buf, tcp_length)); - - conn->seq += 1; - tcp_send_for_status_change(netc, conn->header_buf, tcp_length); - if (conn->status != TCP_STAT_ESTABLISHED) return -2; - return 0; -} - -void tcp_ipv4_close(netc_t *netc) { - tcp_header_t *header; - tcp_conn_t *conn = (tcp_conn_t *)netc->app_private; - header = (tcp_header_t *)conn->header_buf; - - header->seq = HOST2BE_DWORD(conn->seq); - header->ack = HOST2BE_DWORD(conn->ack); - header->flags = TCP_FLAG_FIN | TCP_FLAG_ACK; - header->window = HOST2BE_WORD(conn->rwin.size - conn->rwin.recved - conn->rwin.acked); - header->urgent_pointer = 0; - header->checksum = 0; - header->checksum = HOST2BE_WORD(tcp_checksum(netc, conn->dst_ip, conn->header_buf, sizeof(tcp_header_t))); - - conn->status = TCP_STAT_FIN_WAIT1; - conn->seq += 1; - tcp_send_for_status_change(netc, conn->header_buf, sizeof(tcp_header_t)); - - if (conn->status == TCP_STAT_FIN_WAIT2) { - if (wait_for_status_change(netc) != 0) goto end; - } - if (conn->status == TCP_STAT_TIME_WAIT) { - header->seq = HOST2BE_DWORD(conn->seq); - header->ack = HOST2BE_DWORD(conn->ack); - header->flags = TCP_FLAG_ACK; - header->checksum = 0; - header->checksum = - HOST2BE_WORD(tcp_checksum(netc, conn->dst_ip, conn->header_buf, sizeof(tcp_header_t))); - - netc_ip_send(netc, conn->dst_ip, 0, PROTOCOL_TCP, conn->header_buf, sizeof(tcp_header_t)); - - conn->wait_ms = 2 * TCP_MSL_MS; - timer_settime(conn->timer, conn->wait_ms / 10); - while (!fifo_status(&conn->fifo)) - ; - fifo_get(&conn->fifo); - } -end: - kfree(conn->rwin.mem); - timer_free(conn->timer); - kfree(conn); - return; -} - -void tcp_recv(uint8_t *buf, uint16_t offset, uint16_t length, uint8_t *ip, uint8_t ip_len) { - netc_t *netc; - tcp_header_t *tcp_head = (tcp_header_t *)(buf + offset); - uint16_t chksum = tcp_head->checksum; - tcp_header_t *header; - int flag = 1; - int len, head_len; - - uint16_t src_port = BE2HOST_WORD(tcp_head->src_port); - uint16_t dst_port = BE2HOST_WORD(tcp_head->dst_port); - - tcp_conn_t *conn, *cur, *next; - spin_lock(&tcp_lock); - list_for_each_owner_safe (cur, next, &tcp_lh, list) { - if (cur->src_port == dst_port) { - if ((cur->dst_port == src_port && memcmp(cur->dst_ip, ip, ip_len) == 0) || - cur->status == TCP_STAT_LISTEN) { - conn = cur; - flag = 0; - break; - } - } - } - spin_unlock(&tcp_lock); - - if (flag || conn->status == TCP_STAT_CLOSED) { return; } - netc = conn->netc; - - tcp_head->checksum = 0; - if (chksum != HOST2BE_WORD(tcp_checksum(netc, netc->dst_laddr, buf + offset, length))) { return; } - if (tcp_head->flags & TCP_FLAG_RST) { conn->status = TCP_STAT_CLOSED; } - - header = (tcp_header_t *)conn->header_buf; - head_len = (tcp_head->offset & 0xf0) >> 2; - len = length - head_len; - - uint32_t r_seq = BE2HOST_DWORD(tcp_head->seq); - uint32_t r_ack = BE2HOST_DWORD(tcp_head->ack); - - switch (conn->status) { - case TCP_STAT_LISTEN: - if (tcp_head->flags & TCP_FLAG_SYN) { - conn->ack = r_seq; - conn->dst_port = BE2HOST_WORD(tcp_head->dst_port); - memcpy(conn->dst_ip, ip, ip_len); - conn->status = TCP_STAT_SYN_RCVD; - } - break; - case TCP_STAT_SYN_SENT: - if (tcp_head->flags & TCP_FLAG_SYN) { - conn->swin.size = MIN(wmem_defualt_size, BE2HOST_WORD(tcp_head->window)); - conn->ack = r_seq; - } - if (tcp_head->flags & TCP_FLAG_ACK) { - if (conn->seq == r_ack) { conn->status = TCP_STAT_ESTABLISHED; } - } - len = 1; - break; - case TCP_STAT_SYN_RCVD: - if (tcp_head->flags & TCP_FLAG_ACK) { - if (r_ack == conn->seq) { - conn->ack = r_seq; - conn->status = TCP_STAT_ESTABLISHED; - } - } - len = 1; - break; - case TCP_STAT_ESTABLISHED: - // printk("TCP seq=%04X, ack=%04X\n", r_seq, r_ack); - if (len > 0) { - if (conn->rwin.recved + len < conn->rwin.size) { - memcpy(conn->rwin.mem + conn->rwin.head + conn->rwin.acked + conn->rwin.recved, - buf + offset + head_len, len); - } else { - int tmp = conn->rwin.size - conn->rwin.recved; - memcpy(conn->rwin.mem + conn->rwin.head + conn->rwin.acked + conn->rwin.recved, - buf + offset + head_len, tmp); - memcpy(conn->rwin.mem, buf + offset + head_len + tmp, len - tmp); - } - conn->rwin.recved += len; - } - // 先处理ACK信息 - uint32_t add = 0; - if (tcp_head->flags & TCP_FLAG_ACK) { - add = len; - if (conn->seq < r_ack) { // 对方确认己方发送的数据 - uint32_t tmp = r_ack - conn->seq; - conn->swin.unacked -= tmp; - conn->seq += tmp; - conn->swin.head = (conn->swin.head + tmp) % conn->swin.size; - conn->swin.tail = (conn->swin.tail + tmp) % conn->swin.size; - } - if ((add > 0 && list_empty(&net_rx_tcp_lh)) || tcp_head->flags & TCP_FLAG_PSH) { - header->seq = HOST2BE_DWORD(conn->seq); - header->ack = HOST2BE_DWORD(conn->ack + add); - header->flags = TCP_FLAG_ACK; - header->window = HOST2BE_WORD(conn->rwin.size - conn->rwin.recved); - header->urgent_pointer = 0; - header->checksum = 0; - header->checksum = - HOST2BE_WORD(tcp_checksum(netc, conn->dst_ip, conn->header_buf, sizeof(tcp_header_t))); - conn->swin.head = (conn->swin.head + conn->rwin.unacked + add) % conn->swin.size; - conn->swin.tail = (conn->swin.tail + conn->rwin.unacked + add) % conn->swin.size; - // 发送ACK包表示确认收到 - conn->rwin.acked += conn->rwin.unacked + add; - conn->rwin.recved -= conn->rwin.unacked + add; - conn->rwin.unacked = 0; - netc_ip_send(netc, conn->dst_ip, 0, PROTOCOL_TCP, conn->header_buf, sizeof(tcp_header_t)); - } else { - conn->rwin.unacked += add; - } - } - if (tcp_head->flags & TCP_FLAG_FIN) { - header->seq = HOST2BE_DWORD(conn->seq); - header->ack = HOST2BE_DWORD(conn->ack + len); - header->flags = TCP_FLAG_ACK; - header->window = HOST2BE_WORD(conn->rwin.size - conn->rwin.recved); - header->urgent_pointer = 0; - header->checksum = 0; - header->flags |= TCP_FLAG_FIN; - header->checksum = - HOST2BE_WORD(tcp_checksum(netc, conn->dst_ip, conn->header_buf, sizeof(tcp_header_t))); - netc_ip_send(netc, conn->dst_ip, 0, PROTOCOL_TCP, conn->header_buf, sizeof(tcp_header_t)); - if (conn->swin.unacked == 0) { - conn->status = TCP_STAT_LAST_ACK; - } else { - conn->status = TCP_STAT_CLOSE_WAIT; - } - } - break; - case TCP_STAT_FIN_WAIT1: - if (tcp_head->flags & TCP_FLAG_ACK) { - if (conn->seq == r_ack) { - conn->status = TCP_STAT_FIN_WAIT2; - kfree(conn->swin.mem); - conn->ack = r_seq; - if (tcp_head->flags & TCP_FLAG_FIN) { conn->status = TCP_STAT_TIME_WAIT; } - } - } - break; - case TCP_STAT_FIN_WAIT2: - if (tcp_head->flags & TCP_FLAG_FIN) { conn->status = TCP_STAT_TIME_WAIT; } - if (len == 0) { len = 1; } - break; - case TCP_STAT_LAST_ACK: - if (tcp_head->flags & TCP_FLAG_ACK) { conn->status = TCP_STAT_CLOSED; } - break; - - default: - break; - } - conn->ack += len; -} - -int tcp_write(netc_t *netc, uint8_t *buf, uint32_t length) { - tcp_conn_t *conn = (tcp_conn_t *)netc->app_private; - int tmp; - - tmp = conn->swin.size - conn->swin.unacked - conn->swin.sended; - - do { - tmp = MIN(MIN(length, tmp), conn->mss); - memcpy(conn->swin.mem + conn->swin.sended, buf, tmp); - length -= tmp; - buf += tmp; - conn->swin.sended = (conn->swin.sended + tmp) % conn->swin.size; - tcp_send(netc, conn->swin.mem + conn->swin.unacked, tmp); - } while (length > 0); - return 0; -} - -/** - * @brief 读取TCP数据 - * - * @param netc - * @param buf 数据缓冲区 - * @param length 读取的数据长度 - * @return int 实际读取的数据长度 - */ -int tcp_read(netc_t *netc, uint8_t *buf, uint32_t length) { - tcp_conn_t *conn = (tcp_conn_t *)netc->app_private; - int i = 0; - while (conn->rwin.acked == 0) { - i++; - delay(1); - if (i == 1000) { break; } - } - - /** - * @brief 同时增加head和tail,减小acked,释放部分空间 - * - */ - if (conn->rwin.acked > 0) { - int size = MIN(conn->rwin.acked, length); - memcpy(buf, conn->rwin.mem + conn->rwin.head, size); - conn->rwin.head = (conn->rwin.head + size) % conn->rwin.size; - conn->rwin.tail = (conn->rwin.tail + size) % conn->rwin.size; - conn->rwin.acked -= size; - return size; - } - return 0; -} diff --git a/src/network/udp.c b/src/network/udp.c deleted file mode 100644 index 5d14388..0000000 --- a/src/network/udp.c +++ /dev/null @@ -1,103 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include - -SPINLOCK(udp_lock); -LIST_HEAD(udp_lh); - -int udp_bind(netc_t *netc, uint8_t ip[4], uint16_t src_port, uint16_t dst_port) { - udp_conn_t *conn, *cur, *next; - netc->app_private = kmalloc(sizeof(udp_conn_t)); - - conn = (udp_conn_t *)netc->app_private; - conn->netc = netc; - - spin_lock(&udp_lock); - list_for_each_owner_safe (cur, next, &udp_lh, list) { - if (cur->src_port == src_port) { return -1; } - } - list_add_tail(&conn->list, &udp_lh); - spin_unlock(&udp_lock); - - conn->src_port = src_port; - conn->dst_port = dst_port; - memcpy(conn->dst_ip, ip, 4); - return 0; -} - -int udp_unbind(netc_t *netc) { - udp_conn_t *conn = (udp_conn_t *)netc->app_private; - spin_lock(&udp_lock); - list_del(&conn->list); - list_add_tail(&conn->list, &udp_lh); - return 0; -} - -void udp_send(netc_t *netc, uint16_t *data, uint16_t datalen) { - uint32_t chksum = 0, i; - udp_head_t *udp_head; - udp_conn_t *conn = (udp_conn_t *)netc->app_private; - uint16_t *buf = kmalloc(sizeof(udp_head_t) + datalen); - uint8_t src_ip[4]; - udp_head = (udp_head_t *)buf; - ipv4_get_ip(netc, src_ip); - - udp_head->SourcePort = HOST2BE_WORD(conn->src_port); - udp_head->DestinationPort = HOST2BE_WORD(conn->dst_port); - udp_head->Length = HOST2BE_WORD(sizeof(udp_head_t) + datalen); - udp_head->Checksum = 0; // 为了方便计算,先置0 - memcpy((uint8_t *)buf + sizeof(udp_head_t), data, datalen); - - // 计算校验和 - // UDP伪首部 - for (i = 0; i < 4 / sizeof(uint16_t); i++) { - chksum += (src_ip[i * 2] << 8) + src_ip[i * 2 + 1]; - chksum += (conn->dst_ip[i * 2] << 8) + conn->dst_ip[i * 2 + 1]; - } - chksum += PROTOCOL_UDP; - chksum += HOST2BE_WORD(udp_head->Length); - // UDP首部 - for (i = 0; i < (sizeof(udp_head_t) + datalen) / sizeof(uint16_t); i++) { - chksum += BE2HOST_WORD(buf[i]); - } - udp_head->Checksum = HOST2BE_WORD(~(uint16_t)((chksum & 0xffff) + (chksum >> 16))); - - ipv4_send(netc, conn->dst_ip, 0, 64, PROTOCOL_UDP, (uint8_t *)buf, sizeof(udp_head_t) + datalen); - kfree(buf); -} - -void udp_read(uint8_t *buf, uint16_t offset, uint16_t length) { - netc_t *netc; - udp_head_t *udp_head = (udp_head_t *)(buf + offset); - udp_conn_t *conn, *cur, *next; - int flag = 1; - - udp_head->DestinationPort = BE2HOST_WORD(udp_head->DestinationPort); - udp_head->SourcePort = BE2HOST_WORD(udp_head->SourcePort); - - spin_lock(&udp_lock); - list_for_each_owner_safe (cur, next, &udp_lh, list) { - if (cur->dst_port == udp_head->SourcePort && cur->src_port == udp_head->DestinationPort) { - conn = cur; - flag = 0; - break; - } - } - spin_unlock(&udp_lock); - if (flag) { return; } - netc = conn->netc; - - uint32_t off = (netc->recv_offset + netc->recv_len) % NET_MAX_BUFFER_SIZE; - if (off + length - sizeof(udp_head_t) > NET_MAX_BUFFER_SIZE) { - int tmp = NET_MAX_BUFFER_SIZE - netc->recv_offset; - memcpy(netc->recv_buffer + off, buf + offset + sizeof(udp_head_t), tmp); - memcpy(netc->recv_buffer, buf + offset + sizeof(udp_head_t) + tmp, length - sizeof(udp_head_t) - tmp); - } else { - memcpy(netc->recv_buffer + off, buf + offset + sizeof(udp_head_t), length - sizeof(udp_head_t)); - } - netc->recv_len += length - sizeof(udp_head_t); -} \ No newline at end of file diff --git a/src/objects/Makefile b/src/objects/Makefile new file mode 100644 index 0000000..277cad6 --- /dev/null +++ b/src/objects/Makefile @@ -0,0 +1,6 @@ +SRC += objects.c +SRC += types.c +SRC += mount.c +SRC += ops.c +SRC += permission.c +SRC += handle.c \ No newline at end of file diff --git a/src/objects/config.toml b/src/objects/config.toml new file mode 100644 index 0000000..51d0210 --- /dev/null +++ b/src/objects/config.toml @@ -0,0 +1 @@ +c = ["handle.c", "mount.c", "objects.c", "ops.c", "permission.c", "types.c"] diff --git a/src/objects/handle.c b/src/objects/handle.c new file mode 100644 index 0000000..80086ec --- /dev/null +++ b/src/objects/handle.c @@ -0,0 +1,24 @@ +#include +#include +#include +#include + +ObjectHandle *object_handle_create(Object *object) { + ObjectHandle *handle = kmalloc(sizeof(ObjectHandle)); + if (handle == NULL) return NULL; + handle->object = object; + handle->buf = NULL; + handle->handle_data = NULL; + if (handle->object->fs_info != NULL) { + object->fs_info->file_ops.fs_create_handle(handle); + } + return handle; +} + +ObjectResult object_handle_delete(ObjectHandle *handle) { + if (handle->object->fs_info != NULL) { + handle->object->fs_info->file_ops.fs_delete_handle(handle); + } + kfree(handle); + return OBJECT_OK; +} \ No newline at end of file diff --git a/src/objects/mount.c b/src/objects/mount.c new file mode 100644 index 0000000..fc4cc71 --- /dev/null +++ b/src/objects/mount.c @@ -0,0 +1,14 @@ +#include +#include +#include + +ObjectResult object_mount(Object *origin, Object *dest) { + if (dest->attr->is_mounted) { return OBJECT_ERROR_INVALID_OPERATION; } + dest->attr->is_mounted = true; + dest->origin = origin; + + dest->fs_info = origin->fs_info; + + origin->fs_info->ops->fs_mount(origin->fs_info, dest); + return OBJECT_OK; +} \ No newline at end of file diff --git a/src/objects/objects.c b/src/objects/objects.c new file mode 100644 index 0000000..4cb3988 --- /dev/null +++ b/src/objects/objects.c @@ -0,0 +1,217 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +const Permission sys_permission = { + .subject_id = SUBJECT_ID_SYSTEM, + .permission = {1, 1, 1, 1, 1, 1, 1}, +}; + +Object root_object = { + .name = STRING_INIT(""), // 根对象的名字不会起到任何作用,所以设为空 + .parent = NULL, + +}; +Object bus_object = { + .name = STRING_INIT("Bus"), +}; +Object driver_object = { + .name = STRING_INIT("Driver"), +}; +Object device_object = { + .name = STRING_INIT("Device"), +}; +Object volumes_object = { + .name = STRING_INIT("Volumes"), +}; + +void init_object_directory(Object *object) { + list_init(&object->value.directory.children); +} + +void init_base_obj_sys_attr(Object *object) { + object->attr = kmalloc_from_template(base_obj_sys_attr); + object->attr->object = object; +} + +/** + * @brief 初始化对象树 + * + * @return ObjectResult + */ +ObjectResult init_object_tree() { + init_object_directory(&root_object); + init_object_directory(&bus_object); + init_object_directory(&driver_object); + init_object_directory(&device_object); + init_object_directory(&volumes_object); + init_base_obj_sys_attr(&root_object); + init_base_obj_sys_attr(&bus_object); + init_base_obj_sys_attr(&driver_object); + init_base_obj_sys_attr(&device_object); + init_base_obj_sys_attr(&volumes_object); + add_object(&root_object, &driver_object); + add_object(&root_object, &bus_object); + add_object(&root_object, &device_object); + add_object(&root_object, &volumes_object); + + init_builtin_types(); + return OBJECT_OK; +} + +ObjectResult object_open_path(Object *parent, Object **child, char *path) { + Object *object; + + if (*path == '\0') { + *child = parent; + return OBJECT_OK; + } + + string_t name; + char ascii_name[256]; + char *p = path; + int i = 0; + name.text = ascii_name; + + while (*p != '\0' && *p != '\\') { + ascii_name[i] = *p; + p++; + i++; + } + bool is_directory = false; + if (*p == '\\') { + is_directory = true; + p++; + } + ascii_name[i] = '\0'; + name.length = i + 1; + name.max_length = i + 1; + + ObjectAttr *attr; + OBJ_RESULT_PASS(obj_lookup(parent, &name, &attr)); + if ((is_directory && attr->type == OBJECT_TYPE_DIRECTORY) || + !is_directory) { + if (attr->type == OBJECT_TYPE_DIRECTORY) { + if (attr->object != NULL) { + return object_open_path(attr->object, child, p); + } else { + OBJ_RESULT_PASS(obj_open(parent, attr, &name, &object)); + return object_open_path(object, child, p); + } + } else { + return obj_open(parent, attr, &name, child); + } + } + return OBJECT_ERROR_CANNOT_FIND; +} + +ObjectResult open_oringinal_object_by_path(char *path, Object **out_object) { + // 必须从根对象开始 + if (path[0] != '\\') { return OBJECT_ERROR_ILLEGAL_ARGUMENT; } + path++; + + return object_open_path(&root_object, out_object, path); +} + +ObjectResult open_object_by_path(char *path, Object **object) { + ObjectResult result = open_oringinal_object_by_path(path, object); + if (result == OBJECT_OK) { + while ((*object)->attr->type == OBJECT_TYPE_SYM_LINK) { + *object = (*object)->value.sym_link; + } + } + return result; +} + +ObjectResult add_object(Object *parent, Object *child) { + if (parent->attr->type != OBJECT_TYPE_DIRECTORY) { + return OBJECT_ERROR_INVALID_OPERATION; + } + + child->parent = parent; + list_add_tail(&child->list, &parent->value.directory.children); + + return OBJECT_OK; +} + +Object *create_object(Object *parent, string_t *name, ObjectAttr attr) { + Object *object = kmalloc(sizeof(Object)); + if (object == NULL) { return NULL; } + + object->name = *name; + object->attr = kmalloc_from_template(attr); + object->attr->object = object; + object->parent = parent; + object->reference = 0; + + ObjectResult result = add_object(parent, object); + if (result != OBJECT_OK) { + kfree(object); + return NULL; + } + + return object; +} + +ObjectResult delete_object(Object *object) { + if (object == NULL || object == &root_object) { + return OBJECT_ERROR_INVALID_OPERATION; + } + if (object->attr->type == OBJECT_TYPE_DIRECTORY) { + return OBJECT_ERROR_DELETE_DIRECTORY; + } + list_del(&object->list); + kfree(object->attr); + kfree(object); + return OBJECT_OK; +} + +Object *create_object_directory( + Object *parent, string_t *name, ObjectAttr attr) { + Object *object = create_object(parent, name, attr); + if (object == NULL) { return NULL; } + object->attr->type = OBJECT_TYPE_DIRECTORY; + + init_object_directory(object); + + return object; +} + +void print_symbol_link(Object *object) { + if (object != NULL && object != &root_object) { + print_symbol_link(object->parent); + printk("\\%s", object->name.text); + } +} + +void print_object_directory(Object *object, int level) { + Object *child; + list_for_each_owner (child, &object->value.directory.children, list) { + for (int j = 0; j < level; j++) { + printk("|\t"); + } + printk("|-%s", child->name.text); + if (child->attr->type == OBJECT_TYPE_SYM_LINK) { + printk("\t->\t"); + print_symbol_link(child->value.sym_link); + } + printk("\n"); + if (child->attr->type == OBJECT_TYPE_DIRECTORY) { + print_object_directory(child, level + 1); + } + } +} + +void show_object_tree() { + Object *object = &root_object; + printk("root\n_\n"); + print_object_directory(object, 0); +} \ No newline at end of file diff --git a/src/objects/ops.c b/src/objects/ops.c new file mode 100644 index 0000000..d292e34 --- /dev/null +++ b/src/objects/ops.c @@ -0,0 +1,206 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +ObjectResult obj_lookup_cache( + Object *parent, DEF_MRET(Object *, child), string_t *name) { + Object *child; + list_for_each_owner (child, &parent->value.directory.children, list) { + if (child->name.length == name->length && + strncmp(child->name.text, name->text, name->length) == 0) { + MRET(child) = child; + return OBJECT_OK; + } + } + return OBJECT_ERROR_CANNOT_FIND; +} + +ObjectResult obj_lookup( + Object *parent, string_t *name, DEF_MRET(ObjectAttr *, attr)) { + Object *child; + ObjectResult result = obj_lookup_cache(parent, &child, name); + if (result == OBJECT_OK) { + MRET(attr) = child->attr; + return OBJECT_OK; + } + if (parent->fs_info != NULL) { + FsResult result = parent->fs_info->dir_ops.fs_lookup( + parent->fs_info, parent, name, &MRET(attr)); + if (result == FS_OK) return OBJECT_OK; + } + return OBJECT_ERROR_CANNOT_FIND; +} + +ObjectResult obj_open( + Object *parent, ObjectAttr *attr, string_t *name, + DEF_MRET(Object *, child)) { + Object *child; + ObjectResult result = obj_lookup_cache(parent, &child, name); + if (result == OBJECT_OK) { + MRET(child) = child; + child->reference++; + return OBJECT_OK; + } + // 如果缓存中找不到,则调用文件系统接口读取 + else if (parent->fs_info != NULL) { + FsResult result = parent->fs_info->file_ops.fs_open( + parent->fs_info, parent, attr, name, &MRET(child)); + MRET(child)->reference++; + if (result == FS_OK) return OBJECT_OK; + } + return OBJECT_ERROR_CANNOT_FIND; +} + +ObjectResult obj_opendir(Object *parent, DEF_MRET(ObjectIterator *, iter)) { + ObjectIterator *iter = kmalloc(sizeof(ObjectIterator)); + if (parent->fs_info != NULL) { + iter->type = ITERATOR_TYPE_FS; + FsResult result = parent->fs_info->dir_ops.fs_opendir( + parent->fs_info, parent, &iter->fs_iterator); + if (result != FS_OK) return OBJECT_ERROR_CANNOT_FIND; + } else { + iter->type = ITERATOR_TYPE_MEM; + iter->current_node = parent->value.directory.children.next; + } + MRET(iter) = iter; + + return OBJECT_OK; +} + +ObjectResult obj_readdir(ObjectIterator *iterator, DEF_MRET(Object *, object)) { + if (iterator->type == ITERATOR_TYPE_FS) { + FsResult result = iterator->parent_object->fs_info->dir_ops.fs_readdir( + iterator->parent_object->value.directory.data, iterator, + &MRET(object)); + if (result == FS_ERROR_CANNOT_FIND) return OBJECT_ERROR_CANNOT_FIND; + else if (result != FS_OK) return OBJECT_ERROR_CANNOT_FIND; + } else { + if (iterator->current_node == + &iterator->parent_object->value.directory.children) { + return OBJECT_ERROR_CANNOT_FIND; + } + + MRET(object) = list_owner(iterator->current_node, Object, list); + iterator->current_node = iterator->current_node->next; + } + return OBJECT_OK; +} + +ObjectResult obj_closedir(ObjectIterator *iterator) { + if (iterator->type == ITERATOR_TYPE_FS) { + if (iterator->fs_iterator != NULL) { + FsResult result = + iterator->parent_object->fs_info->dir_ops.fs_closedir(iterator); + if (result != FS_OK) return OBJECT_ERROR_OTHER; + } + } + kfree(iterator); + return OBJECT_OK; +} + +ObjectResult obj_close(Object *object) { + object->reference--; + if (object->reference > 0) return OBJECT_OK; + if (object->fs_info == NULL) return OBJECT_OK; + if (!object->attr->is_mounted) { + if (object->release_data != NULL) object->release_data(object); + if (object->attr->type == OBJECT_TYPE_FILE) { + object->fs_info->file_ops.fs_close(object); + } else if (object->attr->type == OBJECT_TYPE_DIRECTORY) { + object->fs_info->dir_ops.fs_closedir( + object->value.directory.fs_iterator); + } + list_del(&object->list); + obj_close(object->parent); + kfree(object); + } + return OBJECT_OK; +} + +ObjectResult obj_create_file(Object *parent, string_t *name) { + Object *child; + ObjectResult result = obj_lookup_cache(parent, &child, name); + if (result == OBJECT_OK) return OBJECT_ERROR_ALREADY_EXISTS; + if (parent->fs_info != NULL) { + FsResult result = + parent->fs_info->dir_ops.fs_create_file(parent, name, &child); + if (result != FS_OK) return OBJECT_ERROR_OTHER; + } + return OBJECT_OK; +} + +ObjectResult obj_delete_file(Object *parent, ObjectAttr *attr, string_t *name) { + // 先打开文件检查权限,再决定要不要删除 + Permission *permission = get_permission_info(attr); + if (!permission->permission.delete) return OBJECT_ERROR_NO_PERMISSION; + + if (attr->object != NULL) { + Object *child = attr->object; + if (child->reference > 0) return OBJECT_ERROR_OCCUPIED; + } + + if (parent->fs_info != NULL) { + FsResult result = + parent->fs_info->dir_ops.fs_delete_file(parent, attr, name); + if (result != FS_OK) return OBJECT_ERROR_OTHER; + } + + return OBJECT_OK; +} + +ObjectResult obj_mkdir(Object *parent, string_t *name) { + Object *child; + ObjectResult result = obj_lookup_cache(parent, &child, name); + if (result == OBJECT_OK) return OBJECT_ERROR_ALREADY_EXISTS; + if (parent->fs_info != NULL) { + FsResult result = + parent->fs_info->dir_ops.fs_mkdir(parent, name, &child); + if (result != FS_OK) return OBJECT_ERROR_OTHER; + } + return OBJECT_OK; +} + +ObjectResult obj_rmdir(Object *parent, ObjectAttr *attr, string_t *name) { + // 先打开检查权限,再决定要不要删除 + Permission *permission = get_permission_info(attr); + if (!permission->permission.delete) return OBJECT_ERROR_NO_PERMISSION; + + if (attr->object != NULL) { + Object *child = attr->object; + if (child->reference > 0) return OBJECT_ERROR_OCCUPIED; + if (!child->attr->is_mounted) return OBJECT_ERROR_OCCUPIED; + if (!list_empty(&child->value.directory.children)) + return OBJECT_ERROR_NOT_EMPTY; + } + + if (parent->fs_info != NULL) { + FsResult result = parent->fs_info->dir_ops.fs_rmdir(parent, attr, name); + if (result == FS_OK) return OBJECT_OK; + else if (result == FS_ERROR_NOT_EMPTY) return OBJECT_ERROR_NOT_EMPTY; + else return OBJECT_ERROR_OTHER; + } + return OBJECT_OK; +} + +ObjectResult obj_get_attr(Object *object, ObjectAttr *attr) { + *attr = *object->attr; + return OBJECT_OK; +} + +ObjectResult obj_set_attr(Object *object, ObjectAttr *attr) { + Permission *permission = get_permission_info(object->attr); + if (!permission->permission.set_attr) return OBJECT_ERROR_NO_PERMISSION; + + if (object->fs_info != NULL) { + FsResult result = object->fs_info->dir_ops.fs_set_attr(object, attr); + if (result != FS_OK) return OBJECT_ERROR_OTHER; + } + *object->attr = *attr; + return OBJECT_OK; +} diff --git a/src/objects/permission.c b/src/objects/permission.c new file mode 100644 index 0000000..dbb41f5 --- /dev/null +++ b/src/objects/permission.c @@ -0,0 +1,20 @@ +#include +#include +#include +#include +#include + +Permission *get_permission_info(ObjectAttr *attr) { + size_t subject_id = get_current_subject_id(); + if (subject_id == SUBJECT_ID_SYSTEM) { + return &attr->system_permission; + } else if (subject_id == attr->owner_id) { + return &attr->owner_permission; + } else { + Permission *permission; + list_for_each_owner (permission, &attr->permission_lh, list) { + if (permission->subject_id == subject_id) return permission; + } + } + return NULL; +} \ No newline at end of file diff --git a/src/objects/types.c b/src/objects/types.c new file mode 100644 index 0000000..dc358ab --- /dev/null +++ b/src/objects/types.c @@ -0,0 +1,45 @@ +#include +#include +#include +#include + +static int type_number = OBJECT_TYPE_BUILTIN_MAX; + +#define DEFINE_OBJECT_TYPE(type_name) \ + { .name = STRING_INIT(#type_name), .value.type = OBJECT_TYPE_##type_name, } + +Object object_builtin_types[OBJECT_TYPE_BUILTIN_MAX] = { + DEFINE_OBJECT_TYPE(TYPE), DEFINE_OBJECT_TYPE(DIRECTORY), + DEFINE_OBJECT_TYPE(DRIVER), DEFINE_OBJECT_TYPE(DEVICE), + DEFINE_OBJECT_TYPE(FILE), DEFINE_OBJECT_TYPE(VALUE), + DEFINE_OBJECT_TYPE(SYM_LINK), DEFINE_OBJECT_TYPE(PARTITION), + DEFINE_OBJECT_TYPE(VOLUME), +}; + +Object object_type_directory = { + .name = STRING_INIT("ObjectType"), +}; + +ObjectResult init_builtin_types() { + init_object_directory(&object_type_directory); + init_base_obj_sys_attr(&object_type_directory); + add_object(&root_object, &object_type_directory); + + for (int i = 0; i < OBJECT_TYPE_BUILTIN_MAX; i++) { + add_object(&object_type_directory, &object_builtin_types[i]); + init_base_obj_sys_attr(&object_builtin_types[i]); + object_builtin_types[i].attr->type = OBJECT_TYPE_TYPE; + } + + return OBJECT_OK; +} + +Object *create_object_type(string_t *name) { + Object *object = + create_object(&object_type_directory, name, base_obj_sys_attr); + if (object == NULL) { return NULL; } + + object->value.type = type_number - 1; + + return object; +} \ No newline at end of file diff --git a/tools/Makefile b/tools/Makefile index a0e463a..5bc7c8e 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -5,19 +5,24 @@ RM = rm OUTPUT_DIR = bin/ IMAGETOOL_DIR = imagetool +CONFIGURATOR_DIR = configurator .PHONY: all -all: bin imgtool - -bin: - $(MKDIR) $(OUTPUT_DIR) +all: bin imgtool config imgtool: cargo build --release --manifest-path $(IMAGETOOL_DIR)/Cargo.toml cp $(IMAGETOOL_DIR)/target/release/imagetool $(OUTPUT_DIR) - cargo clean --manifest-path imagetool/Cargo.toml + +config: + cargo build --release --manifest-path $(CONFIGURATOR_DIR)/Cargo.toml + cp $(CONFIGURATOR_DIR)/target/release/configurator $(OUTPUT_DIR) + +bin: + $(MKDIR) $(OUTPUT_DIR) clean: - cargo clean --manifest-path imagetool/Cargo.toml + cargo clean --manifest-path $(IMAGETOOL_DIR)/Cargo.toml + cargo clean --manifest-path $(CONFIGURATOR_DIR)/Cargo.toml $(RM) -rf $(OUTPUT_DIR) \ No newline at end of file diff --git a/tools/configurator/.vscode/launch.json b/tools/configurator/.vscode/launch.json new file mode 100644 index 0000000..883a18f --- /dev/null +++ b/tools/configurator/.vscode/launch.json @@ -0,0 +1,45 @@ +{ + // 使用 IntelliSense 了解相关属性。 + // 悬停以查看现有属性的描述。 + // 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "type": "lldb", + "request": "launch", + "name": "Debug executable 'configurator'", + "cargo": { + "args": [ + "build", + "--bin=configurator", + "--package=configurator" + ], + "filter": { + "name": "configurator", + "kind": "bin" + } + }, + "args": ["--work-dir", "../../", "--out-dir", "../../src/build/"], + "cwd": "${workspaceFolder}" + }, + { + "type": "lldb", + "request": "launch", + "name": "Debug unit tests in executable 'configurator'", + "cargo": { + "args": [ + "test", + "--no-run", + "--bin=configurator", + "--package=configurator" + ], + "filter": { + "name": "configurator", + "kind": "bin" + } + }, + "args": [], + "cwd": "${workspaceFolder}" + } + ] +} \ No newline at end of file diff --git a/tools/configurator/.vscode/settings.json b/tools/configurator/.vscode/settings.json new file mode 100644 index 0000000..9184f3f --- /dev/null +++ b/tools/configurator/.vscode/settings.json @@ -0,0 +1,9 @@ +{ + "rust-analyzer.checkOnSave": true, + "rust-analyzer.cargo.autoreload": true, + "rust-analyzer.procMacro.enable": true, + "rust-analyzer.trace.server": "verbose", + "rust-analyzer.linkedProjects": [ + "./Cargo.toml" + ] +} \ No newline at end of file diff --git a/tools/configurator/Cargo.lock b/tools/configurator/Cargo.lock new file mode 100644 index 0000000..f3fdad8 --- /dev/null +++ b/tools/configurator/Cargo.lock @@ -0,0 +1,398 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "anstream" +version = "0.6.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43d5b281e737544384e969a5ccad3f1cdd24b48086a0fc1b2a5262a26b8f4f4a" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78" + +[[package]] +name = "anstyle-parse" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e231f6134f61b71076a3eab506c379d4f36122f2af15a9ff04415ea4c3339e2" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e0633414522a32ffaac8ac6cc8f748e090c5717661fddeea04219e2344f5f2a" +dependencies = [ + "anstyle", + "once_cell_polyfill", + "windows-sys", +] + +[[package]] +name = "clap" +version = "4.5.49" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4512b90fa68d3a9932cea5184017c5d200f5921df706d45e853537dea51508f" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.5.49" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0025e98baa12e766c67ba13ff4695a887a1eba19569aad00a472546795bd6730" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_derive" +version = "4.5.49" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a0b5487afeab2deb2ff4e03a807ad1a03ac532ff5a2cee5d86884440c7f7671" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "clap_lex" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b94f61472cee1439c0b966b47e3aca9ae07e45d070759512cd390ea2bebc6675" + +[[package]] +name = "colorchoice" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" + +[[package]] +name = "configurator" +version = "0.1.0" +dependencies = [ + "clap", + "path-clean", + "serde", + "serde_json", + "toml", +] + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "hashbrown" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5419bdc4f6a9207fbeba6d11b604d481addf78ecd10c11ad51e76c2f6482748d" + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "indexmap" +version = "2.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b0f83760fb341a774ed326568e19f5a863af4a952def8c39f9ab92fd95b88e5" +dependencies = [ + "equivalent", + "hashbrown", +] + +[[package]] +name = "is_terminal_polyfill" +version = "1.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" + +[[package]] +name = "itoa" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" + +[[package]] +name = "memchr" +version = "2.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" + +[[package]] +name = "once_cell_polyfill" +version = "1.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad" + +[[package]] +name = "path-clean" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17359afc20d7ab31fdb42bb844c8b3bb1dabd7dcf7e68428492da7f16966fcef" + +[[package]] +name = "proc-macro2" +version = "1.0.101" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce25767e7b499d1b604768e7cde645d14cc8584231ea6b295e9c9eb22c02e1d1" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "ryu" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" + +[[package]] +name = "serde" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.145" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c" +dependencies = [ + "itoa", + "memchr", + "ryu", + "serde", + "serde_core", +] + +[[package]] +name = "serde_spanned" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e24345aa0fe688594e73770a5f6d1b216508b4f93484c0026d521acd30134392" +dependencies = [ + "serde_core", +] + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "syn" +version = "2.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "toml" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0dc8b1fb61449e27716ec0e1bdf0f6b8f3e8f6b05391e8497b8b6d7804ea6d8" +dependencies = [ + "indexmap", + "serde_core", + "serde_spanned", + "toml_datetime", + "toml_parser", + "toml_writer", + "winnow", +] + +[[package]] +name = "toml_datetime" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2cdb639ebbc97961c51720f858597f7f24c4fc295327923af55b74c3c724533" +dependencies = [ + "serde_core", +] + +[[package]] +name = "toml_parser" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0cbe268d35bdb4bb5a56a2de88d0ad0eb70af5384a99d648cd4b3d04039800e" +dependencies = [ + "winnow", +] + +[[package]] +name = "toml_writer" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df8b2b54733674ad286d16267dcfc7a71ed5c776e4ac7aa3c3e2561f7c637bf2" + +[[package]] +name = "unicode-ident" +version = "1.0.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d" + +[[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-sys" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.53.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" +dependencies = [ + "windows-link", + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" + +[[package]] +name = "windows_i686_gnu" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" + +[[package]] +name = "windows_i686_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" + +[[package]] +name = "winnow" +version = "0.7.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21a0236b59786fed61e2a80582dd500fe61f18b5dca67a4a067d0bc9039339cf" diff --git a/tools/configurator/Cargo.toml b/tools/configurator/Cargo.toml new file mode 100644 index 0000000..e2c2807 --- /dev/null +++ b/tools/configurator/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "configurator" +version = "0.1.0" +edition = "2024" + +[dependencies] +clap = { version = "4.5.48", features = ["derive"] } +path-clean = "1.0.1" +serde = { version = "1.0.228", features = ["derive"] } +serde_json = "1.0.145" +toml = "0.9.8" diff --git a/tools/configurator/src/compile_commands.rs b/tools/configurator/src/compile_commands.rs new file mode 100644 index 0000000..c155304 --- /dev/null +++ b/tools/configurator/src/compile_commands.rs @@ -0,0 +1,101 @@ +use std::{io, path::PathBuf}; +use serde::{Serialize, Deserialize}; +use crate::config::CompilerConfig; +use path_clean::PathClean; + +#[derive(Debug, Serialize, Deserialize)] +pub struct CompileCommand<'a> { + pub arguments: Vec, + directory: &'a str, + file: String, + output: String, +} + +#[derive(Debug, Serialize, Deserialize)] +#[serde(bound(deserialize = "'de: 'a"))] +pub struct CompileCommands<'a> { + pub commands: Vec>, +} + +impl<'a> CompileCommand<'a> { + pub fn new_c(config: &CompilerConfig, directory: &'a str, output: &PathBuf, file: &PathBuf) -> Self { + let mut arguments = Vec::new(); + arguments.push(config.executable.to_string_lossy().to_string()); + arguments.extend(config.flags.iter().map(|s| s.to_string())); + + // name: 输出目标文件名(保持相对名,例如 foo.o) + let name = file.with_extension("c.o").file_name().unwrap() + .to_string_lossy().to_string(); + + // output: 将 output 目录与 name 组合,然后把结果转换为绝对路径。 + let output_path = output.join(name); + let output = output_path.to_string_lossy().to_string(); + + // file: 将 file 转为绝对路径字符串 + let file = file.canonicalize() + .unwrap_or_else(|_| file.clean()) + .to_string_lossy().to_string(); + + arguments.push("-c".to_string()); + arguments.push(file.clone()); + arguments.push("-o".to_string()); + arguments.push(output.clone()); + + CompileCommand { + arguments, + directory, + file, + output, + } + } + + pub fn new_asm(config: &CompilerConfig, directory: &'a str, output: &PathBuf, file: &PathBuf) -> Self { + let mut arguments = Vec::new(); + arguments.push(config.executable.to_string_lossy().to_string()); + arguments.extend(config.flags.iter().map(|s| s.to_string())); + + // name: 输出目标文件名(保持相对名,例如 foo.o) + let name = file.with_extension("asm.o").file_name().unwrap() + .to_string_lossy().to_string(); + + // output: 将 output 目录与 name 组合,然后把结果转换为绝对路径。 + let output_path = output.join(name); + let output = output_path.to_string_lossy().to_string(); + + // file: 将 file 转为绝对路径字符串 + let file = file.canonicalize() + .unwrap_or_else(|_| file.clean()) + .to_string_lossy().to_string(); + + arguments.push(file.clone()); + arguments.push("-o".to_string()); + arguments.push(output.clone()); + + CompileCommand { + arguments, + directory, + file, + output, + } + } +} + +impl<'a> CompileCommands<'a> { + pub fn new() -> Self { + CompileCommands { commands: Vec::new() } + } + + pub fn add_command(&mut self, command: CompileCommand<'a>) { + self.commands.push(command); + } + + pub fn extend(&mut self, other: CompileCommands<'a>) { + self.commands.extend(other.commands); + } + + pub fn to_json(&self, out_file: &PathBuf) -> io::Result<()> { + let json = serde_json::to_string_pretty(&self.commands)?; + std::fs::write(out_file, json)?; + Ok(()) + } +} \ No newline at end of file diff --git a/tools/configurator/src/config.rs b/tools/configurator/src/config.rs new file mode 100644 index 0000000..c8c47aa --- /dev/null +++ b/tools/configurator/src/config.rs @@ -0,0 +1,262 @@ +use std::{ + env, + error::Error, + path::{Path, PathBuf}, +}; + +use toml::Value; + +use crate::rustc_target::RustConfig; + +#[derive(Debug, Clone)] +pub struct CompilerConfig { + pub executable: PathBuf, + pub flags: Vec, +} + +#[derive(Debug, Clone)] +pub struct Tools { + pub cc: CompilerConfig, + pub assembler: CompilerConfig, + pub linker: CompilerConfig, + pub rustc: RustConfig, +} + +#[derive(Debug, Clone, Copy, PartialEq)] +pub enum DebugLevel { + Release, + Debug, +} + +#[derive(Debug, Clone)] +pub struct Config { + pub arch: String, + pub tools: Tools, + pub debug_level: DebugLevel, +} + +impl Tools { + fn new( + cc_executable: PathBuf, + cc_flags: Vec, + assembler_executable: PathBuf, + assembler_flags: Vec, + linker_executable: PathBuf, + linker_flags: Vec, + rust_config: RustConfig, + ) -> Self { + Tools { + cc: CompilerConfig { + executable: cc_executable, + flags: cc_flags, + }, + assembler: CompilerConfig { + executable: assembler_executable, + flags: assembler_flags, + }, + linker: CompilerConfig { + executable: linker_executable, + flags: linker_flags, + }, + rustc: rust_config, + } + } +} + +/// 在工作目录下或 PATH 中查找可执行文件,返回第一个存在的绝对或相对路径 +fn find_executable(work_dir: &Path, name: &str) -> Option { + let name_path = Path::new(name); + + // 如果给定的是包含路径分隔符的相对或绝对路径,先按此解释 + if name_path.is_absolute() + || name.contains(std::path::MAIN_SEPARATOR) + || name.contains('/') + || name.contains('\\') + { + let cand = if name_path.is_absolute() { + name_path.to_path_buf() + } else { + work_dir.join(name_path) + }; + if cand.exists() && cand.is_file() { + return Some(cand); + } + return None; + } + + // 优先检查 work_dir/name + let cand = work_dir.join(name); + if cand.exists() && cand.is_file() { + return Some(cand); + } + + // 在 PATH 中查找 + if let Some(paths) = env::var_os("PATH") { + for p in env::split_paths(&paths) { + let cand = p.join(name); + if cand.exists() && cand.is_file() { + return Some(cand); + } + // On Windows, consider PATHEXT - but keep it simple for now + } + } + + None +} + +impl Config { + pub fn from(work_dir: PathBuf, config: Value) -> Result> { + let arch = config + .get("arch") + .and_then(Value::as_str) + .ok_or("Missing or invalid 'arch' field")? + .to_string(); + + let tools_table = config + .get("tools") + .and_then(Value::as_table) + .ok_or("Missing or invalid 'tools' field")?; + + let tools; + + let mut cc = String::from("gcc"); + let mut as_ = String::from("nasm"); + let mut ld = String::from("ld"); + let mut cflags = Vec::new(); + let mut asflags = Vec::new(); + let mut ldflags = Vec::new(); + let mut rust_flags = Vec::new(); + let mut rust_target = String::new(); + for (name, tool_config) in tools_table { + match name.as_str() { + "cc" => { + cc = tool_config + .as_str() + .ok_or("Invalid 'cc' field")? + .to_string() + } + "as" => { + as_ = tool_config + .as_str() + .ok_or("Invalid 'as' field")? + .to_string() + } + "ld" => { + ld = tool_config + .as_str() + .ok_or("Invalid 'ld' field")? + .to_string() + } + "cflags" => { + cflags = tool_config + .as_array() + .ok_or("Invalid 'cflags' field")? + .iter() + .filter_map(Value::as_str) + .map(String::from) + .collect(); + continue; + } + "asflags" => { + asflags = tool_config + .as_array() + .ok_or("Invalid 'asflags' field")? + .iter() + .filter_map(Value::as_str) + .map(String::from) + .collect(); + } + "ldflags" => { + // 解析链接器标志 + ldflags = tool_config + .as_array() + .ok_or("Invalid 'ldflags' field")? + .iter() + .filter_map(Value::as_str) + .map(String::from) + .collect(); + } + "rust_flags" => { + // 解析 Rust 编译器标志 + rust_flags = tool_config + .as_array() + .ok_or("Invalid 'rust_flags' field")? + .iter() + .filter_map(Value::as_str) + .map(String::from) + .collect(); + } + "rust_target" => { + rust_target = tool_config + .as_str() + .ok_or("Invalid 'rust_target' field")? + .to_string(); + } + _ => {} + }; + } + // 将可执行文件名解析为实际路径,优先在工作目录查找,然后在 PATH 中查找 + let cc_path = find_executable(&work_dir, &cc).ok_or(format!("C 编译器未找到: {}", cc))?; + let as_path = find_executable(&work_dir, &as_).ok_or(format!("汇编器未找到: {}", as_))?; + let ld_path = find_executable(&work_dir, &ld).ok_or(format!("链接器未找到: {}", ld))?; + + let rust_config = RustConfig::new(rust_target, rust_flags, &work_dir); + + let debug_table = config + .get("debug") + .and_then(Value::as_table) + .ok_or("Missing or invalid 'debug' field")?; + let debug_level = debug_table + .get("level") + .and_then(Value::as_str); + let debug_level = if let Some(debug_level) = debug_level { + match debug_level { + "release" => DebugLevel::Release, + "debug" => DebugLevel::Debug, + _ => DebugLevel::Debug, + } + } else { + DebugLevel::Debug + }; + + if debug_level != DebugLevel::Release { + for (name, value) in debug_table { + match name.as_str() { + "cflags" => { + cflags.extend(value + .as_array() + .ok_or("Invalid 'cflags' field")? + .iter() + .filter_map(Value::as_str) + .map(String::from)); + } + "asflags" => { + asflags.extend(value + .as_array() + .ok_or("Invalid 'asflags' field")? + .iter() + .filter_map(Value::as_str) + .map(String::from)); + } + "ldflags" => { + ldflags.extend(value + .as_array() + .ok_or("Invalid 'ldflags' field")? + .iter() + .filter_map(Value::as_str) + .map(String::from)); + } + _ => {} + } + } + } + + tools = Tools::new(cc_path, cflags, as_path, asflags, ld_path, ldflags, rust_config); + + Ok(Config { + arch: arch, + tools, + debug_level + }) + } +} diff --git a/tools/configurator/src/dependency.rs b/tools/configurator/src/dependency.rs new file mode 100644 index 0000000..76f2a29 --- /dev/null +++ b/tools/configurator/src/dependency.rs @@ -0,0 +1,193 @@ +use std::path::PathBuf; + +use std::process::Command; + +use crate::config::{CompilerConfig, Config}; +use crate::rustc_target::{RustConfig, RustcTargetType}; +use std::fs::OpenOptions; +use std::io::Write; + +pub fn do_cc_dependency<'a>(compiler: &'a CompilerConfig, file: &PathBuf, out_dir: &PathBuf) { + let file_name = file.file_name().unwrap().to_str().unwrap(); + let out_cmd_file = out_dir.join(format!("{}.o.cmd", file_name)); + let out_file = out_dir.join(format!("{}.o", file_name)); + let mut command = Command::new(compiler.executable.as_os_str()); + command.args(&compiler.flags); + command.args(["-M", "-MF"]); + command.arg(&out_cmd_file); + command.arg("-MT"); + command.arg(&out_file); + command.arg(file); + + let status = command.status().expect("无法执行编译器以生成依赖文件"); + if !status.success() { + eprintln!("错误: 编译器生成依赖文件失败,状态码: {}", status); + std::process::exit(1); + } + + let mut cmd_file = OpenOptions::new() + .append(true) + .open(&out_cmd_file) + .expect(&format!("无法打开{}", out_cmd_file.display())); + + writeln!(cmd_file, "\t@echo CC $@").unwrap(); + writeln!( + cmd_file, + "\t@{} {} -c $< -o $@", + compiler.executable.display(), + compiler.flags.join(" ") + ) + .unwrap(); +} + +pub fn do_asm_dependency<'a>(assembler: &'a CompilerConfig, file: &PathBuf, out_dir: &PathBuf) { + let file_name = file.file_name().unwrap().to_str().unwrap(); + let out_cmd_file = out_dir.join(format!("{}.o.cmd", file_name)); + let out_file = out_dir.join(format!("{}.o", file_name)); + + let mut cmd_file = OpenOptions::new() + .create(true) + .truncate(true) + .write(true) + .open(&out_cmd_file) + .expect(&format!("无法打开{}", out_cmd_file.display())); + + // 禁用所有默认的后缀规则,防止 make 使用内置规则编译 + writeln!(cmd_file, ".SUFFIXES:\n").unwrap(); + + writeln!(cmd_file, "{}: {}", out_file.display(), file.display()).unwrap(); + + writeln!(cmd_file, "\t@echo AS $@").unwrap(); + writeln!( + cmd_file, + "\t@{} {} $< -o $@", + assembler.executable.display(), + assembler.flags.join(" ") + ) + .unwrap(); +} + +pub fn do_rust_dependency<'a>( + rustc: &'a RustConfig, + file: &PathBuf, + out_dir: &PathBuf, + target_name: &str, + is_release: bool, +) { + let out_cmd_file = out_dir.join("rlib.a.cmd"); + let out_file = out_dir.join("rlib.a"); + + let mut cmd_file = OpenOptions::new() + .create(true) + .truncate(true) + .write(true) + .open(&out_cmd_file) + .expect(&format!("无法打开{}", out_cmd_file.display())); + + // 禁用所有默认的后缀规则,防止 make 使用内置规则编译 + writeln!(cmd_file, ".SUFFIXES:\n").unwrap(); + + writeln!(cmd_file, "{}: {}", out_file.display(), file.display()).unwrap(); + + writeln!(cmd_file, "\t@echo RUSTC $@").unwrap(); + writeln!( + cmd_file, + "\t@rustup run {}", + match rustc.target_type { + RustcTargetType::Builtin => { "cargo rustc" }, + RustcTargetType::Custom => { "nightly cargo rustc" }, + }, + ) + .unwrap(); + + writeln!(cmd_file, "\t@echo COPY $@").unwrap(); + if is_release { + writeln!(cmd_file, "\t@cp ./rustc_target/{}/release/lib*.a $@", target_name).unwrap(); + } else { + writeln!(cmd_file, "\t@cp ./rustc_target/{}/debug/lib*.a $@", target_name).unwrap(); + } +} + +pub fn do_dir_dependency<'a>( + config: &Config, + out_dir: &PathBuf, + files: Vec, + libs: Vec, + dirs: &Vec, +) { + let out_cmd_file = out_dir.join("built-in.o.cmd"); + + let mut cmd_file = OpenOptions::new() + .create(true) + .truncate(true) + .write(true) + .open(&out_cmd_file) + .expect("无法打开目录依赖文件以追加目录"); + + writeln!(cmd_file, "# 由 {} 自动生成", env!("CARGO_PKG_NAME")).unwrap(); + + // 禁用所有默认的后缀规则,防止 make 使用内置规则编译 + writeln!(cmd_file, ".SUFFIXES:\n").unwrap(); + + write!(cmd_file, "{}: ", out_dir.join("built-in.o").display()).unwrap(); + for file in &files { + write!( + cmd_file, + "\\\n {}.o", + out_dir.join(file.file_name().unwrap()).display() + ) + .unwrap(); + } + for lib in &libs { + write!( + cmd_file, + "\\\n {}", + out_dir.join(lib.file_name().unwrap()).display() + ) + .unwrap(); + } + for dir in dirs { + write!(cmd_file, "\\\n {}", dir.join("built-in.o").display()).unwrap(); + } + + write!(cmd_file, "\n").unwrap(); + if files.is_empty() && dirs.is_empty() { + // 没有输入文件时,不调用链接器以避免 "no input files" 错误,改为创建一个空占位文件 + writeln!(cmd_file, "\t@echo TOUCH $@").unwrap(); + writeln!(cmd_file, "\t@mkdir -p $(dir $@) 2>/dev/null || true").unwrap(); + writeln!(cmd_file, "\t@touch $@").unwrap(); + } else { + writeln!(cmd_file, "\t@echo LD $@").unwrap(); + writeln!( + cmd_file, + "\t@{} {} --whole-archive -r $^ -o $@", + config.tools.linker.executable.display(), + config.tools.linker.flags.join(" ") + ) + .unwrap(); + } + for file in &files { + writeln!( + cmd_file, + "-include {}.o.cmd", + out_dir.join(file.file_name().unwrap()).display() + ) + .unwrap(); + } + for lib in &libs { + writeln!( + cmd_file, + "-include {}.cmd", + out_dir.join(lib.file_name().unwrap()).display() + ) + .unwrap(); + } + for dir in dirs { + writeln!( + cmd_file, + "-include {}", + dir.join("built-in.o.cmd").display() + ) + .unwrap(); + } +} diff --git a/tools/configurator/src/main.rs b/tools/configurator/src/main.rs new file mode 100644 index 0000000..755dbee --- /dev/null +++ b/tools/configurator/src/main.rs @@ -0,0 +1,113 @@ +use std::{borrow::Cow, fs, path::PathBuf}; +use clap::Parser; + +mod parse; +mod config; +mod compile_commands; +mod dependency; +mod rustc_target; +use config::Config; +use toml::{self, Value}; + +use crate::parse::parse_config; + +/// 配置工具命令行参数 +#[derive(Parser, Debug)] +#[command(author, version, about, long_about = None)] +struct Args { + /// 工作目录(工作目录路径) + #[arg(short = 'w', long = "work-dir", value_name = "PATH")] + work_dir: PathBuf, + + /// 输出目录(生成文件将写入此目录) + #[arg(short = 'o', long = "out-dir", value_name = "PATH")] + out_dir: PathBuf, + + #[arg(short = 'f', long = "force-update")] + force_update: bool, + + #[arg(long = "compile-commands")] + compile_commands: bool, +} + +fn main() { + let args = Args::parse(); + + if !args.out_dir.exists() || !args.out_dir.is_dir() { + if let Err(e) = std::fs::create_dir_all(&args.out_dir) { + eprintln!( + "错误: 无法创建输出目录 {}: {}", + args.out_dir.display(), + e + ); + std::process::exit(4); + } else { + println!("已创建输出目录: {}", args.out_dir.display()); + } + } + + println!("工作目录: {}", args.work_dir.canonicalize().unwrap().display()); + println!("输出目录: {}", args.out_dir.canonicalize().unwrap().display()); + + // 验证工作目录存在且为目录 + if !args.work_dir.exists() { + eprintln!("错误: 工作目录不存在: {}", args.work_dir.display()); + std::process::exit(2); + } + if !args.work_dir.is_dir() { + eprintln!("错误: 工作目录不是一个目录: {}", args.work_dir.display()); + std::process::exit(3); + } + + // 如果输出目录不存在则尝试创建 + if !args.out_dir.exists() { + if let Err(e) = std::fs::create_dir_all(&args.out_dir) { + eprintln!( + "错误: 无法创建输出目录 {}: {}", + args.out_dir.display(), + e + ); + std::process::exit(4); + } else { + println!("已创建输出目录: {}", args.out_dir.display()); + } + } else if !args.out_dir.is_dir() { + eprintln!("错误: 输出目录路径存在但不是目录: {}", args.out_dir.display()); + std::process::exit(5); + } + + let config_file = args.work_dir.join("config.toml"); + if !config_file.exists() || !config_file.is_file() { + eprintln!("错误: 配置文件不存在或不是文件: {}", config_file.display()); + std::process::exit(6); + } + let config_metadata = fs::metadata(config_file.as_path()).expect("无法获取metadata"); + let config_file = fs::read_to_string(config_file.as_path()).expect("无法读取配置文件"); + let config: Value = toml::from_str(&config_file).expect("无法解析配置文件"); + let config = Config::from(args.work_dir.clone(), config).expect("无法加载配置"); + + let out_dir = args.out_dir.canonicalize().unwrap(); + let work_dir = args.work_dir.canonicalize().unwrap(); + let work_dir = work_dir.join("src/"); + + let directory = work_dir.to_string_lossy().to_string(); + + let mut force_update = args.force_update; + let target_metadata = fs::metadata(out_dir.as_path().join("built-in.o.cmd")); + if let Ok(target_metadata) = target_metadata { + if config_metadata.modified().unwrap() > target_metadata.modified().unwrap() { + force_update = true; + } + } + + let config = Cow::Owned(config); + let compile_commands = parse_config(config, work_dir, out_dir, &directory, force_update); + + if args.compile_commands { + let out_file = args.work_dir.join("compile_commands.json"); + compile_commands + .to_json(&out_file) + .expect(&format!("无法写入 {}", out_file.display())); + println!("已生成 {}", out_file.display()); + } +} \ No newline at end of file diff --git a/tools/configurator/src/parse.rs b/tools/configurator/src/parse.rs new file mode 100644 index 0000000..23166d1 --- /dev/null +++ b/tools/configurator/src/parse.rs @@ -0,0 +1,401 @@ +use crate::{ + compile_commands::{CompileCommand, CompileCommands}, + config::Config, + dependency, +}; +use std::{ + borrow::Cow, + fs::{self, File}, + io::{self, Read}, + path::PathBuf, +}; +use toml::Value; + +struct DirectoryContext<'a> { + config: Cow<'a, Config>, + work_dir: PathBuf, + out_dir: PathBuf, + force_update: bool, + toml: Option, +} + +impl<'a> DirectoryContext<'a> { + fn new( + config: Cow<'a, Config>, + work_dir: PathBuf, + out_dir: PathBuf, + force_update: bool, + ) -> Self { + DirectoryContext { + config, + work_dir, + out_dir, + force_update, + toml: None, + } + } + + fn check_dir_update(&mut self) -> io::Result<()> { + let config_file_path = self.work_dir.join("config.toml"); + let target_file_path = self.out_dir.join("built-in.o.cmd"); + + let source_meta = match File::open(config_file_path) { + Ok(mut file) => { + self.toml = Some({ + let mut buf = String::new(); + file.read_to_string(&mut buf)?; + toml::from_str(&buf).map_err(|e| { + io::Error::new( + io::ErrorKind::InvalidData, + format!("无法解析 config.toml: {}", e), + ) + })? + }); + file.metadata()? + } + Err(e) => return Err(e), + }; + let target_meta = match fs::metadata(&target_file_path) { + Ok(metadata) => metadata, + Err(_) => { + self.force_update = true; + return Ok(()); + } + }; + if source_meta.modified()? > target_meta.modified()? { + self.force_update = true; + } + Ok(()) + } + + fn enter_subdir(&'_ self, subdir: &str) -> DirectoryContext<'_> { + let new_work_dir = self.work_dir.join(subdir); + let new_out_dir = self.out_dir.join(subdir); + + if !new_out_dir.exists() || !new_out_dir.is_dir() { + if let Err(e) = fs::create_dir_all(&new_out_dir) { + eprintln!( + "错误: 无法创建子目录输出目录 {}: {}", + new_out_dir.display(), + e + ); + std::process::exit(9); + } + } + DirectoryContext { + config: Cow::Borrowed(&self.config), + work_dir: new_work_dir, + out_dir: new_out_dir, + force_update: self.force_update, + toml: None, + } + } +} + +fn parse_string_array(config_toml: &Value, key: &str) -> Option> { + config_toml.get(key).and_then(|v| { + Some( + v.as_array()? + .iter() + .filter_map(|v| v.as_str()) + .map(String::from) + .collect::>(), + ) + }) +} + +fn parse_includes(work_dir: &PathBuf, config: &mut Config, config_toml: &Value) { + let includes = parse_string_array(config_toml, "includes"); + if let Some(includes) = includes { + config.tools.cc.flags.extend( + includes + .iter() + .map(|s| format!("-I{}{}", work_dir.display(), s)), + ); + config.tools.assembler.flags.extend( + includes + .iter() + .map(|s| format!("-I{}{}", work_dir.display(), s)), + ); + } +} + +fn parse_macros(config: &mut Config, config_toml: &Value) { + let macros = config_toml.get("macro").and_then(|v| { + Some( + v.as_table()? + .iter() + .filter_map(|(k, v)| { + let v = v.as_str()?; + Some((k, v)) + }) + .collect::>(), + ) + }); + if let Some(macros) = macros { + config + .tools + .cc + .flags + .extend(macros.iter().map(|(k, v)| format!("-D{}={}", k, v))); + config + .tools + .assembler + .flags + .extend(macros.iter().map(|(k, v)| format!("-D{}={}", k, v))); + } +} + +pub fn parse_arch_config( + config: &mut Config, + work_dir: &PathBuf, + config_toml: &Value, +) -> (Vec, String) { + let archs = config_toml.get("arch").and_then(|v| v.as_table()).unwrap(); + + let arch = archs.get(&config.arch).unwrap_or_else(|| { + eprintln!("错误: 配置文件中未找到目标架构的配置: {}", config.arch); + std::process::exit(1); + }); + + let dirs = parse_string_array(arch, "dir").unwrap_or_else(|| { + eprintln!("错误: 配置文件中目标架构缺少 'dir' 字段或格式不正确"); + std::process::exit(1); + }); + + let lds = arch.get("lds").and_then(Value::as_str).unwrap().to_string(); + + parse_includes(work_dir, config, arch); + parse_macros(config, arch); + + (dirs, lds) +} + +pub fn parse_config<'a, 'b>( + config: Cow<'a, Config>, + work_dir: PathBuf, + out_dir: PathBuf, + directory: &'b str, + force_update: bool, +) -> CompileCommands<'b> { + let mut compile_commands = CompileCommands::new(); + let mut ctx = DirectoryContext::new(config, work_dir, out_dir, force_update); + let mut real_dirs = Vec::new(); + + ctx.check_dir_update().expect("检查目录更新失败!"); + if ctx.force_update { + ctx.config.tools.rustc.set_force_update(true); + } + + let cargo_toml = ctx.work_dir.join("Cargo.template.toml"); + if cargo_toml.exists() && cargo_toml.is_file() { + ctx.config.to_mut().tools.rustc.use_cargo_toml(cargo_toml, &ctx.work_dir, &ctx.out_dir); + } + + let dirs = { + let config_toml = ctx.toml.as_ref().expect("未获取到config.toml!"); + let (dirs, lds, output) = { + let config = ctx.config.to_mut(); + let (mut dirs, lds) = parse_arch_config(config, &ctx.work_dir, &config_toml); + dirs.extend(parse_string_array(&config_toml, "dir").unwrap_or(Vec::new())); + + let output = config_toml.get("output").and_then(|v| v.as_str()).unwrap(); + parse_includes(&ctx.work_dir, config, &config_toml); + parse_macros(config, &config_toml); + + (dirs, lds, output) + }; + + let file_path = ctx.out_dir.join("Makefile"); + if !file_path.exists() || force_update { + let mut makefile = File::create(&file_path).expect("无法创建 Makefile"); + use std::io::Write; + writeln!(makefile, ".SUFFIXES:\n").unwrap(); + writeln!(makefile, ".PHONY: {}\n", output).unwrap(); + writeln!( + makefile, + "{}: {}", + output, + ctx.out_dir.join("built-in.o").display() + ) + .unwrap(); + writeln!(makefile, "\t@echo LD $@").unwrap(); + writeln!( + makefile, + "\t@{} {} -T {} --gc-sections -o $@ $^", + ctx.config.tools.linker.executable.display(), + ctx.config.tools.linker.flags.join(" "), + ctx.work_dir.join(lds).display() + ) + .unwrap(); + + writeln!(makefile, "-include built-in.o.cmd").unwrap(); + writeln!(makefile, "\nclean:\n\t@echo RM *.o\n\t@find . -type f \\( -name '*.o' -o -name '*.a' \\) -print -delete").unwrap(); + } + dirs + }; + + for dir in &dirs { + let mut new_ctx = ctx.enter_subdir(dir); + + new_ctx.check_dir_update().expect("检查目录更新失败!"); + + if new_ctx.force_update { + real_dirs.push(new_ctx.out_dir.clone()); + } + + compile_commands.extend(parse_dir_config(new_ctx, directory)); + } + + let files = Vec::new(); + let mut libs = Vec::new(); + if let Some(file) = + ctx.config + .tools + .rustc + .write_configs(&ctx.work_dir, &ctx.out_dir, ctx.config.debug_level) + { + libs.push(file); + } + + if ctx.force_update{ + dependency::do_dir_dependency(&ctx.config, &ctx.out_dir, files, libs, &real_dirs); + } + + compile_commands +} + +// 因为ctx所有权传递给了这个函数,在函数结束时会被释放,所以CompileCommands需要和ctx使用不同的生命周期标记 +fn parse_dir_config<'a, 'b>(mut ctx: DirectoryContext<'a>, directory: &'b str) -> CompileCommands<'b> { + let mut compile_commands = CompileCommands::new(); + + let config_toml = ctx.toml.as_ref().expect("未获取到config.toml!"); + let dirs = parse_string_array(config_toml, "dir").unwrap_or(Vec::new()); + let mut real_dirs = Vec::new(); + let mut files = Vec::new(); + + let asm_files = config_toml.get("asm").and_then(|v| { + Some( + v.as_array()? + .iter() + .filter_map(|v| v.as_str()) + .collect::>(), + ) + }); + if let Some(asm_files) = asm_files { + for asm_file in asm_files { + let asm_file_path = ctx.work_dir.join(asm_file); + if !asm_file_path.exists() || !asm_file_path.is_file() { + eprintln!( + "错误: ASM 源文件不存在或不是文件: {}", + asm_file_path.display() + ); + std::process::exit(7); + } + compile_commands.add_command(CompileCommand::new_asm( + &ctx.config.tools.assembler, + directory, + &ctx.out_dir, + &asm_file_path, + )); + + files.push(asm_file_path.clone()); + if ctx.force_update { + dependency::do_asm_dependency( + &ctx.config.tools.assembler, + &asm_file_path, + &ctx.out_dir, + ); + } + } + } + + let c_files = config_toml.get("c").and_then(|v| { + Some( + v.as_array()? + .iter() + .filter_map(|v| v.as_str()) + .collect::>(), + ) + }); + if let Some(c_files) = c_files { + for c_file in c_files { + let c_file_path = ctx.work_dir.join(c_file); + if !c_file_path.exists() || !c_file_path.is_file() { + eprintln!("错误: C 源文件不存在或不是文件: {}", c_file_path.display()); + std::process::exit(7); + } + compile_commands.add_command(CompileCommand::new_c( + &ctx.config.tools.cc, + directory, + &ctx.out_dir, + &c_file_path, + )); + + files.push(c_file_path.clone()); + if ctx.force_update { + dependency::do_cc_dependency(&ctx.config.tools.cc, &c_file_path, &ctx.out_dir); + } + } + } + + let cargo_toml = ctx.work_dir.join("Cargo.template.toml"); + if cargo_toml.exists() && cargo_toml.is_file() { + ctx.config.to_mut().tools.rustc.use_cargo_toml(cargo_toml, &ctx.work_dir, &ctx.out_dir); + } + + let rust_files = config_toml.get("rust").and_then(|v| { + Some( + v.as_array()? + .iter() + .filter_map(|v| v.as_str()) + .collect::>(), + ) + }); + if let Some(ref rust_files) = rust_files { + for rust_file in rust_files { + let rust_file_path = ctx.work_dir.join(rust_file); + if !rust_file_path.exists() || !rust_file_path.is_file() { + eprintln!( + "错误: Rust 源文件不存在或不是文件: {}", + rust_file_path.display() + ); + std::process::exit(7); + } + + ctx.config.tools.rustc.add_file(&rust_file_path); + if ctx.force_update { + ctx.config.tools.rustc.set_force_update(true); + } + } + } + + for dir in &dirs { + let mut new_ctx = ctx.enter_subdir(dir); + + new_ctx.check_dir_update().expect("检查目录更新失败!"); + + if ctx.force_update { + real_dirs.push(new_ctx.out_dir.clone()); + } + + let sub_compile_commands = parse_dir_config(new_ctx, directory); + compile_commands.extend(sub_compile_commands); + } + + let mut libs = Vec::new(); + if let Some(file) = + ctx.config + .tools + .rustc + .write_configs(&ctx.work_dir, &ctx.out_dir, ctx.config.debug_level) + { + libs.push(file); + } + + if ctx.force_update && (!files.is_empty() || !real_dirs.is_empty()) { + dependency::do_dir_dependency(&ctx.config, &ctx.out_dir, files, libs, &real_dirs); + } + + compile_commands +} diff --git a/tools/configurator/src/rustc_target.rs b/tools/configurator/src/rustc_target.rs new file mode 100644 index 0000000..57a50ce --- /dev/null +++ b/tools/configurator/src/rustc_target.rs @@ -0,0 +1,311 @@ +use std::cell::RefCell; +use std::collections::HashMap; +use std::fs::{self, File}; +use std::io::Write; +use std::path::PathBuf; +use std::sync::Arc; + +use crate::config::DebugLevel; +use crate::dependency; + +#[derive(Debug, Clone, Copy)] +pub enum RustcTargetType { + Builtin, + Custom, +} + +#[derive(Debug, Clone)] +pub struct RustConfig { + pub target: String, + pub target_type: RustcTargetType, + pub cargo_toml: RefCell>, + rust_flags: Vec, + modules: Arc>, + force_update: Arc>, +} + +#[derive(Debug, Clone, Copy)] +enum ModuleType { + Exist, // 存在 mod.rs 的目录 + NotExist, +} + +#[derive(Debug)] +struct ModuleNode { + module_type: ModuleType, + children: HashMap, +} + +impl ModuleNode { + fn new(module_type: ModuleType) -> Self { + ModuleNode { + module_type, + children: HashMap::new(), + } + } + + fn add_child(&mut self, name: &str, module_type: ModuleType) -> &mut ModuleNode { + let entry = self.children.entry(name.to_string()); + entry.or_insert_with(|| ModuleNode::new(module_type)) + } +} + +#[derive(Debug)] +pub struct RustModules { + root: ModuleNode, +} + +impl RustModules { + pub fn new() -> Self { + RustModules { + root: ModuleNode::new(ModuleType::Exist), + } + } + + pub fn add_path(&mut self, cargo_toml: &PathBuf, path: &PathBuf) { + if !cargo_toml.exists() || !cargo_toml.is_file() { + panic!("Cargo.template.toml不存在!"); + } + let path = path.strip_prefix( + cargo_toml.parent().unwrap()).expect("路径不在Cargo.template.toml目录下"); + let components = path.components().map(|v| v.as_os_str().to_string_lossy().to_string()); + + let mut entry = &mut self.root; + let mut path = cargo_toml.parent().unwrap().to_path_buf(); + for component in components { + let tmp_path = path.join(&component); + let mod_rs = tmp_path.join("mod.rs"); + let module_type = if mod_rs.exists() { + ModuleType::Exist + } else { + ModuleType::NotExist + }; + entry = entry.add_child(&component, module_type); + path = tmp_path; + if let ModuleType::Exist = module_type { + break; + } + } + } +} + +impl RustConfig { + pub fn new(target: String, rust_flags: Vec, work_dir: &PathBuf) -> Self { + if target.ends_with(".json") { + let work_dir = work_dir.canonicalize().unwrap(); + let target = work_dir.join(target).to_string_lossy().to_string(); + RustConfig { + target, + target_type: RustcTargetType::Custom, + rust_flags, + modules: Arc::new(RefCell::new(RustModules::new())), + force_update: Arc::new(RefCell::new(false)), + cargo_toml: RefCell::new(None), + } + } else { + RustConfig { + target, + target_type: RustcTargetType::Builtin, + rust_flags, + modules: Arc::new(RefCell::new(RustModules::new())), + force_update: Arc::new(RefCell::new(false)), + cargo_toml: RefCell::new(None), + } + } + } + + pub fn use_cargo_toml(&mut self, cargo_toml: PathBuf, work_dir: &PathBuf, out_dir: &PathBuf) { + self.write_cargo_configs(&cargo_toml, work_dir, out_dir); + if self.cargo_toml.borrow().is_some() { + self.cargo_toml = RefCell::new(Some(cargo_toml)); + } else { + self.cargo_toml.borrow_mut().replace(cargo_toml); + } + } + + fn write_module_declaration( + &self, + file: &mut File, + node: &ModuleNode, + indent_level: usize, + ) -> std::io::Result<()> { + let indent = " ".repeat(indent_level); + + for (name, node) in node.children.iter().clone() { + match node.module_type { + ModuleType::NotExist => { + writeln!(file, "{}pub mod {} {{", indent, name)?; + self.write_module_declaration(file, node, indent_level + 1)?; + writeln!(file, "{}}}", indent)?; + } + ModuleType::Exist => { + writeln!(file, "{}pub mod {};", indent, name)?; + } + } + } + Ok(()) + } + + fn write_root_file(&self, work_dir: &PathBuf) -> std::io::Result<()> { + let root_file_path = work_dir.canonicalize()?.join("lib.rs"); + let mut file = std::fs::File::create(&root_file_path)?; + + writeln!(file, "// Auto-generated root file for this crate")?; + writeln!(file, "// Target: {}", self.target)?; + writeln!(file, "#![no_std]")?; + writeln!(file, "#![no_main]")?; + writeln!(file, "\nuse core::panic::PanicInfo;\n")?; + writeln!(file, "\n#[panic_handler]")?; + writeln!(file, "fn panic(_info: &PanicInfo) -> ! {{")?; + writeln!(file, " loop {{}}")?; + writeln!(file, "}}\n")?; + + let modules = self.modules.borrow(); + self.write_module_declaration(&mut file, &modules.root, 0)?; + + Ok(()) + } + + fn write_cargo_config(&self, out_dir: &PathBuf) -> std::io::Result<()> { + let cargo_config_path = out_dir.join(".cargo"); + if !cargo_config_path.exists() { + fs::create_dir_all(&cargo_config_path)?; + } + let config_toml_path = cargo_config_path.canonicalize()?.join("config.toml"); + let mut file = fs::File::create(&config_toml_path)?; + + writeln!(file, "# Auto-generated Cargo config file")?; + writeln!(file, "[build]")?; + writeln!(file, "target = \"{}\"", self.target)?; + writeln!( + file, + "target-dir = \"{}\"", + out_dir.join("rustc_target/").display() + )?; + write!(file, "rustflags = [")?; + for flag in self.rust_flags.iter() { + write!(file, "\"{}\",", flag)?; + } + writeln!(file, "]")?; + + if let RustcTargetType::Custom = self.target_type { + writeln!(file, "\n[unstable]")?; + writeln!(file, "build-std = [\"core\", \"compiler_builtins\"]")?; + } + + Ok(()) + } + + fn write_cargo_toml(&self, cargo_toml: &PathBuf, work_dir: &PathBuf, out_dir: &PathBuf) -> std::io::Result<()> { + let cargo_toml_path = out_dir.join("Cargo.template.toml"); + let cargo_toml = fs::read_to_string(cargo_toml)?; + + let mut lines: Vec = cargo_toml.lines().map(|s| s.to_string()).collect(); + + let mut lib_index: Option = None; + for (i, line) in lines.iter().enumerate() { + if line.trim_start().starts_with("[lib]") { + lib_index = Some(i); + break; + } + } + + if let Some(idx) = lib_index { + // 找到下一个以 '[' 开头的 section 行位置(如果没有则使用文件末尾) + let mut next_idx = lines.len(); + for (j, line) in lines.iter().enumerate().skip(idx + 1) { + if line.trim_start().starts_with('[') { + next_idx = j; + break; + } + } + + // 在 [lib] 和下一个 section 之间检查是否已有 path 字段 + for line in &lines[idx + 1..next_idx] { + if let Some(eq_pos) = line.find('=') { + let key = line[..eq_pos].trim(); + if key == "path" { + return Err(std::io::Error::new( + std::io::ErrorKind::Other, + "Cargo.template.toml 中 [lib] 已包含 path 字段", + )); + } + } else if line.trim_start().starts_with("path") { + // 保守检查,处理没有等号的异常格式 + return Err(std::io::Error::new( + std::io::ErrorKind::Other, + "Cargo.template.toml 中 [lib] 已包含 path 字段", + )); + } + } + + // 在该 section 的末尾插入 path 字段(即在 next_idx 处插入) + lines.insert(next_idx, format!("path = \"{}\"", work_dir.join("lib.rs").display())); + } else { + // 如果没有 [lib] 节,则追加一个新的 [lib] 节并写入 path + if !cargo_toml.ends_with('\n') { + lines.push(String::new()); + } + lines.push("[lib]".to_string()); + lines.push("path = \"./lib.rs\"".to_string()); + } + + let new_contents = lines.join("\n"); + let cargo_toml_path = out_dir.join("Cargo.toml"); + fs::write(cargo_toml_path, new_contents)?; + + Ok(()) + } + + pub fn add_file(&self, file_path: &PathBuf) { + let mut modules = self.modules.borrow_mut(); + match self.cargo_toml.borrow().as_ref() { + Some(cargo_toml) => {modules.add_path(cargo_toml, file_path);}, + None => {panic!("使用了rust文件但没有定义Cargo.template.toml!");}, + } + } + + pub fn set_force_update(&self, value: bool) { + let mut force_update = self.force_update.borrow_mut(); + *force_update = value; + } + + fn need_update(&self) -> bool { + *self.force_update.borrow() + } + + fn is_empty(&self) -> bool { + let modules = self.modules.borrow(); + modules.root.children.is_empty() + } + + fn write_cargo_configs(&self, cargo_toml: &PathBuf, work_dir: &PathBuf, out_dir: &PathBuf) { + if self.need_update() { + self.write_cargo_toml(cargo_toml, work_dir, out_dir) + .expect("写入Cargo.template.toml失败"); + self.write_cargo_config(out_dir) + .expect("写入cargo config失败"); + } + } + + pub fn write_configs(&self, work_dir: &PathBuf, out_dir: &PathBuf, debug_level: DebugLevel) -> Option { + let cargo_toml = work_dir.join("Cargo.template.toml"); + if cargo_toml.exists() && cargo_toml.is_file() { + if self.need_update() { + self.write_root_file(work_dir) + .expect("写入lib.rs失败"); + + let target_name = self.target.split(".").next().unwrap().rsplit('/').next().unwrap(); + dependency::do_rust_dependency( + &self, + &work_dir.join("lib.rs"), + &out_dir, + &target_name, + debug_level == DebugLevel::Release, + ); + return Some(out_dir.join("rlib.a")); + } + } + None + } +} diff --git a/tools/grub/grub_dep_detect.py b/tools/grub/grub_dep_detect.py new file mode 100644 index 0000000..c5270a0 --- /dev/null +++ b/tools/grub/grub_dep_detect.py @@ -0,0 +1,85 @@ +import os +from collections import deque + +class GrubModDependencyResolver: + def __init__(self, mod_dir): + self.mod_dir = mod_dir + self.dep_map = {} + + def _read_deps_from_elf(self, path): + with open(path, 'rb') as f: + magic = f.read(4) + if magic != b'\x7fELF': + print("Not an ELF file:", path) + return [] + byte_len = f.read(1) + if byte_len == b'\x01': + byte_len = 4 + elif byte_len == b'\x02': + byte_len = 8 + else: + print("Unknown ELF class:", path) + return [] + endian = f.read(1) + if endian == b'\x01': + is_little = True + elif endian == b'\x02': + is_little = False + else: + print("Unknown ELF endianness:", path) + return [] + f.seek(24 + byte_len * 2) + shoff = int.from_bytes(f.read(4), 'little' if is_little else 'big') + f.seek(10, os.SEEK_CUR) + shentsize = int.from_bytes(f.read(2), 'little' if is_little else 'big') + shnum = int.from_bytes(f.read(2), 'little' if is_little else 'big') + shstrndx = int.from_bytes(f.read(2), 'little' if is_little else 'big') + + f.seek(shoff + shentsize * shstrndx + 12 + byte_len) + shstroff = int.from_bytes(f.read(byte_len), 'little' if is_little else 'big') + + for _ in range(shnum): + f.seek(shoff) + sh_name_index = int.from_bytes(f.read(4), 'little' if is_little else 'big') + f.seek(shstroff + sh_name_index) + name = f.read(8) + if name == b'.moddeps': + f.seek(shoff + 12 + byte_len) + sh_offset = int.from_bytes(f.read(byte_len), 'little' if is_little else 'big') + sh_size = int.from_bytes(f.read(4), 'little' if is_little else 'big') + f.seek(sh_offset) + data = f.read(sh_size) + return [d.decode('utf-8') for d in data.split(b'\x00') if d] + f.seek(shoff + 12 + byte_len) + sh_offset = int.from_bytes(f.read(byte_len), 'little' if is_little else 'big') + sh_size = int.from_bytes(f.read(4), 'little' if is_little else 'big') + shoff += shentsize + + return [] + + def resolve_dependencies(self, mods = []): + all_deps = set(mods) + queue = deque(mods if isinstance(mods, list) else [mods]) + while queue: + mod = queue.popleft() + if mod not in all_deps: + all_deps.add(mod) + deps = self._read_deps_from_elf(os.path.join(self.mod_dir, mod + '.mod')) + for dep in deps: + if dep not in all_deps: + queue.append(dep) + all_deps.add(dep) + return list(all_deps) + +if __name__ == "__main__": + import sys + if len(sys.argv) < 3: + print("Usage: python grub_dep_detect.py [ ...]") + sys.exit(1) + + mod_dir = sys.argv[1] + mods = sys.argv[2:] + + resolver = GrubModDependencyResolver(mod_dir) + all_deps = resolver.resolve_dependencies(mods) + print("All dependencies:", all_deps) \ No newline at end of file diff --git a/tools/grub/install_grub.py b/tools/grub/install_grub.py new file mode 100644 index 0000000..cd1dc73 --- /dev/null +++ b/tools/grub/install_grub.py @@ -0,0 +1,148 @@ +import os +import subprocess +import shutil +import struct +import argparse +from grub_dep_detect import GrubModDependencyResolver + +# 定义变量 +imagetool_path = os.path.join('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/" +cross_prefix = "" +default_grub_dir = "/usr/lib/grub/" +grub_mkimage_path = "" +default_mods =\ +"normal biosdisk part_gpt part_msdos fat ext2 multiboot2 all_video" + +def run_command(command, hide=False): + if not hide: + print("execute 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, grub_dir_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 = os.path.join(grub_dir_path, platform) + if not os.path.isfile(os.path.join(_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 += ')' + resolver = GrubModDependencyResolver(os.path.join(grub_dir_path, platform)) + all_deps = " ".join(resolver.resolve_dependencies(mods.split())) + run_command(f"{grub_mkimage_path} -O {platform} -o {core_image_path} --prefix \"{prefix_device + prefix_path}\" {all_deps}") + + # 写入引导扇区 + 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="目标平台", required=True) + parser.add_argument("--fs", help="文件系统", required=True) + parser.add_argument("--mods", help="要额外附加的模块", default=default_mods) + parser.add_argument("--grub-dir", help=f"GRUB平台目录(如{default_grub_dir})", default=default_grub_dir) + parser.add_argument("--grub-mkimage", help="grub-mkimage路径") + args = parser.parse_args() + + grub_mkimage_path = "grub-mkimage" + if args.grub_dir == None: + # 使用了默认设置,检查一下 + if os.name == "Darwin": + if args.grub_mkimage == None: + if args.platform == "i386-pc": + cross_prefix = "i686-elf-" + elif args.platform == "x86_64-efi": + cross_prefix = "x86_64-elf-" + grub_mkimage_path = cross_prefix + grub_mkimage_path + + def get_brew_prefix(): + try: + result = subprocess.run(['brew', '--prefix', cross_prefix + 'grub'], capture_output=True, text=True, check=True) + return result.stdout.strip() + except subprocess.CalledProcessError: + print("Error: Unable to get Homebrew prefix. Make sure Homebrew is installed.") + exit(1) + brew_prefix = get_brew_prefix() + + versions = sorted(os.listdir(brew_prefix)) + latest_version = versions[-1] + grub_dir_path = os.path.join(brew_prefix, latest_version, 'lib', cross_prefix[:-1], 'grub') + grub_mkimage_path = cross_prefix + grub_mkimage_path + elif os.name == "nt": + print("检测到为Windows,请输入grub路径:") + path = input() + grub_dir_path = path + if args.grub_mkimage == None: + grub_mkimage_path = cross_prefix + grub_mkimage_path + grub_mkimage_path = os.path.join(grub_dir_path, grub_mkimage_path) + else: + grub_mkimage_path = args.grub_mkimage + else: + if args.grub_mkimage != None: + grub_mkimage_path = args.grub_mkimage + else: + grub_dir_path = args.grub_dir + if args.grub_mkimage != None: + grub_mkimage_path = args.grub_mkimage + + install_grub(args.image, grub_dir_path, args.platform, args.fs, args.mods) diff --git a/tools/imagetool b/tools/imagetool index eeb6ba6..de2b403 160000 --- a/tools/imagetool +++ b/tools/imagetool @@ -1 +1 @@ -Subproject commit eeb6ba602d5272ecfefe0c2a1d2fad55a8a0d61a +Subproject commit de2b403d546b5b67af8cc9004c646528769ccf4b