diff --git a/.gitignore b/.gitignore
index 8c827b2..6f7b02f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,6 @@
out
*.map
*.o
+*.a
+*.su
.dccache
diff --git a/.vscode/c_boilerplates.code-snippets b/.vscode/c_boilerplates.code-snippets
index 366f30a..a3c12a1 100644
--- a/.vscode/c_boilerplates.code-snippets
+++ b/.vscode/c_boilerplates.code-snippets
@@ -24,5 +24,29 @@
"/** @brief $0 */"
],
"description": "Create documentation brief."
+ },
+ "License": {
+ "prefix": [
+ "license",
+ ],
+ "body": [
+ "/*",
+ "\tThis file is part of Fennix Drivers.",
+ "",
+ "\tFennix Drivers is free software: you can redistribute it and/or",
+ "\tmodify it under the terms of the GNU General Public License as",
+ "\tpublished by the Free Software Foundation, either version 3 of",
+ "\tthe License, or (at your option) any later version.",
+ "",
+ "\tFennix Drivers is distributed in the hope that it will be useful,",
+ "\tbut WITHOUT ANY WARRANTY; without even the implied warranty of",
+ "\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the",
+ "\tGNU General Public License for more details.",
+ "",
+ "\tYou should have received a copy of the GNU General Public License",
+ "\talong with Fennix Drivers. If not, see .",
+ "*/"
+ ],
+ "description": "Create kernel license."
}
}
\ No newline at end of file
diff --git a/Audio/Makefile b/Audio/Makefile
deleted file mode 100644
index cbb34d8..0000000
--- a/Audio/Makefile
+++ /dev/null
@@ -1,3 +0,0 @@
-build:
-
-clean:
diff --git a/Doxyfile b/Doxyfile
index 0a1450e..b278f92 100644
--- a/Doxyfile
+++ b/Doxyfile
@@ -32,7 +32,7 @@ DOXYFILE_ENCODING = UTF-8
# title of most generated pages and in a few other places.
# The default value is: My Project.
-PROJECT_NAME = "Fennix Modules"
+PROJECT_NAME = "Fennix Drivers"
# The PROJECT_NUMBER tag can be used to enter a project or revision number. This
# could be handy for archiving the generated documentation or if some version
@@ -44,7 +44,7 @@ PROJECT_NUMBER = 1.0.0
# for a project that appears at the top of each page and should give viewer a
# quick idea about the purpose of the project. Keep the description short.
-PROJECT_BRIEF = "Fennix Userspace Documentation"
+PROJECT_BRIEF = "Driver API Documentation"
# With the PROJECT_LOGO tag one can specify a logo or an icon that is included
# in the documentation. The maximum height of the logo should not exceed 55
@@ -864,7 +864,7 @@ WARN_LOGFILE =
# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING
# Note: If this tag is empty the current directory is searched.
-INPUT = Modules tools/Doxygen_README.md
+INPUT = Drivers/include tools/doxymds/drivers.md
# This tag can be used to specify the character encoding of the source files
# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
@@ -1064,7 +1064,7 @@ FILTER_SOURCE_PATTERNS =
# (index.html). This can be useful if you have a project on for instance GitHub
# and want to reuse the introduction page also for the doxygen output.
-USE_MDFILE_AS_MAINPAGE = tools/Doxygen_README.md
+USE_MDFILE_AS_MAINPAGE = tools/doxymds/drivers.md
#---------------------------------------------------------------------------
# Configuration options related to source browsing
@@ -1224,7 +1224,7 @@ GENERATE_HTML = YES
# The default directory is: html.
# This tag requires that the tag GENERATE_HTML is set to YES.
-HTML_OUTPUT = doxygen-doc/modules
+HTML_OUTPUT = doxygen-doc/drivers
# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
# generated HTML page (for example: .htm, .php, .asp).
diff --git a/FileSystem/Makefile b/FileSystem/Makefile
deleted file mode 100644
index cbb34d8..0000000
--- a/FileSystem/Makefile
+++ /dev/null
@@ -1,3 +0,0 @@
-build:
-
-clean:
diff --git a/Generic/ExampleDriver/Example.cpp b/Generic/ExampleDriver/Example.cpp
deleted file mode 100644
index 139a52e..0000000
--- a/Generic/ExampleDriver/Example.cpp
+++ /dev/null
@@ -1,92 +0,0 @@
-#include "../../../Kernel/mapi.hpp"
-#include "../../../Kernel/Fex.hpp"
-
-extern "C" int ModuleEntry(void *Data);
-int CallbackHandler(KernelCallback *Data);
-int InterruptCallback(CPURegisters *Registers);
-
-/* The module is
- * This is a module for Fennix Module Entry Extended Header
- * * * * */
-HEAD(FexFormatType_Module, FexOSType_Fennix, ModuleEntry);
-
-/* Ignore the warning about missing field initializers. */
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
-
-/* Extended header which is used to give additional information to the kernel. */
-__attribute__((section(".extended"))) FexExtended ExtendedHeader = {
- .Module = {
- .Name = "Example Module",
- .Type = FexModuleType_Generic,
- .Callback = CallbackHandler,
- .InterruptCallback = InterruptCallback,
- .Bind = {
- .Type = BIND_INTERRUPT,
- .Interrupt = {
- .Vector = {222}, /* IRQ222 */
- }}}};
-
-#pragma GCC diagnostic pop
-
-/* Global structure that holds the kernel API. */
-KernelAPI KAPI{};
-
-/* Macro that prints a message to the kernel debugger. */
-#define print(msg) KAPI.Util.DebugPrint((char *)(msg), KAPI.Info.modUniqueID)
-
-/* --------------------------------------------------------------------------------------------------------- */
-
-/* Module entry point. This is called at initialization.
- "Data" argument points to the kernel API structure. */
-int ModuleEntry(void *Data)
-{
- /* Check if kernel API is valid */
- if (!Data)
- return INVALID_KERNEL_API;
-
- /* Set the global structure to the kernel API. */
- KAPI = *(KernelAPI *)Data;
-
- /* Check if kernel API version is valid.
- This is important because the kernel
- API may change in the future. */
- if (KAPI.Version.Major < 0 || KAPI.Version.Minor < 0 || KAPI.Version.Patch < 0)
- return KERNEL_API_VERSION_NOT_SUPPORTED;
-
- /* We print "Hello World!" to the kernel debugger. */
- print("Hello World!");
- return OK;
-}
-
-/* This is called when the module is bound to an interrupt, process,
- or PCI device or when the kernel wants to send a message to the module. */
-int CallbackHandler(KernelCallback *Data)
-{
- switch (Data->Reason)
- {
- case AcknowledgeReason:
- {
- print("Kernel acknowledged the module.");
- break;
- }
- case StopReason:
- {
- print("Module stopped.");
- break;
- }
- default:
- {
- print("Unknown reason.");
- break;
- }
- }
- return OK;
-}
-
-/* Interrupt handler. */
-int InterruptCallback(CPURegisters *)
-{
- print("Interrupt received.");
- return OK;
-}
diff --git a/Generic/ExampleDriver/Makefile b/Generic/ExampleDriver/Makefile
deleted file mode 100644
index 2d586cc..0000000
--- a/Generic/ExampleDriver/Makefile
+++ /dev/null
@@ -1,98 +0,0 @@
-# Config file
-include ../../../Makefile.conf
-
-FILENAME = ExampleDriver.fex
-
-CC = ../../../$(COMPILER_PATH)/$(COMPILER_ARCH)gcc
-CPP = ../../../$(COMPILER_PATH)/$(COMPILER_ARCH)g++
-LD = ../../../$(COMPILER_PATH)/$(COMPILER_ARCH)ld
-AS = ../../../$(COMPILER_PATH)/$(COMPILER_ARCH)as
-OBJDUMP = ../../../$(COMPILER_PATH)/$(COMPILER_ARCH)objdump
-
-GIT_COMMIT = $(shell git rev-parse HEAD)
-GIT_COMMIT_SHORT = $(shell git rev-parse --short HEAD)
-
-ifeq ($(OSARCH), amd64)
-S_SOURCES = $(shell find ./ -type f -name '*.S' -not -path "./arch/i386/*" -not -path "./arch/aarch64/*")
-C_SOURCES = $(shell find ./ -type f -name '*.c' -not -path "./arch/i386/*" -not -path "./arch/aarch64/*")
-CPP_SOURCES = $(shell find ./ -type f -name '*.cpp' -not -path "./arch/i386/*" -not -path "./arch/aarch64/*")
-else ifeq ($(OSARCH), i386)
-S_SOURCES = $(shell find ./ -type f -name '*.S' -not -path "./arch/amd64/*" -not -path "./arch/aarch64/*")
-C_SOURCES = $(shell find ./ -type f -name '*.c' -not -path "./arch/amd64/*" -not -path "./arch/aarch64/*")
-CPP_SOURCES = $(shell find ./ -type f -name '*.cpp' -not -path "./arch/amd64/*" -not -path "./arch/aarch64/*")
-else ifeq ($(OSARCH), aarch64)
-S_SOURCES = $(shell find ./ -type f -name '*.S' -not -path "./arch/amd64/*" -not -path "./arch/i386/*")
-C_SOURCES = $(shell find ./ -type f -name '*.c' -not -path "./arch/amd64/*" -not -path "./arch/i386/*")
-CPP_SOURCES = $(shell find ./ -type f -name '*.cpp' -not -path "./arch/amd64/*" -not -path "./arch/i386/*")
-endif
-HEADERS = $(sort $(dir $(wildcard ../../include/*)))
-OBJ = $(C_SOURCES:.c=.o) $(CPP_SOURCES:.cpp=.o) $(ASM_SOURCES:.asm=.o) $(S_SOURCES:.S=.o) $(PSF_SOURCES:.psf=.o) $(BMP_SOURCES:.bmp=.o)
-INCLUDE_DIR = ../../include
-
-LDFLAGS := \
- -fPIC -fPIE -pie -Wl,-eDriverEntry \
- -Wl,-static,--no-dynamic-linker,-ztext,--no-warn-rwx-segment \
- -nostdlib -nodefaultlibs -nolibc \
- -zmax-page-size=0x1000 \
- -Wl,-Map file.map -static
-
-WARNCFLAG = -Wall -Wextra
-
-CFLAGS := \
- -I$(INCLUDE_DIR) \
- -DGIT_COMMIT='"$(GIT_COMMIT)"' \
- -DGIT_COMMIT_SHORT='"$(GIT_COMMIT_SHORT)"'
-
-ifeq ($(OSARCH), amd64)
-
-LDFLAGS += -Tlinker_amd64.ld
-
-CFLAGS += -fPIC -fPIE -pie -mno-80387 -mno-mmx -mno-3dnow \
- -mno-red-zone -mno-sse -mno-sse2 \
- -march=x86-64 -pipe -ffunction-sections \
- -msoft-float -fno-builtin
-
-else ifeq ($(OSARCH), i386)
-
-LDFLAGS += -Tlinker_i386.ld
-
-CFLAGS += -fPIC -fPIE -pie -mno-80387 -mno-mmx -mno-3dnow \
- -mno-red-zone -mno-sse -mno-sse2 -ffunction-sections \
- -march=i386 -pipe -msoft-float -fno-builtin
-
-else ifeq ($(OSARCH), aarch64)
-
-LDFLAGS += -Tlinker_aarch64.ld
-
-CFLAGS += -pipe -fno-builtin -fPIC
-
-endif
-
-build: $(FILENAME)
-ifeq ($(OSARCH), amd64)
- $(OBJDUMP) -b binary -D -m i386:x86-64 -d $(FILENAME) > file_dump.map
-else ifeq ($(OSARCH), i386)
- $(OBJDUMP) -b binary -D -m i386 -d $(FILENAME) > file_dump.map
-else ifeq ($(OSARCH), aarch64)
- $(OBJDUMP) -b binary -D -m aarch64 -d $(FILENAME) > file_dump.map
-endif
- mv $(FILENAME) ../../out/$(FILENAME)
-
-$(FILENAME): $(OBJ)
- $(info Linking $@)
- $(CC) $(LDFLAGS) $(OBJ) -o $@
-
-%.o: %.c $(HEADERS)
- $(info Compiling $<)
- $(CC) $(CFLAGS) $(WARNCFLAG) -std=c17 -c $< -o $@
-
-%.o: %.cpp $(HEADERS)
- $(info Compiling $<)
- $(CPP) $(CFLAGS) $(WARNCFLAG) -std=c++20 -fexceptions -c $< -o $@
-
-%.o: %.S
- $(info Compiling $<)
- $(AS) -o $@ $<
-
-clean:
- rm -f file.map file_dump.map $(OBJ)
diff --git a/Generic/ExampleDriver/linker_amd64.ld b/Generic/ExampleDriver/linker_amd64.ld
deleted file mode 100644
index 29cd11c..0000000
--- a/Generic/ExampleDriver/linker_amd64.ld
+++ /dev/null
@@ -1,40 +0,0 @@
-OUTPUT_FORMAT(binary)
-OUTPUT_ARCH(i386:x86-64)
-
-ENTRY(DriverEntry)
-
-SECTIONS
-{
- .header :
- {
- *(.header .header.*)
- *(.extended .extended.*)
- }
-
- .text :
- {
- *(.text .text.*)
- }
-
- .data :
- {
- *(.data .data.*)
- }
-
- .rodata :
- {
- *(.rodata .rodata.*)
- }
-
- .bss :
- {
- *(COMMON)
- *(.bss .bss.*)
- }
-
- /DISCARD/ :
- {
- *(.eh_frame)
- *(.note .note.*)
- }
-}
diff --git a/Generic/ExampleDriver/linker_i386.ld b/Generic/ExampleDriver/linker_i386.ld
deleted file mode 100644
index 9d72554..0000000
--- a/Generic/ExampleDriver/linker_i386.ld
+++ /dev/null
@@ -1,41 +0,0 @@
-OUTPUT_FORMAT(binary)
-OUTPUT_ARCH(i386)
-
-ENTRY(DriverEntry)
-
-SECTIONS
-{
- .header :
- {
- *(.header .header.*)
- *(.extended .extended.*)
- }
-
- .text :
- {
- *(.text .text.*)
- }
-
- .data :
- {
- *(.data .data.*)
- PROVIDE(_GLOBAL_OFFSET_TABLE_ = .);
- }
-
- .rodata :
- {
- *(.rodata .rodata.*)
- }
-
- .bss :
- {
- *(COMMON)
- *(.bss .bss.*)
- }
-
- /DISCARD/ :
- {
- *(.eh_frame)
- *(.note .note.*)
- }
-}
diff --git a/Generic/Makefile b/Generic/Makefile
deleted file mode 100644
index f011df9..0000000
--- a/Generic/Makefile
+++ /dev/null
@@ -1,5 +0,0 @@
-build:
- make -C ExampleDriver build
-
-clean:
- make -C ExampleDriver clean
diff --git a/Input/Makefile b/Input/Makefile
deleted file mode 100644
index cbb34d8..0000000
--- a/Input/Makefile
+++ /dev/null
@@ -1,3 +0,0 @@
-build:
-
-clean:
diff --git a/Makefile b/Makefile
index 8f4b619..324f07d 100644
--- a/Makefile
+++ b/Makefile
@@ -1,22 +1,21 @@
build:
+ cp -f ../Kernel/driver.h include/driver.h
mkdir -p out
- make -C Input build
- make -C Storage build
- make -C Audio build
- make -C FileSystem build
- make -C Generic build
- make -C Network build
- make -C Video build
+ make -C library build
+ make -C audio build
+ make -C input build
+ make -C misc build
+ make -C network build
+ make -C storage build
prepare:
$(info Nothing to prepare)
clean:
rm -rf out
- make -C Input clean
- make -C Storage clean
- make -C Audio clean
- make -C FileSystem clean
- make -C Generic clean
- make -C Network clean
- make -C Video clean
+ make -C library clean
+ make -C audio clean
+ make -C input clean
+ make -C misc clean
+ make -C network clean
+ make -C storage clean
diff --git a/Network/Makefile b/Network/Makefile
deleted file mode 100644
index cbb34d8..0000000
--- a/Network/Makefile
+++ /dev/null
@@ -1,3 +0,0 @@
-build:
-
-clean:
diff --git a/README.md b/README.md
index 49e33e2..e863fdd 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
-# Modules
+# Drivers
-Modules for [Fennix](https://github.com/Fennix-Project/Fennix).
+Drivers for [Fennix](https://github.com/Fennix-Project/Fennix).
---
diff --git a/Storage/Makefile b/Storage/Makefile
deleted file mode 100644
index cbb34d8..0000000
--- a/Storage/Makefile
+++ /dev/null
@@ -1,3 +0,0 @@
-build:
-
-clean:
diff --git a/Video/Makefile b/Video/Makefile
deleted file mode 100644
index cbb34d8..0000000
--- a/Video/Makefile
+++ /dev/null
@@ -1,3 +0,0 @@
-build:
-
-clean:
diff --git a/audio/Makefile b/audio/Makefile
new file mode 100644
index 0000000..017a1dd
--- /dev/null
+++ b/audio/Makefile
@@ -0,0 +1,7 @@
+build:
+ make -C ac97 build
+ make -C hda build
+
+clean:
+ make -C ac97 clean
+ make -C hda clean
diff --git a/audio/ac97/Makefile b/audio/ac97/Makefile
new file mode 100644
index 0000000..a76f72b
--- /dev/null
+++ b/audio/ac97/Makefile
@@ -0,0 +1,83 @@
+# Config file
+include ../../../Makefile.conf
+
+FILENAME = ac97.drv
+
+CC = ../../../$(COMPILER_PATH)/$(COMPILER_ARCH)gcc
+CPP = ../../../$(COMPILER_PATH)/$(COMPILER_ARCH)g++
+LD = ../../../$(COMPILER_PATH)/$(COMPILER_ARCH)ld
+AS = ../../../$(COMPILER_PATH)/$(COMPILER_ARCH)as
+OBJDUMP = ../../../$(COMPILER_PATH)/$(COMPILER_ARCH)objdump
+
+S_SOURCES = $(shell find ./ -type f -name '*.S')
+C_SOURCES = $(shell find ./ -type f -name '*.c')
+CPP_SOURCES = $(shell find ./ -type f -name '*.cpp')
+HEADERS = $(sort $(dir $(wildcard ../../include/*)))
+OBJ = $(C_SOURCES:.c=.o) $(CPP_SOURCES:.cpp=.o) $(ASM_SOURCES:.asm=.o) $(S_SOURCES:.S=.o) $(PSF_SOURCES:.psf=.o) $(BMP_SOURCES:.bmp=.o)
+STACK_USAGE_OBJ = $(C_SOURCES:.c=.su) $(CPP_SOURCES:.cpp=.su)
+INCLUDE_DIR = ../../include
+
+LIBS := ../../out/dcrt0.o -L../../out -ldriver
+
+LDFLAGS := \
+ -fPIC -fPIE -pie \
+ -Wl,--no-dynamic-linker,-ztext,--no-warn-rwx-segment \
+ -nostdlib -nodefaultlibs -nolibc \
+ -zmax-page-size=0x1000 \
+ -Wl,-Map file.map -shared -fvisibility=hidden
+
+WARNCFLAG = -Wall -Wextra
+
+CFLAGS := -I$(INCLUDE_DIR) -fvisibility=hidden
+
+ifeq ($(OSARCH), amd64)
+
+CFLAGS += -fPIC -fPIE -pie -mno-80387 -mno-mmx -mno-3dnow \
+ -mno-red-zone -mno-sse -mno-sse2 \
+ -march=x86-64 -pipe -ffunction-sections \
+ -msoft-float -fno-builtin
+
+else ifeq ($(OSARCH), i386)
+
+CFLAGS += -fPIC -fPIE -pie -mno-80387 -mno-mmx -mno-3dnow \
+ -mno-red-zone -mno-sse -mno-sse2 -ffunction-sections \
+ -march=i386 -pipe -msoft-float -fno-builtin
+
+else ifeq ($(OSARCH), aarch64)
+
+CFLAGS += -pipe -fno-builtin -fPIC
+
+endif
+
+ifeq ($(DEBUG), 1)
+ CFLAGS += -DDEBUG -ggdb3 -O0 -fdiagnostics-color=always -fstack-usage
+ifeq ($(OSARCH), amd64)
+ CFLAGS += -fverbose-asm
+endif
+ifneq ($(OSARCH), aarch64)
+ CFLAGS += -fstack-check
+endif
+ LDFLAGS += -ggdb3 -O0
+endif
+
+build: $(FILENAME)
+ mv $(FILENAME) ../../out/$(FILENAME)
+
+$(FILENAME): $(OBJ)
+ $(info Linking $@)
+ $(CC) $(LDFLAGS) $(OBJ) $(LIBS) -o $@
+
+%.o: %.c $(HEADERS)
+ $(info Compiling $<)
+ $(CC) $(CFLAGS) $(WARNCFLAG) -std=c17 -c $< -o $@
+
+%.o: %.cpp $(HEADERS)
+ $(info Compiling $<)
+ $(CPP) $(CFLAGS) $(WARNCFLAG) -std=c++20 -fno-exceptions -fno-rtti -c $< -o $@
+
+%.o: %.S
+ $(info Compiling $<)
+ $(AS) -o $@ $<
+
+clean:
+ rm -f file.map $(OBJ) $(STACK_USAGE_OBJ)
diff --git a/audio/ac97/ac97.cpp b/audio/ac97/ac97.cpp
new file mode 100644
index 0000000..d12163b
--- /dev/null
+++ b/audio/ac97/ac97.cpp
@@ -0,0 +1,857 @@
+/*
+ This file is part of Fennix Kernel.
+
+ Fennix Kernel is free software: you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation, either version 3 of
+ the License, or (at your option) any later version.
+
+ Fennix Kernel is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Fennix Kernel. If not, see .
+*/
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+#define DescriptorListLength 0x20
+
+enum AudioVolumeValues
+{
+ AV_Maximum = 0x0,
+ AV_Minimum = 0x3F,
+};
+
+enum AudioEncodingValues
+{
+ AE_PCMs8,
+ AE_PCMu8,
+
+ AE_PCMs16le,
+ AE_PCMs20le,
+ AE_PCMs24le,
+ AE_PCMs32le,
+
+ AE_PCMu16le,
+ AE_PCMu20le,
+ AE_PCMu24le,
+ AE_PCMu32le,
+
+ AE_PCMs16be,
+ AE_PCMs20be,
+ AE_PCMs24be,
+ AE_PCMs32be,
+
+ AE_PCMu16be,
+ AE_PCMu20be,
+ AE_PCMu24be,
+ AE_PCMu32be,
+};
+
+enum NativeAudioMixerRegisters
+{
+ /**
+ * @brief Reset Register
+ * @note Length: word
+ */
+ NAM_Reset = 0x00,
+
+ /**
+ * @brief Master Volume Register
+ * @note Length: word
+ */
+ NAM_MasterVolume = 0x02,
+
+ /**
+ * @brief Microphone Volume Register
+ * @note Length: word
+ */
+ NAM_MicrophoneVolume = 0x0E,
+
+ /**
+ * @brief PCM Out Volume Register
+ * @note Length: word
+ */
+ NAM_PCMOutVolume = 0x18,
+
+ /**
+ * @brief Select Record Input Register
+ * @note Length: word
+ */
+ NAM_SelectRecordInput = 0x1A,
+
+ /**
+ * @brief Record Gain Register
+ * @note Length: word
+ */
+ NAM_RecordGain = 0x1C,
+
+ /**
+ * @brief Record Gain Microphone Register
+ * @note Length: word
+ */
+ NAM_RecordGainMicrophone = 0x1E,
+};
+
+enum NativeAudioBusMasterRegisters
+{
+ /**
+ * @brief Register box for PCM IN
+ * @note Length: below
+ */
+ NABM_PCMInBox = 0x00,
+
+ /**
+ * @brief Register box for PCM OUT
+ * @note Length: below
+ */
+ NABM_PCMOutBox = 0x10,
+
+ /**
+ * @brief Register box for Microphone
+ * @note Length: below
+ */
+ NABM_MicrophoneBox = 0x20,
+
+ /**
+ * @brief Global Control Register
+ * @note Length: dword
+ */
+ NABM_GlobalControl = 0x2C, /* 0x30 */
+
+ /**
+ * @brief Global Status Register
+ * @note Length: dword
+ */
+ NABM_GlobalStatus = 0x30, /* 0x34 */
+};
+
+enum NativeAudioBusMasterBoxOffsets
+{
+ /**
+ * @brief Physical Address of Buffer Descriptor List
+ * @note Length: dword
+ */
+ NABMBOFF_BufferDescriptorList = 0x00,
+
+ /**
+ * @brief Number of Actual Processed Buffer Descriptor Entry
+ * @note Length: byte
+ */
+ NABMBOFF_BufferDescriptorEntry = 0x04,
+
+ /**
+ * @brief Number of all Descriptor Entries
+ * @note Length: byte
+ */
+ NABMBOFF_DescriptorEntries = 0x05,
+
+ /**
+ * @brief Status of transferring Data
+ * @note Length: word
+ */
+ NABMBOFF_Status = 0x06,
+
+ /**
+ * @brief Number of transferred Samples in Actual Processed Entry
+ * @note Length: word
+ */
+ NABMBOFF_TransferredSamples = 0x08,
+
+ /**
+ * @brief Number of next processed Buffer Entry
+ * @note Length: byte
+ */
+ NABMBOFF_NextProcessedBufferEntry = 0x0A,
+
+ /**
+ * @brief Transfer Control
+ * @note Length: byte
+ */
+ NABMBOFF_TransferControl = 0x0B,
+};
+
+enum OutputPulseCodeModulationRegisters
+{
+ /**
+ * @brief Physical Address of Buffer Descriptor List
+ * @note Length: dword
+ */
+ PCMOUT_BufferDescriptorList = (int)NABM_PCMOutBox + (int)NABMBOFF_BufferDescriptorList,
+
+ /**
+ * @brief Number of Actual Processed Buffer Descriptor Entry
+ * @note Length: byte
+ */
+ PCMOUT_BufferDescriptorEntry = (int)NABM_PCMOutBox + (int)NABMBOFF_BufferDescriptorEntry,
+
+ /**
+ * @brief Number of all Descriptor Entries
+ * @note Length: byte
+ */
+ PCMOUT_DescriptorEntries = (int)NABM_PCMOutBox + (int)NABMBOFF_DescriptorEntries,
+
+ /**
+ * @brief Status of transferring Data
+ * @note Length: word
+ */
+ PCMOUT_Status = (int)NABM_PCMOutBox + (int)NABMBOFF_Status,
+
+ /**
+ * @brief Number of transferred Samples in Actual Processed Entry
+ * @note Length: word
+ */
+ PCMOUT_TransferredSamples = (int)NABM_PCMOutBox + (int)NABMBOFF_TransferredSamples,
+
+ /**
+ * @brief Number of next processed Buffer Entry
+ * @note Length: byte
+ */
+ PCMOUT_NextProcessedBufferEntry = (int)NABM_PCMOutBox + (int)NABMBOFF_NextProcessedBufferEntry,
+
+ /**
+ * @brief Transfer Control
+ * @note Length: byte
+ */
+ PCMOUT_TransferControl = (int)NABM_PCMOutBox + (int)NABMBOFF_TransferControl,
+};
+
+enum TransferControlRegisters
+{
+ /**
+ * @brief DMA controller control
+ *
+ * 0 = Pause transfer
+ * 1 = Transfer sound data
+ */
+ TC_DMAControllerControl = 0x01,
+
+ /**
+ * @brief Reset
+ *
+ * 0 = Remove reset condition
+ * 1 = Reset this NABM register box, this bit is cleared by card when is reset complete
+ */
+ TC_TransferReset = 0x02,
+
+ /**
+ * @brief Last Buffer Entry Interrupt enable
+ *
+ * 0 = Disable interrupt
+ * 1 = Enable interrupt
+ */
+ TC_LastBufferEntryInterruptEnable = 0x04,
+
+ /**
+ * @brief IOC Interrupt enable
+ *
+ * 0 = Disable interrupt
+ * 1 = Enable interrupt
+ */
+ TC_IOCInterruptEnable = 0x08,
+
+ /**
+ * @brief Fifo ERROR Interrupt enable
+ *
+ * 0 = Disable interrupt
+ * 1 = Enable interrupt
+ */
+ TC_FifoERRORInterruptEnable = 0x10,
+};
+
+enum GlobalControlRegisters
+{
+ /**
+ * @brief Global Interrupt Enable
+ *
+ * 0 = Disable Interrupts
+ * 1 = Enable Interrupts
+ */
+ GC_GlobalInterruptEnable = 0x01,
+
+ /**
+ * @brief Cold reset
+ *
+ * 0 = Device is in reset and can not be used
+ * 1 = Resume to operational state
+ */
+ GC_ColdReset = 0x02,
+
+ /**
+ * @brief Warm reset
+ */
+ GC_WarmReset = 0x04,
+
+ /**
+ * @brief Shut down
+ *
+ * 0 = Device is powered
+ * 1 = Shut down
+ */
+ GC_ShutDown = 0x08,
+
+ /**
+ * @brief Channels for PCM Output
+ *
+ * 00 = 2 channels
+ * 01 = 4 channels
+ * 10 = 6 channels
+ * 11 = Reserved
+ */
+ GC_ChannelsForPCMOutput = 0x30,
+
+ /**
+ * @brief PCM Output mode
+ *
+ * 00 = 16 bit samples
+ * 01 = 20 bit samples
+ */
+ GC_PCMOutputMode = 0xC0,
+};
+
+struct BufferDescriptorList
+{
+ /**
+ * @brief Physical Address to sound data in memory
+ * @note Length: dword
+ */
+ uint32_t Address;
+
+ /**
+ * @brief Number of samples in this buffer
+ * @note Length: word
+ */
+ uint16_t SampleCount;
+
+ /**
+ * @brief Flags
+ * @note Length: word
+ *
+ * Bit 15 = Interrupt fired when data from this entry is transferred
+ * Bit 14 = Last entry of buffer, stop playing
+ * Other bits = Reserved
+ */
+ uint16_t Flags;
+} __attribute__((packed));
+
+uint16_t MixerVolume(uint8_t Left, uint8_t Right, bool Mute)
+{
+ return ((uint16_t)((Right & 0x3F) |
+ ((Left & 0x3F) << 0x8) |
+ (Mute & 1 << 0xF)));
+}
+
+class AC97Device
+{
+private:
+ PCIHeader0 *Header;
+ BufferDescriptorList *DescriptorList = nullptr;
+
+ uint16_t MixerAddress;
+ uint16_t BusMasterAddress;
+
+ AudioEncodingValues Encoding = AE_PCMs16le;
+ char Channels = 2;
+ uint8_t Volume = AV_Maximum;
+ bool Mute = false;
+ int SampleRate = 48000;
+ char SampleSize = 2;
+
+public:
+ size_t write(uint8_t *Buffer, size_t Size)
+ {
+ if (Buffer == nullptr)
+ {
+ Log("Invalid buffer.");
+ return -EINVAL;
+ }
+
+ if ((Size == 0) || (Size % (SampleSize * Channels)))
+ {
+ Log("Invalid buffer length.");
+ return -EINVAL;
+ }
+
+ int TotalBDLToFill = (int)((Size + PAGE_SIZE - 1) >> 12);
+
+ while (Size > 0)
+ {
+ bool ActiveDMA = !(inw(BusMasterAddress + PCMOUT_Status) & TC_DMAControllerControl);
+
+ if (ActiveDMA)
+ {
+ int RemainingBDL = 0;
+
+ do
+ {
+ int CurrentBDL = inb(BusMasterAddress + PCMOUT_BufferDescriptorEntry);
+ int LastBDL = inb(BusMasterAddress + PCMOUT_DescriptorEntries);
+
+ RemainingBDL = LastBDL - CurrentBDL;
+ if (RemainingBDL < 0)
+ RemainingBDL += DescriptorListLength;
+
+ RemainingBDL += 1;
+
+ if (RemainingBDL >= DescriptorListLength - 1)
+ {
+ long SampleCount = DescriptorList[(CurrentBDL + 1) % DescriptorListLength].SampleCount / Channels;
+ if (SampleCount > 0)
+ Sleep(SampleCount * 1000 / SampleRate);
+ }
+
+ } while (RemainingBDL >= DescriptorListLength - 1 &&
+ !(inw(BusMasterAddress + PCMOUT_Status) & TC_DMAControllerControl));
+ }
+
+ uint8_t CurrentBDL = inb(BusMasterAddress + PCMOUT_BufferDescriptorEntry);
+ uint8_t LastBDL = inb(BusMasterAddress + PCMOUT_DescriptorEntries);
+ uint8_t NextBDL = LastBDL % DescriptorListLength;
+
+ ActiveDMA = !(inw(BusMasterAddress + PCMOUT_Status) & TC_DMAControllerControl);
+ if (ActiveDMA)
+ {
+ NextBDL = (uint8_t)((LastBDL + 1) % DescriptorListLength);
+ if (NextBDL == CurrentBDL)
+ continue;
+ }
+
+ do
+ {
+ size_t Wrote = (PAGE_SIZE > Size) ? size_t(Size)
+ : size_t(PAGE_SIZE);
+
+ if (Wrote == 0)
+ {
+ Log("Wrote 0 bytes.");
+ break;
+ }
+
+ memcpy((void *)((uint64_t)DescriptorList[NextBDL].Address), Buffer, Wrote);
+ DescriptorList[NextBDL].Flags = 0;
+
+ Buffer += Wrote;
+ Size -= (unsigned int)Wrote;
+
+ DescriptorList[NextBDL].SampleCount = uint16_t(Wrote / SampleSize);
+ TotalBDLToFill--;
+ NextBDL = (uint8_t)((NextBDL + 1) % DescriptorListLength);
+ } while (TotalBDLToFill-- && NextBDL != CurrentBDL);
+
+ outb(BusMasterAddress + PCMOUT_DescriptorEntries, NextBDL - 1);
+
+ ActiveDMA = !(inw(BusMasterAddress + PCMOUT_Status) & TC_DMAControllerControl);
+ if (!ActiveDMA)
+ {
+ // Start DMA
+ outb(BusMasterAddress + PCMOUT_TransferControl,
+ inb(BusMasterAddress + PCMOUT_TransferControl) | TC_DMAControllerControl);
+ }
+ }
+ return Size;
+ }
+
+ int ioctl(AudioIoctl, void *)
+ {
+ // if (Data->AudioCallback.Adjust._Volume)
+ // {
+ // Volume = (uint8_t)(0x3F - (0x3F * Data->AudioCallback.Adjust.Volume / 100));
+ // outw(BAR.MixerAddress + NAM_MasterVolume, MixerVolume(Volume, Volume, Mute));
+ // // outw(BAR.MixerAddress + NAM_PCMOutVolume, MixerVolume(Volume, Volume, Mute));
+ // }
+ // else if (Data->AudioCallback.Adjust._Encoding)
+ // {
+ // fixme("Encoding changing not supported yet.");
+ // }
+ // else if (Data->AudioCallback.Adjust._SampleRate)
+ // {
+ // switch (Data->AudioCallback.Adjust.SampleRate)
+ // {
+ // case 0:
+ // {
+ // SampleRate = 8000;
+ // break;
+ // }
+ // case 1:
+ // {
+ // SampleRate = 11025;
+ // break;
+ // }
+ // case 2:
+ // {
+ // SampleRate = 16000;
+ // break;
+ // }
+ // case 3:
+ // {
+ // SampleRate = 22050;
+ // break;
+ // }
+ // case 4:
+ // {
+ // SampleRate = 32000;
+ // break;
+ // }
+ // case 5:
+ // {
+ // SampleRate = 44100;
+ // break;
+ // }
+ // case 6:
+ // {
+ // SampleRate = 48000;
+ // break;
+ // }
+ // case 7:
+ // {
+ // SampleRate = 88200;
+ // break;
+ // }
+ // case 8:
+ // {
+ // SampleRate = 96000;
+ // break;
+ // }
+ // default:
+ // {
+ // SampleRate = 16000;
+ // error("Invalid sample rate. Defaulting to 16000.");
+ // break;
+ // }
+ // }
+ // }
+ // else if (Data->AudioCallback.Adjust._Channels)
+ // {
+ // switch (Data->AudioCallback.Adjust.Channels)
+ // {
+ // case 0:
+ // {
+ // Channels = 1; // Mono
+ // break;
+ // }
+ // case 1:
+ // {
+ // Channels = 2; // Stereo
+ // break;
+ // }
+ // default:
+ // {
+ // Channels = 2;
+ // error("Invalid channel count. Defaulting to 2.");
+ // break;
+ // }
+ // }
+ // }
+ return 0;
+ }
+
+ void OnInterruptReceived(TrapFrame *)
+ {
+ uint16_t Status = inw(MixerAddress + PCMOUT_Status);
+ if (Status & TC_IOCInterruptEnable)
+ {
+ DebugLog("IOC");
+ outw(MixerAddress + PCMOUT_Status, TC_IOCInterruptEnable);
+ uint16_t CurrentBDL = inb(BusMasterAddress + PCMOUT_BufferDescriptorEntry);
+ uint16_t LastBDL = (CurrentBDL + 2) & (DescriptorListLength - 1);
+ outb(BusMasterAddress + PCMOUT_DescriptorEntries, LastBDL);
+ Log("FIXME: CurrentBDL: %d, LastBDL: %d", CurrentBDL, LastBDL);
+ }
+ else if (Status & TC_LastBufferEntryInterruptEnable)
+ {
+ DebugLog("Last buffer entry");
+ // Stop DMA
+ uint8_t TransferControl = inb((uint16_t)(BusMasterAddress + PCMOUT_TransferControl));
+ TransferControl &= ~TC_DMAControllerControl;
+ outb((uint16_t)(BusMasterAddress + PCMOUT_TransferControl), TransferControl);
+
+ outw(MixerAddress + PCMOUT_Status, TC_LastBufferEntryInterruptEnable);
+ }
+ else if (Status & TC_FifoERRORInterruptEnable)
+ {
+ Log("FIFO error");
+ outw(MixerAddress + PCMOUT_Status, TC_FifoERRORInterruptEnable);
+ }
+ else
+ {
+ DebugLog("Unknown interrupt status %#x", Status);
+ outw(MixerAddress + PCMOUT_Status, 0xFFFF);
+ }
+ }
+
+ void Panic()
+ {
+ uint8_t TransferControl = inb((uint16_t)(BusMasterAddress + PCMOUT_TransferControl));
+ TransferControl &= ~(TC_LastBufferEntryInterruptEnable |
+ TC_IOCInterruptEnable |
+ TC_FifoERRORInterruptEnable);
+ outb((uint16_t)(BusMasterAddress + PCMOUT_TransferControl), TransferControl);
+
+ uint32_t GlobalControl = inl((uint16_t)(BusMasterAddress + NABM_GlobalControl));
+ GlobalControl &= ~GC_GlobalInterruptEnable;
+ GlobalControl |= GC_ShutDown;
+ outl((uint16_t)(BusMasterAddress + NABM_GlobalControl), GlobalControl);
+ }
+
+ AC97Device(PCIHeader0 *_Header)
+ : Header(_Header)
+ {
+ /* Native Audio Mixer Base Address */
+ uint32_t PCIBAR0 = Header->BAR0;
+
+ /* Native Audio Bus Master Base Address */
+ uint32_t PCIBAR1 = Header->BAR1;
+
+ // uint8_t Type = PCIBAR0 & 1;
+ MixerAddress = (uint16_t)(PCIBAR0 & (~3));
+ BusMasterAddress = PCIBAR1 & (~15);
+
+ uint16_t OutputPCMTransferControl = BusMasterAddress + PCMOUT_TransferControl;
+
+ /* DescriptorList address MUST be physical. */
+ DescriptorList = (BufferDescriptorList *)AllocateMemory(TO_PAGES(sizeof(BufferDescriptorList) * DescriptorListLength));
+ memset(DescriptorList, 0, sizeof(BufferDescriptorList) * DescriptorListLength);
+
+ uint16_t DLSampleCount = (uint16_t)(PAGE_SIZE / SampleSize);
+ for (int i = 0; i < DescriptorListLength; i++)
+ {
+ DescriptorList[i].Address = (uint32_t)(uintptr_t)AllocateMemory(TO_PAGES(sizeof(uint16_t *)));
+ DescriptorList[i].SampleCount = DLSampleCount;
+ DescriptorList[i].Flags = 0;
+ DebugLog("DescriptorList[%d] = { Address: %#lx, SampleCount: %d, Flags: %#lx }",
+ i,
+ DescriptorList[i].Address,
+ DescriptorList[i].SampleCount,
+ DescriptorList[i].Flags);
+ }
+
+ outw(MixerAddress + NAM_MasterVolume, MixerVolume(Volume, Volume, Mute));
+ outw(MixerAddress + NAM_PCMOutVolume, MixerVolume(Volume, Volume, Mute));
+
+ Volume = 0x3F - (0x3F * /* VOL 50% */ 50 / 100);
+ outw(MixerAddress + NAM_MasterVolume, MixerVolume(Volume, Volume, Mute));
+
+ outb(OutputPCMTransferControl, inb(OutputPCMTransferControl) | TC_TransferReset);
+ while (inb(OutputPCMTransferControl) & TC_TransferReset)
+ ;
+
+ uint32_t GlobalControl = inl(BusMasterAddress + NABM_GlobalControl);
+ GlobalControl = (GlobalControl & ~((0x3U) << 0x16)); /* PCM 16-bit mode */
+ GlobalControl = (GlobalControl & ~((0x3U) << 20)); /* 2 channels */
+ GlobalControl |= GC_GlobalInterruptEnable;
+ GlobalControl &= ~GC_ShutDown;
+
+ outl(BusMasterAddress + PCMOUT_BufferDescriptorList,
+ (uint32_t)(uint64_t)DescriptorList);
+
+ outl(BusMasterAddress + NABM_GlobalControl, GlobalControl);
+
+ uint8_t TransferControl = inb(OutputPCMTransferControl);
+ TransferControl |= TC_IOCInterruptEnable |
+ TC_FifoERRORInterruptEnable;
+ outb(OutputPCMTransferControl, TransferControl);
+
+ // Stop DMA
+ outb(OutputPCMTransferControl, inb(OutputPCMTransferControl) & ~TC_DMAControllerControl);
+ }
+
+ ~AC97Device()
+ {
+ outw(MixerAddress + NAM_MasterVolume, MixerVolume(AV_Maximum, AV_Maximum, true));
+ outw(MixerAddress + NAM_PCMOutVolume, MixerVolume(AV_Maximum, AV_Maximum, true));
+
+ // Stop DMA
+ outb((uint16_t)(BusMasterAddress + PCMOUT_TransferControl),
+ inb((uint16_t)(BusMasterAddress + PCMOUT_TransferControl)) & ~TC_DMAControllerControl);
+
+ // Disable interrupts
+ uint8_t TransferControl = inb((uint16_t)(BusMasterAddress + PCMOUT_TransferControl));
+
+ TransferControl &= ~(TC_LastBufferEntryInterruptEnable |
+ TC_IOCInterruptEnable |
+ TC_FifoERRORInterruptEnable);
+ outb((uint16_t)(BusMasterAddress + PCMOUT_TransferControl), TransferControl);
+
+ // Disable global control
+ uint32_t GlobalControl = inl((uint16_t)(BusMasterAddress + NABM_GlobalControl));
+ GlobalControl &= ~GC_GlobalInterruptEnable;
+ GlobalControl |= GC_ShutDown;
+ outl((uint16_t)(BusMasterAddress + NABM_GlobalControl), GlobalControl);
+ }
+};
+
+AC97Device *Drivers[4] = {nullptr};
+dev_t AudioID[4] = {0};
+
+#define OIR(x) OIR_##x
+#define CREATE_OIR(x) \
+ void OIR_##x(TrapFrame *f) { Drivers[x]->OnInterruptReceived(f); }
+
+CREATE_OIR(0);
+CREATE_OIR(1);
+CREATE_OIR(2);
+CREATE_OIR(3);
+
+int drvOpen(dev_t, dev_t, int, mode_t) { return 0; }
+int drvClose(dev_t, dev_t) { return 0; }
+size_t drvRead(dev_t, dev_t, uint8_t *, size_t, off_t) { return 0; }
+
+size_t drvWrite(dev_t, dev_t min, uint8_t *Buffer, size_t Size, off_t)
+{
+ return Drivers[AudioID[min]]->write(Buffer, Size);
+}
+
+int drvIoctl(dev_t, dev_t min, unsigned long Request, void *Argp)
+{
+ return Drivers[AudioID[min]]->ioctl((AudioIoctl)Request, Argp);
+}
+
+PCIArray *Devices;
+EXTERNC int cxx_Panic()
+{
+ PCIArray *ctx = Devices;
+ short Count = 0;
+ while (ctx != nullptr)
+ {
+ if (Drivers[Count] != nullptr)
+ Drivers[Count]->Panic();
+ Count++;
+ ctx = (PCIArray *)ctx->Next;
+ }
+
+ return 0;
+}
+
+EXTERNC int cxx_Probe()
+{
+ uint16_t VendorIDs[] = {0x8086, PCI_END};
+ uint16_t DeviceIDs[] = {0x2415, PCI_END};
+ Devices = FindPCIDevices(VendorIDs, DeviceIDs);
+ if (Devices == nullptr)
+ {
+ Log("No AC'97 device found.");
+ return -ENODEV;
+ }
+
+ PCIArray *ctx = Devices;
+ bool Found = false;
+ size_t Count = 0;
+ while (ctx != nullptr)
+ {
+ if (Count++ > sizeof(Drivers) / sizeof(AC97Device *))
+ break;
+
+ PCIHeader0 *PCIBaseAddress = (PCIHeader0 *)ctx->Device->Header;
+ uint32_t PCIBAR0 = PCIBaseAddress->BAR0;
+ uint8_t Type = PCIBAR0 & 1;
+ if (Type != 1)
+ {
+ Log("Device %x:%x.%d BAR0 is not I/O.",
+ PCIBaseAddress->Header.VendorID,
+ PCIBaseAddress->Header.DeviceID,
+ PCIBaseAddress->Header.ProgIF);
+ continue;
+ }
+
+ Found = true;
+ ctx = (PCIArray *)ctx->Next;
+ }
+
+ if (!Found)
+ {
+ Log("No valid AC'97 device found.");
+ return -EINVAL;
+ }
+ return 0;
+}
+
+EXTERNC int cxx_Initialize()
+{
+ PCIArray *ctx = Devices;
+ size_t Count = 0;
+ while (ctx != nullptr)
+ {
+ if (Count > sizeof(Drivers) / sizeof(AC97Device *))
+ break;
+
+ PCIHeader0 *PCIBaseAddress = (PCIHeader0 *)ctx->Device->Header;
+ uint32_t PCIBAR0 = PCIBaseAddress->BAR0;
+ uint8_t Type = PCIBAR0 & 1;
+ if (Type != 1)
+ {
+ Log("Device %x:%x.%d BAR0 is not I/O.",
+ PCIBaseAddress->Header.VendorID,
+ PCIBaseAddress->Header.DeviceID,
+ PCIBaseAddress->Header.ProgIF);
+ continue;
+ }
+
+ InitializePCI(ctx->Device);
+
+ Drivers[Count] = new AC97Device((PCIHeader0 *)ctx->Device->Header);
+ /* FIXME: bad code */
+ switch (Count)
+ {
+ case 0:
+ RegisterInterruptHandler(iLine(ctx->Device), (void *)OIR(0));
+ break;
+ case 1:
+ RegisterInterruptHandler(iLine(ctx->Device), (void *)OIR(1));
+ break;
+ case 2:
+ RegisterInterruptHandler(iLine(ctx->Device), (void *)OIR(2));
+ break;
+ case 3:
+ RegisterInterruptHandler(iLine(ctx->Device), (void *)OIR(3));
+ break;
+ default:
+ break;
+ }
+ dev_t ret = RegisterAudioDevice(ddt_Audio,
+ drvOpen, drvClose,
+ drvRead, drvWrite,
+ drvIoctl);
+ AudioID[Count] = ret;
+ Count++;
+ ctx = (PCIArray *)ctx->Next;
+ }
+
+ return 0;
+}
+
+EXTERNC int cxx_Finalize()
+{
+ PCIArray *ctx = Devices;
+ size_t Count = 0;
+ while (ctx != nullptr)
+ {
+ if (Count++ > sizeof(Drivers) / sizeof(AC97Device *))
+ break;
+
+ PCIHeader0 *PCIBaseAddress = (PCIHeader0 *)ctx->Device->Header;
+ uint32_t PCIBAR0 = PCIBaseAddress->BAR0;
+ uint8_t Type = PCIBAR0 & 1;
+ if (Type != 1)
+ {
+ Log("Device %x:%x.%d BAR0 is not I/O.",
+ PCIBaseAddress->Header.VendorID,
+ PCIBaseAddress->Header.DeviceID,
+ PCIBaseAddress->Header.ProgIF);
+ continue;
+ }
+
+ delete Drivers[Count++];
+ ctx->Device->Header->Command |= PCI_COMMAND_INTX_DISABLE;
+ ctx = (PCIArray *)ctx->Next;
+ }
+
+ return 0;
+}
diff --git a/audio/ac97/ac97.hpp b/audio/ac97/ac97.hpp
new file mode 100644
index 0000000..99242b9
--- /dev/null
+++ b/audio/ac97/ac97.hpp
@@ -0,0 +1,25 @@
+/*
+ This file is part of Fennix Drivers.
+
+ Fennix Drivers is free software: you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation, either version 3 of
+ the License, or (at your option) any later version.
+
+ Fennix Drivers is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Fennix Drivers. If not, see .
+*/
+
+#pragma once
+
+#include
+
+EXTERNC int cxx_Panic();
+EXTERNC int cxx_Probe();
+EXTERNC int cxx_Initialize();
+EXTERNC int cxx_Finalize();
diff --git a/audio/ac97/main.c b/audio/ac97/main.c
new file mode 100644
index 0000000..bfb84d5
--- /dev/null
+++ b/audio/ac97/main.c
@@ -0,0 +1,31 @@
+/*
+ This file is part of Fennix Drivers.
+
+ Fennix Drivers is free software: you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation, either version 3 of
+ the License, or (at your option) any later version.
+
+ Fennix Drivers is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Fennix Drivers. If not, see .
+*/
+
+#include
+
+#include "ac97.hpp"
+
+int DriverEntry() { return cxx_Initialize(); }
+int DriverFinal() { return cxx_Finalize(); }
+int DriverPanic() { return cxx_Panic(); }
+int DriverProbe() { return cxx_Probe(); }
+
+DriverInfo("ac97",
+ "Audio Codec '97 Driver",
+ "EnderIce2",
+ "0.1",
+ "GPLv3");
diff --git a/audio/hda/Makefile b/audio/hda/Makefile
new file mode 100644
index 0000000..ade5826
--- /dev/null
+++ b/audio/hda/Makefile
@@ -0,0 +1,83 @@
+# Config file
+include ../../../Makefile.conf
+
+FILENAME = hda.drv
+
+CC = ../../../$(COMPILER_PATH)/$(COMPILER_ARCH)gcc
+CPP = ../../../$(COMPILER_PATH)/$(COMPILER_ARCH)g++
+LD = ../../../$(COMPILER_PATH)/$(COMPILER_ARCH)ld
+AS = ../../../$(COMPILER_PATH)/$(COMPILER_ARCH)as
+OBJDUMP = ../../../$(COMPILER_PATH)/$(COMPILER_ARCH)objdump
+
+S_SOURCES = $(shell find ./ -type f -name '*.S')
+C_SOURCES = $(shell find ./ -type f -name '*.c')
+CPP_SOURCES = $(shell find ./ -type f -name '*.cpp')
+HEADERS = $(sort $(dir $(wildcard ../../include/*)))
+OBJ = $(C_SOURCES:.c=.o) $(CPP_SOURCES:.cpp=.o) $(ASM_SOURCES:.asm=.o) $(S_SOURCES:.S=.o) $(PSF_SOURCES:.psf=.o) $(BMP_SOURCES:.bmp=.o)
+STACK_USAGE_OBJ = $(C_SOURCES:.c=.su) $(CPP_SOURCES:.cpp=.su)
+INCLUDE_DIR = ../../include
+
+LIBS := ../../out/dcrt0.o -L../../out -ldriver
+
+LDFLAGS := \
+ -fPIC -fPIE -pie \
+ -Wl,--no-dynamic-linker,-ztext,--no-warn-rwx-segment \
+ -nostdlib -nodefaultlibs -nolibc \
+ -zmax-page-size=0x1000 \
+ -Wl,-Map file.map -shared -fvisibility=hidden
+
+WARNCFLAG = -Wall -Wextra
+
+CFLAGS := -I$(INCLUDE_DIR) -fvisibility=hidden
+
+ifeq ($(OSARCH), amd64)
+
+CFLAGS += -fPIC -fPIE -pie -mno-80387 -mno-mmx -mno-3dnow \
+ -mno-red-zone -mno-sse -mno-sse2 \
+ -march=x86-64 -pipe -ffunction-sections \
+ -msoft-float -fno-builtin
+
+else ifeq ($(OSARCH), i386)
+
+CFLAGS += -fPIC -fPIE -pie -mno-80387 -mno-mmx -mno-3dnow \
+ -mno-red-zone -mno-sse -mno-sse2 -ffunction-sections \
+ -march=i386 -pipe -msoft-float -fno-builtin
+
+else ifeq ($(OSARCH), aarch64)
+
+CFLAGS += -pipe -fno-builtin -fPIC
+
+endif
+
+ifeq ($(DEBUG), 1)
+ CFLAGS += -DDEBUG -ggdb3 -O0 -fdiagnostics-color=always -fstack-usage
+ifeq ($(OSARCH), amd64)
+ CFLAGS += -fverbose-asm
+endif
+ifneq ($(OSARCH), aarch64)
+ CFLAGS += -fstack-check
+endif
+ LDFLAGS += -ggdb3 -O0
+endif
+
+build: $(FILENAME)
+ mv $(FILENAME) ../../out/$(FILENAME)
+
+$(FILENAME): $(OBJ)
+ $(info Linking $@)
+ $(CC) $(LDFLAGS) $(OBJ) $(LIBS) -o $@
+
+%.o: %.c $(HEADERS)
+ $(info Compiling $<)
+ $(CC) $(CFLAGS) $(WARNCFLAG) -std=c17 -c $< -o $@
+
+%.o: %.cpp $(HEADERS)
+ $(info Compiling $<)
+ $(CPP) $(CFLAGS) $(WARNCFLAG) -std=c++20 -fno-exceptions -fno-rtti -c $< -o $@
+
+%.o: %.S
+ $(info Compiling $<)
+ $(AS) -o $@ $<
+
+clean:
+ rm -f file.map $(OBJ) $(STACK_USAGE_OBJ)
diff --git a/audio/hda/hda.cpp b/audio/hda/hda.cpp
new file mode 100644
index 0000000..40303de
--- /dev/null
+++ b/audio/hda/hda.cpp
@@ -0,0 +1,239 @@
+/*
+ This file is part of Fennix Kernel.
+
+ Fennix Kernel is free software: you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation, either version 3 of
+ the License, or (at your option) any later version.
+
+ Fennix Kernel is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Fennix Kernel. If not, see .
+*/
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "hda.hpp"
+
+class HDADevice
+{
+private:
+ PCIHeader0 *Header;
+ bool Initialized = false;
+
+ ControllerRegisters *CTL;
+
+ uint32_t *CORB;
+ uint64_t *RIRB;
+
+public:
+ bool IsInitialized() { return Initialized; }
+
+ size_t write(uint8_t *, size_t Size)
+ {
+ return Size;
+ }
+
+ int ioctl(AudioIoctl, void *)
+ {
+ return 0;
+ }
+
+ void OnInterruptReceived(TrapFrame *)
+ {
+ }
+
+ void Panic()
+ {
+ }
+
+ HDADevice(PCIHeader0 *_Header)
+ : Header(_Header),
+ CORB((uint32_t *)(uintptr_t)AllocateMemory(1)),
+ RIRB((uint64_t *)AllocateMemory(1))
+ {
+ CTL = (ControllerRegisters *)(uintptr_t)Header->BAR0;
+ Log("Unimplemented HDA driver");
+ return;
+ Initialized = true;
+ }
+
+ ~HDADevice()
+ {
+ if (!Initialized)
+ return;
+ }
+};
+
+HDADevice *Drivers[4] = {nullptr};
+dev_t AudioID[4] = {0};
+
+#define OIR(x) OIR_##x
+#define CREATE_OIR(x) \
+ void OIR_##x(TrapFrame *f) { Drivers[x]->OnInterruptReceived(f); }
+
+CREATE_OIR(0);
+CREATE_OIR(1);
+CREATE_OIR(2);
+CREATE_OIR(3);
+
+int drvOpen(dev_t, dev_t, int, mode_t) { return 0; }
+int drvClose(dev_t, dev_t) { return 0; }
+size_t drvRead(dev_t, dev_t, uint8_t *, size_t, off_t) { return 0; }
+
+size_t drvWrite(dev_t, dev_t min, uint8_t *Buffer, size_t Size, off_t)
+{
+ return Drivers[AudioID[min]]->write(Buffer, Size);
+}
+
+int drvIoctl(dev_t, dev_t min, unsigned long Request, void *Argp)
+{
+ return Drivers[AudioID[min]]->ioctl((AudioIoctl)Request, Argp);
+}
+
+PCIArray *Devices;
+EXTERNC int cxx_Panic()
+{
+ PCIArray *ctx = Devices;
+ short Count = 0;
+ while (ctx != nullptr)
+ {
+ if (Drivers[Count] != nullptr)
+ Drivers[Count]->Panic();
+ Count++;
+ ctx = (PCIArray *)ctx->Next;
+ }
+
+ return 0;
+}
+
+EXTERNC int cxx_Probe()
+{
+ uint16_t VendorIDs[] = {0x8086, /* Intel */
+ 0x15AD, /* VMware */
+ PCI_END};
+ uint16_t DeviceIDs[] = {0x9D71 /* Sunrise Point-LP HD Audio */,
+ 0x2668 /* ICH6 */,
+ 0x293E /* ICH9 */,
+ PCI_END};
+ Devices = FindPCIDevices(VendorIDs, DeviceIDs);
+ if (Devices == nullptr)
+ {
+ Log("No HDA device found.");
+ return -ENODEV;
+ }
+
+ PCIArray *ctx = Devices;
+ bool Found = false;
+ size_t Count = 0;
+ while (ctx != nullptr)
+ {
+ if (Count++ > sizeof(Drivers) / sizeof(HDADevice *))
+ break;
+
+ PCIHeader0 *PCIBaseAddress = (PCIHeader0 *)ctx->Device->Header;
+ uint32_t PCIBAR0 = PCIBaseAddress->BAR0;
+ uint8_t Type = PCIBAR0 & 1;
+ if (Type == 1)
+ {
+ Log("Device %x:%x.%d BAR0 is I/O.",
+ PCIBaseAddress->Header.VendorID,
+ PCIBaseAddress->Header.DeviceID,
+ PCIBaseAddress->Header.ProgIF);
+ continue;
+ }
+
+ Found = true;
+ ctx = (PCIArray *)ctx->Next;
+ }
+
+ if (!Found)
+ {
+ Log("No valid HDA device found.");
+ return -EINVAL;
+ }
+ return 0;
+}
+
+EXTERNC int cxx_Initialize()
+{
+ PCIArray *ctx = Devices;
+ size_t Count = 0;
+ while (ctx != nullptr)
+ {
+ if (Count > sizeof(Drivers) / sizeof(HDADevice *))
+ break;
+
+ PCIHeader0 *PCIBaseAddress = (PCIHeader0 *)ctx->Device->Header;
+ uint32_t PCIBAR0 = PCIBaseAddress->BAR0;
+ uint8_t Type = PCIBAR0 & 1;
+ if (Type == 1)
+ {
+ Log("Device %x:%x.%d BAR0 is I/O.",
+ PCIBaseAddress->Header.VendorID,
+ PCIBaseAddress->Header.DeviceID,
+ PCIBaseAddress->Header.ProgIF);
+ continue;
+ }
+
+ InitializePCI(ctx->Device);
+
+ Drivers[Count] = new HDADevice((PCIHeader0 *)ctx->Device->Header);
+
+ if (Drivers[Count]->IsInitialized())
+ {
+ dev_t ret = RegisterAudioDevice(ddt_Audio,
+ drvOpen, drvClose,
+ drvRead, drvWrite,
+ drvIoctl);
+ AudioID[Count] = ret;
+ Count++;
+ }
+ ctx = (PCIArray *)ctx->Next;
+ }
+
+ if (Count == 0)
+ {
+ Log("No valid HDA device found.");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+EXTERNC int cxx_Finalize()
+{
+ PCIArray *ctx = Devices;
+ size_t Count = 0;
+ while (ctx != nullptr)
+ {
+ if (Count++ > sizeof(Drivers) / sizeof(HDADevice *))
+ break;
+
+ PCIHeader0 *PCIBaseAddress = (PCIHeader0 *)ctx->Device->Header;
+ uint32_t PCIBAR0 = PCIBaseAddress->BAR0;
+ uint8_t Type = PCIBAR0 & 1;
+ if (Type == 1)
+ {
+ Log("Device %x:%x.%d BAR0 is I/O.",
+ PCIBaseAddress->Header.VendorID,
+ PCIBaseAddress->Header.DeviceID,
+ PCIBaseAddress->Header.ProgIF);
+ continue;
+ }
+
+ delete Drivers[Count++];
+ ctx = (PCIArray *)ctx->Next;
+ }
+
+ return 0;
+}
diff --git a/audio/hda/hda.hpp b/audio/hda/hda.hpp
new file mode 100644
index 0000000..d1587c5
--- /dev/null
+++ b/audio/hda/hda.hpp
@@ -0,0 +1,635 @@
+/*
+ This file is part of Fennix Drivers.
+
+ Fennix Drivers is free software: you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation, either version 3 of
+ the License, or (at your option) any later version.
+
+ Fennix Drivers is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Fennix Drivers. If not, see .
+*/
+
+#pragma once
+
+#include
+
+#ifdef __cplusplus
+
+struct StreamDescriptor
+{
+ /** Control */
+ uint32_t CTL : 24;
+
+ /** Status */
+ uint8_t STS;
+
+ /** Link Position in Current Buffer */
+ uint32_t LPIB;
+
+ /** Cyclic Buffer Length */
+ uint32_t CBL;
+
+ /** Last Valid Index */
+ uint16_t LVI;
+
+ /** Reserved */
+ uint8_t Rsvd0[2];
+
+ /** FIFO Size */
+ uint16_t FIFOD;
+
+ /** Format */
+ uint16_t FMT;
+
+ /** Reserved */
+ uint8_t Rsvd1[4];
+
+ /** Buffer Descriptor List Pointer - Lower */
+ uint32_t BDPL;
+
+ /** Buffer Descriptor List Pointer - Upper */
+ uint32_t BDPU;
+} __attribute__((packed));
+
+struct ControllerRegisters
+{
+ uint16_t GCAP;
+ uint8_t VMIN;
+ uint8_t VMJ;
+ uint16_t OUTPAY;
+ uint16_t INPAY;
+ uint32_t GCTL;
+ uint16_t WAKEEN;
+ uint16_t WAKESTS;
+ uint16_t GSTS;
+ uint8_t Rsvd0[6];
+ uint16_t OUTSTRMPAY;
+ uint16_t INSTRMPAY;
+ uint8_t Rsvd1[4];
+ uint32_t INTCTL;
+ uint32_t INTSTS;
+ uint8_t Rsvd2[8];
+ uint32_t WALCLK;
+ uint8_t Rsvd3[4];
+ uint32_t SSYNC;
+ uint8_t Rsvd4[4];
+ uint32_t CORBLBASE;
+ uint32_t CORBUBASE;
+ uint16_t CORBWP;
+ uint16_t CORBRP;
+ uint8_t CORBCTL;
+ uint8_t CORBSTS;
+ uint8_t CORBSIZE;
+ uint8_t Rsvd5;
+ uint32_t RIRBLBASE;
+ uint32_t RIRBUBASE;
+ uint16_t RIRBWP;
+ uint16_t RINTCNT;
+ uint8_t RIRBCTL;
+ uint8_t RIRBSTS;
+ uint8_t RIRBSIZE;
+ uint8_t Rsvd6;
+ uint32_t ICOI;
+ uint32_t ICII;
+ uint16_t ICIS;
+ uint8_t Rsvd7[6];
+ uint32_t DPIBLBASE;
+ uint32_t DPIBUBASE;
+ uint8_t Rsvd8[8];
+ StreamDescriptor SD[];
+} __attribute__((packed));
+
+/* Not working as expected */
+struct __ControllerRegisters
+{
+ /** Global Capabilities */
+ union
+ {
+ struct
+ {
+ /** 64 Bit Address Supported
+ *
+ * 0 = 32-bit addressing
+ * 1 = 64-bit addressing
+ */
+ uint16_t _64OK : 1;
+
+ /** Number of Serial Data Out Signals
+ *
+ * 00 = 1 SDO
+ * 01 = 2 SDOs
+ * 10 = 4 SDOs
+ * 11 = Reserved
+ */
+ uint16_t NSDO : 2;
+
+ /** Number of Bidirectional Streams Supported
+ *
+ * 00000b = No bidirectional streams supported
+ * 00001b = 1 bidirectional stream supported
+ * ...
+ * 11110b = 30 bidirectional streams supported
+ */
+ uint16_t BSS : 5;
+
+ /** Number of Input Streams Supported
+ *
+ * 0000b = No input streams supported
+ * 0001b = 1 input stream supported
+ * ...
+ * 1111b = 15 input streams supported
+ */
+ uint16_t ISS : 4;
+
+ /** Number of Output Streams Supported
+ *
+ * 0000b = No output streams supported
+ * 0001b = 1 output stream supported
+ * ...
+ * 1111b = 15 output streams supported
+ */
+ uint16_t OSS : 4;
+ } __attribute__((packed));
+ uint16_t Raw;
+ } GCAP;
+
+ /** Minor Version */
+ uint8_t VMIN;
+
+ /** Major Version */
+ uint8_t VMJ;
+
+ /** Output Payload Capability
+ *
+ * 00h = 0 Words
+ * 01h = 1 Word payload
+ * ...
+ * FFh = 255h Word payload
+ */
+ uint16_t OUTPAY;
+
+ /** Input Payload Capability
+ *
+ * 00h = 0 Words
+ * 01h = 1 Word payload
+ * ...
+ * FFh = 255h Word payload
+ */
+ uint16_t INPAY;
+
+ /** Global Control */
+ union
+ {
+ struct
+ {
+ /** Controller Reset
+ *
+ * 0 = Reset
+ * 1 = Normal Operation
+ */
+ uint32_t CRST : 1;
+
+ /** Flush Control
+ *
+ * 0 = Idle
+ * 1 = Flush
+ */
+ uint32_t FCNTRL : 1;
+
+ /** Reserved */
+ uint32_t RsvdP0 : 6;
+
+ /** Accept Unsolicited Response Enable
+ *
+ * 0 = Disabled
+ * 1 = Enabled
+ */
+ uint32_t UNSOL : 1;
+
+ /** Reserved */
+ uint32_t RsvdP1 : 23;
+ } __attribute__((packed));
+ uint32_t Raw;
+ } GCTL;
+
+ /** Wake Enable */
+ union
+ {
+ struct
+ {
+ /** SDIN Wake Enable Flags */
+ uint16_t SDIWEN : 15;
+
+ /** Reserved */
+ uint16_t RsvdP0 : 1;
+ } __attribute__((packed));
+ uint16_t Raw;
+ } WAKEEN;
+
+ /** Wake Status */
+ union
+ {
+ struct
+ {
+ /** SDIN State Change Status Flags */
+ uint16_t SDIWAKE : 15;
+
+ /** Reserved */
+ uint16_t RsvdZ0 : 1;
+ } __attribute__((packed));
+ uint16_t Raw;
+ } WAKESTS;
+
+ /** Global Status */
+ union
+ {
+ struct
+ {
+ uint16_t RsvdZ0 : 1;
+ uint16_t FSTS : 1;
+ uint16_t RsvdZ1 : 14;
+ } __attribute__((packed));
+ uint16_t Raw;
+ } GSTS;
+
+ /** Reserved */
+ uint8_t Rsvd0[6];
+
+ /** Output Stream Payload Capability */
+ uint16_t OUTSTRMPAY;
+
+ /** Input Stream Payload Capability */
+ uint16_t INSTRMPAY;
+
+ /** Reserved */
+ uint8_t Rsvd1[4];
+
+ /** Interrupt Control */
+ union
+ {
+ struct
+ {
+ /** Stream Interrupt Enable
+ *
+ * Bit 0 = Input Stream 0
+ * Bit 1 = Input Stream 1
+ * Bit 2 = Output Stream 0
+ * Bit 3 = Output Stream 1
+ * Bit 4 = Output Stream 2
+ * Bit 5 = Bidirectional Stream 0
+ * Bits 6-28 = Reserved
+ */
+ uint32_t SIE : 30;
+
+ /** Controller Interrupt Enable */
+ uint32_t CIE : 1;
+
+ /** Global Interrupt Enable */
+ uint32_t GIE : 1;
+ } __attribute__((packed));
+ uint32_t Raw;
+ } INTCTL;
+
+ /** Interrupt Status */
+ union
+ {
+ struct
+ {
+ /** Stream Interrupt Status */
+ uint32_t SIS : 30;
+
+ /** Controller Interrupt Status */
+ uint32_t CIS : 1;
+
+ /** Global Interrupt Status */
+ uint32_t GIS : 1;
+ } __attribute__((packed));
+ uint32_t Raw;
+ } INTSTS;
+
+ /** Reserved */
+ uint8_t Rsvd2[8];
+
+ /** Wall Clock Counter */
+ uint32_t WALCLK;
+
+ /** Reserved */
+ uint8_t Rsvd3[4];
+
+ /** Stream Synchronization */
+ union
+ {
+ struct
+ {
+ /** Stream Synchronization Bits */
+ uint32_t SSYNC : 30;
+
+ /** Reserved */
+ uint32_t RsvdP0 : 2;
+ } __attribute__((packed));
+ uint32_t Raw;
+ } SSYNC;
+
+ /** Reserved */
+ uint8_t Rsvd4[4];
+
+ /** CORB Lower Base Address */
+ union
+ {
+ struct
+ {
+ /** CORB Lower Base Unimplemented Bits */
+ uint32_t Unimplemented : 7;
+
+ /** CORB Lower Base Address */
+ uint32_t CORBLBASE : 25;
+ } __attribute__((packed));
+ uint32_t Raw;
+ } CORBLBASE;
+
+ /** CORB Upper Base Address */
+ uint32_t CORBUBASE;
+
+ /** CORB Write Pointer */
+ union
+ {
+ struct
+ {
+ /** CORB Write Pointer */
+ uint16_t CORBWP : 8;
+
+ /** Reserved */
+ uint16_t RsvdP0 : 8;
+ } __attribute__((packed));
+ uint16_t Raw;
+ } CORBWP;
+
+ /** CORB Read Pointer */
+ union
+ {
+ struct
+ {
+ /** CORB Read Pointer */
+ uint16_t CORBRP : 8;
+
+ /** Reserved */
+ uint16_t RsvdP0 : 7;
+
+ /** CORB Read Pointer Reset */
+ uint16_t CORBRPRST : 1;
+ } __attribute__((packed));
+ uint16_t Raw;
+ } CORBRP;
+
+ /** CORB Control */
+ union
+ {
+ struct
+ {
+ /** CORB Memory Error Interrupt Enable */
+ uint8_t CMEIE : 1;
+
+ /** Enable CORB DMA Engine
+ *
+ * 0 = DMA Stop
+ * 1 = DMA Run
+ *
+ * @note Must read the value back.
+ */
+ uint8_t CORBRUN : 1;
+
+ /** Reserved */
+ uint8_t RsvdP0 : 6;
+ } __attribute__((packed));
+ uint8_t Raw;
+ } CORBCTL;
+
+ /** CORB Status */
+ union
+ {
+ struct
+ {
+ /** CORB Memory Error Indication */
+ uint8_t CMEI : 1;
+
+ /** Reserved */
+ uint8_t RsvdZ0 : 7;
+ } __attribute__((packed));
+ uint8_t Raw;
+ } CORBSTS;
+
+ /** CORB Size */
+ union
+ {
+ struct
+ {
+ /** CORB Size
+ *
+ * 00b = 2 entries
+ * 01b = 16 entries
+ * 10b = 256 entries
+ * 11b = Reserved
+ */
+ uint8_t CORBSIZE : 2;
+
+ /** Reserved */
+ uint8_t RsvdP0 : 2;
+
+ /** CORB Size Capability
+ *
+ * 0001b = 2 entries
+ * 0010b = 16 entries
+ * 0100b = 256 entries
+ * 1000b = Reserved
+ */
+ uint8_t CORBSZCAP : 4;
+ } __attribute__((packed));
+ uint8_t Raw;
+ } CORBSIZE;
+
+ /** Reserved */
+ uint8_t Rsvd5;
+
+ /** RIRB Lower Base Address */
+ union
+ {
+ struct
+ {
+ /** RIRB Lower Base Unimplemented Bits */
+ uint32_t Unimplemented : 7;
+
+ /** RIRB Lower Base Address */
+ uint32_t RIRBLBASE : 25;
+ } __attribute__((packed));
+ uint32_t Raw;
+ } RIRBLBASE;
+
+ /** RIRB Upper Base Address */
+ uint32_t RIRBUBASE;
+
+ /** RIRB Write Pointer */
+ union
+ {
+ struct
+ {
+ /** RIRB Write Pointer */
+ uint16_t RIRBWP : 8;
+
+ /** Reserved */
+ uint16_t RsvdP0 : 7;
+
+ /** RIRB Write Pointer Reset */
+ uint16_t RIRBWPRST : 1;
+ } __attribute__((packed));
+ uint16_t Raw;
+ } RIRBWP;
+
+ /** Response Interrupt Count */
+ union
+ {
+ struct
+ {
+ /** N Response Interrupt Count
+ *
+ * 00000001b = 1 Response sent to RIRB
+ * ...
+ * 11111111b = 255 Responses sent to RIRB
+ * 00000000b = 256 Response sent to RIRB
+ */
+ uint16_t RINTCNT : 8;
+
+ /** Reserved */
+ uint16_t RsvdP0 : 8;
+ } __attribute__((packed));
+ uint16_t Raw;
+ } RINTCNT;
+
+ /** RIRB Control */
+ union
+ {
+ struct
+ {
+ /** Response Interrupt Control
+ *
+ * 0 = Disable Interrupt
+ * 1 = Generate an interrupt after N responses are sent to the RIRB
+ */
+ uint8_t RINTCTL : 1;
+
+ /** RIRB DMA Enable
+ *
+ * 0 = DMA Stop
+ * 1 = DMA Run
+ */
+ uint8_t RIRBDMAEN : 1;
+
+ /** Response Overrun Interrupt Control */
+ uint8_t RIRBOIC : 1;
+
+ /** Reserved */
+ uint8_t RsvdP0 : 5;
+ } __attribute__((packed));
+ uint8_t Raw;
+ } RIRBCTL;
+
+ /** RIRB Status */
+ union
+ {
+ struct
+ {
+ /** Response Interrupt */
+ uint8_t RINTFL : 1;
+
+ /** Reserved */
+ uint8_t RsvdZ0 : 1;
+
+ /** Response Overrun Interrupt Status */
+ uint8_t RIRBOIS : 1;
+
+ /** Reserved */
+ uint8_t RsvdZ1 : 5;
+ } __attribute__((packed));
+ uint8_t Raw;
+ } RIRBSTS;
+
+ /** RIRB Size */
+ union
+ {
+ struct
+ {
+ /** RIRB Size
+ *
+ * 00b = 2 entries
+ * 01b = 16 entries
+ * 10b = 256 entries
+ * 11b = Reserved
+ */
+ uint8_t RIRBSIZE : 2;
+
+ /** Reserved */
+ uint8_t RsvdP0 : 2;
+
+ /** RIRB Size Capability
+ *
+ * 0001b = 2 entries
+ * 0010b = 16 entries
+ * 0100b = 256 entries
+ * 1000b = Reserved
+ */
+ uint8_t RIRBSZCAP : 4;
+ } __attribute__((packed));
+ uint8_t Raw;
+ } RIRBSIZE;
+
+ /** Reserved */
+ uint8_t Rsvd6;
+
+ /** Immediate Command Output Interface */
+ uint32_t ICOI;
+
+ /** Immediate Command Input Interface */
+ uint32_t ICII;
+
+ /** Immediate Command Status */
+ uint16_t ICIS;
+
+ /** Reserved */
+ uint8_t Rsvd7[6];
+
+ /** DMA Position Buffer Lower Base */
+ union
+ {
+ struct
+ {
+ /** DMA Position Buffer Enable */
+ uint32_t DPBEN : 1;
+
+ /** Reserved */
+ uint32_t RsvdZ0 : 6;
+
+ /** DMA Position Lower Base Address */
+ uint32_t DPLBASE : 25;
+ } __attribute__((packed));
+ uint32_t Raw;
+ } DPIBLBASE;
+
+ /** DMA Position Buffer Upper Base */
+ uint32_t DPIBUBASE;
+
+ /** Reserved */
+ uint8_t Rsvd8[8];
+
+ StreamDescriptor SD[];
+} __attribute__((packed));
+#endif
+
+EXTERNC int cxx_Panic();
+EXTERNC int cxx_Probe();
+EXTERNC int cxx_Initialize();
+EXTERNC int cxx_Finalize();
diff --git a/audio/hda/main.c b/audio/hda/main.c
new file mode 100644
index 0000000..771e0f8
--- /dev/null
+++ b/audio/hda/main.c
@@ -0,0 +1,31 @@
+/*
+ This file is part of Fennix Drivers.
+
+ Fennix Drivers is free software: you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation, either version 3 of
+ the License, or (at your option) any later version.
+
+ Fennix Drivers is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Fennix Drivers. If not, see .
+*/
+
+#include
+
+#include "hda.hpp"
+
+int DriverEntry() { return cxx_Initialize(); }
+int DriverFinal() { return cxx_Finalize(); }
+int DriverPanic() { return cxx_Panic(); }
+int DriverProbe() { return cxx_Probe(); }
+
+DriverInfo("hda",
+ "Intel High Definition Audio Driver",
+ "EnderIce2",
+ "0.1",
+ "GPLv3");
diff --git a/driver.template b/driver.template
new file mode 100644
index 0000000..91b4354
--- /dev/null
+++ b/driver.template
@@ -0,0 +1,50 @@
+/*
+ This file is part of Fennix Drivers.
+
+ Fennix Drivers is free software: you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation, either version 3 of
+ the License, or (at your option) any later version.
+
+ Fennix Drivers is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Fennix Drivers. If not, see .
+*/
+
+#include
+#include
+#include
+
+void InterruptHandler(TrapFrame *Frame)
+{
+}
+
+int DriverEntry()
+{
+ return 0;
+}
+
+int DriverFinal()
+{
+ return 0;
+}
+
+int DriverPanic()
+{
+ return 0;
+}
+
+int DriverProbe()
+{
+ return 0;
+}
+
+DriverInfo("name",
+ "description",
+ "author",
+ "version",
+ "license");
diff --git a/include/aip.h b/include/aip.h
new file mode 100644
index 0000000..0a070b5
--- /dev/null
+++ b/include/aip.h
@@ -0,0 +1,123 @@
+/*
+ This file is part of Fennix Drivers.
+
+ Fennix Drivers is free software: you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation, either version 3 of
+ the License, or (at your option) any later version.
+
+ Fennix Drivers is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Fennix Drivers. If not, see .
+*/
+
+#ifndef __FENNIX_API_AIP_H__
+#define __FENNIX_API_AIP_H__
+
+#include
+#include
+#include
+
+#define PIC1_CMD 0x20
+#define PIC1_DATA (PIC1_CMD + 1)
+#define PIC2_CMD 0xA0
+#define PIC2_DATA (PIC2_CMD + 1)
+#define _PIC_EOI 0x20
+
+#define PS2_DATA 0x60
+#define PS2_STATUS 0x64
+#define PS2_CMD PS2_STATUS
+#define PS2_ACK 0xFA
+#define PS2_TEST_PASSED 0x55
+#define PS2_TEST_FAILED 0xFC
+
+#define PS2_CMD_READ_CONFIG 0x20
+#define PS2_CMD_READ_CONFIG_N(n) (PS2_CMD_READ_CONFIG + n)
+#define PS2_CMD_WRITE_CONFIG 0x60
+#define PS2_CMD_WRITE_CONFIG_N(n) (PS2_CMD_WRITE_CONFIG + n)
+#define PS2_CMD_DISABLE_PORT_2 0xA7
+#define PS2_CMD_ENABLE_PORT_2 0xA8
+#define PS2_CMD_TEST_PORT_2 0xA9
+#define PS2_CMD_TEST_CONTROLLER 0xAA
+#define PS2_CMD_TEST_PORT_1 0xAB
+#define PS2_CMD_DIAGNOSTIC_DUMP 0xAC
+#define PS2_CMD_DISABLE_PORT_1 0xAD
+#define PS2_CMD_ENABLE_PORT_1 0xAE
+#define PS2_CMD_READ_INPUT_PORT 0xC0
+#define PS2_CMD_COPY_INPUT_0_3_TO_4_7_STATUS 0xC1
+#define PS2_CMD_COPY_INPUT_4_7_TO_4_7_STATUS 0xC2
+#define PS2_CMD_READ_OUTPUT_PORT 0xD0
+#define PS2_CMD_WRITE_NEXT_BYTE_TO_OUTPUT_PORT 0xD1
+#define PS2_CMD_WRITE_NEXT_BYTE_TO_PS2_PORT_1_OUTPUT 0xD2
+#define PS2_CMD_WRITE_NEXT_BYTE_TO_PS2_PORT_2_OUTPUT 0xD3
+#define PS2_CMD_WRITE_NEXT_BYTE_TO_PS2_PORT_2_INPUT 0xD4
+#define PS2_CMD_PULSE_OUTPUT_LINE(n) (0xF0 + n)
+
+typedef union
+{
+ struct
+ {
+ uint8_t OutputBufferFull : 1;
+ uint8_t InputBufferFull : 1;
+ uint8_t SystemFlag : 1;
+ uint8_t CommandData : 1;
+ uint8_t Unknown1 : 1;
+ uint8_t Unknown2 : 1;
+ uint8_t TimeoutError : 1;
+ uint8_t ParityError : 1;
+ };
+ uint8_t Raw;
+} PS2_STATUSES;
+
+typedef union
+{
+ struct
+ {
+ uint8_t Port1Interrupt : 1;
+ uint8_t Port2Interrupt : 1;
+ uint8_t SystemFlag : 1;
+ uint8_t Zero0 : 1;
+ uint8_t Port1Clock : 1;
+ uint8_t Port2Clock : 1;
+ uint8_t Port1Translation : 1;
+ uint8_t Zero1 : 1;
+ };
+ uint8_t Raw;
+} PS2_CONFIGURATION;
+
+typedef union
+{
+ struct
+ {
+ uint8_t SystemReset : 1;
+ uint8_t A20Gate : 1;
+ uint8_t Port2Clock : 1;
+ uint8_t Port2Data : 1;
+ uint8_t Port1OutputBufferFull : 1;
+ uint8_t Port2OutputBufferFull : 1;
+ uint8_t Port1InputBufferFull : 1;
+ uint8_t Port2InputBufferFull : 1;
+ };
+ uint8_t Raw;
+} PS2_OUTPUT_PORT;
+
+void PIC_EOI(uint8_t IRQ);
+void IRQ_MASK(uint8_t IRQ);
+void IRQ_UNMASK(uint8_t IRQ);
+void PS2Wait(const bool Output);
+void PS2WriteCommand(uint8_t Command);
+void PS2WriteData(uint8_t Data);
+uint8_t PS2ReadData();
+uint8_t PS2ReadStatus();
+uint8_t PS2ReadAfterACK();
+void PS2ClearOutputBuffer();
+int PS2ACKTimeout();
+
+#define WaitOutput PS2Wait(true)
+#define WaitInput PS2Wait(false)
+
+#endif // !__FENNIX_API_AIP_H__
diff --git a/include/aip/kbd.h b/include/aip/kbd.h
new file mode 100644
index 0000000..c174a3c
--- /dev/null
+++ b/include/aip/kbd.h
@@ -0,0 +1,93 @@
+/*
+ This file is part of Fennix Drivers.
+
+ Fennix Drivers is free software: you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation, either version 3 of
+ the License, or (at your option) any later version.
+
+ Fennix Drivers is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Fennix Drivers. If not, see .
+*/
+
+#ifndef __FENNIX_API_AIP_KBD_H__
+#define __FENNIX_API_AIP_KBD_H__
+
+#include
+
+#define PS2_KBD_CMD_SET_LEDS 0xED
+#define PS2_KBD_CMD_ECHO 0xEE
+#define PS2_KBD_CMD_SCAN_CODE_SET 0xF0
+#define PS2_KBD_CMD_IDENTIFY 0xF2
+#define PS2_KBD_CMD_TYPEMATIC 0xF3
+#define PS2_KBD_CMD_ENABLE_SCANNING 0xF4
+#define PS2_KBD_CMD_DISABLE_SCANNING 0xF5
+#define PS2_KBD_CMD_DEFAULTS 0xF6
+#define PS2_KBD_CMD_ALL_TYPEMATIC 0xF7
+#define PS2_KBD_CMD_ALL_MAKE_RELEASE 0xF8
+#define PS2_KBD_CMD_ALL_MAKE 0xF9
+#define PS2_KBD_CMD_ALL_TYPEMATIC_MAKE_RELEASE 0xFA
+#define PS2_KBD_CMD_SPECIFIC_TYPEMATIC 0xFB
+#define PS2_KBD_CMD_SPECIFIC_MAKE_RELEASE 0xFC
+#define PS2_KBD_CMD_SPECIFIC_MAKE 0xFD
+#define PS2_KBD_CMD_RESEND 0xFE
+#define PS2_KBD_CMD_RESET 0xFF
+
+#define PS2_KBD_RESP_ACK 0xFA
+#define PS2_KBD_RESP_ECHO 0xEE
+#define PS2_KBD_RESP_RESEND 0xFE
+#define PS2_KBD_RESP_TEST_PASSED 0xAA
+#define PS2_KBD_RESP_TEST_FAILED 0xFC
+#define PS2_KBD_RESP_TEST_FAILED_2 0xFD
+
+typedef enum
+{
+ PS2_KBD_LED_SCROLL_LOCK = 1,
+ PS2_KBD_LED_NUM_LOCK = 2,
+ PS2_KBD_LED_CAPS_LOCK = 4
+} PS2_KBD_LEDS;
+
+typedef enum
+{
+ PS2_KBD_SCAN_CODE_GET_CURRENT = 0,
+ PS2_KBD_SCAN_CODE_SET_1 = 1,
+ PS2_KBD_SCAN_CODE_SET_2 = 2,
+ PS2_KBD_SCAN_CODE_SET_3 = 3,
+
+ PS2_KBD_SC_SET_1 = 0x43,
+ PS2_KBD_SC_SET_2 = 0x41,
+ PS2_KBD_SC_SET_3 = 0x3F
+} PS2_KBD_SCAN_CODE_SET;
+
+typedef union
+{
+ struct
+ {
+ /**
+ * 00000b - 30Hz
+ * 11111b - 2Hz
+ */
+ uint8_t RepeatRate : 5;
+
+ /**
+ * 00b - 250ms
+ * 01b - 500ms
+ * 10b - 750ms
+ * 11b - 1000ms
+ */
+ uint8_t Delay : 2;
+
+ /**
+ * Must be zero
+ */
+ uint8_t Zero : 1;
+ };
+ uint8_t Raw;
+} PS2_KBD_TYPEMATIC;
+
+#endif // !__FENNIX_API_AIP_KBD_H__
diff --git a/include/aip/mouse.h b/include/aip/mouse.h
new file mode 100644
index 0000000..5ebed16
--- /dev/null
+++ b/include/aip/mouse.h
@@ -0,0 +1,89 @@
+/*
+ This file is part of Fennix Drivers.
+
+ Fennix Drivers is free software: you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation, either version 3 of
+ the License, or (at your option) any later version.
+
+ Fennix Drivers is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Fennix Drivers. If not, see .
+*/
+
+#ifndef __FENNIX_API_AIP_MOUSE_H__
+#define __FENNIX_API_AIP_MOUSE_H__
+
+#include
+
+#define PS2_MOUSE_CMD_SET_SCALING_1_1 0xE6
+#define PS2_MOUSE_CMD_SET_SCALING_2_1 0xE7
+#define PS2_MOUSE_CMD_SET_RESOLUTION 0xE8
+#define PS2_MOUSE_CMD_GET_STATUS 0xE9
+#define PS2_MOUSE_CMD_SET_STREAM_MODE 0xEA
+#define PS2_MOUSE_CMD_READ_DATA 0xEB
+#define PS2_MOUSE_CMD_RESET_WRAP_MODE 0xEC
+#define PS2_MOUSE_CMD_SET_WRAP_MODE 0xEE
+#define PS2_MOUSE_CMD_SET_REMOTE_MODE 0xF0
+#define PS2_MOUSE_CMD_READ_ID 0xF2
+/** Values: 10, 20, 40, 60, 80, 100, 200 */
+#define PS2_MOUSE_CMD_SET_SAMPLE_RATE 0xF3
+#define PS2_MOUSE_CMD_ENABLE_DATA_REPORTING 0xF4
+#define PS2_MOUSE_CMD_DISABLE_DATA_REPORTING 0xF5
+#define PS2_MOUSE_CMD_SET_DEFAULTS 0xF6
+#define PS2_MOUSE_CMD_RESEND 0xFE
+#define PS2_MOUSE_CMD_RESET 0xFF
+
+#define PS2_MOUSE_RESP_ACK 0xFA
+#define PS2_MOUSE_RESP_RESEND 0xFE
+#define PS2_MOUSE_RESP_TEST_PASSED 0xAA
+#define PS2_MOUSE_RESP_TEST_FAILED 0xFC
+
+typedef enum
+{
+ PS2_MOUSE_RES_1 = 0,
+ PS2_MOUSE_RES_2 = 1,
+ PS2_MOUSE_RES_4 = 2,
+ PS2_MOUSE_RES_8 = 3
+} PS2_MOUSE_RESOLUTION;
+
+typedef struct
+{
+ union
+ {
+ struct
+ {
+ uint8_t LeftButton : 1;
+ uint8_t RightButton : 1;
+ uint8_t MiddleButton : 1;
+ uint8_t Always1 : 1;
+ uint8_t XSign : 1;
+ uint8_t YSign : 1;
+ uint8_t XOverflow : 1;
+ uint8_t YOverflow : 1;
+ } __attribute__((packed));
+ uint8_t Raw;
+ } Base;
+
+ uint8_t XMovement;
+ uint8_t YMovement;
+
+ union
+ {
+ struct
+ {
+ uint8_t Z : 4;
+ uint8_t Button4 : 1;
+ uint8_t Button5 : 1;
+ uint8_t Always0 : 1;
+ uint8_t Always0_2 : 1;
+ } __attribute__((packed));
+ uint8_t Raw;
+ } ZMovement;
+} PS2_MOUSE_PACKET;
+
+#endif // !__FENNIX_API_AIP_MOUSE_H__
diff --git a/include/audio.h b/include/audio.h
new file mode 100644
index 0000000..73183b0
--- /dev/null
+++ b/include/audio.h
@@ -0,0 +1,45 @@
+/*
+ This file is part of Fennix Drivers.
+
+ Fennix Drivers is free software: you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation, either version 3 of
+ the License, or (at your option) any later version.
+
+ Fennix Drivers is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Fennix Drivers. If not, see .
+*/
+
+#ifndef __FENNIX_API_AUDIO_H__
+#define __FENNIX_API_AUDIO_H__
+
+#include
+#include
+
+typedef int (*drvOpen_t)(dev_t, dev_t, int, mode_t);
+typedef int (*drvClose_t)(dev_t, dev_t);
+typedef size_t (*drvRead_t)(dev_t, dev_t, uint8_t *, size_t, off_t);
+typedef size_t (*drvWrite_t)(dev_t, dev_t, uint8_t *, size_t, off_t);
+typedef int (*drvIoctl_t)(dev_t, dev_t, unsigned long, void *);
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif // __cplusplus
+
+ dev_t RegisterAudioDevice(DeviceDriverType Type,
+ drvOpen_t Open, drvClose_t Close,
+ drvRead_t Read, drvWrite_t Write, drvIoctl_t Ioctl);
+
+ int UnregisterAudioDevice(dev_t DeviceID, DeviceDriverType Type);
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif // !__FENNIX_API_AUDIO_H__
diff --git a/include/base.h b/include/base.h
new file mode 100644
index 0000000..8806d2a
--- /dev/null
+++ b/include/base.h
@@ -0,0 +1,277 @@
+/*
+ This file is part of Fennix Drivers.
+
+ Fennix Drivers is free software: you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation, either version 3 of
+ the License, or (at your option) any later version.
+
+ Fennix Drivers is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Fennix Drivers. If not, see .
+*/
+
+#ifndef __FENNIX_API_BASE_H__
+#define __FENNIX_API_BASE_H__
+
+#include
+
+#define PAGE_SIZE 0x1000
+
+typedef int CriticalState;
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif // __cplusplus
+
+ /**
+ * @brief Allocate an amount of memory pages
+ * @param Pages The amount of pages to allocate
+ * @return A pointer to the allocated memory, NULL if failed
+ */
+ void *AllocateMemory(size_t Pages);
+
+ /**
+ * @brief Free an amount of memory pages
+ * @param Pointer The pointer to the memory to free
+ * @param Pages The amount of pages to free
+ *
+ * @note If the pointer is invalid, the error is ignored and the
+ * function returns
+ */
+ void FreeMemory(void *Pointer, size_t Pages);
+
+ /**
+ * @brief Append a flag to a page
+ * @param Address The address of the page
+ * @param Flag The flag to append
+ */
+ void AppendMapFlag(void *Address, PageMapFlags Flag);
+
+ /**
+ * @brief Remove a flag from a page
+ * @param Address The address of the page
+ * @param Flag The flag to remove
+ */
+ void RemoveMapFlag(void *Address, PageMapFlags Flag);
+
+ /**
+ * @brief Map pages
+ * @param PhysicalAddress The physical address to map
+ * @param VirtualAddress The virtual address to map to
+ * @param Pages The amount of pages to map
+ * @param Flags The flags to map the pages with
+ */
+ void MapPages(void *PhysicalAddress, void *VirtualAddress, size_t Pages, uint32_t Flags);
+
+ /**
+ * @brief Unmap pages
+ * @param VirtualAddress The virtual address to unmap
+ * @param Pages The amount of pages to unmap
+ */
+ void UnmapPages(void *VirtualAddress, size_t Pages);
+
+ /**
+ * @brief Print to the screen
+ * @param Format The format string
+ * @param ... The arguments to the format string
+ *
+ * @note The newline character is automatically appended
+ */
+ void KPrint(const char *Format, ...);
+
+ /**
+ * @brief Print to the kernel logger
+ * @param Format The format string
+ * @param ... The arguments to the format string
+ */
+ void Log(const char *Format, ...);
+
+ /**
+ * @brief Register an interrupt handler
+ * @param IRQ The IRQ to register the handler for (IRQ0 != 0x32 but 0)
+ * @param Handler Function pointer to the handler
+ * @return 0 on success, errno on failure
+ */
+ int RegisterInterruptHandler(uint8_t IRQ, void *Handler);
+
+ /**
+ * @brief Override an interrupt handler
+ *
+ * This function will check all registered handlers (by the drivers)
+ * for the given IRQ and remove them. Then it will register the new
+ * handler.
+ *
+ * @param IRQ The IRQ to override the handler for (IRQ0 != 0x32 but 0)
+ * @param Handler Function pointer to the handler
+ * @return 0 on success, errno on failure
+ */
+ int OverrideInterruptHandler(uint8_t IRQ, void *Handler);
+
+ /**
+ * @brief Unregister an interrupt handler
+ * @param IRQ The IRQ to unregister the handler for (IRQ0 != 0x32 but 0)
+ * @param Handler Function pointer to the handler
+ * @return 0 on success, errno on failure
+ */
+ int UnregisterInterruptHandler(uint8_t IRQ, void *Handler);
+
+ /**
+ * @brief Unregister all interrupt handlers for a given handler
+ * @param Handler Function pointer to the handler
+ * @return 0 on success, errno on failure
+ */
+ int UnregisterAllInterruptHandlers(void *Handler);
+
+ /**
+ * @brief Copy memory
+ * @param Destination The destination
+ * @param Source The source
+ * @param Length The length of the memory to copy
+ * @return The destination
+ */
+ void *MemoryCopy(void *Destination, const void *Source, size_t Length);
+
+ /**
+ * @brief Set memory
+ * @param Destination The destination
+ * @param Value The value to set
+ * @param Length The length of the memory to set
+ * @return The destination
+ */
+ void *MemorySet(void *Destination, int Value, size_t Length);
+
+ /**
+ * @brief Move memory
+ * @param Destination The destination
+ * @param Source The source
+ * @param Length The length of the memory to move
+ * @return The destination
+ */
+ void *MemoryMove(void *Destination, const void *Source, size_t Length);
+
+ /**
+ * @brief String length
+ * @param String The string
+ * @return The length of the string
+ */
+ size_t StringLength(const char String[]);
+
+ char *strstr(const char *Haystack, const char *Needle);
+
+ /**
+ * @brief Create a kernel process
+ * @param Name The name of the process
+ * @return The PID of the process, this function never fails
+ */
+ pid_t CreateKernelProcess(const char *Name);
+
+ /**
+ * @brief Create a kernel thread
+ * @param pId The PID of the process to create the thread in
+ * @param Name The name of the thread
+ * @param EntryPoint The entry point of the thread
+ * @param Argument The argument to pass to the thread (rdi)
+ * @return The TID of the thread, this function never fails
+ */
+ pid_t CreateKernelThread(pid_t pId, const char *Name, void *EntryPoint,
+ void *Argument);
+
+ /**
+ * @brief Kill a process
+ * @param pId The PID of the process to kill
+ * @param ExitCode The exit code of the process
+ * @return 0 on success, errno on failure
+ */
+ int KillProcess(pid_t pId, int ExitCode);
+
+ /**
+ * @brief Kill a thread
+ * @param tId The TID of the thread to kill
+ * @param ExitCode The exit code of the thread
+ * @return 0 on success, errno on failure
+ */
+ int KillThread(pid_t tId, int ExitCode);
+
+ /**
+ * @brief Yield the current thread
+ *
+ * This function will yield the current thread to the scheduler.
+ */
+ void Yield();
+
+ /**
+ * @brief Sleep for a given amount of milliseconds
+ * @param Milliseconds The amount of milliseconds to sleep
+ */
+ void Sleep(uint64_t Milliseconds);
+
+ /**
+ * @brief Enter a critical section
+ * @return The previous interrupt state
+ *
+ * This function will disable interrupts and return the previous
+ * interrupt state.
+ */
+ CriticalState EnterCriticalSection();
+
+ /**
+ * @brief Leave a critical section
+ * @param PreviousState The previous interrupt state
+ *
+ * This function will restore the previous interrupt state.
+ */
+ void LeaveCriticalSection(CriticalState PreviousState);
+
+ /** @copydoc EnterCriticalSection */
+#define ECS CriticalState __ECS = EnterCriticalSection()
+
+ /** @copydoc LeaveCriticalSection */
+#define LCS LeaveCriticalSection(__ECS)
+
+#define DriverInfo(Name, Description, Author, Version, License) \
+ void __IdentifyDriver( \
+ dev_t ID, \
+ int (*GetDriverInfo)(dev_t, const char *, const char *, \
+ const char *, const char *, const char *)) \
+ { \
+ GetDriverInfo(ID, Name, Description, Author, Version, License); \
+ }
+
+#ifdef DEBUG
+#define DebugLog(m, ...) Log(m, ##__VA_ARGS__)
+#else
+#define DebugLog(m, ...)
+#endif // DEBUG
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#ifdef __cplusplus
+namespace std
+{
+ typedef decltype(sizeof(0)) size_t;
+}
+
+void *operator new(std::size_t Size);
+void *operator new[](std::size_t Size);
+void operator delete(void *Pointer);
+void operator delete[](void *Pointer);
+void operator delete(void *Pointer, std::size_t Size);
+void operator delete[](void *Pointer, std::size_t Size);
+
+#endif // __cplusplus
+
+#define memcpy(dest, src, len) MemoryCopy(dest, src, len)
+#define memset(dest, val, len) MemorySet(dest, val, len)
+#define memmove(dest, src, len) MemoryMove(dest, src, len)
+
+#define strlen(str) StringLength(str)
+
+#endif // !__FENNIX_API_BASE_H__
diff --git a/include/block.h b/include/block.h
new file mode 100644
index 0000000..e87fa2d
--- /dev/null
+++ b/include/block.h
@@ -0,0 +1,45 @@
+/*
+ This file is part of Fennix Drivers.
+
+ Fennix Drivers is free software: you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation, either version 3 of
+ the License, or (at your option) any later version.
+
+ Fennix Drivers is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Fennix Drivers. If not, see .
+*/
+
+#ifndef __FENNIX_API_BLOCK_H__
+#define __FENNIX_API_BLOCK_H__
+
+#include
+#include
+
+typedef int (*drvOpen_t)(dev_t, dev_t, int, mode_t);
+typedef int (*drvClose_t)(dev_t, dev_t);
+typedef size_t (*drvRead_t)(dev_t, dev_t, uint8_t *, size_t, off_t);
+typedef size_t (*drvWrite_t)(dev_t, dev_t, uint8_t *, size_t, off_t);
+typedef int (*drvIoctl_t)(dev_t, dev_t, unsigned long, void *);
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif // __cplusplus
+
+ dev_t RegisterBlockDevice(DeviceDriverType Type,
+ drvOpen_t Open, drvClose_t Close,
+ drvRead_t Read, drvWrite_t Write, drvIoctl_t Ioctl);
+
+ int UnregisterBlockDevice(dev_t DeviceID, DeviceDriverType Type);
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif // !__FENNIX_API_BLOCK_H__
diff --git a/include/driver.h b/include/driver.h
new file mode 100644
index 0000000..b072c0c
--- /dev/null
+++ b/include/driver.h
@@ -0,0 +1,326 @@
+/*
+ This file is part of Fennix Kernel.
+
+ Fennix Kernel is free software: you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation, either version 3 of
+ the License, or (at your option) any later version.
+
+ Fennix Kernel is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Fennix Kernel. If not, see .
+*/
+
+#ifndef __FENNIX_API_DRIVER_FUNCTIONS_H__
+#define __FENNIX_API_DRIVER_FUNCTIONS_H__
+
+#include
+
+typedef enum
+{
+ _drf_Entry,
+ _drf_Final,
+ _drf_Panic,
+ _drf_Probe,
+} __driverRegFunc;
+
+typedef union
+{
+ struct
+ {
+ uint8_t LeftButton : 1;
+ uint8_t RightButton : 1;
+ uint8_t MiddleButton : 1;
+ uint8_t Button4 : 1;
+ uint8_t Button5 : 1;
+ uint8_t Button6 : 1;
+ uint8_t Button7 : 1;
+ uint8_t Button8 : 1;
+ };
+ uint8_t Value;
+} __MouseButtons;
+
+typedef struct
+{
+ /* PCIDevice */ void *Device;
+ /* __PCIArray */ void *Next;
+} __PCIArray;
+
+/* ========================================== */
+
+#define PCI_END 0x0000
+#define KEY_NULL 0x00
+
+typedef enum
+{
+ KEY_1,
+ KEY_2,
+ KEY_3,
+ KEY_4,
+ KEY_5,
+ KEY_6,
+ KEY_7,
+ KEY_8,
+ KEY_9,
+ KEY_0,
+
+ KEY_Q,
+ KEY_W,
+ KEY_E,
+ KEY_R,
+ KEY_T,
+ KEY_Y,
+ KEY_U,
+ KEY_I,
+ KEY_O,
+ KEY_P,
+ KEY_A,
+ KEY_S,
+ KEY_D,
+ KEY_F,
+ KEY_G,
+ KEY_H,
+ KEY_J,
+ KEY_K,
+ KEY_L,
+ KEY_Z,
+ KEY_X,
+ KEY_C,
+ KEY_V,
+ KEY_B,
+ KEY_N,
+ KEY_M,
+
+ KEY_F1,
+ KEY_F2,
+ KEY_F3,
+ KEY_F4,
+ KEY_F5,
+ KEY_F6,
+ KEY_F7,
+ KEY_F8,
+ KEY_F9,
+ KEY_F10,
+ KEY_F11,
+ KEY_F12,
+
+ KEYPAD_7,
+ KEYPAD_8,
+ KEYPAD_9,
+ KEYPAD_MINUS,
+ KEYPAD_4,
+ KEYPAD_5,
+ KEYPAD_6,
+ KEYPAD_PLUS,
+ KEYPAD_1,
+ KEYPAD_2,
+ KEYPAD_3,
+ KEYPAD_0,
+ KEYPAD_PERIOD,
+ KEYPAD_RETURN,
+ KEYPAD_ASTERISK,
+ KEYPAD_SLASH,
+
+ KEY_LEFT_CTRL,
+ KEY_RIGHT_CTRL,
+ KEY_LEFT_SHIFT,
+ KEY_RIGHT_SHIFT,
+ KEY_LEFT_ALT,
+ KEY_RIGHT_ALT,
+ KEY_ESCAPE,
+ KEY_MINUS,
+ KEY_EQUAL,
+ KEY_BACKSPACE,
+ KEY_TAB,
+ KEY_LEFT_BRACKET,
+ KEY_RIGHT_BRACKET,
+ KEY_RETURN,
+ KEY_SEMICOLON,
+ KEY_APOSTROPHE,
+ KEY_BACK_TICK,
+ KEY_BACKSLASH,
+ KEY_COMMA,
+ KEY_PERIOD,
+ KEY_SLASH,
+ KEY_SPACE,
+ KEY_CAPS_LOCK,
+ KEY_NUM_LOCK,
+ KEY_SCROLL_LOCK,
+ KEY_PRINT_SCREEN,
+
+ KEY_HOME,
+ KEY_UP_ARROW,
+ KEY_LEFT_ARROW,
+ KEY_RIGHT_ARROW,
+ KEY_DOWN_ARROW,
+ KEY_PAGE_UP,
+ KEY_PAGE_DOWN,
+ KEY_END,
+ KEY_INSERT,
+ KEY_DELETE,
+ KEY_LEFT_GUI,
+ KEY_RIGHT_GUI,
+ KEY_APPS,
+
+ KEY_MULTIMEDIA_PREV_TRACK,
+ KEY_MULTIMEDIA_NEXT_TRACK,
+ KEY_MULTIMEDIA_MUTE,
+ KEY_MULTIMEDIA_CALCULATOR,
+ KEY_MULTIMEDIA_PLAY,
+ KEY_MULTIMEDIA_STOP,
+ KEY_MULTIMEDIA_VOL_DOWN,
+ KEY_MULTIMEDIA_VOL_UP,
+ KEY_MULTIMEDIA_WWW_HOME,
+ KEY_MULTIMEDIA_WWW_SEARCH,
+ KEY_MULTIMEDIA_WWW_FAVORITES,
+ KEY_MULTIMEDIA_WWW_REFRESH,
+ KEY_MULTIMEDIA_WWW_STOP,
+ KEY_MULTIMEDIA_WWW_FORWARD,
+ KEY_MULTIMEDIA_WWW_BACK,
+ KEY_MULTIMEDIA_MY_COMPUTER,
+ KEY_MULTIMEDIA_EMAIL,
+ KEY_MULTIMEDIA_MEDIA_SELECT,
+
+ KEY_ACPI_POWER,
+ KEY_ACPI_SLEEP,
+ KEY_ACPI_WAKE,
+
+ KEY_PRESSED = 0x80,
+} KeyScanCodes;
+
+typedef enum
+{
+ ddt_Keyboard,
+ ddt_Mouse,
+ ddt_Joystick,
+ ddt_Gamepad,
+ ddt_Touchpad,
+ ddt_Touchscreen,
+
+ ddt_SATA,
+ ddt_ATA,
+ ddt_NVMe,
+
+ ddt_Audio,
+
+ ddt_Network,
+} DeviceDriverType;
+
+typedef enum
+{
+ IOCTL_AUDIO_GET_VOLUME,
+ IOCTL_AUDIO_SET_VOLUME,
+
+ IOCTL_AUDIO_GET_MUTE,
+ IOCTL_AUDIO_SET_MUTE,
+
+ IOCTL_AUDIO_GET_SAMPLE_RATE,
+ IOCTL_AUDIO_SET_SAMPLE_RATE,
+
+ IOCTL_AUDIO_GET_CHANNELS,
+ IOCTL_AUDIO_SET_CHANNELS,
+} AudioIoctl;
+
+typedef enum
+{
+ IOCTL_NET_GET_MAC,
+} NetIoctl;
+
+typedef enum
+{
+ MAP_PRESENT = 1 << 0,
+ MAP_WRITE = 1 << 1,
+ MAP_USER = 1 << 2,
+ MAP_WRITE_THROUGH = 1 << 3,
+ MAP_CACHE_DISABLE = 1 << 4,
+} PageMapFlags;
+
+typedef struct
+{
+ struct
+ {
+ uint8_t Major;
+ uint8_t Minor;
+ uint8_t Patch;
+ } APIVersion;
+
+ dev_t MajorID;
+ uintptr_t Base;
+
+ /* Internal */
+ int (*RegisterFunction)(dev_t MajorID, void *Function, __driverRegFunc Type);
+ int (*GetDriverInfo)(dev_t MajorID, const char *Name, const char *Description, const char *Author, const char *Version, const char *License);
+
+ /* Interrupts */
+ int (*RegisterInterruptHandler)(dev_t MajorID, uint8_t IRQ, void *Handler);
+ int (*OverrideInterruptHandler)(dev_t MajorID, uint8_t IRQ, void *Handler);
+ int (*UnregisterInterruptHandler)(dev_t MajorID, uint8_t IRQ, void *Handler);
+ int (*UnregisterAllInterruptHandlers)(dev_t MajorID, void *Handler);
+
+ /* Input */
+ dev_t (*RegisterInputDevice)(dev_t MajorID, DeviceDriverType Type);
+ int (*UnregisterInputDevice)(dev_t MajorID, dev_t MinorID, DeviceDriverType Type);
+ int (*ReportKeyboardEvent)(dev_t MajorID, dev_t MinorID, uint8_t ScanCode);
+ int (*ReportRelativeMouseEvent)(dev_t MajorID, dev_t MinorID, __MouseButtons Button, int X, int Y, int8_t Z);
+ int (*ReportAbsoluteMouseEvent)(dev_t MajorID, dev_t MinorID, __MouseButtons Button, uintptr_t X, uintptr_t Y, int8_t Z);
+
+ /* Storage */
+ dev_t (*RegisterBlockDevice)(dev_t MajorID, DeviceDriverType Type, void *Open, void *Close, void *Read, void *Write, void *Ioctl);
+ int (*UnregisterBlockDevice)(dev_t MajorID, dev_t MinorID, DeviceDriverType Type);
+
+ /* Audio */
+ dev_t (*RegisterAudioDevice)(dev_t MajorID, DeviceDriverType Type, void *Open, void *Close, void *Read, void *Write, void *Ioctl);
+ int (*UnregisterAudioDevice)(dev_t MajorID, dev_t MinorID, DeviceDriverType Type);
+
+ /* Network */
+ dev_t (*RegisterNetDevice)(dev_t MajorID, DeviceDriverType Type, void *Open, void *Close, void *Read, void *Write, void *Ioctl);
+ int (*UnregisterNetDevice)(dev_t MajorID, dev_t MinorID, DeviceDriverType Type);
+ int (*ReportNetworkPacket)(dev_t MajorID, dev_t MinorID, void *Buffer, size_t Size);
+
+ /* Logging */
+ void (*KPrint)(dev_t MajorID, const char *Format, va_list args);
+ void (*KernelLog)(dev_t MajorID, const char *Format, va_list args);
+
+ /* Memory */
+ void *(*RequestPages)(dev_t MajorID, size_t Pages);
+ void (*FreePages)(dev_t MajorID, void *Pointer, size_t Pages);
+
+ /* Mapping */
+ void (*AppendMapFlag)(dev_t MajorID, void *Address, PageMapFlags Flag);
+ void (*RemoveMapFlag)(dev_t MajorID, void *Address, PageMapFlags Flag);
+ void (*MapPages)(dev_t MajorID, void *PhysicalAddress, void *VirtualAddress, size_t Pages, uint32_t Flags);
+ void (*UnmapPages)(dev_t MajorID, void *VirtualAddress, size_t Pages);
+
+ /* Scheduling */
+ pid_t (*CreateKernelProcess)(dev_t MajorID, const char *Name);
+ pid_t (*CreateKernelThread)(dev_t MajorID, pid_t pId, const char *Name, void *EntryPoint, void *Argument);
+ int (*KillProcess)(dev_t MajorID, pid_t pId, int ExitCode);
+ int (*KillThread)(dev_t MajorID, pid_t tId, int ExitCode);
+ void (*Yield)(dev_t MajorID);
+ void (*Sleep)(dev_t MajorID, uint64_t Milliseconds);
+
+ /* PCI */
+ __PCIArray *(*GetPCIDevices)(dev_t MajorID, uint16_t Vendors[], uint16_t Devices[]);
+ void (*InitializePCI)(dev_t MajorID, void *Header);
+ uint32_t (*GetBAR)(dev_t MajorID, uint8_t Index, void *Header);
+
+ /* Kernel std API */
+ void *(*memcpy)(dev_t MajorID, void *Destination, const void *Source, size_t Length);
+ void *(*memset)(dev_t MajorID, void *Destination, int Value, size_t Length);
+ void *(*memmove)(dev_t MajorID, void *Destination, const void *Source, size_t Length);
+ int (*memcmp)(dev_t MajorID, const void *Left, const void *Right, size_t Length);
+ size_t (*strlen)(dev_t MajorID, const char *String);
+ char *(*strcpy)(dev_t MajorID, char *Destination, const char *Source);
+ char *(*strcat)(dev_t MajorID, char *Destination, const char *Source);
+ int (*strcmp)(dev_t MajorID, const char *Left, const char *Right);
+ int (*strncmp)(dev_t MajorID, const char *Left, const char *Right, size_t Length);
+ char *(*strchr)(dev_t MajorID, const char *String, int Character);
+ char *(*strrchr)(dev_t MajorID, const char *String, int Character);
+ char *(*strstr)(dev_t MajorID, const char *Haystack, const char *Needle);
+} __driverAPI;
+
+#endif // !__FENNIX_API_DRIVER_FUNCTIONS_H__
diff --git a/include/errno.h b/include/errno.h
new file mode 100644
index 0000000..159afeb
--- /dev/null
+++ b/include/errno.h
@@ -0,0 +1,408 @@
+/*
+ This file is part of Fennix Drivers.
+
+ Fennix Drivers is free software: you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation, either version 3 of
+ the License, or (at your option) any later version.
+
+ Fennix Drivers is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Fennix Drivers. If not, see .
+*/
+
+#ifndef _ERRNO_H
+#define _ERRNO_H
+
+/** Operation not permitted */
+#define EPERM 1
+
+/** No such file or directory */
+#define ENOENT 2
+
+/** No such process */
+#define ESRCH 3
+
+/** Interrupted system call */
+#define EINTR 4
+
+/** I/O error */
+#define EIO 5
+
+/** No such device or address */
+#define ENXIO 6
+
+/** Argument list too long */
+#define E2BIG 7
+
+/** Exec format error */
+#define ENOEXEC 8
+
+/** Bad file number */
+#define EBADF 9
+
+/** No child processes */
+#define ECHILD 10
+
+/** Try again */
+#define EAGAIN 11
+
+/** Out of memory */
+#define ENOMEM 12
+
+/** Permission denied */
+#define EACCES 13
+
+/** Bad address */
+#define EFAULT 14
+
+/** Block device required */
+#define ENOTBLK 15
+
+/** Device or resource busy */
+#define EBUSY 16
+
+/** File exists */
+#define EEXIST 17
+
+/** Cross-device link */
+#define EXDEV 18
+
+/** No such device */
+#define ENODEV 19
+
+/** Not a directory */
+#define ENOTDIR 20
+
+/** Is a directory */
+#define EISDIR 21
+
+/** Invalid argument */
+#define EINVAL 22
+
+/** File table overflow */
+#define ENFILE 23
+
+/** Too many open files */
+#define EMFILE 24
+
+/** Not a typewriter */
+#define ENOTTY 25
+
+/** Text file busy */
+#define ETXTBSY 26
+
+/** File too large */
+#define EFBIG 27
+
+/** No space left on device */
+#define ENOSPC 28
+
+/** Illegal seek */
+#define ESPIPE 29
+
+/** Read-only file system */
+#define EROFS 30
+
+/** Too many links */
+#define EMLINK 31
+
+/** Broken pipe */
+#define EPIPE 32
+
+/** Math argument out of domain of func */
+#define EDOM 33
+
+/** Math result not representable */
+#define ERANGE 34
+
+/** Resource deadlock would occur */
+#define EDEADLK 35
+
+/** File name too long */
+#define ENAMETOOLONG 36
+
+/** No record locks available */
+#define ENOLCK 37
+
+/** Function not implemented */
+#define ENOSYS 38
+
+/** Directory not empty */
+#define ENOTEMPTY 39
+
+/** Too many symbolic links encountered */
+#define ELOOP 40
+
+/** No message of desired type */
+#define ENOMSG 42
+
+/** Identifier removed */
+#define EIDRM 43
+
+/** Channel number out of range */
+#define ECHRNG 44
+
+/** Level 2 not synchronized */
+#define EL2NSYNC 45
+
+/** Level 3 halted */
+#define EL3HLT 46
+
+/** Level 3 reset */
+#define EL3RST 47
+
+/** Link number out of range */
+#define ELNRNG 48
+
+/** Protocol driver not attached */
+#define EUNATCH 49
+
+/** No CSI structure available */
+#define ENOCSI 50
+
+/** Level 2 halted */
+#define EL2HLT 51
+
+/** Invalid exchange */
+#define EBADE 52
+
+/** Invalid request descriptor */
+#define EBADR 53
+
+/** Exchange full */
+#define EXFULL 54
+
+/** No anode */
+#define ENOANO 55
+
+/** Invalid request code */
+#define EBADRQC 56
+
+/** Invalid slot */
+#define EBADSLT 57
+
+/** Bad font file format */
+#define EBFONT 59
+
+/** Device not a stream */
+#define ENOSTR 60
+
+/** No data available */
+#define ENODATA 61
+
+/** Timer expired */
+#define ETIME 62
+
+/** Out of streams resources */
+#define ENOSR 63
+
+/** Machine is not on the network */
+#define ENONET 64
+
+/** Package not installed */
+#define ENOPKG 65
+
+/** Object is remote */
+#define EREMOTE 66
+
+/** Link has been severed */
+#define ENOLINK 67
+
+/** Advertise error */
+#define EADV 68
+
+/** Srmount error */
+#define ESRMNT 69
+
+/** Communication error on send */
+#define ECOMM 70
+
+/** Protocol error */
+#define EPROTO 71
+
+/** Multihop attempted */
+#define EMULTIHOP 72
+
+/** RFS specific error */
+#define EDOTDOT 73
+
+/** Not a data message */
+#define EBADMSG 74
+
+/** Value too large for defined data type */
+#define EOVERFLOW 75
+
+/** Name not unique on network */
+#define ENOTUNIQ 76
+
+/** File descriptor in bad state */
+#define EBADFD 77
+
+/** Remote address changed */
+#define EREMCHG 78
+
+/** Can not access a needed shared library */
+#define ELIBACC 79
+
+/** Accessing a corrupted shared library */
+#define ELIBBAD 80
+
+/** .lib section in a.out corrupted */
+#define ELIBSCN 81
+
+/** Attempting to link in too many shared libraries */
+#define ELIBMAX 82
+
+/** Cannot exec a shared library directly */
+#define ELIBEXEC 83
+
+/** Illegal byte sequence */
+#define EILSEQ 84
+
+/** Interrupted system call should be restarted */
+#define ERESTART 85
+
+/** Streams pipe error */
+#define ESTRPIPE 86
+
+/** Too many users */
+#define EUSERS 87
+
+/** Socket operation on non-socket */
+#define ENOTSOCK 88
+
+/** Destination address required */
+#define EDESTADDRREQ 89
+
+/** Message too long */
+#define EMSGSIZE 90
+
+/** Protocol wrong type for socket */
+#define EPROTOTYPE 91
+
+/** Protocol not available */
+#define ENOPROTOOPT 92
+
+/** Protocol not supported */
+#define EPROTONOSUPPORT 93
+
+/** Socket type not supported */
+#define ESOCKTNOSUPPORT 94
+
+/** Operation not supported on transport endpoint */
+#define EOPNOTSUPP 95
+
+/** Protocol family not supported */
+#define EPFNOSUPPORT 96
+
+/** Address family not supported by protocol */
+#define EAFNOSUPPORT 97
+
+/** Address already in use */
+#define EADDRINUSE 98
+
+/** Cannot assign requested address */
+#define EADDRNOTAVAIL 99
+
+/** Network is down */
+#define ENETDOWN 100
+
+/** Network is unreachable */
+#define ENETUNREACH 101
+
+/** Network dropped connection because of reset */
+#define ENETRESET 102
+
+/** Software caused connection abort */
+#define ECONNABORTED 103
+
+/** Connection reset by peer */
+#define ECONNRESET 104
+
+/** No buffer space available */
+#define ENOBUFS 105
+
+/** Transport endpoint is already connected */
+#define EISCONN 106
+
+/** Transport endpoint is not connected */
+#define ENOTCONN 107
+
+/** Cannot send after transport endpoint shutdown */
+#define ESHUTDOWN 108
+
+/** Too many references: cannot splice */
+#define ETOOMANYREFS 109
+
+/** Connection timed out */
+#define ETIMEDOUT 110
+
+/** Connection refused */
+#define ECONNREFUSED 111
+
+/** Host is down */
+#define EHOSTDOWN 112
+
+/** No route to host */
+#define EHOSTUNREACH 113
+
+/** Operation already in progress */
+#define EALREADY 114
+
+/** Operation now in progress */
+#define EINPROGRESS 115
+
+/** Stale NFS file handle */
+#define ESTALE 116
+
+/** Structure needs cleaning */
+#define EUCLEAN 117
+
+/** Not a XENIX named type file */
+#define ENOTNAM 118
+
+/** No XENIX semaphores available */
+#define ENAVAIL 119
+
+/** Is a named type file */
+#define EISNAM 120
+
+/** Remote I/O error */
+#define EREMOTEIO 121
+
+/** Quota exceeded */
+#define EDQUOT 122
+
+/** No medium found */
+#define ENOMEDIUM 123
+
+/** Wrong medium type */
+#define EMEDIUMTYPE 124
+
+/** Operation Canceled */
+#define ECANCELED 125
+
+/** Required key not available */
+#define ENOKEY 126
+
+/** Key has expired */
+#define EKEYEXPIRED 127
+
+/** Key has been revoked */
+#define EKEYREVOKED 128
+
+/** Key was rejected by service */
+#define EKEYREJECTED 129
+
+/** Owner died */
+#define EOWNERDEAD 130
+
+/** State not recoverable */
+#define ENOTRECOVERABLE 131
+
+#endif // !_ERRNO_H
diff --git a/include/input.h b/include/input.h
new file mode 100644
index 0000000..4117043
--- /dev/null
+++ b/include/input.h
@@ -0,0 +1,66 @@
+/*
+ This file is part of Fennix Drivers.
+
+ Fennix Drivers is free software: you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation, either version 3 of
+ the License, or (at your option) any later version.
+
+ Fennix Drivers is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Fennix Drivers. If not, see .
+*/
+
+#ifndef __FENNIX_API_INPUT_H__
+#define __FENNIX_API_INPUT_H__
+
+#include
+#include
+
+typedef struct
+{
+ union
+ {
+ struct
+ {
+ uint8_t LeftButton : 1;
+ uint8_t RightButton : 1;
+ uint8_t MiddleButton : 1;
+ uint8_t Button4 : 1;
+ uint8_t Button5 : 1;
+ };
+ uint8_t Buttons;
+ };
+
+ /**
+ * @note Ignored if is absolute
+ */
+ int X;
+
+ /**
+ * @note Ignored if is absolute
+ */
+ int Y;
+ int8_t Z;
+} MouseReport;
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif // __cplusplus
+
+ dev_t RegisterInputDevice(DeviceDriverType Type);
+ int UnregisterInputDevice(dev_t DeviceID, DeviceDriverType Type);
+ int ReportKeyboardEvent(dev_t DeviceID, KeyScanCodes ScanCode, uint8_t Pressed);
+ int ReportRelativeMouseEvent(dev_t DeviceID, MouseReport Report);
+ int ReportAbsoluteMouseEvent(dev_t DeviceID, MouseReport Report, uintptr_t X, uintptr_t Y);
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif // !__FENNIX_API_INPUT_H__
diff --git a/include/io.h b/include/io.h
index ca17bc7..cb1d9d9 100644
--- a/include/io.h
+++ b/include/io.h
@@ -1,3 +1,20 @@
+/*
+ This file is part of Fennix Drivers.
+
+ Fennix Drivers is free software: you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation, either version 3 of
+ the License, or (at your option) any later version.
+
+ Fennix Drivers is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Fennix Drivers. If not, see .
+*/
+
#ifndef __FENNIX_API_IO_H__
#define __FENNIX_API_IO_H__
@@ -9,201 +26,203 @@
extern "C"
{
#endif
- static inline uint8_t inportb(uint16_t Port)
- {
- uint8_t Result;
- __asm__("in %%dx, %%al"
- : "=a"(Result)
- : "d"(Port));
- return Result;
- }
- static inline uint16_t inportw(uint16_t Port)
- {
- uint16_t Result;
- __asm__("in %%dx, %%ax"
- : "=a"(Result)
- : "d"(Port));
- return Result;
- }
+ static inline uint8_t inportb(uint16_t Port)
+ {
+ uint8_t Result;
+ __asm__("in %%dx, %%al"
+ : "=a"(Result)
+ : "d"(Port));
+ return Result;
+ }
- static inline uint32_t inportl(uint16_t Port)
- {
- uint32_t Result;
- __asm__ volatile("inl %1, %0"
- : "=a"(Result)
- : "dN"(Port));
- return Result;
- }
+ static inline uint16_t inportw(uint16_t Port)
+ {
+ uint16_t Result;
+ __asm__("in %%dx, %%ax"
+ : "=a"(Result)
+ : "d"(Port));
+ return Result;
+ }
- static inline void outportb(uint16_t Port, uint8_t Data)
- {
- __asm__ volatile("out %%al, %%dx"
- :
- : "a"(Data), "d"(Port));
- }
+ static inline uint32_t inportl(uint16_t Port)
+ {
+ uint32_t Result;
+ __asm__ volatile("inl %1, %0"
+ : "=a"(Result)
+ : "dN"(Port));
+ return Result;
+ }
- static inline void outportw(uint16_t Port, uint16_t Data)
- {
- __asm__ volatile("out %%ax, %%dx"
- :
- : "a"(Data), "d"(Port));
- }
+ static inline void outportb(uint16_t Port, uint8_t Data)
+ {
+ __asm__ volatile("out %%al, %%dx"
+ :
+ : "a"(Data), "d"(Port));
+ }
- static inline void outportl(uint16_t Port, uint32_t Data)
- {
- __asm__ volatile("outl %1, %0"
- :
- : "dN"(Port), "a"(Data));
- }
+ static inline void outportw(uint16_t Port, uint16_t Data)
+ {
+ __asm__ volatile("out %%ax, %%dx"
+ :
+ : "a"(Data), "d"(Port));
+ }
- static inline uint8_t mmioin8(uint64_t Address)
- {
- __asm__ volatile("" ::
- : "memory");
- uint8_t Result = *(volatile uint8_t *)Address;
- __asm__ volatile("" ::
- : "memory");
- return Result;
- }
+ static inline void outportl(uint16_t Port, uint32_t Data)
+ {
+ __asm__ volatile("outl %1, %0"
+ :
+ : "dN"(Port), "a"(Data));
+ }
- static inline uint16_t mmioin16(uint64_t Address)
- {
- __asm__ volatile("" ::
- : "memory");
- uint16_t Result = *(volatile uint16_t *)Address;
- __asm__ volatile("" ::
- : "memory");
- return Result;
- }
+ static inline uint8_t mmioin8(uint64_t Address)
+ {
+ __asm__ volatile("" ::
+ : "memory");
+ uint8_t Result = *(volatile uint8_t *)Address;
+ __asm__ volatile("" ::
+ : "memory");
+ return Result;
+ }
- static inline uint32_t mmioin32(uint64_t Address)
- {
- __asm__ volatile("" ::
- : "memory");
- uint32_t Result = *(volatile uint32_t *)Address;
- __asm__ volatile("" ::
- : "memory");
- return Result;
- }
+ static inline uint16_t mmioin16(uint64_t Address)
+ {
+ __asm__ volatile("" ::
+ : "memory");
+ uint16_t Result = *(volatile uint16_t *)Address;
+ __asm__ volatile("" ::
+ : "memory");
+ return Result;
+ }
- static inline uint64_t mmioin64(uint64_t Address)
- {
- __asm__ volatile("" ::
- : "memory");
- uint64_t Result = *(volatile uint64_t *)Address;
- __asm__ volatile("" ::
- : "memory");
- return Result;
- }
+ static inline uint32_t mmioin32(uint64_t Address)
+ {
+ __asm__ volatile("" ::
+ : "memory");
+ uint32_t Result = *(volatile uint32_t *)Address;
+ __asm__ volatile("" ::
+ : "memory");
+ return Result;
+ }
- static inline void mmioout8(uint64_t Address, uint8_t Data)
- {
- __asm__ volatile("" ::
- : "memory");
- *(volatile uint8_t *)Address = Data;
- __asm__ volatile("" ::
- : "memory");
- }
+ static inline uint64_t mmioin64(uint64_t Address)
+ {
+ __asm__ volatile("" ::
+ : "memory");
+ uint64_t Result = *(volatile uint64_t *)Address;
+ __asm__ volatile("" ::
+ : "memory");
+ return Result;
+ }
- static inline void mmioout16(uint64_t Address, uint16_t Data)
- {
- __asm__ volatile("" ::
- : "memory");
- *(volatile uint16_t *)Address = Data;
- __asm__ volatile("" ::
- : "memory");
- }
+ static inline void mmioout8(uint64_t Address, uint8_t Data)
+ {
+ __asm__ volatile("" ::
+ : "memory");
+ *(volatile uint8_t *)Address = Data;
+ __asm__ volatile("" ::
+ : "memory");
+ }
- static inline void mmioout32(uint64_t Address, uint32_t Data)
- {
- __asm__ volatile("" ::
- : "memory");
- *(volatile uint32_t *)Address = Data;
- __asm__ volatile("" ::
- : "memory");
- }
+ static inline void mmioout16(uint64_t Address, uint16_t Data)
+ {
+ __asm__ volatile("" ::
+ : "memory");
+ *(volatile uint16_t *)Address = Data;
+ __asm__ volatile("" ::
+ : "memory");
+ }
- static inline void mmioout64(uint64_t Address, uint64_t Data)
- {
- __asm__ volatile("" ::
- : "memory");
- *(volatile uint64_t *)Address = Data;
- __asm__ volatile("" ::
- : "memory");
- }
+ static inline void mmioout32(uint64_t Address, uint32_t Data)
+ {
+ __asm__ volatile("" ::
+ : "memory");
+ *(volatile uint32_t *)Address = Data;
+ __asm__ volatile("" ::
+ : "memory");
+ }
- static inline void mmoutb(void *Address, uint8_t Value)
- {
- __asm__ volatile("mov %1, %0"
- : "=m"((*(uint8_t *)(Address)))
- : "r"(Value)
- : "memory");
- }
+ static inline void mmioout64(uint64_t Address, uint64_t Data)
+ {
+ __asm__ volatile("" ::
+ : "memory");
+ *(volatile uint64_t *)Address = Data;
+ __asm__ volatile("" ::
+ : "memory");
+ }
- static inline void mmoutw(void *Address, uint16_t Value)
- {
- __asm__ volatile("mov %1, %0"
- : "=m"((*(uint16_t *)(Address)))
- : "r"(Value)
- : "memory");
- }
+ static inline void mmoutb(void *Address, uint8_t Value)
+ {
+ __asm__ volatile("mov %1, %0"
+ : "=m"((*(uint8_t *)(Address)))
+ : "r"(Value)
+ : "memory");
+ }
- static inline void mmoutl(void *Address, uint32_t Value)
- {
- __asm__ volatile("mov %1, %0"
- : "=m"((*(uint32_t *)(Address)))
- : "r"(Value)
- : "memory");
- }
+ static inline void mmoutw(void *Address, uint16_t Value)
+ {
+ __asm__ volatile("mov %1, %0"
+ : "=m"((*(uint16_t *)(Address)))
+ : "r"(Value)
+ : "memory");
+ }
- static inline void mmoutq(void *Address, uint64_t Value)
- {
- __asm__ volatile("mov %1, %0"
- : "=m"((*(uint64_t *)(Address)))
- : "r"(Value)
- : "memory");
- }
+ static inline void mmoutl(void *Address, uint32_t Value)
+ {
+ __asm__ volatile("mov %1, %0"
+ : "=m"((*(uint32_t *)(Address)))
+ : "r"(Value)
+ : "memory");
+ }
- static inline uint8_t mminb(void *Address)
- {
- uint8_t Result;
- __asm__ volatile("mov %1, %0"
- : "=r"(Result)
- : "m"((*(uint8_t *)(Address)))
- : "memory");
- return Result;
- }
+ static inline void mmoutq(void *Address, uint64_t Value)
+ {
+ __asm__ volatile("mov %1, %0"
+ : "=m"((*(uint64_t *)(Address)))
+ : "r"(Value)
+ : "memory");
+ }
- static inline uint16_t mminw(void *Address)
- {
- uint16_t Result;
- __asm__ volatile("mov %1, %0"
- : "=r"(Result)
- : "m"((*(uint16_t *)(Address)))
- : "memory");
- return Result;
- }
+ static inline uint8_t mminb(void *Address)
+ {
+ uint8_t Result;
+ __asm__ volatile("mov %1, %0"
+ : "=r"(Result)
+ : "m"((*(uint8_t *)(Address)))
+ : "memory");
+ return Result;
+ }
- static inline uint32_t mminl(void *Address)
- {
- uint32_t Result;
- __asm__ volatile("mov %1, %0"
- : "=r"(Result)
- : "m"((*(uint32_t *)(Address)))
- : "memory");
- return Result;
- }
+ static inline uint16_t mminw(void *Address)
+ {
+ uint16_t Result;
+ __asm__ volatile("mov %1, %0"
+ : "=r"(Result)
+ : "m"((*(uint16_t *)(Address)))
+ : "memory");
+ return Result;
+ }
+
+ static inline uint32_t mminl(void *Address)
+ {
+ uint32_t Result;
+ __asm__ volatile("mov %1, %0"
+ : "=r"(Result)
+ : "m"((*(uint32_t *)(Address)))
+ : "memory");
+ return Result;
+ }
+
+ static inline uint64_t mminq(void *Address)
+ {
+ uint64_t Result;
+ __asm__ volatile("mov %1, %0"
+ : "=r"(Result)
+ : "m"((*(uint64_t *)(Address)))
+ : "memory");
+ return Result;
+ }
- static inline uint64_t mminq(void *Address)
- {
- uint64_t Result;
- __asm__ volatile("mov %1, %0"
- : "=r"(Result)
- : "m"((*(uint64_t *)(Address)))
- : "memory");
- return Result;
- }
#ifdef __cplusplus
}
#endif
diff --git a/include/net.h b/include/net.h
new file mode 100644
index 0000000..42ca0de
--- /dev/null
+++ b/include/net.h
@@ -0,0 +1,47 @@
+/*
+ This file is part of Fennix Drivers.
+
+ Fennix Drivers is free software: you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation, either version 3 of
+ the License, or (at your option) any later version.
+
+ Fennix Drivers is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Fennix Drivers. If not, see .
+*/
+
+#ifndef __FENNIX_API_AUDIO_H__
+#define __FENNIX_API_AUDIO_H__
+
+#include
+#include
+
+typedef int (*drvOpen_t)(dev_t, dev_t, int, mode_t);
+typedef int (*drvClose_t)(dev_t, dev_t);
+typedef size_t (*drvRead_t)(dev_t, dev_t, uint8_t *, size_t, off_t);
+typedef size_t (*drvWrite_t)(dev_t, dev_t, uint8_t *, size_t, off_t);
+typedef int (*drvIoctl_t)(dev_t, dev_t, unsigned long, void *);
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif // __cplusplus
+
+ dev_t RegisterNetDevice(DeviceDriverType Type,
+ drvOpen_t Open, drvClose_t Close,
+ drvRead_t Read, drvWrite_t Write, drvIoctl_t Ioctl);
+
+ int UnregisterNetDevice(dev_t DeviceID, DeviceDriverType Type);
+
+ int ReportNetworkPacket(dev_t DeviceID, void *Buffer, size_t Size);
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif // !__FENNIX_API_AUDIO_H__
diff --git a/include/netools.h b/include/netools.h
index 7f92626..3e795fd 100644
--- a/include/netools.h
+++ b/include/netools.h
@@ -1,3 +1,20 @@
+/*
+ This file is part of Fennix Drivers.
+
+ Fennix Drivers is free software: you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation, either version 3 of
+ the License, or (at your option) any later version.
+
+ Fennix Drivers is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Fennix Drivers. If not, see .
+*/
+
#ifndef __FENNIX_API_NETWORK_UTILS_H__
#define __FENNIX_API_NETWORK_UTILS_H__
diff --git a/include/pci.h b/include/pci.h
index 0751259..a307cf7 100644
--- a/include/pci.h
+++ b/include/pci.h
@@ -1,3 +1,20 @@
+/*
+ This file is part of Fennix Drivers.
+
+ Fennix Drivers is free software: you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation, either version 3 of
+ the License, or (at your option) any later version.
+
+ Fennix Drivers is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Fennix Drivers. If not, see .
+*/
+
#ifndef __FENNIX_API_PCI_H__
#define __FENNIX_API_PCI_H__
@@ -6,123 +23,162 @@
/* https://sites.uclouvain.be/SystInfo/usr/include/linux/pci_regs.h.html */
enum PCICommands
{
- /** @brief Enable response in I/O space */
- PCI_COMMAND_IO = 0x1,
- /** @brief Enable response in Memory space */
- PCI_COMMAND_MEMORY = 0x2,
- /** @brief Enable bus mastering */
- PCI_COMMAND_MASTER = 0x4,
- /** @brief Enable response to special cycles */
- PCI_COMMAND_SPECIAL = 0x8,
- /** @brief Use memory write and invalidate */
- PCI_COMMAND_INVALIDATE = 0x10,
- /** @brief Enable palette snooping */
- PCI_COMMAND_VGA_PALETTE = 0x20,
- /** @brief Enable parity checking */
- PCI_COMMAND_PARITY = 0x40,
- /** @brief Enable address/data stepping */
- PCI_COMMAND_WAIT = 0x80,
- /** @brief Enable SERR */
- PCI_COMMAND_SERR = 0x100,
- /** @brief Enable back-to-back writes */
- PCI_COMMAND_FAST_BACK = 0x200,
- /** @brief INTx Emulation Disable */
- PCI_COMMAND_INTX_DISABLE = 0x400
+ /** @brief Enable response in I/O space */
+ PCI_COMMAND_IO = 0x1,
+ /** @brief Enable response in Memory space */
+ PCI_COMMAND_MEMORY = 0x2,
+ /** @brief Enable bus mastering */
+ PCI_COMMAND_MASTER = 0x4,
+ /** @brief Enable response to special cycles */
+ PCI_COMMAND_SPECIAL = 0x8,
+ /** @brief Use memory write and invalidate */
+ PCI_COMMAND_INVALIDATE = 0x10,
+ /** @brief Enable palette snooping */
+ PCI_COMMAND_VGA_PALETTE = 0x20,
+ /** @brief Enable parity checking */
+ PCI_COMMAND_PARITY = 0x40,
+ /** @brief Enable address/data stepping */
+ PCI_COMMAND_WAIT = 0x80,
+ /** @brief Enable SERR */
+ PCI_COMMAND_SERR = 0x100,
+ /** @brief Enable back-to-back writes */
+ PCI_COMMAND_FAST_BACK = 0x200,
+ /** @brief INTx Emulation Disable */
+ PCI_COMMAND_INTX_DISABLE = 0x400
};
-struct PCIDeviceHeader
+typedef struct
{
- uint16_t VendorID;
- uint16_t DeviceID;
- uint16_t Command;
- uint16_t Status;
- uint8_t RevisionID;
- uint8_t ProgIF;
- uint8_t Subclass;
- uint8_t Class;
- uint8_t CacheLineSize;
- uint8_t LatencyTimer;
- uint8_t HeaderType;
- uint8_t BIST;
-};
+ uint16_t VendorID;
+ uint16_t DeviceID;
+ uint16_t Command;
+ uint16_t Status;
+ uint8_t RevisionID;
+ uint8_t ProgIF;
+ uint8_t Subclass;
+ uint8_t Class;
+ uint8_t CacheLineSize;
+ uint8_t LatencyTimer;
+ uint8_t HeaderType;
+ uint8_t BIST;
+} __attribute__((packed)) PCIDeviceHeader;
-struct PCIHeader0
+typedef struct
{
- PCIDeviceHeader Header;
- uint32_t BAR0;
- uint32_t BAR1;
- uint32_t BAR2;
- uint32_t BAR3;
- uint32_t BAR4;
- uint32_t BAR5;
- uint32_t CardbusCISPointer;
- uint16_t SubsystemVendorID;
- uint16_t SubsystemID;
- uint32_t ExpansionROMBaseAddress;
- uint8_t CapabilitiesPointer;
- uint8_t Reserved0;
- uint16_t Reserved1;
- uint32_t Reserved2;
- uint8_t InterruptLine;
- uint8_t InterruptPin;
- uint8_t MinGrant;
- uint8_t MaxLatency;
-};
+ PCIDeviceHeader Header;
+ uint32_t BAR0;
+ uint32_t BAR1;
+ uint32_t BAR2;
+ uint32_t BAR3;
+ uint32_t BAR4;
+ uint32_t BAR5;
+ uint32_t CardbusCISPointer;
+ uint16_t SubsystemVendorID;
+ uint16_t SubsystemID;
+ uint32_t ExpansionROMBaseAddress;
+ uint8_t CapabilitiesPointer;
+ uint8_t Reserved0;
+ uint16_t Reserved1;
+ uint32_t Reserved2;
+ uint8_t InterruptLine;
+ uint8_t InterruptPin;
+ uint8_t MinGrant;
+ uint8_t MaxLatency;
+} __attribute__((packed)) PCIHeader0;
-struct PCIHeader1
+typedef struct
{
- PCIDeviceHeader Header;
- uint32_t BAR0;
- uint32_t BAR1;
- uint8_t PrimaryBusNumber;
- uint8_t SecondaryBusNumber;
- uint8_t SubordinateBusNumber;
- uint8_t SecondaryLatencyTimer;
- uint8_t IOBase;
- uint8_t IOLimit;
- uint16_t SecondaryStatus;
- uint16_t MemoryBase;
- uint16_t MemoryLimit;
- uint16_t PrefetchableMemoryBase;
- uint16_t PrefetchableMemoryLimit;
- uint32_t PrefetchableMemoryBaseUpper32;
- uint32_t PrefetchableMemoryLimitUpper32;
- uint16_t IOBaseUpper16;
- uint16_t IOLimitUpper16;
- uint8_t CapabilitiesPointer;
- uint8_t Reserved0;
- uint16_t Reserved1;
- uint32_t ExpansionROMBaseAddress;
- uint8_t InterruptLine;
- uint8_t InterruptPin;
- uint16_t BridgeControl;
-};
+ PCIDeviceHeader Header;
+ uint32_t BAR0;
+ uint32_t BAR1;
+ uint8_t PrimaryBusNumber;
+ uint8_t SecondaryBusNumber;
+ uint8_t SubordinateBusNumber;
+ uint8_t SecondaryLatencyTimer;
+ uint8_t IOBase;
+ uint8_t IOLimit;
+ uint16_t SecondaryStatus;
+ uint16_t MemoryBase;
+ uint16_t MemoryLimit;
+ uint16_t PrefetchableMemoryBase;
+ uint16_t PrefetchableMemoryLimit;
+ uint32_t PrefetchableMemoryBaseUpper32;
+ uint32_t PrefetchableMemoryLimitUpper32;
+ uint16_t IOBaseUpper16;
+ uint16_t IOLimitUpper16;
+ uint8_t CapabilitiesPointer;
+ uint8_t Reserved0;
+ uint16_t Reserved1;
+ uint32_t ExpansionROMBaseAddress;
+ uint8_t InterruptLine;
+ uint8_t InterruptPin;
+ uint16_t BridgeControl;
+} __attribute__((packed)) PCIHeader1;
-struct PCIHeader2
+typedef struct
{
- PCIDeviceHeader Header;
- uint32_t CardbusSocketRegistersBaseAddress;
- uint8_t CapabilitiesPointer;
- uint8_t Reserved0;
- uint16_t SecondaryStatus;
- uint8_t PCIbusNumber;
- uint8_t CardbusBusNumber;
- uint8_t SubordinateBusNumber;
- uint8_t CardbusLatencyTimer;
- uint32_t MemoryBase0;
- uint32_t MemoryLimit0;
- uint32_t MemoryBase1;
- uint32_t MemoryLimit1;
- uint32_t IOBase0;
- uint32_t IOLimit0;
- uint32_t IOBase1;
- uint32_t IOLimit1;
- uint8_t InterruptLine;
- uint8_t InterruptPin;
- uint16_t BridgeControl;
- uint16_t SubsystemVendorID;
- uint16_t SubsystemID;
- uint32_t LegacyBaseAddress;
-};
+ PCIDeviceHeader Header;
+ uint32_t CardbusSocketRegistersBaseAddress;
+ uint8_t CapabilitiesPointer;
+ uint8_t Reserved0;
+ uint16_t SecondaryStatus;
+ uint8_t PCIbusNumber;
+ uint8_t CardbusBusNumber;
+ uint8_t SubordinateBusNumber;
+ uint8_t CardbusLatencyTimer;
+ uint32_t MemoryBase0;
+ uint32_t MemoryLimit0;
+ uint32_t MemoryBase1;
+ uint32_t MemoryLimit1;
+ uint32_t IOBase0;
+ uint32_t IOLimit0;
+ uint32_t IOBase1;
+ uint32_t IOLimit1;
+ uint8_t InterruptLine;
+ uint8_t InterruptPin;
+ uint16_t BridgeControl;
+ uint16_t SubsystemVendorID;
+ uint16_t SubsystemID;
+ uint32_t LegacyBaseAddress;
+} __attribute__((packed)) PCIHeader2;
+
+typedef struct
+{
+ uint64_t BaseAddress;
+ uint16_t PCISegGroup;
+ uint8_t StartBus;
+ uint8_t EndBus;
+ uint32_t Reserved;
+} __attribute__((packed)) DeviceConfig;
+
+typedef struct
+{
+ PCIDeviceHeader *Header;
+ DeviceConfig *Config;
+ uint32_t Bus;
+ uint32_t Device;
+ uint32_t Function;
+} __attribute__((packed)) PCIDevice;
+
+typedef struct
+{
+ PCIDevice *Device;
+ /* PCIArray */ void *Next;
+} __attribute__((packed)) PCIArray;
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+ PCIArray *FindPCIDevices(uint16_t Vendors[], uint16_t Devices[]);
+ void InitializePCI(PCIDevice *Device);
+ uint32_t GetBAR(uint8_t Index, PCIDevice *Device);
+ uint8_t iLine(PCIDevice *Device);
+ uint8_t iPin(PCIDevice *Device);
+
+#ifdef __cplusplus
+}
+#endif
#endif // !__FENNIX_API_PCI_H__
diff --git a/include/regs.h b/include/regs.h
new file mode 100644
index 0000000..c731529
--- /dev/null
+++ b/include/regs.h
@@ -0,0 +1,100 @@
+/*
+ This file is part of Fennix Drivers.
+
+ Fennix Drivers is free software: you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation, either version 3 of
+ the License, or (at your option) any later version.
+
+ Fennix Drivers is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Fennix Drivers. If not, see .
+*/
+
+#ifndef __FENNIX_API_REGISTERS_H__
+#define __FENNIX_API_REGISTERS_H__
+
+#include
+
+#if defined(__amd64__)
+typedef struct
+{
+ uint64_t r15; // General purpose
+ uint64_t r14; // General purpose
+ uint64_t r13; // General purpose
+ uint64_t r12; // General purpose
+ uint64_t r11; // General purpose
+ uint64_t r10; // General purpose
+ uint64_t r9; // General purpose
+ uint64_t r8; // General purpose
+
+ uint64_t rbp; // Base Pointer (meant for stack frames)
+ uint64_t rdi; // Destination index for string operations
+ uint64_t rsi; // Source index for string operations
+ uint64_t rdx; // Data (commonly extends the A register)
+ uint64_t rcx; // Counter
+ uint64_t rbx; // Base
+ uint64_t rax; // Accumulator
+
+ uint64_t InterruptNumber; // Interrupt Number
+ uint64_t ErrorCode; // Error code
+
+ uint64_t rip; // Instruction Pointer
+ uint64_t cs; // Code Segment
+ uint64_t rflags; // Register Flags
+ uint64_t rsp; // Stack Pointer
+ uint64_t ss; // Stack Segment
+} TrapFrame;
+#elif defined(__i386__)
+typedef struct TrapFrame
+{
+ uint32_t edi; // Destination index for string operations
+ uint32_t esi; // Source index for string operations
+ uint32_t ebp; // Base Pointer (meant for stack frames)
+ uint32_t esp; // Stack Pointer
+ uint32_t ebx; // Base
+ uint32_t edx; // Data (commonly extends the A register)
+ uint32_t ecx; // Counter
+ uint32_t eax; // Accumulator
+
+ uint32_t InterruptNumber; // Interrupt Number
+ uint32_t ErrorCode; // Error code
+
+ uint32_t eip; // Instruction Pointer
+ uint32_t cs; // Code Segment
+ uint32_t eflags; // Register Flags
+
+ uint32_t r3_esp; // Stack Pointer
+ uint32_t r3_ss; // Stack Segment
+} TrapFrame;
+#elif defined(__aarch64__)
+typedef struct TrapFrame
+{
+ uint64_t x19; // General purpose
+ uint64_t x20; // General purpose
+ uint64_t x21; // General purpose
+ uint64_t x22; // General purpose
+ uint64_t x23; // General purpose
+ uint64_t x24; // General purpose
+ uint64_t x25; // General purpose
+ uint64_t x26; // General purpose
+
+ uint64_t x27; // Stack frame pointer
+ uint64_t x28; // Link register
+ uint64_t x29; // Frame pointer
+ uint64_t x30; // Program counter
+
+ uint64_t sp_el0; // Stack pointer
+ uint64_t elr_el1; // Exception Link Register
+ uint64_t spsr_el1; // Saved Program Status Register
+ uint64_t ErrorCode /* esr_el1 */; // Exception Syndrome Register
+
+ uint64_t InterruptNumber /* iar_el1 */; // Interrupt Acknowledge Register
+} TrapFrame;
+#endif
+
+#endif // !__FENNIX_API_REGISTERS_H__
diff --git a/include/syscall.h b/include/syscall.h
new file mode 100644
index 0000000..1fdf92a
--- /dev/null
+++ b/include/syscall.h
@@ -0,0 +1,231 @@
+/*
+ BSD 3-Clause License
+
+ Copyright (c) 2023, EnderIce2
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ 3. Neither the name of the copyright holder nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef __FENNIX_KERNEL_SYSCALLS_LIST_H__
+#define __FENNIX_KERNEL_SYSCALLS_LIST_H__
+
+/* mmap */
+
+#define sc_PROT_NONE 0
+#define sc_PROT_READ 1
+#define sc_PROT_WRITE 2
+#define sc_PROT_EXEC 4
+
+#define sc_MAP_SHARED 1
+#define sc_MAP_PRIVATE 2
+#define sc_MAP_FIXED 4
+#define sc_MAP_ANONYMOUS 8
+
+/* lseek */
+
+#define sc_SEEK_SET 0
+#define sc_SEEK_CUR 1
+#define sc_SEEK_END 2
+
+/**
+ * Enumeration of all the native syscalls
+ * available in the kernel
+ */
+typedef enum
+{
+ /**
+ * This syscall is used to exit the current
+ * process with the provided exit code.
+ *
+ * @fn void exit(int status);
+ *
+ * @param Code The exit code
+ * @return This syscall does not return
+ *
+ * @note No permissions are required to call
+ * this syscall
+ */
+ sc_exit = 0,
+
+ /**
+ * Map pages of memory
+ *
+ * @fn void *mmap(void *addr, size_t len, int prot, int flags, int fildes, off_t off);
+ */
+ sc_mmap,
+
+ /**
+ * Unmap pages of memory
+ *
+ * @fn int munmap(void *addr, size_t len);
+ */
+ sc_munmap,
+
+ /**
+ * Change the protection of a page of memory
+ *
+ * @fn int mprotect(void *addr, size_t len, int prot);
+ */
+ sc_mprotect,
+
+ /**
+ * Open a file
+ *
+ * @fn int open(const char *path, int oflag, ... );
+ */
+ sc_open,
+
+ /**
+ * Close a file descriptor
+ *
+ * @fn int close(int fildes);
+ */
+ sc_close,
+
+ /**
+ * Read from a file descriptor
+ *
+ * @fn ssize_t read(int fildes, void *buf, size_t nbyte);
+ */
+ sc_read,
+
+ /**
+ * Write to a file descriptor
+ *
+ * @fn ssize_t write(int fildes, const void *buf, size_t nbyte);
+ */
+ sc_write,
+
+ /**
+ * Seek to a position in a file descriptor
+ *
+ * @fn off_t lseek(int fildes, off_t offset, int whence);
+ */
+ sc_lseek,
+
+ /**
+ * Create a new process
+ *
+ * @fn pid_t fork(void);
+ */
+ sc_fork,
+
+ /** Not a real syscall */
+ sc_MaxSyscall
+} NativeSyscalls;
+
+#ifndef syscall0
+static inline long syscall0(long syscall)
+{
+ long ret;
+ __asm__ __volatile__("syscall"
+ : "=a"(ret)
+ : "a"(syscall)
+ : "rcx", "r11", "memory");
+ return ret;
+}
+#endif
+
+#ifndef syscall1
+static inline long syscall1(long syscall, long arg1)
+{
+ long ret;
+ __asm__ __volatile__("syscall"
+ : "=a"(ret)
+ : "a"(syscall), "D"(arg1)
+ : "rcx", "r11", "memory");
+ return ret;
+}
+#endif
+
+#ifndef syscall2
+static inline long syscall2(long syscall, long arg1, long arg2)
+{
+ long ret;
+ __asm__ __volatile__("syscall"
+ : "=a"(ret)
+ : "a"(syscall), "D"(arg1), "S"(arg2)
+ : "rcx", "r11", "memory");
+ return ret;
+}
+#endif
+
+#ifndef syscall3
+static inline long syscall3(long syscall, long arg1, long arg2, long arg3)
+{
+ long ret;
+ __asm__ __volatile__("syscall"
+ : "=a"(ret)
+ : "a"(syscall), "D"(arg1), "S"(arg2), "d"(arg3)
+ : "rcx", "r11", "memory");
+ return ret;
+}
+#endif
+
+#ifndef syscall4
+static inline long syscall4(long syscall, long arg1, long arg2, long arg3, long arg4)
+{
+ long ret;
+ register long r10 __asm__("r10") = arg4;
+ __asm__ __volatile__("syscall"
+ : "=a"(ret)
+ : "a"(syscall), "D"(arg1), "S"(arg2), "d"(arg3), "r"(r10)
+ : "rcx", "r11", "memory");
+ return ret;
+}
+#endif
+
+#ifndef syscall5
+static inline long syscall5(long syscall, long arg1, long arg2, long arg3, long arg4, long arg5)
+{
+ long ret;
+ register long r10 __asm__("r10") = arg4;
+ register long r8 __asm__("r8") = arg5;
+ __asm__ __volatile__("syscall"
+ : "=a"(ret)
+ : "a"(syscall), "D"(arg1), "S"(arg2), "d"(arg3), "r"(r10), "r"(r8)
+ : "rcx", "r11", "memory");
+ return ret;
+}
+#endif
+
+#ifndef syscall6
+static inline long syscall6(long syscall, long arg1, long arg2, long arg3, long arg4, long arg5, long arg6)
+{
+ long ret;
+ register long r10 __asm__("r10") = arg4;
+ register long r8 __asm__("r8") = arg5;
+ register long r9 __asm__("r9") = arg6;
+ __asm__ __volatile__("syscall"
+ : "=a"(ret)
+ : "a"(syscall), "D"(arg1), "S"(arg2), "d"(arg3), "r"(r10), "r"(r8), "r"(r9)
+ : "rcx", "r11", "memory");
+ return ret;
+}
+#endif
+
+#endif // !__FENNIX_KERNEL_SYSCALLS_LIST_H__
diff --git a/include/types.h b/include/types.h
index b0eecc2..f9a717d 100644
--- a/include/types.h
+++ b/include/types.h
@@ -1,3 +1,20 @@
+/*
+ This file is part of Fennix Drivers.
+
+ Fennix Drivers is free software: you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation, either version 3 of
+ the License, or (at your option) any later version.
+
+ Fennix Drivers is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Fennix Drivers. If not, see .
+*/
+
#ifndef __FENNIX_API_TYPES_H__
#define __FENNIX_API_TYPES_H__
@@ -37,6 +54,58 @@ typedef __UINTMAX_TYPE__ uintmax_t;
typedef __PTRDIFF_TYPE__ ptrdiff_t;
typedef __SIZE_TYPE__ size_t;
+typedef __SIZE_TYPE__ dev_t;
+typedef __SIZE_TYPE__ off_t;
+typedef __INT32_TYPE__ mode_t;
+typedef int pid_t;
+
#define UNUSED(x) (void)(x)
+#ifdef __cplusplus
+#define EXTERNC extern "C"
+#define NULL 0
+#else // __cplusplus
+#define NULL ((void *)0)
+#define bool _Bool
+#define EXTERNC
+#endif // __cplusplus
+
+#define true 1
+#define false 0
+
+#define likely(x) __builtin_expect(!!(x), 1)
+#define unlikely(x) __builtin_expect(!!(x), 0)
+
+#define MAX(a, b) \
+ ({ \
+ __typeof__(a) _a = (a); \
+ __typeof__(b) _b = (b); \
+ _a > _b ? _a : _b; \
+ })
+
+#define MIN(a, b) \
+ ({ \
+ __typeof__(a) _a = (a); \
+ __typeof__(b) _b = (b); \
+ _a < _b ? _a : _b; \
+ })
+
+#ifndef __va_list__
+typedef __builtin_va_list va_list;
+#endif
+
+#define asm __asm__
+#define asmv __asm__ volatile
+
+#if __STDC_VERSION__ >= 201112L && !defined(__cplusplus)
+#define static_assert _Static_assert
+#endif
+
+#define va_start(v, l) __builtin_va_start(v, l)
+#define va_end(v) __builtin_va_end(v)
+#define va_arg(v, l) __builtin_va_arg(v, l)
+
+#define TO_PAGES(d) (((d) + PAGE_SIZE - 1) / PAGE_SIZE)
+#define FROM_PAGES(d) ((d) * PAGE_SIZE)
+
#endif // !__FENNIX_API_TYPES_H__
diff --git a/include/vm.h b/include/vm.h
new file mode 100644
index 0000000..a90ad18
--- /dev/null
+++ b/include/vm.h
@@ -0,0 +1,25 @@
+/*
+ This file is part of Fennix Drivers.
+
+ Fennix Drivers is free software: you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation, either version 3 of
+ the License, or (at your option) any later version.
+
+ Fennix Drivers is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Fennix Drivers. If not, see .
+*/
+
+#ifndef __FENNIX_API_VM_H__
+#define __FENNIX_API_VM_H__
+
+#include
+
+bool IsVMwareBackdoorAvailable();
+
+#endif // !__FENNIX_API_VM_H__
diff --git a/input/Makefile b/input/Makefile
new file mode 100644
index 0000000..4279619
--- /dev/null
+++ b/input/Makefile
@@ -0,0 +1,5 @@
+build:
+ make -C aip build
+
+clean:
+ make -C aip clean
diff --git a/input/aip/Makefile b/input/aip/Makefile
new file mode 100644
index 0000000..0c529af
--- /dev/null
+++ b/input/aip/Makefile
@@ -0,0 +1,83 @@
+# Config file
+include ../../../Makefile.conf
+
+FILENAME = aip.drv
+
+CC = ../../../$(COMPILER_PATH)/$(COMPILER_ARCH)gcc
+CPP = ../../../$(COMPILER_PATH)/$(COMPILER_ARCH)g++
+LD = ../../../$(COMPILER_PATH)/$(COMPILER_ARCH)ld
+AS = ../../../$(COMPILER_PATH)/$(COMPILER_ARCH)as
+OBJDUMP = ../../../$(COMPILER_PATH)/$(COMPILER_ARCH)objdump
+
+S_SOURCES = $(shell find ./ -type f -name '*.S')
+C_SOURCES = $(shell find ./ -type f -name '*.c')
+CPP_SOURCES = $(shell find ./ -type f -name '*.cpp')
+HEADERS = $(sort $(dir $(wildcard ../../include/*)))
+OBJ = $(C_SOURCES:.c=.o) $(CPP_SOURCES:.cpp=.o) $(ASM_SOURCES:.asm=.o) $(S_SOURCES:.S=.o) $(PSF_SOURCES:.psf=.o) $(BMP_SOURCES:.bmp=.o)
+STACK_USAGE_OBJ = $(C_SOURCES:.c=.su) $(CPP_SOURCES:.cpp=.su)
+INCLUDE_DIR = ../../include
+
+LIBS := ../../out/dcrt0.o -L../../out -ldriver
+
+LDFLAGS := \
+ -fPIC -fPIE -pie \
+ -Wl,--no-dynamic-linker,-ztext,--no-warn-rwx-segment \
+ -nostdlib -nodefaultlibs -nolibc \
+ -zmax-page-size=0x1000 \
+ -Wl,-Map file.map -shared -fvisibility=hidden
+
+WARNCFLAG = -Wall -Wextra
+
+CFLAGS := -I$(INCLUDE_DIR) -fvisibility=hidden
+
+ifeq ($(OSARCH), amd64)
+
+CFLAGS += -fPIC -fPIE -pie -mno-80387 -mno-mmx -mno-3dnow \
+ -mno-red-zone -mno-sse -mno-sse2 \
+ -march=x86-64 -pipe -ffunction-sections \
+ -msoft-float -fno-builtin
+
+else ifeq ($(OSARCH), i386)
+
+CFLAGS += -fPIC -fPIE -pie -mno-80387 -mno-mmx -mno-3dnow \
+ -mno-red-zone -mno-sse -mno-sse2 -ffunction-sections \
+ -march=i386 -pipe -msoft-float -fno-builtin
+
+else ifeq ($(OSARCH), aarch64)
+
+CFLAGS += -pipe -fno-builtin -fPIC
+
+endif
+
+ifeq ($(DEBUG), 1)
+ CFLAGS += -DDEBUG -ggdb3 -O0 -fdiagnostics-color=always -fstack-usage
+ifeq ($(OSARCH), amd64)
+ CFLAGS += -fverbose-asm
+endif
+ifneq ($(OSARCH), aarch64)
+ CFLAGS += -fstack-check
+endif
+ LDFLAGS += -ggdb3 -O0
+endif
+
+build: $(FILENAME)
+ mv $(FILENAME) ../../out/$(FILENAME)
+
+$(FILENAME): $(OBJ)
+ $(info Linking $@)
+ $(CC) $(LDFLAGS) $(OBJ) $(LIBS) -o $@
+
+%.o: %.c $(HEADERS)
+ $(info Compiling $<)
+ $(CC) $(CFLAGS) $(WARNCFLAG) -std=c17 -c $< -o $@
+
+%.o: %.cpp $(HEADERS)
+ $(info Compiling $<)
+ $(CPP) $(CFLAGS) $(WARNCFLAG) -std=c++20 -fno-exceptions -fno-rtti -c $< -o $@
+
+%.o: %.S
+ $(info Compiling $<)
+ $(AS) -o $@ $<
+
+clean:
+ rm -f file.map $(OBJ) $(STACK_USAGE_OBJ)
diff --git a/input/aip/aip.h b/input/aip/aip.h
new file mode 100644
index 0000000..95ea010
--- /dev/null
+++ b/input/aip/aip.h
@@ -0,0 +1,38 @@
+/*
+ This file is part of Fennix Drivers.
+
+ Fennix Drivers is free software: you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation, either version 3 of
+ the License, or (at your option) any later version.
+
+ Fennix Drivers is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Fennix Drivers. If not, see .
+*/
+
+#ifndef __FENNIX_DRIVER_AIP_H__
+#define __FENNIX_DRIVER_AIP_H__
+
+#include
+#include
+#include
+
+extern uint8_t Device1ID[];
+extern uint8_t Device2ID[];
+
+void PS2KbdInterruptHandler(TrapFrame *);
+int InitializeKeyboard();
+int FinalizeKeyboard();
+int DetectPS2Keyboard();
+
+void PS2MouseInterruptHandler(TrapFrame *);
+int InitializeMouse();
+int FinalizeMouse();
+int DetectPS2Mouse();
+
+#endif // !__FENNIX_DRIVER_AIP_H__
diff --git a/input/aip/keyboard.c b/input/aip/keyboard.c
new file mode 100644
index 0000000..7f2c165
--- /dev/null
+++ b/input/aip/keyboard.c
@@ -0,0 +1,309 @@
+/*
+ This file is part of Fennix Drivers.
+
+ Fennix Drivers is free software: you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation, either version 3 of
+ the License, or (at your option) any later version.
+
+ Fennix Drivers is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Fennix Drivers. If not, see .
+*/
+
+#include "aip.h"
+
+#include
+#include
+#include
+#include
+#include
+
+uint8_t KeyboardScanCodeSet = 0;
+dev_t KeyboardDevID = -1;
+
+const unsigned short ScanCodeSet1[] =
+ {KEY_NULL, KEY_ESCAPE,
+ 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_LEFT_BRACKET, KEY_RIGHT_BRACKET, KEY_RETURN, KEY_LEFT_CTRL,
+ KEY_A, KEY_S, KEY_D, KEY_F, KEY_G, KEY_H, KEY_J, KEY_K, KEY_L,
+ KEY_SEMICOLON, KEY_APOSTROPHE, KEY_BACK_TICK, KEY_LEFT_SHIFT, KEY_BACKSLASH,
+ KEY_Z, KEY_X, KEY_C, KEY_V, KEY_B, KEY_N, KEY_M,
+ KEY_COMMA, KEY_PERIOD, KEY_SLASH, KEY_RIGHT_SHIFT,
+ KEYPAD_ASTERISK, KEY_LEFT_ALT, KEY_SPACE, KEY_CAPS_LOCK,
+ KEY_F1, KEY_F2, KEY_F3, KEY_F4, KEY_F5, KEY_F6, KEY_F7, KEY_F8, KEY_F9, KEY_F10,
+ KEY_NUM_LOCK, KEY_SCROLL_LOCK,
+ KEYPAD_7, KEYPAD_8, KEYPAD_9, KEYPAD_MINUS,
+ KEYPAD_4, KEYPAD_5, KEYPAD_6, KEYPAD_PLUS,
+ KEYPAD_1, KEYPAD_2, KEYPAD_3, KEYPAD_0, KEYPAD_PERIOD,
+ KEY_NULL, KEY_NULL, KEY_NULL,
+ KEY_F11, KEY_F12};
+
+const unsigned short ScanCodeSet1mm[] = {
+ [0x10] = KEY_MULTIMEDIA_PREV_TRACK,
+ [0x19] = KEY_MULTIMEDIA_NEXT_TRACK,
+ [0x1C] = KEYPAD_RETURN,
+ [0x1D] = KEY_RIGHT_CTRL,
+ [0x20] = KEY_MULTIMEDIA_MUTE,
+ [0x21] = KEY_MULTIMEDIA_CALCULATOR,
+ [0x22] = KEY_MULTIMEDIA_PLAY,
+ [0x24] = KEY_MULTIMEDIA_STOP,
+ [0x2A] = KEY_PRINT_SCREEN,
+ [0x2E] = KEY_MULTIMEDIA_VOL_DOWN,
+ [0x30] = KEY_MULTIMEDIA_VOL_UP,
+ [0x32] = KEY_MULTIMEDIA_WWW_HOME,
+ [0x35] = KEYPAD_SLASH,
+ [0x37] = KEY_PRINT_SCREEN,
+ [0x38] = KEY_RIGHT_ALT,
+ [0x47] = KEY_HOME,
+ [0x48] = KEY_UP_ARROW,
+ [0x49] = KEY_PAGE_UP,
+ [0x4B] = KEY_LEFT_ARROW,
+ [0x4D] = KEY_RIGHT_ARROW,
+ [0x4F] = KEY_END,
+ [0x50] = KEY_DOWN_ARROW,
+ [0x51] = KEY_PAGE_DOWN,
+ [0x52] = KEY_INSERT,
+ [0x53] = KEY_DELETE,
+ [0x5B] = KEY_LEFT_GUI,
+ [0x5C] = KEY_RIGHT_GUI,
+ [0x5D] = KEY_APPS,
+ [0x5E] = KEY_ACPI_POWER,
+ [0x5F] = KEY_ACPI_SLEEP,
+ [0x63] = KEY_ACPI_WAKE,
+ [0x65] = KEY_MULTIMEDIA_WWW_SEARCH,
+ [0x66] = KEY_MULTIMEDIA_WWW_FAVORITES,
+ [0x67] = KEY_MULTIMEDIA_WWW_REFRESH,
+ [0x68] = KEY_MULTIMEDIA_WWW_STOP,
+ [0x69] = KEY_MULTIMEDIA_WWW_FORWARD,
+ [0x6A] = KEY_MULTIMEDIA_WWW_BACK,
+ [0x6B] = KEY_MULTIMEDIA_MY_COMPUTER,
+ [0x6C] = KEY_MULTIMEDIA_EMAIL,
+ [0x6D] = KEY_MULTIMEDIA_MEDIA_SELECT,
+
+ /* RELEASED */
+
+ [0x90] = KEY_MULTIMEDIA_PREV_TRACK,
+ [0x99] = KEY_MULTIMEDIA_NEXT_TRACK,
+ [0x9C] = KEYPAD_RETURN,
+ [0x9D] = KEY_RIGHT_CTRL,
+ [0xA0] = KEY_MULTIMEDIA_MUTE,
+ [0xA1] = KEY_MULTIMEDIA_CALCULATOR,
+ [0xA2] = KEY_MULTIMEDIA_PLAY,
+ [0xA4] = KEY_MULTIMEDIA_STOP,
+ [0xAA] = KEY_PRINT_SCREEN,
+ [0xAE] = KEY_MULTIMEDIA_VOL_DOWN,
+ [0xB0] = KEY_MULTIMEDIA_VOL_UP,
+ [0xB2] = KEY_MULTIMEDIA_WWW_HOME,
+ [0xB5] = KEYPAD_SLASH,
+ [0xB7] = KEY_PRINT_SCREEN,
+ [0xB8] = KEY_RIGHT_ALT,
+ [0xC7] = KEY_HOME,
+ [0xC8] = KEY_UP_ARROW,
+ [0xC9] = KEY_PAGE_UP,
+ [0xCB] = KEY_LEFT_ARROW,
+ [0xCD] = KEY_RIGHT_ARROW,
+ [0xCF] = KEY_END,
+ [0xD0] = KEY_DOWN_ARROW,
+ [0xD1] = KEY_PAGE_DOWN,
+ [0xD2] = KEY_INSERT,
+ [0xD3] = KEY_DELETE,
+ [0xDB] = KEY_LEFT_GUI,
+ [0xDC] = KEY_RIGHT_GUI,
+ [0xDD] = KEY_APPS,
+ [0xDE] = KEY_ACPI_POWER,
+ [0xDF] = KEY_ACPI_SLEEP,
+ [0xE3] = KEY_ACPI_WAKE,
+ [0xE5] = KEY_MULTIMEDIA_WWW_SEARCH,
+ [0xE6] = KEY_MULTIMEDIA_WWW_FAVORITES,
+ [0xE7] = KEY_MULTIMEDIA_WWW_REFRESH,
+ [0xE8] = KEY_MULTIMEDIA_WWW_STOP,
+ [0xE9] = KEY_MULTIMEDIA_WWW_FORWARD,
+ [0xEA] = KEY_MULTIMEDIA_WWW_BACK,
+ [0xEB] = KEY_MULTIMEDIA_MY_COMPUTER,
+ [0xEC] = KEY_MULTIMEDIA_EMAIL,
+ [0xED] = KEY_MULTIMEDIA_MEDIA_SELECT};
+
+const unsigned short ScanCodeSet3[] = {
+ [0x15] = KEY_Q,
+ [0x1A] = KEY_Z,
+ [0x1B] = KEY_S,
+ [0x1C] = KEY_A,
+ [0x1D] = KEY_W,
+
+ [0x21] = KEY_C,
+ [0x22] = KEY_X,
+ [0x23] = KEY_D,
+ [0x24] = KEY_E,
+ [0x2A] = KEY_V,
+ [0x2B] = KEY_F,
+ [0x2C] = KEY_T,
+ [0x2D] = KEY_R,
+
+ [0x31] = KEY_N,
+ [0x32] = KEY_B,
+ [0x33] = KEY_H,
+ [0x34] = KEY_G,
+ [0x35] = KEY_Y,
+ [0x3A] = KEY_M,
+ [0x3B] = KEY_J,
+ [0x3C] = KEY_U,
+
+ [0x42] = KEY_K,
+ [0x43] = KEY_I,
+ [0x44] = KEY_O,
+ [0x4B] = KEY_L,
+ [0x4D] = KEY_P};
+
+bool IsE0 = false;
+bool IsE1 = false;
+void PS2KbdInterruptHandler(TrapFrame *)
+{
+ uint8_t sc = inb(PS2_DATA);
+ if (sc == PS2_KBD_RESP_ACK ||
+ sc == PS2_KBD_RESP_ECHO ||
+ sc == PS2_KBD_RESP_RESEND)
+ return;
+
+ if (sc == 0xE0)
+ {
+ IsE0 = true;
+ return;
+ }
+
+ if (sc == 0xE1)
+ {
+ IsE1 = true;
+ return;
+ }
+
+ switch (KeyboardScanCodeSet)
+ {
+ case PS2_KBD_SC_SET_1:
+ case PS2_KBD_SC_SET_2:
+ {
+ if (IsE0)
+ {
+ IsE0 = false;
+ ReportKeyboardEvent(KeyboardDevID, ScanCodeSet1mm[sc], sc < 0x90);
+ return;
+ }
+ else
+ {
+ bool released = sc & 0x80;
+ uint8_t scFinal = released ? sc & 0x7F : sc;
+ ReportKeyboardEvent(KeyboardDevID, ScanCodeSet1[scFinal], !released);
+ return;
+ }
+ }
+ /* FIXME: https://wiki.osdev.org/PS/2_Keyboard */
+ // case PS2_KBD_SC_SET_2:
+ // {
+ // break;
+ // }
+ case PS2_KBD_SC_SET_3:
+ {
+ ReportKeyboardEvent(KeyboardDevID, ScanCodeSet3[sc], true);
+ ReportKeyboardEvent(KeyboardDevID, ScanCodeSet3[sc], false);
+ break;
+ }
+ default:
+ {
+ if (IsE0)
+ IsE0 = false;
+ Log("Unknown PS/2 Keyboard Scan Code Set: %#x", KeyboardScanCodeSet);
+ break;
+ }
+ }
+}
+
+int InitializeKeyboard()
+{
+ // PS2WriteData(PS2_KBD_CMD_RESET);
+ // uint8_t test = PS2ReadData();
+ // if (test != PS2_KBD_RESP_TEST_PASSED &&
+ // test != PS2_KBD_RESP_ACK)
+ // {
+ // Log("PS/2 keyboard reset failed (%#x)", test);
+ // return -EFAULT;
+ // }
+
+ PS2WriteData(PS2_KBD_CMD_DEFAULTS);
+ if (PS2ACKTimeout() != 0)
+ Log("PS/2 keyboard failed to set defaults");
+
+ PS2WriteData(PS2_KBD_CMD_SCAN_CODE_SET);
+ if (PS2ACKTimeout() != 0)
+ Log("PS/2 keyboard failed to set scan code set");
+
+ /* We want Scan Code Set 1 */
+ PS2WriteData(PS2_KBD_SCAN_CODE_SET_2); /* It will set to 1 but with translation? */
+ if (PS2ACKTimeout() != 0)
+ Log("PS/2 keyboard failed to set scan code set 2");
+
+ PS2WriteData(PS2_KBD_CMD_SCAN_CODE_SET);
+ if (PS2ACKTimeout() != 0)
+ Log("PS/2 keyboard failed to set scan code set");
+
+ PS2WriteData(PS2_KBD_SCAN_CODE_GET_CURRENT);
+ if (PS2ACKTimeout() != 0)
+ Log("PS/2 keyboard failed to get current scan code set");
+
+ KeyboardScanCodeSet = PS2ReadAfterACK();
+ Log("PS/2 Keyboard Scan Code Set: 0x%X", KeyboardScanCodeSet);
+ PS2ClearOutputBuffer();
+
+ PS2WriteData(PS2_KBD_CMD_ENABLE_SCANNING);
+
+ RegisterInterruptHandler(1, PS2KbdInterruptHandler);
+ KeyboardDevID = RegisterInputDevice(ddt_Keyboard);
+ return 0;
+}
+
+int FinalizeKeyboard()
+{
+ UnregisterInputDevice(KeyboardDevID, ddt_Keyboard);
+ return 0;
+}
+
+int DetectPS2Keyboard()
+{
+ PS2WriteData(PS2_KBD_CMD_DISABLE_SCANNING);
+ if (PS2ACKTimeout() != 0)
+ Log("PS/2 keyboard failed to disable scanning");
+
+ PS2WriteData(PS2_KBD_CMD_IDENTIFY);
+ if (PS2ACKTimeout() != 0)
+ Log("PS/2 keyboard failed to identify");
+
+ uint8_t recByte;
+ int timeout = 1000000;
+ while (timeout--)
+ {
+ recByte = PS2ReadData();
+ if (recByte != PS2_ACK)
+ break;
+ }
+ Device1ID[0] = recByte;
+
+ timeout = 1000000;
+ while (timeout--)
+ {
+ recByte = PS2ReadData();
+ if (recByte != PS2_ACK)
+ break;
+ }
+ if (timeout == 0)
+ Log("PS/2 keyboard second byte timed out");
+ else
+ Device1ID[1] = recByte;
+
+ Log("PS2 Keyboard Device: 0x%X 0x%X", Device1ID[0], Device1ID[1]);
+ return 0;
+}
diff --git a/input/aip/main.c b/input/aip/main.c
new file mode 100644
index 0000000..a63a513
--- /dev/null
+++ b/input/aip/main.c
@@ -0,0 +1,234 @@
+/*
+ This file is part of Fennix Drivers.
+
+ Fennix Drivers is free software: you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation, either version 3 of
+ the License, or (at your option) any later version.
+
+ Fennix Drivers is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Fennix Drivers. If not, see .
+*/
+
+#include "aip.h"
+
+#include
+#include
+
+bool IsKeyboard(uint8_t ID)
+{
+ /* Common keyboard IDs */
+ return ID == 0xAB || ID == 0xAC || ID == 0x5D ||
+ ID == 0x2B || ID == 0x47 || ID == 0x60;
+}
+
+bool IsMouse(uint8_t ID)
+{
+ /* Common mouse IDs */
+ return ID == 0x00 || ID == 0x03 || ID == 0x04;
+}
+
+const char *GetPS2DeviceName(uint8_t ID, uint8_t SubID)
+{
+ switch (ID)
+ {
+ case 0x00:
+ return "Standard PS/2 Mouse";
+ case 0x03:
+ return "Mouse with scroll wheel";
+ case 0x04:
+ return "Mouse 5 buttons";
+ case 0xAB:
+ {
+ switch (SubID)
+ {
+ case 0x83: /* Normal */
+ case 0x41: /* Translated */
+ case 0xC1: /* Normal + Translated */
+ return "Standard PS/2 Keyboard";
+ case 0x84:
+ case 0x54:
+ return "IBM Thinkpad/Spacesaver Keyboard";
+ case 0x85:
+ return "NCD N-97/122-Key Host Connect(ed) Keyboard";
+ case 0x86:
+ return "122-Key Keyboard";
+ case 0x90:
+ return "Japanese \"G\" Keyboard";
+ case 0x91:
+ return "Japanese \"P\" Keyboard";
+ case 0x92:
+ return "Japanese \"A\" Keyboard";
+ default:
+ return "Unknown PS/2 Keyboard";
+ }
+ }
+ case 0xAC:
+ {
+ switch (SubID)
+ {
+ case 0xA1:
+ return "NCD Sun Keyboard";
+ default:
+ return "Unknown NCD Sun Keyboard";
+ }
+ }
+ case 0x5D:
+ case 0x2B:
+ return "Trust Keyboard";
+ case 0x47:
+ case 0x60:
+ return "NMB SGI Keyboard";
+ default:
+ return "Unknown PS/2 Device";
+ }
+}
+
+uint8_t Device1ID[2] = {0x00, 0x00};
+uint8_t Device2ID[2] = {0x00, 0x00};
+bool DualChannel = false;
+
+int DriverEntry()
+{
+ PS2WriteCommand(PS2_CMD_DISABLE_PORT_1);
+ PS2WriteCommand(PS2_CMD_DISABLE_PORT_2);
+ PS2ClearOutputBuffer();
+
+ PS2WriteCommand(PS2_CMD_READ_CONFIG);
+ PS2_CONFIGURATION cfg = {.Raw = PS2ReadData()};
+
+ DualChannel = cfg.Port2Clock;
+ if (DualChannel)
+ Log("Dual channel PS/2 controller detected");
+ cfg.Port1Interrupt = 1;
+ cfg.Port2Interrupt = 1;
+ cfg.Port1Translation = 1;
+
+ PS2WriteCommand(PS2_CMD_WRITE_CONFIG);
+ PS2WriteData(cfg.Raw);
+
+ PS2WriteCommand(PS2_CMD_TEST_CONTROLLER);
+ uint8_t test = PS2ReadData();
+ if (test != PS2_TEST_PASSED)
+ {
+ Log("PS/2 controller self test failed (%#x)", test);
+ return -EFAULT;
+ }
+
+ PS2WriteCommand(PS2_CMD_WRITE_CONFIG);
+ PS2WriteData(cfg.Raw);
+
+ // bool port2avail = false;
+ // if (DualChannel)
+ // {
+ // PS2WriteCommand(PS2_CMD_ENABLE_PORT_1);
+ // PS2WriteCommand(PS2_CMD_READ_CONFIG);
+ // cfg.Raw = PS2ReadData();
+ // port2avail = cfg.Port2Clock;
+ // PS2WriteCommand(PS2_CMD_DISABLE_PORT_1);
+ // }
+
+ PS2WriteCommand(PS2_CMD_TEST_PORT_1);
+ test = PS2ReadData();
+ if (test != 0x00)
+ {
+ Log("PS/2 Port 1 self test failed (%#x)", test);
+ return -EFAULT;
+ }
+
+ if (DualChannel)
+ {
+ PS2WriteCommand(PS2_CMD_TEST_PORT_2);
+ test = PS2ReadData();
+ if (test != 0x00)
+ {
+ Log("PS/2 Port 2 self test failed (%#x)", test);
+ return -EFAULT;
+ }
+ }
+
+ PS2WriteCommand(PS2_CMD_ENABLE_PORT_1);
+ if (DualChannel)
+ PS2WriteCommand(PS2_CMD_ENABLE_PORT_2);
+
+ int errK = InitializeKeyboard();
+
+ int errM = 0;
+ if (DualChannel)
+ errM = InitializeMouse();
+
+ /** A device may fail, but if the other one works,
+ * we can still use it.
+ */
+ if (errK != 0 && errM != 0)
+ return -ENODEV;
+ return 0;
+}
+
+int DriverFinal()
+{
+ FinalizeKeyboard();
+ FinalizeMouse();
+ PS2WriteCommand(PS2_CMD_DISABLE_PORT_1);
+ PS2WriteCommand(PS2_CMD_DISABLE_PORT_2);
+ return 0;
+}
+
+int DriverPanic()
+{
+ PS2WriteCommand(PS2_CMD_DISABLE_PORT_1);
+ PS2WriteCommand(PS2_CMD_DISABLE_PORT_2);
+ return 0;
+}
+
+void __intStub() {}
+int DriverProbe()
+{
+ RegisterInterruptHandler(1, __intStub);
+ RegisterInterruptHandler(12, __intStub);
+
+ int kbd = DetectPS2Keyboard();
+ int mouse = DetectPS2Mouse();
+
+ UnregisterAllInterruptHandlers(__intStub);
+
+ if (kbd != 0 && mouse != 0)
+ return -ENODEV;
+
+ if (kbd == 0)
+ {
+ if (!IsKeyboard(Device1ID[0]))
+ {
+ Log("PS/2 Port 1 is not a keyboard");
+ // return -EINVAL;
+ }
+ }
+
+ if (mouse == 0)
+ {
+ if (!IsMouse(Device2ID[0]))
+ {
+ Log("PS/2 Port 2 is not a mouse");
+ // return -EINVAL;
+ }
+ }
+
+ KPrint("PS/2 Port 1: %s (0x%X 0x%X)",
+ GetPS2DeviceName(Device1ID[0], Device1ID[1]),
+ Device1ID[0], Device1ID[1]);
+ KPrint("PS/2 Port 2: %s (0x%X 0x%X)",
+ GetPS2DeviceName(Device2ID[0], Device2ID[1]),
+ Device2ID[0], Device2ID[1]);
+ return 0;
+}
+
+DriverInfo("aip",
+ "Advanced Integrated Peripheral Driver",
+ "EnderIce2",
+ "0.1",
+ "GPLv3");
diff --git a/input/aip/mouse.c b/input/aip/mouse.c
new file mode 100644
index 0000000..2ac8337
--- /dev/null
+++ b/input/aip/mouse.c
@@ -0,0 +1,233 @@
+/*
+ This file is part of Fennix Drivers.
+
+ Fennix Drivers is free software: you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation, either version 3 of
+ the License, or (at your option) any later version.
+
+ Fennix Drivers is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Fennix Drivers. If not, see .
+*/
+
+#include "aip.h"
+
+#include
+#include
+#include
+
+dev_t MouseDevID = -1;
+bool PacketReady = false;
+bool FourPackets = false;
+bool MouseButton45 = false;
+uint8_t Cycle = 0;
+PS2_MOUSE_PACKET Packet = {0};
+
+void PS2MouseInterruptHandler(TrapFrame *)
+{
+ uint8_t data = PS2ReadData();
+ if (data == PS2_MOUSE_RESP_ACK ||
+ data == PS2_MOUSE_RESP_RESEND)
+ return;
+
+ if (!PacketReady)
+ {
+ switch (Cycle)
+ {
+ case 0:
+ {
+ if ((data & 0b00001000 /* Always 1 */) == 0)
+ return;
+
+ Packet.Base.Raw = data;
+ Cycle++;
+ break;
+ }
+ case 1:
+ {
+ Packet.XMovement = data;
+ Cycle++;
+ break;
+ }
+ case 2:
+ {
+ Packet.YMovement = data;
+ if (FourPackets)
+ Cycle++;
+ else
+ {
+ Cycle = 0;
+ PacketReady = true;
+ }
+ break;
+ }
+ case 3:
+ {
+ Packet.ZMovement.Raw = data;
+ Cycle = 0;
+ PacketReady = true;
+ break;
+ }
+ default:
+ break;
+ }
+ return;
+ }
+
+/* https://stackoverflow.com/a/3208376/9352057 */
+#define BYTE_TO_BINARY_PATTERN "%c%c%c%c%c%c%c%c"
+#define BYTE_TO_BINARY(byte) \
+ ((byte) & 0x80 ? '1' : '0'), \
+ ((byte) & 0x40 ? '1' : '0'), \
+ ((byte) & 0x20 ? '1' : '0'), \
+ ((byte) & 0x10 ? '1' : '0'), \
+ ((byte) & 0x08 ? '1' : '0'), \
+ ((byte) & 0x04 ? '1' : '0'), \
+ ((byte) & 0x02 ? '1' : '0'), \
+ ((byte) & 0x01 ? '1' : '0')
+
+ DebugLog("PS/2 Mouse Packet: [" BYTE_TO_BINARY_PATTERN ":" BYTE_TO_BINARY_PATTERN ":" BYTE_TO_BINARY_PATTERN ":" BYTE_TO_BINARY_PATTERN "] LB:%d RB:%d MB:%d A1:%d XS:%d YS:%d XO:%d YO:%d | X:%03d Y:%03d | Z:%d B4:%d B5:%d A0:%d A0:%d",
+ BYTE_TO_BINARY(Packet.Base.Raw),
+ BYTE_TO_BINARY(Packet.XMovement),
+ BYTE_TO_BINARY(Packet.YMovement),
+ BYTE_TO_BINARY(Packet.ZMovement.Raw),
+ Packet.Base.LeftButton, Packet.Base.RightButton, Packet.Base.MiddleButton,
+ Packet.Base.Always1,
+ Packet.Base.XSign, Packet.Base.YSign,
+ Packet.Base.XOverflow, Packet.Base.YOverflow,
+ Packet.XMovement, Packet.YMovement,
+ Packet.ZMovement.Z, Packet.ZMovement.Button4, Packet.ZMovement.Button5,
+ Packet.ZMovement.Always0, Packet.ZMovement.Always0_2);
+
+ int X, Y;
+ X = Packet.XMovement - (Packet.Base.XSign ? 256 : 0);
+ Y = Packet.YMovement - (Packet.Base.YSign ? 256 : 0);
+
+ if (Packet.Base.XOverflow)
+ X = 0;
+
+ if (Packet.Base.YOverflow)
+ Y = 0;
+
+ MouseReport mr = {
+ .LeftButton = Packet.Base.LeftButton,
+ .RightButton = Packet.Base.RightButton,
+ .MiddleButton = Packet.Base.MiddleButton,
+ .Button4 = Packet.ZMovement.Button4,
+ .Button5 = Packet.ZMovement.Button5,
+ .X = X,
+ .Y = -Y,
+ .Z = Packet.ZMovement.Z,
+ };
+ ReportRelativeMouseEvent(MouseDevID, mr);
+
+ PacketReady = false;
+}
+
+void MouseSampleRate(uint8_t SampleRate)
+{
+ PS2WriteCommand(PS2_CMD_WRITE_NEXT_BYTE_TO_PS2_PORT_2_INPUT);
+ PS2WriteData(PS2_MOUSE_CMD_SET_SAMPLE_RATE);
+ PS2ReadData();
+
+ PS2WriteCommand(PS2_CMD_WRITE_NEXT_BYTE_TO_PS2_PORT_2_INPUT);
+ PS2WriteData(SampleRate);
+ PS2ReadData();
+}
+
+int InitializeMouse()
+{
+ PS2WriteData(PS2_CMD_WRITE_NEXT_BYTE_TO_PS2_PORT_2_INPUT);
+ PS2WriteData(PS2_MOUSE_CMD_RESET);
+ uint8_t test = PS2ReadData();
+ if (test != PS2_MOUSE_RESP_TEST_PASSED &&
+ test != PS2_MOUSE_RESP_ACK)
+ {
+ Log("PS/2 mouse reset failed! (%#x)", test);
+ return -EFAULT;
+ }
+
+ RegisterInterruptHandler(12, PS2MouseInterruptHandler);
+ MouseDevID = RegisterInputDevice(ddt_Mouse);
+
+ PS2WriteCommand(PS2_CMD_WRITE_NEXT_BYTE_TO_PS2_PORT_2_INPUT);
+ PS2WriteData(PS2_MOUSE_CMD_SET_DEFAULTS);
+ PS2ReadData();
+
+ PS2WriteCommand(PS2_CMD_WRITE_NEXT_BYTE_TO_PS2_PORT_2_INPUT);
+ PS2WriteData(PS2_MOUSE_CMD_ENABLE_DATA_REPORTING);
+
+ MouseSampleRate(200);
+ MouseSampleRate(100);
+ MouseSampleRate(80);
+
+ PS2WriteCommand(PS2_CMD_WRITE_NEXT_BYTE_TO_PS2_PORT_2_INPUT);
+ PS2WriteData(PS2_MOUSE_CMD_READ_ID);
+ uint8_t Device2ID = PS2ReadData();
+ Log("PS/2 Mouse ID: %#x", Device2ID);
+
+ MouseSampleRate(200);
+ MouseSampleRate(200);
+ MouseSampleRate(80);
+
+ PS2WriteCommand(PS2_CMD_WRITE_NEXT_BYTE_TO_PS2_PORT_2_INPUT);
+ PS2WriteData(PS2_MOUSE_CMD_READ_ID);
+ Device2ID = PS2ReadData();
+ Log("PS/2 Mouse ID: %#x", Device2ID);
+
+ if (Device2ID >= 3 && Device2ID <= 4)
+ FourPackets = true;
+ if (Device2ID == 4)
+ MouseButton45 = true;
+
+ return 0;
+}
+
+int FinalizeMouse()
+{
+ UnregisterInputDevice(MouseDevID, ddt_Mouse);
+
+ PS2WriteCommand(PS2_CMD_WRITE_NEXT_BYTE_TO_PS2_PORT_2_INPUT);
+ PS2WriteData(PS2_MOUSE_CMD_DISABLE_DATA_REPORTING);
+ return 0;
+}
+
+int DetectPS2Mouse()
+{
+ PS2WriteCommand(PS2_CMD_WRITE_NEXT_BYTE_TO_PS2_PORT_2_INPUT);
+ PS2WriteData(PS2_MOUSE_CMD_DISABLE_DATA_REPORTING);
+ if (PS2ACKTimeout() != 0)
+ Log("PS/2 mouse failed to disable data reporting!");
+
+ PS2WriteCommand(PS2_CMD_WRITE_NEXT_BYTE_TO_PS2_PORT_2_INPUT);
+ PS2WriteData(PS2_MOUSE_CMD_READ_ID);
+ if (PS2ACKTimeout() != 0)
+ Log("PS/2 mouse failed to read ID!");
+
+ uint8_t recByte;
+ int timeout = 1000000;
+ while (timeout--)
+ {
+ recByte = PS2ReadData();
+ if (recByte != PS2_ACK)
+ break;
+ }
+ Device2ID[0] = recByte;
+
+ timeout = 1000000;
+ while (timeout--)
+ {
+ recByte = PS2ReadData();
+ if (recByte != PS2_ACK)
+ break;
+ }
+ Device2ID[1] = recByte;
+
+ Log("PS2 Mouse Device: 0x%X 0x%X", Device2ID[0], Device2ID[1]);
+ return 0;
+}
diff --git a/library/Makefile b/library/Makefile
new file mode 100644
index 0000000..752d3a5
--- /dev/null
+++ b/library/Makefile
@@ -0,0 +1,82 @@
+# Config file
+include ../../Makefile.conf
+
+FILENAME = libdriver.a
+
+CC = ../../$(COMPILER_PATH)/$(COMPILER_ARCH)gcc
+CPP = ../../$(COMPILER_PATH)/$(COMPILER_ARCH)g++
+LD = ../../$(COMPILER_PATH)/$(COMPILER_ARCH)ld
+AS = ../../$(COMPILER_PATH)/$(COMPILER_ARCH)as
+AR = ../../$(COMPILER_PATH)/$(COMPILER_ARCH)ar
+
+S_SOURCES = $(shell find ./ -type f -name '*.S' -not -path "./crt/*")
+C_SOURCES = $(shell find ./ -type f -name '*.c' -not -path "./crt/*")
+CPP_SOURCES = $(shell find ./ -type f -name '*.cpp' -not -path "./crt/*")
+HEADERS = $(sort $(dir $(wildcard ../include/*)))
+OBJ = $(C_SOURCES:.c=.o) $(CPP_SOURCES:.cpp=.o) $(ASM_SOURCES:.asm=.o) $(S_SOURCES:.S=.o) $(PSF_SOURCES:.psf=.o) $(BMP_SOURCES:.bmp=.o)
+STACK_USAGE_OBJ = $(C_SOURCES:.c=.su) $(CPP_SOURCES:.cpp=.su)
+INCLUDE_DIR = ../include
+
+LDFLAGS := \
+ -fPIC -fPIE -pie \
+ -nostdlib -nodefaultlibs -nolibc \
+ -zmax-page-size=0x1000 \
+ -Wl,-Map driver.map -static -fvisibility=hidden
+
+WARNCFLAG = -Wall -Wextra
+
+CFLAGS := -I$(INCLUDE_DIR) -fvisibility=hidden
+
+ifeq ($(OSARCH), amd64)
+
+CFLAGS += -fPIC -fPIE -pie -mno-80387 -mno-mmx -mno-3dnow \
+ -mno-red-zone -mno-sse -mno-sse2 \
+ -march=x86-64 -pipe -ffunction-sections \
+ -msoft-float -fno-builtin
+
+else ifeq ($(OSARCH), i386)
+
+CFLAGS += -fPIC -fPIE -pie -mno-80387 -mno-mmx -mno-3dnow \
+ -mno-red-zone -mno-sse -mno-sse2 -ffunction-sections \
+ -march=i386 -pipe -msoft-float -fno-builtin
+
+else ifeq ($(OSARCH), aarch64)
+
+CFLAGS += -pipe -fno-builtin -fPIC
+
+endif
+
+ifeq ($(DEBUG), 1)
+ CFLAGS += -DDEBUG -ggdb3 -O0 -fdiagnostics-color=always -fstack-usage
+ifeq ($(OSARCH), amd64)
+ CFLAGS += -fverbose-asm
+endif
+ifneq ($(OSARCH), aarch64)
+ CFLAGS += -fstack-check
+endif
+ LDFLAGS += -ggdb3 -O0
+endif
+
+build: $(FILENAME)
+ $(CC) $(CFLAGS) $(WARNCFLAG) -std=c17 -shared -c crt/crt0.c -o dcrt0.o
+ mv dcrt0.o ../out/dcrt0.o
+
+$(FILENAME): $(OBJ)
+ $(info Linking $@)
+ $(AR) rcs $@ $(OBJ)
+ mv $(FILENAME) ../out/$(FILENAME)
+
+%.o: %.c $(HEADERS)
+ $(info Compiling $<)
+ $(CC) $(CFLAGS) $(WARNCFLAG) -std=c17 -c $< -o $@
+
+%.o: %.cpp $(HEADERS)
+ $(info Compiling $<)
+ $(CPP) $(CFLAGS) $(WARNCFLAG) -std=c++20 -fexceptions -c $< -o $@
+
+%.o: %.S
+ $(info Compiling $<)
+ $(AS) -o $@ $<
+
+clean:
+ rm -f driver.map $(OBJ) $(FILENAME) $(STACK_USAGE_OBJ) dcrt0.su
diff --git a/library/aip.c b/library/aip.c
new file mode 100644
index 0000000..6314983
--- /dev/null
+++ b/library/aip.c
@@ -0,0 +1,146 @@
+/*
+ This file is part of Fennix Drivers.
+
+ Fennix Drivers is free software: you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation, either version 3 of
+ the License, or (at your option) any later version.
+
+ Fennix Drivers is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Fennix Drivers. If not, see .
+*/
+
+#include
+
+#include
+#include
+
+extern void Log(const char *Format, ...);
+
+void PIC_EOI(uint8_t IRQ)
+{
+ if (IRQ >= 8)
+ outb(PIC2_CMD, _PIC_EOI);
+ outb(PIC1_CMD, _PIC_EOI);
+}
+
+void IRQ_MASK(uint8_t IRQ)
+{
+ uint16_t port;
+ uint8_t value;
+
+ if (IRQ < 8)
+ port = PIC1_DATA;
+ else
+ {
+ port = PIC2_DATA;
+ IRQ -= 8;
+ }
+
+ value = inb(port) | (1 << IRQ);
+ outb(port, value);
+}
+
+void IRQ_UNMASK(uint8_t IRQ)
+{
+ uint16_t port;
+ uint8_t value;
+
+ if (IRQ < 8)
+ port = PIC1_DATA;
+ else
+ {
+ port = PIC2_DATA;
+ IRQ -= 8;
+ }
+
+ value = inb(port) & ~(1 << IRQ);
+ outb(port, value);
+}
+
+void PS2Wait(const bool Output)
+{
+ int Timeout = 100000;
+ PS2_STATUSES Status = {.Raw = inb(PS2_STATUS)};
+ while (Timeout--)
+ {
+ if (!Output) /* FIXME: Reverse? */
+ {
+ if (Status.OutputBufferFull == 0)
+ return;
+ }
+ else
+ {
+ if (Status.InputBufferFull == 0)
+ return;
+ }
+ Status.Raw = inb(PS2_STATUS);
+ }
+
+ Log("PS/2 controller timeout! (Status: %#x, %d)", Status, Output);
+}
+
+void PS2WriteCommand(uint8_t Command)
+{
+ WaitInput;
+ outb(PS2_CMD, Command);
+}
+
+void PS2WriteData(uint8_t Data)
+{
+ WaitInput;
+ outb(PS2_DATA, Data);
+}
+
+uint8_t PS2ReadData()
+{
+ WaitOutput;
+ return inb(PS2_DATA);
+}
+
+uint8_t PS2ReadStatus()
+{
+ WaitOutput;
+ return inb(PS2_STATUS);
+}
+
+uint8_t PS2ReadAfterACK()
+{
+ uint8_t ret = PS2ReadData();
+ while (ret == PS2_ACK)
+ {
+ WaitOutput;
+ ret = inb(PS2_DATA);
+ }
+ return ret;
+}
+
+void PS2ClearOutputBuffer()
+{
+ PS2_STATUSES Status;
+ int timeout = 0x500;
+ while (timeout--)
+ {
+ Status.Raw = inb(PS2_STATUS);
+ if (Status.OutputBufferFull == 0)
+ return;
+ inb(PS2_DATA);
+ }
+}
+
+int PS2ACKTimeout()
+{
+ int timeout = 0x500;
+ while (timeout > 0)
+ {
+ if (PS2ReadData() == PS2_ACK)
+ return 0;
+ timeout--;
+ }
+ return -ETIMEDOUT;
+}
diff --git a/library/audio.c b/library/audio.c
new file mode 100644
index 0000000..ef51d46
--- /dev/null
+++ b/library/audio.c
@@ -0,0 +1,31 @@
+/*
+ This file is part of Fennix Drivers.
+
+ Fennix Drivers is free software: you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation, either version 3 of
+ the License, or (at your option) any later version.
+
+ Fennix Drivers is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Fennix Drivers. If not, see .
+*/
+
+#include
+
+extern __driverAPI *API;
+
+dev_t RegisterAudioDevice(DeviceDriverType Type, drvOpen_t Open, drvClose_t Close,
+ drvRead_t Read, drvWrite_t Write, drvIoctl_t Ioctl)
+{
+ return API->RegisterAudioDevice(API->MajorID, Type, Open, Close, Read, Write, Ioctl);
+}
+
+int UnregisterAudioDevice(dev_t DeviceID, DeviceDriverType Type)
+{
+ return API->UnregisterAudioDevice(API->MajorID, DeviceID, Type);
+}
diff --git a/library/base.c b/library/base.c
new file mode 100644
index 0000000..6b661aa
--- /dev/null
+++ b/library/base.c
@@ -0,0 +1,182 @@
+/*
+ This file is part of Fennix Drivers.
+
+ Fennix Drivers is free software: you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation, either version 3 of
+ the License, or (at your option) any later version.
+
+ Fennix Drivers is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Fennix Drivers. If not, see .
+*/
+
+#include
+
+#include
+#include
+
+__driverAPI *API = NULL;
+
+int RegisterInterruptHandler(uint8_t IRQ, void *Handler)
+{
+ if (Handler == NULL)
+ return -EINVAL;
+
+ return API->RegisterInterruptHandler(API->MajorID,
+ IRQ,
+ Handler);
+}
+
+int OverrideInterruptHandler(uint8_t IRQ, void *Handler)
+{
+ if (Handler == NULL)
+ return -EINVAL;
+
+ return API->OverrideInterruptHandler(API->MajorID,
+ IRQ,
+ Handler);
+}
+
+int UnregisterInterruptHandler(uint8_t IRQ, void *Handler)
+{
+ if (Handler == NULL)
+ return -EINVAL;
+
+ return API->UnregisterInterruptHandler(API->MajorID,
+ IRQ,
+ Handler);
+}
+
+int UnregisterAllInterruptHandlers(void *Handler)
+{
+ if (Handler == NULL)
+ return -EINVAL;
+
+ return API->UnregisterAllInterruptHandlers(API->MajorID,
+ Handler);
+}
+
+void *AllocateMemory(size_t Pages)
+{
+ if (Pages == 0)
+ return NULL;
+
+ return API->RequestPages(API->MajorID,
+ Pages);
+}
+
+void FreeMemory(void *Pointer, size_t Pages)
+{
+ if (Pointer == NULL || Pages == 0)
+ return;
+
+ API->FreePages(API->MajorID,
+ Pointer,
+ Pages);
+}
+
+void AppendMapFlag(void *Address, PageMapFlags Flag)
+{
+ API->AppendMapFlag(API->MajorID,
+ Address,
+ Flag);
+}
+
+void RemoveMapFlag(void *Address, PageMapFlags Flag)
+{
+ API->RemoveMapFlag(API->MajorID,
+ Address,
+ Flag);
+}
+
+void MapPages(void *PhysicalAddress, void *VirtualAddress, size_t Pages, uint32_t Flags)
+{
+ API->MapPages(API->MajorID,
+ PhysicalAddress,
+ VirtualAddress,
+ Pages,
+ Flags);
+}
+
+void UnmapPages(void *VirtualAddress, size_t Pages)
+{
+ API->UnmapPages(API->MajorID,
+ VirtualAddress,
+ Pages);
+}
+
+void KPrint(const char *Format, ...)
+{
+ va_list Args;
+ va_start(Args, Format);
+
+ API->KPrint(API->MajorID,
+ Format,
+ Args);
+
+ va_end(Args);
+}
+
+void Log(const char *Format, ...)
+{
+ va_list Args;
+ va_start(Args, Format);
+
+ API->KernelLog(API->MajorID,
+ Format,
+ Args);
+
+ va_end(Args);
+}
+
+CriticalState EnterCriticalSection()
+{
+ CriticalState cs;
+
+#if defined(__i386__) || defined(__x86_64__)
+
+ uintptr_t Flags;
+#if defined(__x86_64__)
+ asmv("pushfq");
+ asmv("popq %0"
+ : "=r"(Flags));
+#else
+ asmv("pushfl");
+ asmv("popl %0"
+ : "=r"(Flags));
+#endif
+ cs = Flags & (1 << 9);
+ asmv("cli");
+
+#elif defined(__arm__) || defined(__aarch64__)
+
+ uintptr_t Flags;
+ asmv("mrs %0, cpsr"
+ : "=r"(Flags));
+ cs = Flags & (1 << 7);
+ asmv("cpsid i");
+
+#endif
+
+ return cs;
+}
+
+void LeaveCriticalSection(CriticalState PreviousState)
+{
+#if defined(__i386__) || defined(__x86_64__)
+
+ if (PreviousState)
+ asmv("sti");
+
+#elif defined(__arm__) || defined(__aarch64__)
+
+ if (PreviousState)
+ asmv("cpsie i");
+
+#endif
+}
diff --git a/library/block.c b/library/block.c
new file mode 100644
index 0000000..10dd2db
--- /dev/null
+++ b/library/block.c
@@ -0,0 +1,31 @@
+/*
+ This file is part of Fennix Drivers.
+
+ Fennix Drivers is free software: you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation, either version 3 of
+ the License, or (at your option) any later version.
+
+ Fennix Drivers is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Fennix Drivers. If not, see .
+*/
+
+#include
+
+extern __driverAPI *API;
+
+dev_t RegisterBlockDevice(DeviceDriverType Type, drvOpen_t Open, drvClose_t Close,
+ drvRead_t Read, drvWrite_t Write, drvIoctl_t Ioctl)
+{
+ return API->RegisterBlockDevice(API->MajorID, Type, Open, Close, Read, Write, Ioctl);
+}
+
+int UnregisterBlockDevice(dev_t DeviceID, DeviceDriverType Type)
+{
+ return API->UnregisterBlockDevice(API->MajorID, DeviceID, Type);
+}
diff --git a/library/crt/crt0.c b/library/crt/crt0.c
new file mode 100644
index 0000000..509492c
--- /dev/null
+++ b/library/crt/crt0.c
@@ -0,0 +1,85 @@
+/*
+ This file is part of Fennix Drivers.
+
+ Fennix Drivers is free software: you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation, either version 3 of
+ the License, or (at your option) any later version.
+
+ Fennix Drivers is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Fennix Drivers. If not, see .
+*/
+
+#include
+#include
+
+extern __driverAPI *API;
+
+int DriverEntry();
+int DriverFinal();
+int DriverPanic();
+int DriverProbe();
+void __IdentifyDriver(
+ dev_t ID,
+ int (*GetDriverInfo)(dev_t, const char *, const char *,
+ const char *, const char *, const char *));
+
+typedef void (*CallPtr)(void);
+extern CallPtr __init_array_start[0], __init_array_end[0];
+extern CallPtr __fini_array_start[0], __fini_array_end[0];
+
+int _entry()
+{
+ for (CallPtr *func = __init_array_start; func != __init_array_end; func++)
+ (*func)();
+
+ return DriverEntry();
+}
+
+int _final()
+{
+ int err = DriverFinal();
+
+ for (CallPtr *func = __fini_array_start; func != __fini_array_end; func++)
+ (*func)();
+
+ return err;
+}
+
+#define API_MajorRequiredVersion 0
+#define API_MinorRequiredVersion 0
+#define API_PatchRequiredVersion 0
+
+int _start(__driverAPI *__API)
+{
+ if (unlikely(__API == NULL))
+ return -EINVAL;
+
+ if (unlikely(__API->APIVersion.Major != API_MajorRequiredVersion ||
+ __API->APIVersion.Minor != API_MinorRequiredVersion ||
+ __API->APIVersion.Patch != API_PatchRequiredVersion))
+ return -EPROTO;
+
+ if (unlikely(__API->RegisterFunction == NULL))
+ return -ENOSYS;
+
+ if (unlikely(DriverEntry == NULL ||
+ DriverFinal == NULL ||
+ DriverPanic == NULL ||
+ DriverProbe == NULL ||
+ __IdentifyDriver == NULL))
+ return -EFAULT;
+
+ API = __API;
+ __API->RegisterFunction(__API->MajorID, _entry, _drf_Entry);
+ __API->RegisterFunction(__API->MajorID, _final, _drf_Final);
+ __API->RegisterFunction(__API->MajorID, DriverPanic, _drf_Panic);
+ __API->RegisterFunction(__API->MajorID, DriverProbe, _drf_Probe);
+ __IdentifyDriver(__API->MajorID, __API->GetDriverInfo);
+ return 0;
+}
diff --git a/library/input.c b/library/input.c
new file mode 100644
index 0000000..19bc1d0
--- /dev/null
+++ b/library/input.c
@@ -0,0 +1,61 @@
+/*
+ This file is part of Fennix Drivers.
+
+ Fennix Drivers is free software: you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation, either version 3 of
+ the License, or (at your option) any later version.
+
+ Fennix Drivers is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Fennix Drivers. If not, see .
+*/
+
+#include
+
+extern __driverAPI *API;
+
+dev_t RegisterInputDevice(DeviceDriverType Type)
+{
+ return API->RegisterInputDevice(API->MajorID, Type);
+}
+
+int UnregisterInputDevice(dev_t DeviceID, DeviceDriverType Type)
+{
+ return API->UnregisterInputDevice(API->MajorID, DeviceID, Type);
+}
+
+int ReportKeyboardEvent(dev_t DeviceID, KeyScanCodes ScanCode, uint8_t Pressed)
+{
+ if (Pressed)
+ ScanCode |= KEY_PRESSED;
+ return API->ReportKeyboardEvent(API->MajorID, DeviceID, ScanCode);
+}
+
+int ReportRelativeMouseEvent(dev_t DeviceID, MouseReport Report)
+{
+ __MouseButtons mb = {
+ .LeftButton = Report.LeftButton,
+ .RightButton = Report.RightButton,
+ .MiddleButton = Report.MiddleButton,
+ .Button4 = Report.Button4,
+ .Button5 = Report.Button5,
+ };
+ return API->ReportRelativeMouseEvent(API->MajorID, DeviceID, mb, Report.X, Report.Y, Report.Z);
+}
+
+int ReportAbsoluteMouseEvent(dev_t DeviceID, MouseReport Report, uintptr_t X, uintptr_t Y)
+{
+ __MouseButtons mb = {
+ .LeftButton = Report.LeftButton,
+ .RightButton = Report.RightButton,
+ .MiddleButton = Report.MiddleButton,
+ .Button4 = Report.Button4,
+ .Button5 = Report.Button5,
+ };
+ return API->ReportAbsoluteMouseEvent(API->MajorID, DeviceID, mb, X, Y, Report.Z);
+}
diff --git a/library/net.c b/library/net.c
new file mode 100644
index 0000000..fa37a70
--- /dev/null
+++ b/library/net.c
@@ -0,0 +1,36 @@
+/*
+ This file is part of Fennix Drivers.
+
+ Fennix Drivers is free software: you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation, either version 3 of
+ the License, or (at your option) any later version.
+
+ Fennix Drivers is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Fennix Drivers. If not, see .
+*/
+
+#include
+
+extern __driverAPI *API;
+
+dev_t RegisterNetDevice(DeviceDriverType Type, drvOpen_t Open, drvClose_t Close,
+ drvRead_t Read, drvWrite_t Write, drvIoctl_t Ioctl)
+{
+ return API->RegisterNetDevice(API->MajorID, Type, Open, Close, Read, Write, Ioctl);
+}
+
+int UnregisterNetDevice(dev_t DeviceID, DeviceDriverType Type)
+{
+ return API->UnregisterNetDevice(API->MajorID, DeviceID, Type);
+}
+
+int ReportNetworkPacket(dev_t DeviceID, void *Buffer, size_t Size)
+{
+ return API->ReportNetworkPacket(API->MajorID, DeviceID, Buffer, Size);
+}
diff --git a/library/pci.c b/library/pci.c
new file mode 100644
index 0000000..7bea853
--- /dev/null
+++ b/library/pci.c
@@ -0,0 +1,57 @@
+/*
+ This file is part of Fennix Drivers.
+
+ Fennix Drivers is free software: you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation, either version 3 of
+ the License, or (at your option) any later version.
+
+ Fennix Drivers is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Fennix Drivers. If not, see .
+*/
+
+#include
+
+#include
+
+extern __driverAPI *API;
+
+static_assert(sizeof(PCIArray) == sizeof(__PCIArray),
+ "PCIArray size mismatch");
+
+PCIArray *FindPCIDevices(uint16_t Vendors[], uint16_t Devices[])
+{
+ return (PCIArray *)API->GetPCIDevices(API->MajorID,
+ Vendors,
+ Devices);
+}
+
+void InitializePCI(PCIDevice *Device)
+{
+ API->InitializePCI(API->MajorID,
+ (void *)Device->Header);
+}
+
+uint32_t GetBAR(uint8_t Index, PCIDevice *Device)
+{
+ return API->GetBAR(API->MajorID,
+ Index,
+ (void *)Device->Header);
+}
+
+uint8_t iLine(PCIDevice *Device)
+{
+ PCIHeader0 *Header = (PCIHeader0 *)Device->Header;
+ return Header->InterruptLine;
+}
+
+uint8_t iPin(PCIDevice *Device)
+{
+ PCIHeader0 *Header = (PCIHeader0 *)Device->Header;
+ return Header->InterruptPin;
+}
diff --git a/library/std.c b/library/std.c
new file mode 100644
index 0000000..3cbe942
--- /dev/null
+++ b/library/std.c
@@ -0,0 +1,51 @@
+/*
+ This file is part of Fennix Drivers.
+
+ Fennix Drivers is free software: you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation, either version 3 of
+ the License, or (at your option) any later version.
+
+ Fennix Drivers is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Fennix Drivers. If not, see .
+*/
+
+#include
+#include
+
+#undef memcpy
+#undef memset
+#undef memmove
+#undef strlen
+
+extern __driverAPI *API;
+
+void *MemoryCopy(void *Destination, const void *Source, size_t Length)
+{
+ return API->memcpy(API->MajorID, Destination, Source, Length);
+}
+
+void *MemorySet(void *Destination, int Value, size_t Length)
+{
+ return API->memset(API->MajorID, Destination, Value, Length);
+}
+
+void *MemoryMove(void *Destination, const void *Source, size_t Length)
+{
+ return API->memmove(API->MajorID, Destination, Source, Length);
+}
+
+size_t StringLength(const char String[])
+{
+ return API->strlen(API->MajorID, String);
+}
+
+char *strstr(const char *Haystack, const char *Needle)
+{
+ return API->strstr(API->MajorID, Haystack, Needle);
+}
diff --git a/library/stdcpp.cpp b/library/stdcpp.cpp
new file mode 100644
index 0000000..ecf7751
--- /dev/null
+++ b/library/stdcpp.cpp
@@ -0,0 +1,73 @@
+/*
+ This file is part of Fennix Drivers.
+
+ Fennix Drivers is free software: you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation, either version 3 of
+ the License, or (at your option) any later version.
+
+ Fennix Drivers is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Fennix Drivers. If not, see .
+*/
+
+#include
+#include
+
+extern __driverAPI *API;
+
+/**
+ * TODO: memory allocator
+ * we can't really call kernel's malloc because the
+ * kernel keep track of memory usage for each driver
+ *
+ * maybe implement the allocator in vma?
+ */
+
+void *__new_alloc_page(std::size_t Size)
+{
+ /* Do not allow allocations larger than 4 KiB */
+ if (Size > PAGE_SIZE)
+ asmv("ud2");
+
+ return API->RequestPages(API->MajorID, 1);
+}
+
+void __delete_alloc_page(void *Pointer)
+{
+ API->FreePages(API->MajorID, Pointer, 1);
+}
+
+void *operator new(std::size_t Size)
+{
+ return __new_alloc_page(Size);
+}
+
+void *operator new[](std::size_t Size)
+{
+ return __new_alloc_page(Size);
+}
+
+void operator delete(void *Pointer)
+{
+ __delete_alloc_page(Pointer);
+}
+
+void operator delete[](void *Pointer)
+{
+ __delete_alloc_page(Pointer);
+}
+
+void operator delete(void *Pointer, std::size_t)
+{
+ __delete_alloc_page(Pointer);
+}
+
+void operator delete[](void *Pointer, std::size_t)
+{
+ __delete_alloc_page(Pointer);
+}
diff --git a/library/task.c b/library/task.c
new file mode 100644
index 0000000..de7e65d
--- /dev/null
+++ b/library/task.c
@@ -0,0 +1,59 @@
+/*
+ This file is part of Fennix Drivers.
+
+ Fennix Drivers is free software: you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation, either version 3 of
+ the License, or (at your option) any later version.
+
+ Fennix Drivers is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Fennix Drivers. If not, see .
+*/
+
+#include
+#include
+
+extern __driverAPI *API;
+
+pid_t CreateKernelProcess(const char *Name)
+{
+ return API->CreateKernelProcess(API->MajorID,
+ Name);
+}
+
+pid_t CreateKernelThread(pid_t pId, const char *Name, void *EntryPoint, void *Argument)
+{
+ return API->CreateKernelThread(API->MajorID,
+ pId,
+ Name,
+ EntryPoint,
+ Argument);
+}
+
+int KillProcess(pid_t pId, int ExitCode)
+{
+ return API->KillProcess(API->MajorID,
+ pId, ExitCode);
+}
+
+int KillThread(pid_t tId, int ExitCode)
+{
+ return API->KillThread(API->MajorID,
+ tId, ExitCode);
+}
+
+void Yield()
+{
+ API->Yield(API->MajorID);
+}
+
+void Sleep(uint64_t Milliseconds)
+{
+ API->Sleep(API->MajorID,
+ Milliseconds);
+}
diff --git a/library/vm.c b/library/vm.c
new file mode 100644
index 0000000..f0cd2fc
--- /dev/null
+++ b/library/vm.c
@@ -0,0 +1,114 @@
+/*
+ This file is part of Fennix Drivers.
+
+ Fennix Drivers is free software: you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation, either version 3 of
+ the License, or (at your option) any later version.
+
+ Fennix Drivers is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Fennix Drivers. If not, see .
+*/
+
+#include
+
+int __strcmp(const char *l, const char *r)
+{
+ for (; *l == *r && *l; l++, r++)
+ ;
+
+ return *(unsigned char *)l - *(unsigned char *)r;
+}
+
+void __cpuid(uint32_t Function,
+ uint32_t *eax, uint32_t *ebx,
+ uint32_t *ecx, uint32_t *edx)
+{
+ asmv("cpuid"
+ : "=a"(*eax), "=b"(*ebx), "=c"(*ecx), "=d"(*edx)
+ : "a"(Function));
+}
+
+bool __CheckHypervisorBit()
+{
+ uint32_t eax, ebx, ecx, edx;
+ __cpuid(0x1, &eax, &ebx, &ecx, &edx);
+ if (!(ecx & (1 << 31)))
+ return false; /* Hypervisor not detected */
+ return true;
+}
+
+bool __VMwareBackdoorHypervisors()
+{
+ const char hv[13] = {0};
+ uint32_t eax, ebx, ecx, edx;
+ __cpuid(0x40000000, &eax, &ebx, &ecx, &edx);
+
+ *(uint32_t *)hv = ebx;
+ *(uint32_t *)(hv + 4) = ecx;
+ *(uint32_t *)(hv + 8) = edx;
+
+ if (__strcmp(hv, "VMwareVMware") != 0 &&
+ __strcmp(hv, "KVMKVMKVM") != 0 &&
+ __strcmp(hv, "TCGTCGTCGTCG") != 0)
+ {
+ return false;
+ }
+ return true;
+}
+
+bool IsVMwareBackdoorAvailable()
+{
+ if (!__CheckHypervisorBit())
+ return false;
+
+ if (!__VMwareBackdoorHypervisors())
+ return false;
+
+ struct
+ {
+ union
+ {
+ uint32_t ax;
+ uint32_t magic;
+ };
+ union
+ {
+ uint32_t bx;
+ size_t size;
+ };
+ union
+ {
+ uint32_t cx;
+ uint16_t command;
+ };
+ union
+ {
+ uint32_t dx;
+ uint16_t port;
+ };
+ uint32_t si;
+ uint32_t di;
+ } cmd;
+
+ cmd.si = cmd.di = 0;
+ cmd.bx = ~0x564D5868;
+ cmd.command = 0xA;
+ cmd.magic = 0x564D5868;
+ cmd.port = 0x5658;
+
+ asmv("in %%dx, %0"
+ : "+a"(cmd.ax), "+b"(cmd.bx),
+ "+c"(cmd.cx), "+d"(cmd.dx),
+ "+S"(cmd.si), "+D"(cmd.di));
+
+ if (cmd.bx != 0x564D5868 ||
+ cmd.ax == 0xFFFFFFFF)
+ return false;
+ return true;
+}
diff --git a/misc/Makefile b/misc/Makefile
new file mode 100644
index 0000000..f90db13
--- /dev/null
+++ b/misc/Makefile
@@ -0,0 +1,7 @@
+build:
+ make -C example build
+ make -C vmware build
+
+clean:
+ make -C example clean
+ make -C vmware clean
diff --git a/misc/example/Makefile b/misc/example/Makefile
new file mode 100644
index 0000000..b15790f
--- /dev/null
+++ b/misc/example/Makefile
@@ -0,0 +1,83 @@
+# Config file
+include ../../../Makefile.conf
+
+FILENAME = example.drv
+
+CC = ../../../$(COMPILER_PATH)/$(COMPILER_ARCH)gcc
+CPP = ../../../$(COMPILER_PATH)/$(COMPILER_ARCH)g++
+LD = ../../../$(COMPILER_PATH)/$(COMPILER_ARCH)ld
+AS = ../../../$(COMPILER_PATH)/$(COMPILER_ARCH)as
+OBJDUMP = ../../../$(COMPILER_PATH)/$(COMPILER_ARCH)objdump
+
+S_SOURCES = $(shell find ./ -type f -name '*.S')
+C_SOURCES = $(shell find ./ -type f -name '*.c')
+CPP_SOURCES = $(shell find ./ -type f -name '*.cpp')
+HEADERS = $(sort $(dir $(wildcard ../../include/*)))
+OBJ = $(C_SOURCES:.c=.o) $(CPP_SOURCES:.cpp=.o) $(ASM_SOURCES:.asm=.o) $(S_SOURCES:.S=.o) $(PSF_SOURCES:.psf=.o) $(BMP_SOURCES:.bmp=.o)
+STACK_USAGE_OBJ = $(C_SOURCES:.c=.su) $(CPP_SOURCES:.cpp=.su)
+INCLUDE_DIR = ../../include
+
+LIBS := ../../out/dcrt0.o -L../../out -ldriver
+
+LDFLAGS := \
+ -fPIC -fPIE -pie \
+ -Wl,--no-dynamic-linker,-ztext,--no-warn-rwx-segment \
+ -nostdlib -nodefaultlibs -nolibc \
+ -zmax-page-size=0x1000 \
+ -Wl,-Map file.map -shared -fvisibility=hidden
+
+WARNCFLAG = -Wall -Wextra
+
+CFLAGS := -I$(INCLUDE_DIR) -fvisibility=hidden
+
+ifeq ($(OSARCH), amd64)
+
+CFLAGS += -fPIC -fPIE -pie -mno-80387 -mno-mmx -mno-3dnow \
+ -mno-red-zone -mno-sse -mno-sse2 \
+ -march=x86-64 -pipe -ffunction-sections \
+ -msoft-float -fno-builtin
+
+else ifeq ($(OSARCH), i386)
+
+CFLAGS += -fPIC -fPIE -pie -mno-80387 -mno-mmx -mno-3dnow \
+ -mno-red-zone -mno-sse -mno-sse2 -ffunction-sections \
+ -march=i386 -pipe -msoft-float -fno-builtin
+
+else ifeq ($(OSARCH), aarch64)
+
+CFLAGS += -pipe -fno-builtin -fPIC
+
+endif
+
+ifeq ($(DEBUG), 1)
+ CFLAGS += -DDEBUG -ggdb3 -O0 -fdiagnostics-color=always -fstack-usage
+ifeq ($(OSARCH), amd64)
+ CFLAGS += -fverbose-asm
+endif
+ifneq ($(OSARCH), aarch64)
+ CFLAGS += -fstack-check
+endif
+ LDFLAGS += -ggdb3 -O0
+endif
+
+build: $(FILENAME)
+ mv $(FILENAME) ../../out/$(FILENAME)
+
+$(FILENAME): $(OBJ)
+ $(info Linking $@)
+ $(CC) $(LDFLAGS) $(OBJ) $(LIBS) -o $@
+
+%.o: %.c $(HEADERS)
+ $(info Compiling $<)
+ $(CC) $(CFLAGS) $(WARNCFLAG) -std=c17 -c $< -o $@
+
+%.o: %.cpp $(HEADERS)
+ $(info Compiling $<)
+ $(CPP) $(CFLAGS) $(WARNCFLAG) -std=c++20 -fno-exceptions -fno-rtti -c $< -o $@
+
+%.o: %.S
+ $(info Compiling $<)
+ $(AS) -o $@ $<
+
+clean:
+ rm -f file.map $(OBJ) $(STACK_USAGE_OBJ)
diff --git a/misc/example/main.c b/misc/example/main.c
new file mode 100644
index 0000000..b4f363b
--- /dev/null
+++ b/misc/example/main.c
@@ -0,0 +1,87 @@
+/*
+ This file is part of Fennix Drivers.
+
+ Fennix Drivers is free software: you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation, either version 3 of
+ the License, or (at your option) any later version.
+
+ Fennix Drivers is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Fennix Drivers. If not, see .
+*/
+
+#include
+
+int DriverEntry()
+{
+ /** This is the main function of the driver.
+ * This function is called when the driver is loaded.
+ * This function should be used to initialize the PCI device
+ * and allocate resources.
+ */
+
+ /* Print a message to the screen */
+ KPrint("Hello World from Example Driver!");
+
+ /* Print a message to the kernel log */
+ Log("Hello World from Example Driver!");
+
+ /* Print a message only if DEBUG is set */
+ DebugLog("Hello World from Example Driver!");
+
+ /* Return 0 to indicate success */
+ return 0;
+}
+
+int DriverFinal()
+{
+ /** This function is called when the driver is unloaded.
+ * This function should be used to stop the PCI device and
+ * free any resources.
+ */
+
+ return 0;
+}
+
+int DriverPanic()
+{
+ /** This function is called when the kernel panics.
+ * This function should be used to stop the driver from
+ * receiving interrupts or anything else that is not
+ * safe to do when the kernel panics.
+ */
+
+ return 0;
+}
+
+int DriverProbe()
+{
+ /** This is the first function that is called when the
+ * driver is loaded.
+ * We can use this function to test if the driver is
+ * compatible with the hardware.
+ * Like if we have a specific PCI device or if we have
+ * a specific CPU feature.
+ *
+ * Return 0 if the driver is compatible with the hardware.
+ * Otherwise, we return a value from the errno.h header.
+ *
+ * Note: In this function you cannot use variables that
+ * have constructors or destructors. Before DriverEntry,
+ * the constructors are called and after DriverFinalize,
+ * the destructors are called.
+ */
+
+ return 0;
+}
+
+DriverInfo("example",
+ "Example Driver",
+ "EnderIce2",
+ "0.1",
+ "GPLv3");
diff --git a/misc/vmware/Makefile b/misc/vmware/Makefile
new file mode 100644
index 0000000..171f3b4
--- /dev/null
+++ b/misc/vmware/Makefile
@@ -0,0 +1,83 @@
+# Config file
+include ../../../Makefile.conf
+
+FILENAME = vmware.drv
+
+CC = ../../../$(COMPILER_PATH)/$(COMPILER_ARCH)gcc
+CPP = ../../../$(COMPILER_PATH)/$(COMPILER_ARCH)g++
+LD = ../../../$(COMPILER_PATH)/$(COMPILER_ARCH)ld
+AS = ../../../$(COMPILER_PATH)/$(COMPILER_ARCH)as
+OBJDUMP = ../../../$(COMPILER_PATH)/$(COMPILER_ARCH)objdump
+
+S_SOURCES = $(shell find ./ -type f -name '*.S')
+C_SOURCES = $(shell find ./ -type f -name '*.c')
+CPP_SOURCES = $(shell find ./ -type f -name '*.cpp')
+HEADERS = $(sort $(dir $(wildcard ../../include/*)))
+OBJ = $(C_SOURCES:.c=.o) $(CPP_SOURCES:.cpp=.o) $(ASM_SOURCES:.asm=.o) $(S_SOURCES:.S=.o) $(PSF_SOURCES:.psf=.o) $(BMP_SOURCES:.bmp=.o)
+STACK_USAGE_OBJ = $(C_SOURCES:.c=.su) $(CPP_SOURCES:.cpp=.su)
+INCLUDE_DIR = ../../include
+
+LIBS := ../../out/dcrt0.o -L../../out -ldriver
+
+LDFLAGS := \
+ -fPIC -fPIE -pie \
+ -Wl,--no-dynamic-linker,-ztext,--no-warn-rwx-segment \
+ -nostdlib -nodefaultlibs -nolibc \
+ -zmax-page-size=0x1000 \
+ -Wl,-Map file.map -shared -fvisibility=hidden
+
+WARNCFLAG = -Wall -Wextra
+
+CFLAGS := -I$(INCLUDE_DIR) -fvisibility=hidden
+
+ifeq ($(OSARCH), amd64)
+
+CFLAGS += -fPIC -fPIE -pie -mno-80387 -mno-mmx -mno-3dnow \
+ -mno-red-zone -mno-sse -mno-sse2 \
+ -march=x86-64 -pipe -ffunction-sections \
+ -msoft-float -fno-builtin
+
+else ifeq ($(OSARCH), i386)
+
+CFLAGS += -fPIC -fPIE -pie -mno-80387 -mno-mmx -mno-3dnow \
+ -mno-red-zone -mno-sse -mno-sse2 -ffunction-sections \
+ -march=i386 -pipe -msoft-float -fno-builtin
+
+else ifeq ($(OSARCH), aarch64)
+
+CFLAGS += -pipe -fno-builtin -fPIC
+
+endif
+
+ifeq ($(DEBUG), 1)
+ CFLAGS += -DDEBUG -ggdb3 -O0 -fdiagnostics-color=always -fstack-usage
+ifeq ($(OSARCH), amd64)
+ CFLAGS += -fverbose-asm
+endif
+ifneq ($(OSARCH), aarch64)
+ CFLAGS += -fstack-check
+endif
+ LDFLAGS += -ggdb3 -O0
+endif
+
+build: $(FILENAME)
+ mv $(FILENAME) ../../out/$(FILENAME)
+
+$(FILENAME): $(OBJ)
+ $(info Linking $@)
+ $(CC) $(LDFLAGS) $(OBJ) $(LIBS) -o $@
+
+%.o: %.c $(HEADERS)
+ $(info Compiling $<)
+ $(CC) $(CFLAGS) $(WARNCFLAG) -std=c17 -c $< -o $@
+
+%.o: %.cpp $(HEADERS)
+ $(info Compiling $<)
+ $(CPP) $(CFLAGS) $(WARNCFLAG) -std=c++20 -fno-exceptions -fno-rtti -c $< -o $@
+
+%.o: %.S
+ $(info Compiling $<)
+ $(AS) -o $@ $<
+
+clean:
+ rm -f file.map $(OBJ) $(STACK_USAGE_OBJ)
diff --git a/misc/vmware/main.c b/misc/vmware/main.c
new file mode 100644
index 0000000..515e1a7
--- /dev/null
+++ b/misc/vmware/main.c
@@ -0,0 +1,753 @@
+/*
+ This file is part of Fennix Drivers.
+
+ Fennix Drivers is free software: you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation, either version 3 of
+ the License, or (at your option) any later version.
+
+ Fennix Drivers is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Fennix Drivers. If not, see .
+*/
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+enum RPCMessages
+{
+ MSG_OPEN,
+ MSG_SENDSIZE,
+ MSG_SENDPAYLOAD,
+ MSG_RECVSIZE,
+ MSG_RECVPAYLOAD,
+ MSG_RECVSTATUS,
+ MSG_CLOSE,
+};
+
+enum RPCStatus
+{
+ STATUS_SUCCESS = 0x1,
+ STATUS_DORECV = 0x2,
+ STATUS_CPT = 0x10,
+ STATUS_HB = 0x80,
+};
+
+typedef struct
+{
+ union
+ {
+ uint32_t ax;
+ uint32_t magic;
+ };
+ union
+ {
+ uint32_t bx;
+ size_t size;
+ };
+ union
+ {
+ uint32_t cx;
+ uint16_t command;
+ };
+ union
+ {
+ uint32_t dx;
+ uint16_t port;
+ };
+ uint32_t si;
+ uint32_t di;
+} VMwareCommand;
+
+#define VMWARE_MAGIC 0x564D5868
+
+#define VMWARE_PORT 0x5658
+#define VMWARE_PORTHB 0x5659
+
+#define VMWARE_HYPERVISOR_HB 0x00000000
+#define VMWARE_HYPERVISOR_OUT 0x00000001
+
+#define CMD_GETVERSION 0xA
+#define CMD_MESSAGE 0x1E
+#define CMD_ABSPOINTER_DATA 0x27
+#define CMD_ABSPOINTER_STATUS 0x28
+#define CMD_ABSPOINTER_COMMAND 0x29
+
+#define ABSPOINTER_ENABLE 0x45414552
+#define ABSPOINTER_RELATIVE 0xF5
+#define ABSPOINTER_ABSOLUTE 0x53424152
+
+#define MESSAGE_RPCI 0x49435052
+#define MESSAGE_TCLO 0x4f4c4354
+
+#define FLAG_COOKIE 0x80000000
+
+#define ToMsg(x) ((x) << 16 | CMD_MESSAGE)
+#define HighWord(x) ((x & 0xFFFF0000) >> 16)
+
+#define MESSAGE_HB_MSG 0
+
+#define MESSAGE_OPEN_CHANNEL ToMsg(MSG_OPEN)
+#define MESSAGE_CLOSE_CHANNEL ToMsg(MSG_CLOSE)
+
+#define MESSAGE_SEND_SIZE ToMsg(MSG_SENDSIZE)
+#define MESSAGE_SEND_PAYLOAD ToMsg(MSG_SENDPAYLOAD)
+
+#define MESSAGE_RECV_SIZE ToMsg(MSG_RECVSIZE)
+#define MESSAGE_RECV_PAYLOAD ToMsg(MSG_RECVPAYLOAD)
+#define MESSAGE_RECV_STATUS ToMsg(MSG_RECVSTATUS)
+
+#define VM_PORT(cmd, in_ebx, isi, idi, \
+ flags, magic, \
+ ax, bx, cx, dx, si, di) \
+ __asm__ __volatile__("movw $0x5658, %%dx\n" \
+ "inl %%dx, %%eax\n" \
+ : "=a"(ax), \
+ "=b"(bx), \
+ "=c"(cx), \
+ "=d"(dx), \
+ "=S"(si), \
+ "=D"(di) \
+ : "a"(magic), \
+ "b"(in_ebx), \
+ "c"(cmd), \
+ "d"(flags), \
+ "S"(isi), \
+ "D"(idi) : "memory")
+
+#define VM_PORT_HB_OUT(cmd, in_ecx, isi, idi, \
+ flags, magic, bp, \
+ ax, bx, cx, dx, si, di) \
+ __asm__ __volatile__("push %%rbp\n" \
+ "mov %12, %%rbp\n" \
+ "movw $0x5659, %%dx\n" \
+ "rep outsb\n" \
+ "pop %%rbp\n" \
+ : "=a"(ax), \
+ "=b"(bx), \
+ "=c"(cx), \
+ "=d"(dx), \
+ "=S"(si), \
+ "=D"(di) \
+ : "a"(magic), \
+ "b"(cmd), \
+ "c"(in_ecx), \
+ "d"(flags), \
+ "S"(isi), \
+ "D"(idi), \
+ "r"(bp) : "memory", "cc")
+
+#define VM_PORT_HB_IN(cmd, in_ecx, isi, idi, \
+ flags, magic, bp, \
+ ax, bx, cx, dx, si, di) \
+ __asm__ __volatile__("push %%rbp\n" \
+ "mov %12, %%rbp\n" \
+ "movw $0x5659, %%dx\n" \
+ "rep insb\n" \
+ "pop %%rbp\n" \
+ : "=a"(ax), \
+ "=b"(bx), \
+ "=c"(cx), \
+ "=d"(dx), \
+ "=S"(si), \
+ "=D"(di) \
+ : "a"(magic), \
+ "b"(cmd), \
+ "c"(in_ecx), \
+ "d"(flags), \
+ "S"(isi), \
+ "D"(idi), \
+ "r"(bp) : "memory", "cc")
+
+/* TODO:
+ - use vmcall or vmmcall instead of out or in if available
+*/
+
+typedef struct
+{
+ int TCLOChannel;
+ uint16_t ChannelID;
+ uint32_t CookieHigh;
+ uint32_t CookieLow;
+} ToolboxContext;
+
+dev_t MouseDevID = -1;
+
+static int OpenMessageChannel(ToolboxContext *ctx, uint32_t Protocol)
+{
+ uintptr_t ax, bx, cx, dx, si = 0, di = 0;
+
+ VM_PORT(MESSAGE_OPEN_CHANNEL,
+ (Protocol | FLAG_COOKIE), si, di,
+ 0, VMWARE_MAGIC,
+ ax, bx, cx, dx, si, di);
+
+ if ((HighWord(cx) & STATUS_SUCCESS) == 0)
+ {
+ Log("Failed to open message channel %#lx", Protocol);
+ return -EINVAL;
+ }
+
+ DebugLog("Opened message channel %d (Protocol: %#lx)",
+ HighWord(dx), Protocol);
+ ctx->ChannelID = (uint16_t)HighWord(dx);
+ ctx->CookieHigh = si;
+ ctx->CookieLow = di;
+ return 0;
+}
+
+static void MessageClose(ToolboxContext *ctx)
+{
+ uintptr_t ax, bx, cx, dx,
+ si = ctx->CookieHigh,
+ di = ctx->CookieLow;
+
+ VM_PORT(MESSAGE_CLOSE_CHANNEL,
+ 0, si, di,
+ ctx->ChannelID << 16,
+ VMWARE_MAGIC,
+ ax, bx, cx, dx, si, di);
+
+ DebugLog("Closed message channel %d", ctx->ChannelID);
+}
+
+static uintptr_t MessageSendHB(ToolboxContext *ctx,
+ const char *Message)
+{
+ uintptr_t ax, bx, cx, dx,
+ si = (uintptr_t)Message,
+ di = ctx->CookieLow,
+ bp = ctx->CookieHigh;
+
+ uint32_t ChannelID = ctx->ChannelID << 16;
+ size_t Size = StringLength(Message);
+
+ VM_PORT_HB_OUT((STATUS_SUCCESS << 16) | MESSAGE_HB_MSG,
+ Size, si, di,
+ VMWARE_HYPERVISOR_HB | ChannelID | VMWARE_HYPERVISOR_OUT,
+ VMWARE_MAGIC, bp,
+ ax, bx, cx, dx, si, di);
+
+ return bx;
+}
+
+static uintptr_t MessageSendLB(ToolboxContext *ctx,
+ const char *Message)
+{
+ uintptr_t ax, bx,
+ cx = STATUS_SUCCESS << 16,
+ dx, si, di;
+
+ size_t Size = StringLength(Message);
+ while (Size &&
+ (HighWord(cx) & STATUS_SUCCESS))
+ {
+ uint32_t TotalBytes = MIN((uint32_t)Size, (uint32_t)4);
+ uint32_t Word = 0;
+ MemoryCopy(&Word, Message, TotalBytes);
+ Message += TotalBytes;
+
+ si = ctx->CookieHigh;
+ di = ctx->CookieLow;
+
+ VM_PORT(MESSAGE_SEND_PAYLOAD,
+ Word, si, di,
+ ctx->ChannelID << 16,
+ VMWARE_MAGIC,
+ ax, bx, cx, dx, si, di);
+ }
+
+ return cx;
+}
+
+static uintptr_t MessageReceiveHB(ToolboxContext *ctx,
+ char *Buffer,
+ size_t BufferSize)
+{
+ uintptr_t ax, bx, cx, dx,
+ si = ctx->CookieHigh,
+ di = (uintptr_t)Buffer,
+ bp = ctx->CookieLow;
+
+ uint32_t ChannelID = ctx->ChannelID << 16;
+
+ VM_PORT_HB_IN((STATUS_SUCCESS << 16) | MESSAGE_HB_MSG,
+ BufferSize, si, di,
+ VMWARE_HYPERVISOR_HB | ChannelID | VMWARE_HYPERVISOR_OUT,
+ VMWARE_MAGIC, bp,
+ ax, bx, cx, dx, si, di);
+
+ return bx;
+}
+
+static uintptr_t MessageReceiveLB(ToolboxContext *ctx,
+ char *Buffer,
+ size_t BufferSize)
+{
+ uintptr_t ax, bx,
+ cx = STATUS_SUCCESS << 16,
+ dx, si, di;
+
+ while (BufferSize)
+ {
+ uint32_t TotalBytes = MIN((uint32_t)BufferSize, (uint32_t)4);
+
+ si = ctx->CookieHigh;
+ di = ctx->CookieLow;
+
+ VM_PORT(MESSAGE_RECV_PAYLOAD,
+ STATUS_SUCCESS, si, di,
+ ctx->ChannelID << 16,
+ VMWARE_MAGIC,
+ ax, bx, cx, dx, si, di);
+
+ if ((HighWord(cx) & STATUS_SUCCESS) == 0)
+ break;
+
+ MemoryCopy(Buffer, &bx, TotalBytes);
+ Buffer += TotalBytes;
+ BufferSize -= TotalBytes;
+ }
+
+ return cx;
+}
+
+static int MessageSend(ToolboxContext *ctx,
+ const char *Message)
+{
+ uintptr_t ax, bx, cx, dx, si, di;
+ size_t Size = StringLength(Message);
+ int Retries = 0;
+
+ while (Retries < 2)
+ {
+ Retries++;
+ si = ctx->CookieHigh;
+ di = ctx->CookieLow;
+
+ VM_PORT(MESSAGE_SEND_SIZE,
+ Size, si, di,
+ ctx->ChannelID << 16,
+ VMWARE_MAGIC,
+ ax, bx, cx, dx, si, di);
+
+ if ((HighWord(cx) & STATUS_SUCCESS) == 0)
+ {
+ Log("Failed to send message size for \"%s\": %d",
+ Message, cx);
+ return -EINVAL;
+ }
+
+ bool HighBand = (HighWord(cx) & STATUS_HB) != 0;
+ if (HighBand)
+ bx = MessageSendHB(ctx, Message);
+ else
+ bx = MessageSendLB(ctx, Message);
+
+ int status = HighWord(bx);
+
+ if ((status & STATUS_SUCCESS) != 0)
+ {
+ DebugLog("Message \"%s\" sent", Message);
+ return 0;
+ }
+ else if ((status & STATUS_CPT) == 0)
+ {
+ Log("Checkpoint occurred for message \"%s\"", Message);
+ continue;
+ }
+ else
+ break;
+ }
+
+ Log("Failed to send message \"%s\": %#lx", Message, bx);
+ return -EINVAL;
+}
+
+static int MessageReceive(ToolboxContext *ctx,
+ char **Buffer,
+ size_t *BufferSize)
+{
+ uintptr_t ax, bx, cx, dx, si, di;
+ int Retries = 0;
+
+ *Buffer = NULL;
+ *BufferSize = 0;
+
+ char *ReplyBuf = NULL;
+ size_t ReplyBufPages = 0;
+ size_t ReplySize = 0;
+ while (Retries < 2)
+ {
+ Retries++;
+ si = ctx->CookieHigh;
+ di = ctx->CookieLow;
+
+ VM_PORT(MESSAGE_RECV_SIZE,
+ 0, si, di,
+ ctx->ChannelID << 16,
+ VMWARE_MAGIC,
+ ax, bx, cx, dx, si, di);
+
+ if ((HighWord(cx) & STATUS_SUCCESS) == 0)
+ {
+ Log("Failed to receive message size: %d", cx);
+ return -EINVAL;
+ }
+ else if ((HighWord(cx) & STATUS_DORECV) == 0)
+ {
+ // Log("No message to receive");
+ return -EAGAIN;
+ }
+
+ ReplySize = bx;
+
+ if (ReplyBuf != NULL)
+ FreeMemory(ReplyBuf, ReplyBufPages);
+ ReplyBufPages = ReplySize / 0x1000 + 1;
+ ReplyBuf = AllocateMemory(ReplyBufPages);
+
+ bool HighBand = (HighWord(cx) & STATUS_HB) != 0;
+ if (HighBand)
+ bx = MessageReceiveHB(ctx, ReplyBuf, ReplySize);
+ else
+ bx = MessageReceiveLB(ctx, ReplyBuf, ReplySize);
+
+ if ((HighWord(bx) & STATUS_SUCCESS) == 0)
+ {
+ if ((HighWord(bx) & STATUS_CPT) == 0)
+ {
+ Log("Checkpoint occurred for message payload");
+ continue;
+ }
+
+ Log("Failed to receive message payload: %d", HighWord(bx));
+ FreeMemory(ReplyBuf, ReplyBufPages);
+ return -EINVAL;
+ }
+
+ ReplyBuf[ReplySize] = '\0';
+
+ si = ctx->CookieHigh;
+ di = ctx->CookieLow;
+
+ VM_PORT(MESSAGE_RECV_STATUS,
+ STATUS_SUCCESS, si, di,
+ ctx->ChannelID << 16,
+ VMWARE_MAGIC,
+ ax, bx, cx, dx, si, di);
+
+ if ((HighWord(cx) & STATUS_SUCCESS) == 0)
+ {
+ if ((HighWord(cx) & STATUS_CPT) == 0)
+ {
+ Log("Retrying message receive");
+ continue;
+ }
+
+ Log("Failed to receive message status: %d", HighWord(cx));
+ FreeMemory(ReplyBuf, ReplyBufPages);
+ return -EINVAL;
+ }
+
+ break;
+ }
+
+ if (ReplyBuf == NULL)
+ {
+ Log("Failed to receive message");
+ return -EINVAL;
+ }
+
+ *Buffer = ReplyBuf;
+ *BufferSize = ReplySize;
+ DebugLog("Received message \"%s\"", ReplyBuf);
+ return 0;
+}
+
+static int SendRPCI(ToolboxContext *, const char *Request)
+{
+ ToolboxContext rpci_ctx = {0};
+ int status = OpenMessageChannel(&rpci_ctx, MESSAGE_RPCI);
+ if (status < 0)
+ {
+ Log("Failed to open RPCI channel: %d", status);
+ return status;
+ }
+
+ status = MessageSend(&rpci_ctx, Request);
+ if (status < 0)
+ {
+ Log("Failed to send RPCI request: %d", status);
+ return status;
+ }
+
+ MessageClose(&rpci_ctx);
+ return 0;
+}
+
+int MsgEqual(const char *haystack, const char *needle)
+{
+ return strstr(haystack, needle) == haystack;
+}
+
+static int DisplayGetSize(ToolboxContext *ctx)
+{
+ if (ctx->TCLOChannel != -1)
+ MessageClose(ctx);
+ OpenMessageChannel(ctx, MESSAGE_TCLO);
+
+ char EmptyBuffer[256] = {'\0'};
+ MessageSend(ctx, EmptyBuffer);
+
+ while (true)
+ {
+ /* FIXME: buf memory leak */
+ char *buf;
+ size_t len;
+
+ int status = MessageReceive(ctx, &buf, &len);
+ if (status == -EAGAIN)
+ {
+ Sleep(1000);
+ continue;
+ }
+ else if (status < 0)
+ {
+ Log("Failed to receive message");
+ return 1;
+ }
+
+ buf[StringLength(buf)] = '\0';
+ if (MsgEqual(buf, "reset"))
+ {
+ if (MessageSend(ctx, "OK ATR toolbox") < 0)
+ return 1;
+ }
+ else if (MsgEqual(buf, "ping"))
+ {
+ if (MessageSend(ctx, "OK ") < 0)
+ return 1;
+ }
+ else if (MsgEqual(buf, "Capabilities_Register"))
+ {
+ SendRPCI(ctx, "tools.capability.resolution_set 1");
+ SendRPCI(ctx, "tools.capability.resolution_server toolbox 1");
+ SendRPCI(ctx, "tools.capability.display_topology_set 1");
+ SendRPCI(ctx, "tools.capability.color_depth_set 1");
+ SendRPCI(ctx, "tools.capability.resolution_min 0 0");
+ SendRPCI(ctx, "tools.capability.unity 1");
+
+ if (MessageSend(ctx, "OK ") < 0)
+ return 1;
+ }
+ else if (MsgEqual(buf, "Resolution_Set"))
+ {
+ DebugLog("%s", buf);
+ if (MessageSend(ctx, "OK ") < 0)
+ return 1;
+ MessageClose(ctx);
+ return 0;
+ }
+ else
+ {
+ if (MessageSend(ctx, "ERROR Unknown command") < 0)
+ return 1;
+ }
+ }
+}
+
+pid_t dst_id = -1;
+ToolboxContext *tb_ctx = NULL;
+void DisplayScaleThread()
+{
+ /* sizeof ToolboxContext */
+ tb_ctx = AllocateMemory(1);
+ Sleep(2000);
+
+ while (true)
+ {
+ if (DisplayGetSize(tb_ctx) != 0)
+ Log("Failed to scale display");
+ Sleep(1000);
+ }
+}
+
+void CommandSend(VMwareCommand *cmd)
+{
+ cmd->magic = VMWARE_MAGIC;
+ cmd->port = VMWARE_PORT;
+ asm volatile("in %%dx, %0"
+ : "+a"(cmd->ax), "+b"(cmd->bx),
+ "+c"(cmd->cx), "+d"(cmd->dx),
+ "+S"(cmd->si), "+D"(cmd->di));
+}
+
+void Absolute()
+{
+ VMwareCommand cmd = {0};
+
+ /* Enable */
+ cmd.bx = ABSPOINTER_ENABLE;
+ cmd.command = CMD_ABSPOINTER_COMMAND;
+ CommandSend(&cmd);
+
+ /* Status */
+ cmd.bx = 0;
+ cmd.command = CMD_ABSPOINTER_STATUS;
+ CommandSend(&cmd);
+
+ /* Read data (1) */
+ cmd.bx = 1;
+ cmd.command = CMD_ABSPOINTER_DATA;
+ CommandSend(&cmd);
+
+ /* Enable absolute */
+ cmd.bx = ABSPOINTER_ABSOLUTE;
+ cmd.command = CMD_ABSPOINTER_COMMAND;
+ CommandSend(&cmd);
+}
+
+void Relative()
+{
+ VMwareCommand cmd = {0};
+ cmd.bx = ABSPOINTER_RELATIVE;
+ cmd.command = CMD_ABSPOINTER_COMMAND;
+ CommandSend(&cmd);
+}
+
+void InterruptHandler(TrapFrame *)
+{
+ uint8_t Data = inb(0x60);
+ (void)Data;
+
+ VMwareCommand cmd = {0};
+ cmd.bx = 0;
+ cmd.command = CMD_ABSPOINTER_STATUS;
+ CommandSend(&cmd);
+
+ if (cmd.ax == 0xFFFF0000)
+ {
+ Log("VMware mouse is not connected?");
+ Relative();
+ Absolute();
+ return;
+ }
+
+ if ((cmd.ax & 0xFFFF) < 4)
+ return;
+
+ cmd.bx = 4;
+ cmd.command = CMD_ABSPOINTER_DATA;
+ CommandSend(&cmd);
+
+ int Buttons = (cmd.ax & 0xFFFF);
+
+ MouseReport mr = {
+ .LeftButton = Buttons & 0x20,
+ .RightButton = Buttons & 0x10,
+ .MiddleButton = Buttons & 0x08,
+ .Button4 = 0x0,
+ .Button5 = 0x0,
+ .X = 0,
+ .Y = 0,
+ .Z = (int8_t)cmd.dx,
+ };
+
+ /**
+ * How should I handle this?
+ * (cmd.[bx,cx] * Width) / 0xFFFF
+ * Maybe TODO: Width and Height API?
+ */
+ uintptr_t AbsoluteX = cmd.bx;
+ uintptr_t AbsoluteY = cmd.cx;
+ ReportAbsoluteMouseEvent(MouseDevID, mr, AbsoluteX, AbsoluteY);
+}
+
+bool ToolboxSupported = false;
+int DriverEntry()
+{
+ ToolboxContext tb_ctx = {0};
+ /* Test if it's supported */
+ int status = OpenMessageChannel(&tb_ctx, MESSAGE_TCLO);
+ if (status == 0)
+ {
+ ToolboxSupported = true;
+ MessageClose(&tb_ctx);
+ dst_id = CreateKernelThread(0, "VMware Display Scale",
+ (void *)DisplayScaleThread, NULL);
+ }
+
+ PS2WriteCommand(PS2_CMD_ENABLE_PORT_2);
+ PS2WriteCommand(PS2_CMD_READ_CONFIG);
+ PS2_CONFIGURATION config = {.Raw = PS2ReadData()};
+ config.Port2Interrupt = 1;
+ PS2WriteCommand(PS2_CMD_WRITE_CONFIG);
+ PS2WriteData(config.Raw);
+
+ PS2WriteCommand(PS2_CMD_WRITE_NEXT_BYTE_TO_PS2_PORT_2_INPUT);
+ PS2WriteData(PS2_MOUSE_CMD_SET_DEFAULTS);
+ PS2ReadData();
+
+ PS2WriteCommand(PS2_CMD_WRITE_NEXT_BYTE_TO_PS2_PORT_2_INPUT);
+ PS2WriteData(PS2_MOUSE_CMD_ENABLE_DATA_REPORTING);
+ PS2ReadData();
+ Absolute();
+
+ /**
+ * If we have another driver using the PS/2 mouse, we need to
+ * override its interrupt handler.
+ */
+ OverrideInterruptHandler(12, InterruptHandler);
+ MouseDevID = RegisterInputDevice(ddt_Mouse);
+ return 0;
+}
+
+int DriverFinal()
+{
+ PS2WriteCommand(PS2_CMD_WRITE_NEXT_BYTE_TO_PS2_PORT_2_INPUT);
+ PS2WriteData(PS2_MOUSE_CMD_DISABLE_DATA_REPORTING);
+
+ Relative();
+ UnregisterInputDevice(MouseDevID, ddt_Mouse);
+
+ if (ToolboxSupported)
+ {
+ KillThread(dst_id, 0);
+ if (tb_ctx->TCLOChannel != -1)
+ MessageClose(tb_ctx);
+ FreeMemory(tb_ctx, 1);
+ }
+ return 0;
+}
+
+int DriverPanic()
+{
+ Relative();
+ PS2WriteCommand(PS2_CMD_WRITE_NEXT_BYTE_TO_PS2_PORT_2_INPUT);
+ PS2WriteData(PS2_MOUSE_CMD_DISABLE_DATA_REPORTING);
+ return 0;
+}
+
+int DriverProbe()
+{
+ if (!IsVMwareBackdoorAvailable())
+ return -ENODEV;
+ return 0;
+}
+
+DriverInfo("vmware",
+ "VMware Tools Driver",
+ "EnderIce2",
+ "0.1",
+ "GPLv3");
diff --git a/network/Makefile b/network/Makefile
new file mode 100644
index 0000000..1e9340b
--- /dev/null
+++ b/network/Makefile
@@ -0,0 +1,7 @@
+build:
+ make -C e1000 build
+ make -C rtl8139 build
+
+clean:
+ make -C e1000 clean
+ make -C rtl8139 clean
diff --git a/network/e1000/Makefile b/network/e1000/Makefile
new file mode 100644
index 0000000..cd5cbb9
--- /dev/null
+++ b/network/e1000/Makefile
@@ -0,0 +1,83 @@
+# Config file
+include ../../../Makefile.conf
+
+FILENAME = e1000.drv
+
+CC = ../../../$(COMPILER_PATH)/$(COMPILER_ARCH)gcc
+CPP = ../../../$(COMPILER_PATH)/$(COMPILER_ARCH)g++
+LD = ../../../$(COMPILER_PATH)/$(COMPILER_ARCH)ld
+AS = ../../../$(COMPILER_PATH)/$(COMPILER_ARCH)as
+OBJDUMP = ../../../$(COMPILER_PATH)/$(COMPILER_ARCH)objdump
+
+S_SOURCES = $(shell find ./ -type f -name '*.S')
+C_SOURCES = $(shell find ./ -type f -name '*.c')
+CPP_SOURCES = $(shell find ./ -type f -name '*.cpp')
+HEADERS = $(sort $(dir $(wildcard ../../include/*)))
+OBJ = $(C_SOURCES:.c=.o) $(CPP_SOURCES:.cpp=.o) $(ASM_SOURCES:.asm=.o) $(S_SOURCES:.S=.o) $(PSF_SOURCES:.psf=.o) $(BMP_SOURCES:.bmp=.o)
+STACK_USAGE_OBJ = $(C_SOURCES:.c=.su) $(CPP_SOURCES:.cpp=.su)
+INCLUDE_DIR = ../../include
+
+LIBS := ../../out/dcrt0.o -L../../out -ldriver
+
+LDFLAGS := \
+ -fPIC -fPIE -pie \
+ -Wl,--no-dynamic-linker,-ztext,--no-warn-rwx-segment \
+ -nostdlib -nodefaultlibs -nolibc \
+ -zmax-page-size=0x1000 \
+ -Wl,-Map file.map -shared -fvisibility=hidden
+
+WARNCFLAG = -Wall -Wextra
+
+CFLAGS := -I$(INCLUDE_DIR) -fvisibility=hidden
+
+ifeq ($(OSARCH), amd64)
+
+CFLAGS += -fPIC -fPIE -pie -mno-80387 -mno-mmx -mno-3dnow \
+ -mno-red-zone -mno-sse -mno-sse2 \
+ -march=x86-64 -pipe -ffunction-sections \
+ -msoft-float -fno-builtin
+
+else ifeq ($(OSARCH), i386)
+
+CFLAGS += -fPIC -fPIE -pie -mno-80387 -mno-mmx -mno-3dnow \
+ -mno-red-zone -mno-sse -mno-sse2 -ffunction-sections \
+ -march=i386 -pipe -msoft-float -fno-builtin
+
+else ifeq ($(OSARCH), aarch64)
+
+CFLAGS += -pipe -fno-builtin -fPIC
+
+endif
+
+ifeq ($(DEBUG), 1)
+ CFLAGS += -DDEBUG -ggdb3 -O0 -fdiagnostics-color=always -fstack-usage
+ifeq ($(OSARCH), amd64)
+ CFLAGS += -fverbose-asm
+endif
+ifneq ($(OSARCH), aarch64)
+ CFLAGS += -fstack-check
+endif
+ LDFLAGS += -ggdb3 -O0
+endif
+
+build: $(FILENAME)
+ mv $(FILENAME) ../../out/$(FILENAME)
+
+$(FILENAME): $(OBJ)
+ $(info Linking $@)
+ $(CC) $(LDFLAGS) $(OBJ) $(LIBS) -o $@
+
+%.o: %.c $(HEADERS)
+ $(info Compiling $<)
+ $(CC) $(CFLAGS) $(WARNCFLAG) -std=c17 -c $< -o $@
+
+%.o: %.cpp $(HEADERS)
+ $(info Compiling $<)
+ $(CPP) $(CFLAGS) $(WARNCFLAG) -std=c++20 -fno-exceptions -fno-rtti -c $< -o $@
+
+%.o: %.S
+ $(info Compiling $<)
+ $(AS) -o $@ $<
+
+clean:
+ rm -f file.map $(OBJ) $(STACK_USAGE_OBJ)
diff --git a/network/e1000/e1000.cpp b/network/e1000/e1000.cpp
new file mode 100644
index 0000000..43f57c2
--- /dev/null
+++ b/network/e1000/e1000.cpp
@@ -0,0 +1,485 @@
+/*
+ This file is part of Fennix Kernel.
+
+ Fennix Kernel is free software: you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation, either version 3 of
+ the License, or (at your option) any later version.
+
+ Fennix Kernel is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Fennix Kernel. If not, see .
+*/
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "e1000.hpp"
+
+class E1000Device
+{
+private:
+ PCIHeader0 *Header;
+ uint16_t DeviceID;
+ bool Initialized = false;
+
+ bool EEPROMAvailable;
+
+ struct BARData
+ {
+ uint8_t Type;
+ uint16_t IOBase;
+ uint64_t MemoryBase;
+ } BAR;
+
+#define E1000_NUM_RX_DESC 32
+#define E1000_NUM_TX_DESC 8
+ RXDescriptor *RX[E1000_NUM_RX_DESC];
+ TXDescriptor *TX[E1000_NUM_TX_DESC];
+
+ uint16_t RXCurrent;
+ uint16_t TXCurrent;
+
+ const int BaseBufferSize = 8192;
+ const int AdditionalBytes = 16;
+
+ uint32_t CurrentPacket;
+
+ void WriteCMD(uint16_t Address, uint32_t Value)
+ {
+ if (BAR.Type == 0)
+ mmoutl((void *)(BAR.MemoryBase + Address), Value);
+ else
+ {
+ outl(BAR.IOBase, Address);
+ outl(BAR.IOBase + 4, Value);
+ }
+ }
+
+ uint32_t ReadCMD(uint16_t Address)
+ {
+ if (BAR.Type == 0)
+ return mminl((void *)(BAR.MemoryBase + Address));
+ else
+ {
+ outl(BAR.IOBase, Address);
+ return inl(BAR.IOBase + 0x4);
+ }
+ }
+
+ uint32_t ReadEEPROM(uint8_t Address)
+ {
+ uint16_t Data = 0;
+ uint32_t temp = 0;
+ if (EEPROMAvailable)
+ {
+ WriteCMD(REG::EEPROM, (1) | ((uint32_t)(Address) << 8));
+ while (!((temp = ReadCMD(REG::EEPROM)) & (1 << 4)))
+ ;
+ }
+ else
+ {
+ WriteCMD(REG::EEPROM, (1) | ((uint32_t)(Address) << 2));
+ while (!((temp = ReadCMD(REG::EEPROM)) & (1 << 1)))
+ ;
+ }
+ Data = (uint16_t)((temp >> 16) & 0xFFFF);
+ return Data;
+ }
+
+ void InitializeRX()
+ {
+ DebugLog("Initializing RX...");
+ uintptr_t Ptr = (uintptr_t)AllocateMemory(TO_PAGES(sizeof(RXDescriptor) *
+ E1000_NUM_RX_DESC +
+ AdditionalBytes));
+
+ for (int i = 0; i < E1000_NUM_RX_DESC; i++)
+ {
+ RX[i] = (RXDescriptor *)(Ptr + i * 16);
+ RX[i]->Address = (uint64_t)AllocateMemory(TO_PAGES(BaseBufferSize + AdditionalBytes));
+ RX[i]->Status = 0;
+ }
+
+#pragma GCC diagnostic ignored "-Wshift-count-overflow"
+
+ WriteCMD(REG::TXDESCLO, (uint32_t)(Ptr >> 32));
+ WriteCMD(REG::TXDESCHI, (uint32_t)(Ptr & 0xFFFFFFFF));
+
+ WriteCMD(REG::RXDESCLO, (uint32_t)Ptr);
+ WriteCMD(REG::RXDESCHI, 0);
+
+ WriteCMD(REG::RXDESCLEN, E1000_NUM_RX_DESC * 16);
+
+ WriteCMD(REG::RXDESCHEAD, 0);
+ WriteCMD(REG::RXDESCTAIL, E1000_NUM_RX_DESC - 1);
+ RXCurrent = 0;
+ WriteCMD(REG::RCTRL, RCTL::EN | RCTL::SBP | RCTL::UPE |
+ RCTL::MPE | RCTL::LBM_NONE |
+ RTCL::RDMTS_HALF | RCTL::BAM |
+ RCTL::SECRC | RCTL::BSIZE_8192);
+ }
+
+ void InitializeTX()
+ {
+ DebugLog("Initializing TX...");
+ uintptr_t Ptr = (uintptr_t)AllocateMemory(TO_PAGES(sizeof(TXDescriptor) *
+ E1000_NUM_RX_DESC +
+ AdditionalBytes));
+
+ for (short i = 0; i < E1000_NUM_TX_DESC; i++)
+ {
+ TX[i] = (TXDescriptor *)((uintptr_t)Ptr + i * 16);
+ TX[i]->Address = 0;
+ TX[i]->Command = 0;
+ TX[i]->Status = TSTA::DD;
+ }
+
+ WriteCMD(REG::TXDESCHI, (uint32_t)((uint64_t)Ptr >> 32));
+ WriteCMD(REG::TXDESCLO, (uint32_t)((uint64_t)Ptr & 0xFFFFFFFF));
+
+ WriteCMD(REG::TXDESCLEN, E1000_NUM_TX_DESC * 16);
+
+ WriteCMD(REG::TXDESCHEAD, 0);
+ WriteCMD(REG::TXDESCTAIL, 0);
+ TXCurrent = 0;
+ WriteCMD(REG::TCTRL, TCTL::EN_ | TCTL::PSP |
+ (15 << TCTL::CT_SHIFT) |
+ (64 << TCTL::COLD_SHIFT) |
+ TCTL::RTLC);
+
+ WriteCMD(REG::TCTRL, 0b0110000000000111111000011111010);
+ WriteCMD(REG::TIPG, 0x0060200A);
+ }
+
+public:
+ dev_t ID;
+
+ bool IsInitialized() { return Initialized; }
+
+ size_t write(uint8_t *Buffer, size_t Size)
+ {
+ TX[TXCurrent]->Address = (uint64_t)Buffer;
+ TX[TXCurrent]->Length = (uint16_t)Size;
+ TX[TXCurrent]->Command = CMD::EOP | CMD::IFCS | CMD::RS;
+ TX[TXCurrent]->Status = 0;
+ uint16_t OldTXCurrent = TXCurrent;
+ TXCurrent = (uint16_t)((TXCurrent + 1) % E1000_NUM_TX_DESC);
+ WriteCMD(REG::TXDESCTAIL, TXCurrent);
+ while (!(TX[OldTXCurrent]->Status & 0xFF))
+ Yield();
+ return Size;
+ }
+
+ MediaAccessControl GetMAC()
+ {
+ MediaAccessControl mac;
+ if (EEPROMAvailable)
+ {
+ uint32_t temp;
+ temp = ReadEEPROM(0);
+ mac.Address[0] = temp & 0xff;
+ mac.Address[1] = (uint8_t)(temp >> 8);
+ temp = ReadEEPROM(1);
+ mac.Address[2] = temp & 0xff;
+ mac.Address[3] = (uint8_t)(temp >> 8);
+ temp = ReadEEPROM(2);
+ mac.Address[4] = temp & 0xff;
+ mac.Address[5] = (uint8_t)(temp >> 8);
+ }
+ else
+ {
+ uint8_t *BaseMac8 = (uint8_t *)(BAR.MemoryBase + 0x5400);
+ uint32_t *BaseMac32 = (uint32_t *)(BAR.MemoryBase + 0x5400);
+ if (BaseMac32[0] != 0)
+ for (int i = 0; i < 6; i++)
+ mac.Address[i] = BaseMac8[i];
+ else
+ {
+ Log("No MAC address found.");
+ return MediaAccessControl();
+ }
+ }
+
+ return mac;
+ }
+
+ int ioctl(NetIoctl req, void *arg)
+ {
+ switch (req)
+ {
+ case IOCTL_NET_GET_MAC:
+ {
+ MediaAccessControl mac = GetMAC();
+ *((uint48_t *)arg) = mac.ToHex(); /* UNTESTED */
+ return 0;
+ }
+ default:
+ return -EINVAL;
+ }
+ return 0;
+ }
+
+ void OnInterruptReceived(TrapFrame *)
+ {
+ WriteCMD(REG::IMASK, 0x1);
+ uint32_t status = ReadCMD(0xC0);
+ UNUSED(status);
+
+ while ((RX[RXCurrent]->Status & 0x1))
+ {
+ uint8_t *data = (uint8_t *)RX[RXCurrent]->Address;
+ uint16_t dataSz = RX[RXCurrent]->Length;
+
+ ReportNetworkPacket(ID, data, dataSz);
+
+ RX[RXCurrent]->Status = 0;
+ uint16_t OldRXCurrent = RXCurrent;
+ RXCurrent = (uint16_t)((RXCurrent + 1) % E1000_NUM_RX_DESC);
+ WriteCMD(REG::RXDESCTAIL, OldRXCurrent);
+ }
+ }
+
+ void Panic()
+ {
+ WriteCMD(REG::IMASK, 0x00000000);
+ WriteCMD(REG::ITR, 0x00000000);
+ WriteCMD(REG::IAM, 0x00000000);
+ }
+
+ E1000Device(PCIHeader0 *_Header, uint16_t _DeviceID)
+ : Header(_Header),
+ DeviceID(_DeviceID)
+ {
+ uint32_t PCIBAR0 = Header->BAR0;
+ uint32_t PCIBAR1 = Header->BAR1;
+ BAR.Type = PCIBAR0 & 1;
+ BAR.IOBase = (uint16_t)(PCIBAR0 & (~3));
+ BAR.MemoryBase = PCIBAR1 & (~15);
+
+ switch (DeviceID)
+ {
+ case 0x100E:
+ {
+ Log("Found Intel 82540EM Gigabit Ethernet Controller.");
+
+ /* Detect EEPROM */
+ WriteCMD(REG::EEPROM, 0x1);
+ for (int i = 0; i < 1000 && !EEPROMAvailable; i++)
+ if (ReadCMD(REG::EEPROM) & 0x10)
+ EEPROMAvailable = true;
+ else
+ EEPROMAvailable = false;
+
+ if (!GetMAC().Valid())
+ {
+ Log("Failed to get MAC");
+ return;
+ }
+
+ /* Start link */
+ uint32_t cmdret = ReadCMD(REG::CTRL);
+ WriteCMD(REG::CTRL, cmdret | ECTRL::SLU);
+
+ for (int i = 0; i < 0x80; i++)
+ WriteCMD((uint16_t)(0x5200 + i * 4), 0);
+
+ WriteCMD(REG::IMASK, 0x1F6DC);
+ WriteCMD(REG::IMASK, 0xFF & ~4);
+ ReadCMD(0xC0);
+
+ InitializeRX();
+ InitializeTX();
+ break;
+ }
+ default:
+ {
+ Log("Unimplemented E1000 device.");
+ return;
+ }
+ }
+
+ Initialized = true;
+ }
+
+ ~E1000Device()
+ {
+ if (!Initialized)
+ return;
+
+ switch (DeviceID)
+ {
+ case 0x100E:
+ {
+ // Clearing Enable bit in Receive Control Register
+ uint32_t cmdret = ReadCMD(REG::RCTRL);
+ WriteCMD(REG::RCTRL, cmdret & ~RCTL::EN);
+
+ // Masking Interrupt Mask, Interrupt Throttling Rate & Interrupt Auto-Mask
+ WriteCMD(REG::IMASK, 0x00000000);
+ WriteCMD(REG::ITR, 0x00000000);
+ WriteCMD(REG::IAM, 0x00000000);
+
+ // Clearing SLU bit in Device Control Register
+ cmdret = ReadCMD(REG::CTRL);
+ WriteCMD(REG::CTRL, cmdret & ~ECTRL::SLU);
+
+ // Clear the Interrupt Cause Read register by reading it
+ ReadCMD(REG::ICR);
+
+ // Powering down the device (?)
+ WriteCMD(REG::CTRL, PCTRL::POWER_DOWN);
+ /* TODO: Stop link; further testing required */
+ break;
+ }
+ default:
+ {
+ Log("Unimplemented E1000 device.");
+ return;
+ }
+ }
+ }
+};
+
+E1000Device *Drivers[4] = {nullptr};
+dev_t AudioID[4] = {0};
+
+#define OIR(x) OIR_##x
+#define CREATE_OIR(x) \
+ void OIR_##x(TrapFrame *f) { Drivers[x]->OnInterruptReceived(f); }
+
+CREATE_OIR(0);
+CREATE_OIR(1);
+CREATE_OIR(2);
+CREATE_OIR(3);
+
+int drvOpen(dev_t, dev_t, int, mode_t) { return 0; }
+int drvClose(dev_t, dev_t) { return 0; }
+size_t drvRead(dev_t, dev_t, uint8_t *, size_t, off_t) { return 0; }
+
+size_t drvWrite(dev_t, dev_t min, uint8_t *Buffer, size_t Size, off_t)
+{
+ return Drivers[AudioID[min]]->write(Buffer, Size);
+}
+
+int drvIoctl(dev_t, dev_t min, unsigned long Request, void *Argp)
+{
+ return Drivers[AudioID[min]]->ioctl((NetIoctl)Request, Argp);
+}
+
+PCIArray *Devices;
+EXTERNC int cxx_Panic()
+{
+ PCIArray *ctx = Devices;
+ short Count = 0;
+ while (ctx != nullptr)
+ {
+ if (Drivers[Count] != nullptr)
+ Drivers[Count]->Panic();
+ Count++;
+ ctx = (PCIArray *)ctx->Next;
+ }
+
+ return 0;
+}
+
+EXTERNC int cxx_Probe()
+{
+ uint16_t VendorIDs[] = {0x8086, /* Intel */
+ PCI_END};
+ uint16_t DeviceIDs[] = {0x100E, /* 82540EM */
+ 0x100F, /* 82545EM */
+ 0x10D3, /* 82574L */
+ 0x10EA, /* I217-LM */
+ 0x153A, /* 82577LM */
+ PCI_END};
+ Devices = FindPCIDevices(VendorIDs, DeviceIDs);
+ if (Devices == nullptr)
+ {
+ Log("No E1000 device found.");
+ return -ENODEV;
+ }
+ return 0;
+}
+
+EXTERNC int cxx_Initialize()
+{
+ PCIArray *ctx = Devices;
+ size_t Count = 0;
+ while (ctx != nullptr)
+ {
+ if (Count > sizeof(Drivers) / sizeof(E1000Device *))
+ break;
+
+ InitializePCI(ctx->Device);
+
+ Drivers[Count] = new E1000Device((PCIHeader0 *)ctx->Device->Header,
+ ctx->Device->Header->DeviceID);
+
+ if (Drivers[Count]->IsInitialized())
+ {
+ dev_t ret = RegisterNetDevice(ddt_Network,
+ drvOpen, drvClose,
+ drvRead, drvWrite,
+ drvIoctl);
+ AudioID[Count] = ret;
+ Drivers[Count]->ID = ret;
+
+ /* FIXME: bad code */
+ switch (Count)
+ {
+ case 0:
+ RegisterInterruptHandler(iLine(ctx->Device), (void *)OIR(0));
+ break;
+ case 1:
+ RegisterInterruptHandler(iLine(ctx->Device), (void *)OIR(1));
+ break;
+ case 2:
+ RegisterInterruptHandler(iLine(ctx->Device), (void *)OIR(2));
+ break;
+ case 3:
+ RegisterInterruptHandler(iLine(ctx->Device), (void *)OIR(3));
+ break;
+ default:
+ break;
+ }
+
+ Count++;
+ }
+ ctx = (PCIArray *)ctx->Next;
+ }
+
+ if (Count == 0)
+ {
+ Log("No valid E1000 device found.");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+EXTERNC int cxx_Finalize()
+{
+ PCIArray *ctx = Devices;
+ size_t Count = 0;
+ while (ctx != nullptr)
+ {
+ if (Count++ > sizeof(Drivers) / sizeof(E1000Device *))
+ break;
+
+ delete Drivers[Count++];
+ ctx->Device->Header->Command |= PCI_COMMAND_INTX_DISABLE;
+ ctx = (PCIArray *)ctx->Next;
+ }
+
+ return 0;
+}
diff --git a/network/e1000/e1000.hpp b/network/e1000/e1000.hpp
new file mode 100644
index 0000000..73c6848
--- /dev/null
+++ b/network/e1000/e1000.hpp
@@ -0,0 +1,163 @@
+/*
+ This file is part of Fennix Drivers.
+
+ Fennix Drivers is free software: you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation, either version 3 of
+ the License, or (at your option) any later version.
+
+ Fennix Drivers is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Fennix Drivers. If not, see .
+*/
+
+#pragma once
+
+#include
+
+#ifdef __cplusplus
+enum REG
+{
+ CTRL = 0x0000,
+ STATUS = 0x0008,
+ ICR = 0x000C,
+ EEPROM = 0x0014,
+ CTRL_EXT = 0x0018,
+ ITR = 0x00C4,
+ IMASK = 0x00D0,
+ IAM = 0x00D8,
+ RCTRL = 0x0100,
+ RXDESCLO = 0x2800,
+ RXDESCHI = 0x2804,
+ RXDESCLEN = 0x2808,
+ RXDESCHEAD = 0x2810,
+ RXDESCTAIL = 0x2818,
+ TCTRL = 0x0400,
+ TXDESCLO = 0x3800,
+ TXDESCHI = 0x3804,
+ TXDESCLEN = 0x3808,
+ TXDESCHEAD = 0x3810,
+ TXDESCTAIL = 0x3818,
+ RDTR = 0x2820,
+ RXDCTL = 0x3828,
+ RADV = 0x282C,
+ RSRPD = 0x2C00,
+ TIPG = 0x0410
+};
+
+enum PCTRL
+{
+ RESERVED = 0b000000,
+ SPEED_SELECTION_MSB = 0b010000,
+ UPDATE_COLLISION_TEST = 0b001000,
+ DUPLEX_MODE = 0b000100,
+ RESTART_AUTO_NEGOTIATION = 0b000010,
+ ISOLATE = 0b000001,
+ POWER_DOWN = 0b100000,
+ SPEED_SELECTION_LSB = 0b100000,
+};
+
+enum ECTRL
+{
+ SLU = 0x40
+};
+
+enum RTCL
+{
+ RDMTS_HALF = (0 << 8),
+ RDMTS_QUARTER = (1 << 8),
+ RDMTS_EIGHTH = (2 << 8)
+};
+
+enum RCTL
+{
+ EN = (1 << 1),
+ SBP = (1 << 2),
+ UPE = (1 << 3),
+ MPE = (1 << 4),
+ LPE = (1 << 5),
+ LBM_NONE = (0 << 6),
+ LBM_PHY = (3 << 6),
+ MO_36 = (0 << 12),
+ MO_35 = (1 << 12),
+ MO_34 = (2 << 12),
+ MO_32 = (3 << 12),
+ BAM = (1 << 15),
+ VFE = (1 << 18),
+ CFIEN = (1 << 19),
+ CFI = (1 << 20),
+ DPF = (1 << 22),
+ PMCF = (1 << 23),
+ SECRC = (1 << 26),
+ BSIZE_256 = (3 << 16),
+ BSIZE_512 = (2 << 16),
+ BSIZE_1024 = (1 << 16),
+ BSIZE_2048 = (0 << 16),
+ BSIZE_4096 = ((3 << 16) | (1 << 25)),
+ BSIZE_8192 = ((2 << 16) | (1 << 25)),
+ BSIZE_16384 = ((1 << 16) | (1 << 25))
+};
+
+enum CMD
+{
+ EOP = (1 << 0),
+ IFCS = (1 << 1),
+ IC = (1 << 2),
+ RS = (1 << 3),
+ RPS = (1 << 4),
+ VLE = (1 << 6),
+ IDE = (1 << 7)
+};
+
+enum TCTL
+{
+ EN_ = (1 << 1),
+ PSP = (1 << 3),
+ CT_SHIFT = 4,
+ COLD_SHIFT = 12,
+ SWXOFF = (1 << 22),
+ RTLC = (1 << 24)
+};
+
+enum TSTA
+{
+ DD = (1 << 0),
+ EC = (1 << 1),
+ LC = (1 << 2)
+};
+
+enum LSTA
+{
+ LSTA_TU = (1 << 3)
+};
+
+struct RXDescriptor
+{
+ volatile uint64_t Address;
+ volatile uint16_t Length;
+ volatile uint16_t Checksum;
+ volatile uint8_t Status;
+ volatile uint8_t Errors;
+ volatile uint16_t Special;
+} __attribute__((packed));
+
+struct TXDescriptor
+{
+ volatile uint64_t Address;
+ volatile uint16_t Length;
+ volatile uint8_t cso;
+ volatile uint8_t Command;
+ volatile uint8_t Status;
+ volatile uint8_t css;
+ volatile uint16_t Special;
+} __attribute__((packed));
+#endif
+
+EXTERNC int cxx_Panic();
+EXTERNC int cxx_Probe();
+EXTERNC int cxx_Initialize();
+EXTERNC int cxx_Finalize();
diff --git a/network/e1000/main.c b/network/e1000/main.c
new file mode 100644
index 0000000..9f3a46e
--- /dev/null
+++ b/network/e1000/main.c
@@ -0,0 +1,31 @@
+/*
+ This file is part of Fennix Drivers.
+
+ Fennix Drivers is free software: you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation, either version 3 of
+ the License, or (at your option) any later version.
+
+ Fennix Drivers is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Fennix Drivers. If not, see .
+*/
+
+#include
+
+#include "e1000.hpp"
+
+int DriverEntry() { return cxx_Initialize(); }
+int DriverFinal() { return cxx_Finalize(); }
+int DriverPanic() { return cxx_Panic(); }
+int DriverProbe() { return cxx_Probe(); }
+
+DriverInfo("e1000",
+ "Intel(R) PRO/1000 Network Driver",
+ "EnderIce2",
+ "0.1",
+ "GPLv3");
diff --git a/network/rtl8139/Makefile b/network/rtl8139/Makefile
new file mode 100644
index 0000000..1a41216
--- /dev/null
+++ b/network/rtl8139/Makefile
@@ -0,0 +1,83 @@
+# Config file
+include ../../../Makefile.conf
+
+FILENAME = rtl8139.drv
+
+CC = ../../../$(COMPILER_PATH)/$(COMPILER_ARCH)gcc
+CPP = ../../../$(COMPILER_PATH)/$(COMPILER_ARCH)g++
+LD = ../../../$(COMPILER_PATH)/$(COMPILER_ARCH)ld
+AS = ../../../$(COMPILER_PATH)/$(COMPILER_ARCH)as
+OBJDUMP = ../../../$(COMPILER_PATH)/$(COMPILER_ARCH)objdump
+
+S_SOURCES = $(shell find ./ -type f -name '*.S')
+C_SOURCES = $(shell find ./ -type f -name '*.c')
+CPP_SOURCES = $(shell find ./ -type f -name '*.cpp')
+HEADERS = $(sort $(dir $(wildcard ../../include/*)))
+OBJ = $(C_SOURCES:.c=.o) $(CPP_SOURCES:.cpp=.o) $(ASM_SOURCES:.asm=.o) $(S_SOURCES:.S=.o) $(PSF_SOURCES:.psf=.o) $(BMP_SOURCES:.bmp=.o)
+STACK_USAGE_OBJ = $(C_SOURCES:.c=.su) $(CPP_SOURCES:.cpp=.su)
+INCLUDE_DIR = ../../include
+
+LIBS := ../../out/dcrt0.o -L../../out -ldriver
+
+LDFLAGS := \
+ -fPIC -fPIE -pie \
+ -Wl,--no-dynamic-linker,-ztext,--no-warn-rwx-segment \
+ -nostdlib -nodefaultlibs -nolibc \
+ -zmax-page-size=0x1000 \
+ -Wl,-Map file.map -shared -fvisibility=hidden
+
+WARNCFLAG = -Wall -Wextra
+
+CFLAGS := -I$(INCLUDE_DIR) -fvisibility=hidden
+
+ifeq ($(OSARCH), amd64)
+
+CFLAGS += -fPIC -fPIE -pie -mno-80387 -mno-mmx -mno-3dnow \
+ -mno-red-zone -mno-sse -mno-sse2 \
+ -march=x86-64 -pipe -ffunction-sections \
+ -msoft-float -fno-builtin
+
+else ifeq ($(OSARCH), i386)
+
+CFLAGS += -fPIC -fPIE -pie -mno-80387 -mno-mmx -mno-3dnow \
+ -mno-red-zone -mno-sse -mno-sse2 -ffunction-sections \
+ -march=i386 -pipe -msoft-float -fno-builtin
+
+else ifeq ($(OSARCH), aarch64)
+
+CFLAGS += -pipe -fno-builtin -fPIC
+
+endif
+
+ifeq ($(DEBUG), 1)
+ CFLAGS += -DDEBUG -ggdb3 -O0 -fdiagnostics-color=always -fstack-usage
+ifeq ($(OSARCH), amd64)
+ CFLAGS += -fverbose-asm
+endif
+ifneq ($(OSARCH), aarch64)
+ CFLAGS += -fstack-check
+endif
+ LDFLAGS += -ggdb3 -O0
+endif
+
+build: $(FILENAME)
+ mv $(FILENAME) ../../out/$(FILENAME)
+
+$(FILENAME): $(OBJ)
+ $(info Linking $@)
+ $(CC) $(LDFLAGS) $(OBJ) $(LIBS) -o $@
+
+%.o: %.c $(HEADERS)
+ $(info Compiling $<)
+ $(CC) $(CFLAGS) $(WARNCFLAG) -std=c17 -c $< -o $@
+
+%.o: %.cpp $(HEADERS)
+ $(info Compiling $<)
+ $(CPP) $(CFLAGS) $(WARNCFLAG) -std=c++20 -fno-exceptions -fno-rtti -c $< -o $@
+
+%.o: %.S
+ $(info Compiling $<)
+ $(AS) -o $@ $<
+
+clean:
+ rm -f file.map $(OBJ) $(STACK_USAGE_OBJ)
diff --git a/network/rtl8139/main.c b/network/rtl8139/main.c
new file mode 100644
index 0000000..0e6e7da
--- /dev/null
+++ b/network/rtl8139/main.c
@@ -0,0 +1,31 @@
+/*
+ This file is part of Fennix Drivers.
+
+ Fennix Drivers is free software: you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation, either version 3 of
+ the License, or (at your option) any later version.
+
+ Fennix Drivers is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Fennix Drivers. If not, see .
+*/
+
+#include
+
+#include "rtl8139.hpp"
+
+int DriverEntry() { return cxx_Initialize(); }
+int DriverFinal() { return cxx_Finalize(); }
+int DriverPanic() { return cxx_Panic(); }
+int DriverProbe() { return cxx_Probe(); }
+
+DriverInfo("rtl8139",
+ "Realtek RTL8139 Network Driver",
+ "EnderIce2",
+ "0.1",
+ "GPLv3");
diff --git a/network/rtl8139/rtl8139.cpp b/network/rtl8139/rtl8139.cpp
new file mode 100644
index 0000000..8f4e413
--- /dev/null
+++ b/network/rtl8139/rtl8139.cpp
@@ -0,0 +1,298 @@
+/*
+ This file is part of Fennix Kernel.
+
+ Fennix Kernel is free software: you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation, either version 3 of
+ the License, or (at your option) any later version.
+
+ Fennix Kernel is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Fennix Kernel. If not, see .
+*/
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "rtl8139.hpp"
+
+class RTL8139Device
+{
+private:
+ PCIHeader0 *Header;
+ bool Initialized = false;
+
+ struct BARData
+ {
+ uint8_t Type;
+ uint16_t IOBase;
+ uint64_t MemoryBase;
+ } BAR;
+
+ const int BaseBufferSize = 8192;
+ const int WRAPBytes = 1500;
+ const int AdditionalBytes = 16;
+ const int BufferSize = BaseBufferSize +
+ WRAPBytes +
+ AdditionalBytes;
+
+ uint8_t *RXBuffer = nullptr;
+ int TXCurrent = 0;
+ uint16_t CurrentPacket = 0;
+
+ uint8_t TSAD[4] = {0x20, 0x24, 0x28, 0x2C};
+ uint8_t TSD[4] = {0x10, 0x14, 0x18, 0x1C};
+
+public:
+ dev_t ID;
+
+ bool IsInitialized() { return Initialized; }
+
+ size_t write(uint8_t *Buffer, size_t Size)
+ {
+ outl(TSAD[TXCurrent], (uint32_t)(reinterpret_cast(Buffer)));
+ outl(TSD[TXCurrent++], (uint32_t)Size);
+ if (TXCurrent > 3)
+ TXCurrent = 0;
+ return Size;
+ }
+
+ MediaAccessControl GetMAC()
+ {
+ return MediaAccessControl();
+ }
+
+ int ioctl(NetIoctl req, void *)
+ {
+ switch (req)
+ {
+ case IOCTL_NET_GET_MAC:
+ {
+ return -ENOSYS;
+ }
+ default:
+ return -EINVAL;
+ }
+ return 0;
+ }
+
+ void OnInterruptReceived(TrapFrame *)
+ {
+ /* Acknowledge interrupt */
+ uint16_t status = inw(RegISR);
+ DebugLog("%#lx", status);
+
+ /* Read status */
+ if (status & RecOK)
+ {
+ /* Get the current packet */
+ uint16_t *data = (uint16_t *)(RXBuffer + CurrentPacket);
+ uint16_t dataSz = *(data + 1);
+ data += 2;
+
+ ReportNetworkPacket(ID, data, dataSz);
+
+ /* Update CAPR */
+#define RX_READ_PTR_MASK (~0x3)
+ CurrentPacket = (uint16_t)((CurrentPacket + dataSz + 4 + 3) & RX_READ_PTR_MASK);
+ if (CurrentPacket > BufferSize)
+ CurrentPacket -= uint16_t(BufferSize);
+ outw(RegCAPR, CurrentPacket - 0x10);
+ }
+
+ /* Clear interrupt */
+ outw(RegISR, (RecOK | RecBad | SendOK | SendBad));
+ }
+
+ void Panic()
+ {
+ }
+
+ RTL8139Device(PCIHeader0 *_Header)
+ : Header(_Header)
+ {
+ uint32_t PCIBAR0 = Header->BAR0;
+ uint32_t PCIBAR1 = Header->BAR1;
+ BAR.Type = PCIBAR0 & 1;
+ BAR.IOBase = (uint16_t)(PCIBAR0 & (~3));
+ BAR.MemoryBase = PCIBAR1 & (~15);
+
+ RXBuffer = (uint8_t *)AllocateMemory(TO_PAGES(BufferSize));
+
+ /* Power on */
+ outb(RegCONFIG1, 0x0);
+
+ /* Software Reset */
+ outb(RegCMD, 0x10);
+ while (inb(RegCMD) & 0x10)
+ Yield();
+
+ /* Initialize receive buffer */
+ outl(RegRBSTART, (uint32_t)(reinterpret_cast(RXBuffer)));
+
+ /* Configure interrupt mask register */
+ outw(RegIMR, (RecOK | RecBad | SendOK | SendBad));
+ outl(regRCR, (RcAB | RcAM | RcAPM | RcAAP) | RcWRAP);
+
+ /* Enable receive and transmit */
+ outb(RegCMD, 0xC); /* 0xC = RE and TE bit */
+
+ uint32_t MAC1 = inl(RegMAC);
+ uint16_t MAC2 = inw(RegMAR);
+ MediaAccessControl mac = {
+ mac.Address[0] = (uint8_t)MAC1,
+ mac.Address[1] = (uint8_t)(MAC1 >> 8),
+ mac.Address[2] = (uint8_t)(MAC1 >> 16),
+ mac.Address[3] = (uint8_t)(MAC1 >> 24),
+ mac.Address[4] = (uint8_t)MAC2,
+ mac.Address[5] = (uint8_t)(MAC2 >> 8)};
+
+ Initialized = true;
+ }
+
+ ~RTL8139Device()
+ {
+ if (!Initialized)
+ return;
+
+ /* FIXME: Shutdown code */
+ }
+};
+
+RTL8139Device *Drivers[4] = {nullptr};
+dev_t AudioID[4] = {0};
+
+#define OIR(x) OIR_##x
+#define CREATE_OIR(x) \
+ void OIR_##x(TrapFrame *f) { Drivers[x]->OnInterruptReceived(f); }
+
+CREATE_OIR(0);
+CREATE_OIR(1);
+CREATE_OIR(2);
+CREATE_OIR(3);
+
+int drvOpen(dev_t, dev_t, int, mode_t) { return 0; }
+int drvClose(dev_t, dev_t) { return 0; }
+size_t drvRead(dev_t, dev_t, uint8_t *, size_t, off_t) { return 0; }
+
+size_t drvWrite(dev_t, dev_t min, uint8_t *Buffer, size_t Size, off_t)
+{
+ return Drivers[AudioID[min]]->write(Buffer, Size);
+}
+
+int drvIoctl(dev_t, dev_t min, unsigned long Request, void *Argp)
+{
+ return Drivers[AudioID[min]]->ioctl((NetIoctl)Request, Argp);
+}
+
+PCIArray *Devices;
+EXTERNC int cxx_Panic()
+{
+ PCIArray *ctx = Devices;
+ short Count = 0;
+ while (ctx != nullptr)
+ {
+ if (Drivers[Count] != nullptr)
+ Drivers[Count]->Panic();
+ Count++;
+ ctx = (PCIArray *)ctx->Next;
+ }
+
+ return 0;
+}
+
+EXTERNC int cxx_Probe()
+{
+ uint16_t VendorIDs[] = {0x10EC, /* Realtek */
+ PCI_END};
+ uint16_t DeviceIDs[] = {0x8139, /* RTL8139 */
+ PCI_END};
+ Devices = FindPCIDevices(VendorIDs, DeviceIDs);
+ if (Devices == nullptr)
+ {
+ Log("No RTL8139 device found.");
+ return -ENODEV;
+ }
+ return 0;
+}
+
+EXTERNC int cxx_Initialize()
+{
+ PCIArray *ctx = Devices;
+ size_t Count = 0;
+ while (ctx != nullptr)
+ {
+ if (Count > sizeof(Drivers) / sizeof(RTL8139Device *))
+ break;
+
+ InitializePCI(ctx->Device);
+
+ Drivers[Count] = new RTL8139Device((PCIHeader0 *)ctx->Device->Header);
+
+ if (Drivers[Count]->IsInitialized())
+ {
+ dev_t ret = RegisterNetDevice(ddt_Network,
+ drvOpen, drvClose,
+ drvRead, drvWrite,
+ drvIoctl);
+ AudioID[Count] = ret;
+ Drivers[Count]->ID = ret;
+
+ /* FIXME: bad code */
+ switch (Count)
+ {
+ case 0:
+ RegisterInterruptHandler(iLine(ctx->Device), (void *)OIR(0));
+ break;
+ case 1:
+ RegisterInterruptHandler(iLine(ctx->Device), (void *)OIR(1));
+ break;
+ case 2:
+ RegisterInterruptHandler(iLine(ctx->Device), (void *)OIR(2));
+ break;
+ case 3:
+ RegisterInterruptHandler(iLine(ctx->Device), (void *)OIR(3));
+ break;
+ default:
+ break;
+ }
+
+ Count++;
+ }
+ ctx = (PCIArray *)ctx->Next;
+ }
+
+ if (Count == 0)
+ {
+ Log("No valid RTL8139 device found.");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+EXTERNC int cxx_Finalize()
+{
+ PCIArray *ctx = Devices;
+ size_t Count = 0;
+ while (ctx != nullptr)
+ {
+ if (Count++ > sizeof(Drivers) / sizeof(RTL8139Device *))
+ break;
+
+ delete Drivers[Count++];
+ ctx->Device->Header->Command |= PCI_COMMAND_INTX_DISABLE;
+ ctx = (PCIArray *)ctx->Next;
+ }
+
+ return 0;
+}
diff --git a/network/rtl8139/rtl8139.hpp b/network/rtl8139/rtl8139.hpp
new file mode 100644
index 0000000..1f0e78d
--- /dev/null
+++ b/network/rtl8139/rtl8139.hpp
@@ -0,0 +1,93 @@
+/*
+ This file is part of Fennix Drivers.
+
+ Fennix Drivers is free software: you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation, either version 3 of
+ the License, or (at your option) any later version.
+
+ Fennix Drivers is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Fennix Drivers. If not, see .
+*/
+
+#pragma once
+
+#include
+
+struct RXQueueEntry
+{
+ uint8_t *Buffer;
+ uint16_t Size;
+} __attribute__((packed));
+
+enum InterruptStatus
+{
+ RecOK = 0x1,
+ RecBad = 0x2,
+ SendOK = 0x4,
+ SendBad = 0x8,
+};
+
+enum ReceiveConfig
+{
+ /**
+ * Accept broadcast packets
+ * sent to mac ff:ff:ff:ff:ff:ff
+ */
+ RcAB = 0x1,
+
+ /**
+ * Accept packets sent to the
+ * multicast address
+ */
+ RcAM = 0x2,
+
+ /**
+ * Accept packets sent to the
+ * NIC's MAC address
+ */
+ RcAPM = 0x4,
+
+ /**
+ * Accept all packets
+ * (promiscuous mode)
+ */
+ RcAAP = 0x8,
+
+ /**
+ * The WRAP bit is used to tell the
+ * NIC to wrap around the ring
+ * buffer when it reaches the end
+ * of the buffer.
+ *
+ * @note If this bit is set, the
+ * buffer must have an additional
+ * 1500 bytes of space at the end
+ * of the buffer to prevent the
+ * NIC from overflowing the buffer.
+ */
+ RcWRAP = 0x80,
+};
+
+enum Registers
+{
+ RegMAC = 0x0,
+ RegMAR = 0x8,
+ RegRBSTART = 0x30,
+ RegCMD = 0x37,
+ RegCAPR = 0x38,
+ regRCR = 0x44,
+ RegCONFIG1 = 0x52,
+ RegIMR = 0x3C,
+ RegISR = 0x3E,
+};
+
+EXTERNC int cxx_Panic();
+EXTERNC int cxx_Probe();
+EXTERNC int cxx_Initialize();
+EXTERNC int cxx_Finalize();
diff --git a/storage/Makefile b/storage/Makefile
new file mode 100644
index 0000000..89dbd5f
--- /dev/null
+++ b/storage/Makefile
@@ -0,0 +1,7 @@
+build:
+ make -C ahci build
+ make -C ata build
+
+clean:
+ make -C ahci clean
+ make -C ata clean
diff --git a/storage/ahci/Makefile b/storage/ahci/Makefile
new file mode 100644
index 0000000..fd47515
--- /dev/null
+++ b/storage/ahci/Makefile
@@ -0,0 +1,83 @@
+# Config file
+include ../../../Makefile.conf
+
+FILENAME = ahci.drv
+
+CC = ../../../$(COMPILER_PATH)/$(COMPILER_ARCH)gcc
+CPP = ../../../$(COMPILER_PATH)/$(COMPILER_ARCH)g++
+LD = ../../../$(COMPILER_PATH)/$(COMPILER_ARCH)ld
+AS = ../../../$(COMPILER_PATH)/$(COMPILER_ARCH)as
+OBJDUMP = ../../../$(COMPILER_PATH)/$(COMPILER_ARCH)objdump
+
+S_SOURCES = $(shell find ./ -type f -name '*.S')
+C_SOURCES = $(shell find ./ -type f -name '*.c')
+CPP_SOURCES = $(shell find ./ -type f -name '*.cpp')
+HEADERS = $(sort $(dir $(wildcard ../../include/*)))
+OBJ = $(C_SOURCES:.c=.o) $(CPP_SOURCES:.cpp=.o) $(ASM_SOURCES:.asm=.o) $(S_SOURCES:.S=.o) $(PSF_SOURCES:.psf=.o) $(BMP_SOURCES:.bmp=.o)
+STACK_USAGE_OBJ = $(C_SOURCES:.c=.su) $(CPP_SOURCES:.cpp=.su)
+INCLUDE_DIR = ../../include
+
+LIBS := ../../out/dcrt0.o -L../../out -ldriver
+
+LDFLAGS := \
+ -fPIC -fPIE -pie \
+ -Wl,--no-dynamic-linker,-ztext,--no-warn-rwx-segment \
+ -nostdlib -nodefaultlibs -nolibc \
+ -zmax-page-size=0x1000 \
+ -Wl,-Map file.map -shared -fvisibility=hidden
+
+WARNCFLAG = -Wall -Wextra
+
+CFLAGS := -I$(INCLUDE_DIR) -fvisibility=hidden
+
+ifeq ($(OSARCH), amd64)
+
+CFLAGS += -fPIC -fPIE -pie -mno-80387 -mno-mmx -mno-3dnow \
+ -mno-red-zone -mno-sse -mno-sse2 \
+ -march=x86-64 -pipe -ffunction-sections \
+ -msoft-float -fno-builtin
+
+else ifeq ($(OSARCH), i386)
+
+CFLAGS += -fPIC -fPIE -pie -mno-80387 -mno-mmx -mno-3dnow \
+ -mno-red-zone -mno-sse -mno-sse2 -ffunction-sections \
+ -march=i386 -pipe -msoft-float -fno-builtin
+
+else ifeq ($(OSARCH), aarch64)
+
+CFLAGS += -pipe -fno-builtin -fPIC
+
+endif
+
+ifeq ($(DEBUG), 1)
+ CFLAGS += -DDEBUG -ggdb3 -O0 -fdiagnostics-color=always -fstack-usage
+ifeq ($(OSARCH), amd64)
+ CFLAGS += -fverbose-asm
+endif
+ifneq ($(OSARCH), aarch64)
+ CFLAGS += -fstack-check
+endif
+ LDFLAGS += -ggdb3 -O0
+endif
+
+build: $(FILENAME)
+ mv $(FILENAME) ../../out/$(FILENAME)
+
+$(FILENAME): $(OBJ)
+ $(info Linking $@)
+ $(CC) $(LDFLAGS) $(OBJ) $(LIBS) -o $@
+
+%.o: %.c $(HEADERS)
+ $(info Compiling $<)
+ $(CC) $(CFLAGS) $(WARNCFLAG) -std=c17 -c $< -o $@
+
+%.o: %.cpp $(HEADERS)
+ $(info Compiling $<)
+ $(CPP) $(CFLAGS) $(WARNCFLAG) -std=c++20 -fno-exceptions -fno-rtti -c $< -o $@
+
+%.o: %.S
+ $(info Compiling $<)
+ $(AS) -o $@ $<
+
+clean:
+ rm -f file.map $(OBJ) $(STACK_USAGE_OBJ)
diff --git a/storage/ahci/ahci.cpp b/storage/ahci/ahci.cpp
new file mode 100644
index 0000000..54be554
--- /dev/null
+++ b/storage/ahci/ahci.cpp
@@ -0,0 +1,517 @@
+/*
+ This file is part of Fennix Drivers.
+
+ Fennix Drivers is free software: you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation, either version 3 of
+ the License, or (at your option) any later version.
+
+ Fennix Drivers is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Fennix Drivers. If not, see .
+*/
+
+#include
+#include
+#include
+#include
+#include
+
+#define ATA_DEV_BUSY 0x80
+#define ATA_DEV_DRQ 0x08
+#define ATA_CMD_WRITE_DMA_EX 0x35
+#define ATA_CMD_READ_DMA_EX 0x25
+#define HBA_PxIS_TFES (1 << 30)
+
+#define HBA_PORT_DEV_PRESENT 0x3
+#define HBA_PORT_IPM_ACTIVE 0x1
+#define SATA_SIG_ATAPI 0xEB140101
+#define SATA_SIG_ATA 0x00000101
+#define SATA_SIG_SEMB 0xC33C0101
+#define SATA_SIG_PM 0x96690101
+
+#define HBA_PxCMD_CR 0x8000
+#define HBA_PxCMD_FRE 0x0010
+#define HBA_PxCMD_ST 0x0001
+#define HBA_PxCMD_FR 0x4000
+
+enum PortType
+{
+ None = 0,
+ SATA = 1,
+ SEMB = 2,
+ PM = 3,
+ SATAPI = 4,
+};
+
+enum FIS_TYPE
+{
+ FIS_TYPE_REG_H2D = 0x27,
+ FIS_TYPE_REG_D2H = 0x34,
+ FIS_TYPE_DMA_ACT = 0x39,
+ FIS_TYPE_DMA_SETUP = 0x41,
+ FIS_TYPE_DATA = 0x46,
+ FIS_TYPE_BIST = 0x58,
+ FIS_TYPE_PIO_SETUP = 0x5F,
+ FIS_TYPE_DEV_BITS = 0xA1,
+};
+
+struct HBAPort
+{
+ uint32_t CommandListBase;
+ uint32_t CommandListBaseUpper;
+ uint32_t FISBaseAddress;
+ uint32_t FISBaseAddressUpper;
+ uint32_t InterruptStatus;
+ uint32_t InterruptEnable;
+ uint32_t CommandStatus;
+ uint32_t Reserved0;
+ uint32_t TaskFileData;
+ uint32_t Signature;
+ uint32_t SataStatus;
+ uint32_t SataControl;
+ uint32_t SataError;
+ uint32_t SataActive;
+ uint32_t CommandIssue;
+ uint32_t SataNotification;
+ uint32_t FISSwitchControl;
+ uint32_t Reserved1[11];
+ uint32_t Vendor[4];
+};
+
+struct HBAMemory
+{
+ uint32_t HostCapability;
+ uint32_t GlobalHostControl;
+ uint32_t InterruptStatus;
+ uint32_t PortsImplemented;
+ uint32_t Version;
+ uint32_t CCCControl;
+ uint32_t CCCPorts;
+ uint32_t EnclosureManagementLocation;
+ uint32_t EnclosureManagementControl;
+ uint32_t HostCapabilitiesExtended;
+ uint32_t BIOSHandoffControlStatus;
+ uint8_t Reserved0[0x74];
+ uint8_t Vendor[0x60];
+ HBAPort Ports[1];
+};
+
+struct HBACommandHeader
+{
+ uint8_t CommandFISLength : 5;
+ uint8_t ATAPI : 1;
+ uint8_t Write : 1;
+ uint8_t Preferable : 1;
+ uint8_t Reset : 1;
+ uint8_t BIST : 1;
+ uint8_t ClearBusy : 1;
+ uint8_t Reserved0 : 1;
+ uint8_t PortMultiplier : 4;
+ uint16_t PRDTLength;
+ uint32_t PRDBCount;
+ uint32_t CommandTableBaseAddress;
+ uint32_t CommandTableBaseAddressUpper;
+ uint32_t Reserved1[4];
+};
+
+struct HBAPRDTEntry
+{
+ uint32_t DataBaseAddress;
+ uint32_t DataBaseAddressUpper;
+ uint32_t Reserved0;
+ uint32_t ByteCount : 22;
+ uint32_t Reserved1 : 9;
+ uint32_t InterruptOnCompletion : 1;
+};
+
+struct HBACommandTable
+{
+ uint8_t CommandFIS[64];
+ uint8_t ATAPICommand[16];
+ uint8_t Reserved[48];
+ HBAPRDTEntry PRDTEntry[];
+};
+
+struct FIS_REG_H2D
+{
+ uint8_t FISType;
+ uint8_t PortMultiplier : 4;
+ uint8_t Reserved0 : 3;
+ uint8_t CommandControl : 1;
+ uint8_t Command;
+ uint8_t FeatureLow;
+ uint8_t LBA0;
+ uint8_t LBA1;
+ uint8_t LBA2;
+ uint8_t DeviceRegister;
+ uint8_t LBA3;
+ uint8_t LBA4;
+ uint8_t LBA5;
+ uint8_t FeatureHigh;
+ uint8_t CountLow;
+ uint8_t CountHigh;
+ uint8_t ISOCommandCompletion;
+ uint8_t Control;
+ uint8_t Reserved1[4];
+};
+
+class Port
+{
+public:
+ PortType AHCIPortType;
+ HBAPort *HBAPortPtr;
+ uint8_t *Buffer;
+ uint8_t PortNumber;
+
+ Port(PortType Type, HBAPort *PortPtr, uint8_t PortNumber)
+ {
+ this->AHCIPortType = Type;
+ this->HBAPortPtr = PortPtr;
+ this->Buffer = static_cast(AllocateMemory(1));
+ MemorySet(this->Buffer, 0, PAGE_SIZE);
+ this->PortNumber = PortNumber;
+ }
+
+ ~Port()
+ {
+ FreeMemory(this->Buffer, 1);
+ }
+
+ void StartCMD()
+ {
+ while (HBAPortPtr->CommandStatus & HBA_PxCMD_CR)
+ Yield();
+ HBAPortPtr->CommandStatus |= HBA_PxCMD_FRE;
+ HBAPortPtr->CommandStatus |= HBA_PxCMD_ST;
+ }
+
+ void StopCMD()
+ {
+ HBAPortPtr->CommandStatus &= ~HBA_PxCMD_ST;
+ HBAPortPtr->CommandStatus &= ~HBA_PxCMD_FRE;
+ while (true)
+ {
+ if (HBAPortPtr->CommandStatus & HBA_PxCMD_FR)
+ continue;
+ if (HBAPortPtr->CommandStatus & HBA_PxCMD_CR)
+ continue;
+ break;
+ }
+ }
+
+ void Configure()
+ {
+ this->StopCMD();
+ void *CmdBase = AllocateMemory(1);
+ HBAPortPtr->CommandListBase = (uint32_t)(uint64_t)CmdBase;
+ HBAPortPtr->CommandListBaseUpper = (uint32_t)((uint64_t)CmdBase >> 32);
+ MemorySet(reinterpret_cast(HBAPortPtr->CommandListBase), 0, 1024);
+
+ void *FISBase = AllocateMemory(1);
+ HBAPortPtr->FISBaseAddress = (uint32_t)(uint64_t)FISBase;
+ HBAPortPtr->FISBaseAddressUpper = (uint32_t)((uint64_t)FISBase >> 32);
+ MemorySet(FISBase, 0, 256);
+
+ HBACommandHeader *CommandHeader = (HBACommandHeader *)((uint64_t)HBAPortPtr->CommandListBase + ((uint64_t)HBAPortPtr->CommandListBaseUpper << 32));
+ for (int i = 0; i < 32; i++)
+ {
+ CommandHeader[i].PRDTLength = 8;
+ void *CommandTableAddress = AllocateMemory(1);
+ uint64_t Address = (uint64_t)CommandTableAddress + (i << 8);
+ CommandHeader[i].CommandTableBaseAddress = (uint32_t)(uint64_t)Address;
+ CommandHeader[i].CommandTableBaseAddressUpper = (uint32_t)((uint64_t)Address >> 32);
+ MemorySet(CommandTableAddress, 0, 256);
+ }
+ this->StartCMD();
+
+ Log("Port %d \"%x %x %x %x\" configured", PortNumber,
+ HBAPortPtr->Vendor[0], HBAPortPtr->Vendor[1],
+ HBAPortPtr->Vendor[2], HBAPortPtr->Vendor[3]);
+ }
+
+ bool ReadWrite(uint64_t Sector, uint32_t SectorCount, uint8_t *Buffer, bool Write)
+ {
+ if (this->AHCIPortType == PortType::SATAPI &&
+ Write == true)
+ {
+ Log("SATAPI port does not support write.");
+ return false;
+ }
+
+ uint32_t SectorL = (uint32_t)Sector;
+ uint32_t SectorH = (uint32_t)(Sector >> 32);
+
+ HBAPortPtr->InterruptStatus = 0xFFFFFFFF; /* Clear pending interrupt bits */
+
+ HBACommandHeader *CommandHeader = reinterpret_cast(HBAPortPtr->CommandListBase);
+ CommandHeader->CommandFISLength = sizeof(FIS_REG_H2D) / sizeof(uint32_t);
+ if (Write)
+ CommandHeader->Write = 1;
+ else
+ CommandHeader->Write = 0;
+ CommandHeader->PRDTLength = 1;
+
+ HBACommandTable *CommandTable = reinterpret_cast(CommandHeader->CommandTableBaseAddress);
+ MemorySet(CommandTable, 0, sizeof(HBACommandTable) + (CommandHeader->PRDTLength - 1) * sizeof(HBAPRDTEntry));
+
+ CommandTable->PRDTEntry[0].DataBaseAddress = (uint32_t)(uint64_t)Buffer;
+ CommandTable->PRDTEntry[0].DataBaseAddressUpper = (uint32_t)((uint64_t)Buffer >> 32);
+
+#pragma GCC diagnostic push
+/* conversion from 'uint32_t' {aka 'unsigned int'} to 'unsigned int:22' may change value */
+#pragma GCC diagnostic ignored "-Wconversion"
+ CommandTable->PRDTEntry[0].ByteCount = (SectorCount << 9) - 1; /* 512 bytes per sector */
+#pragma GCC diagnostic pop
+
+ CommandTable->PRDTEntry[0].InterruptOnCompletion = 1;
+
+ FIS_REG_H2D *CommandFIS = (FIS_REG_H2D *)(&CommandTable->CommandFIS);
+
+ CommandFIS->FISType = FIS_TYPE_REG_H2D;
+ CommandFIS->CommandControl = 1;
+ if (Write)
+ CommandFIS->Command = ATA_CMD_WRITE_DMA_EX;
+ else
+ CommandFIS->Command = ATA_CMD_READ_DMA_EX;
+
+ CommandFIS->LBA0 = (uint8_t)SectorL;
+ CommandFIS->LBA1 = (uint8_t)(SectorL >> 8);
+ CommandFIS->LBA2 = (uint8_t)(SectorL >> 16);
+ CommandFIS->LBA3 = (uint8_t)SectorH;
+ CommandFIS->LBA4 = (uint8_t)(SectorH >> 8);
+ CommandFIS->LBA5 = (uint8_t)(SectorH >> 16);
+
+ CommandFIS->DeviceRegister = 1 << 6; // LBA mode
+ CommandFIS->CountLow = SectorCount & 0xFF;
+ CommandFIS->CountHigh = (SectorCount >> 8) & 0xFF;
+
+ uint64_t Spin = 0;
+
+ while ((HBAPortPtr->TaskFileData & (ATA_DEV_BUSY | ATA_DEV_DRQ)) && Spin < 1000000)
+ Spin++;
+
+ if (Spin == 1000000)
+ {
+ Log("Port not responding.");
+ return false;
+ }
+
+ HBAPortPtr->CommandIssue = 1;
+
+ Spin = 0;
+ int TryCount = 0;
+
+ while (true)
+ {
+ if (Spin > 100000000)
+ {
+ Log("Port %d not responding. (%d)",
+ this->PortNumber, TryCount);
+
+ Spin = 0;
+ TryCount++;
+ if (TryCount > 10)
+ return false;
+ }
+
+ if (HBAPortPtr->CommandIssue == 0)
+ break;
+ Spin++;
+
+ if (HBAPortPtr->InterruptStatus & HBA_PxIS_TFES)
+ {
+ Log("Error reading/writing (%d).", Write);
+ return false;
+ }
+ }
+
+ return true;
+ }
+};
+
+Port *Ports[64];
+int PortCount = 0;
+
+const char *PortTypeName[] = {"None",
+ "SATA",
+ "SEMB",
+ "PM",
+ "SATAPI"};
+
+PortType CheckPortType(HBAPort *Port)
+{
+ uint32_t SataStatus = Port->SataStatus;
+ uint8_t InterfacePowerManagement = (SataStatus >> 8) & 0b111;
+ uint8_t DeviceDetection = SataStatus & 0b111;
+
+ if (DeviceDetection != HBA_PORT_DEV_PRESENT)
+ return PortType::None;
+ if (InterfacePowerManagement != HBA_PORT_IPM_ACTIVE)
+ return PortType::None;
+
+ switch (Port->Signature)
+ {
+ case SATA_SIG_ATAPI:
+ return PortType::SATAPI;
+ case SATA_SIG_ATA:
+ return PortType::SATA;
+ case SATA_SIG_PM:
+ return PortType::PM;
+ case SATA_SIG_SEMB:
+ return PortType::SEMB;
+ default:
+ return PortType::None;
+ }
+}
+
+size_t drvRead(dev_t, dev_t min,
+ uint8_t *Buffer, size_t Size, off_t Offset)
+{
+ bool ok = Ports[min]->ReadWrite(Offset / 512,
+ uint32_t(Size / 512),
+ Buffer,
+ false);
+ return ok ? Size : 0;
+}
+
+size_t drvWrite(dev_t, dev_t min,
+ uint8_t *Buffer, size_t Size, off_t Offset)
+{
+ bool ok = Ports[min]->ReadWrite(Offset / 512,
+ uint32_t(Size / 512),
+ Buffer,
+ true);
+ return ok ? Size : 0;
+}
+
+void OnInterruptReceived(TrapFrame *)
+{
+}
+
+EXTERNC int cxx_Panic()
+{
+ for (int i = 0; i < PortCount; i++)
+ Ports[i]->StopCMD();
+ return 0;
+}
+
+PCIArray *Devices;
+EXTERNC int cxx_Probe()
+{
+ uint16_t VendorIDs[] = {0x8086, /* Intel */
+ 0x15AD, /* VMware */
+ PCI_END};
+ uint16_t DeviceIDs[] = {0x2922, /* ICH9 */
+ 0x2829, /* ICH8 */
+ 0x07E0, /* SATA AHCI (VMware) */
+ PCI_END};
+ Devices = FindPCIDevices(VendorIDs, DeviceIDs);
+ if (Devices == nullptr)
+ {
+ Log("No AHCI device found.");
+ return -ENODEV;
+ }
+ return 0;
+}
+
+EXTERNC int cxx_Initialize()
+{
+ PCIArray *ctx = Devices;
+
+ /**
+ * We loop through all the devices and initialize them
+ */
+ while (ctx != nullptr)
+ {
+ /* We don't use the interrupt handler now... maybe we will in the future */
+ // RegisterInterruptHandler(iLine(ctx->Device), (void *)OnInterruptReceived);
+
+ InitializePCI(ctx->Device);
+ HBAMemory *HBA = (HBAMemory *)(uintptr_t)GetBAR(5, ctx->Device);
+
+ uint32_t PortsImplemented = HBA->PortsImplemented;
+ Log("AHCI ports implemented: %x", PortsImplemented);
+ for (int i = 0; i < 32; i++)
+ {
+ if (PortCount > 64)
+ {
+ Log("There are more than 64 AHCI ports implemented");
+ break;
+ }
+
+ if (PortsImplemented & (1 << i))
+ {
+ Log("Port %d implemented", i);
+ PortType portType = CheckPortType(&HBA->Ports[i]);
+ if (portType == PortType::SATA || portType == PortType::SATAPI)
+ {
+ KPrint("%s drive found at port %d", PortTypeName[portType], i);
+ Ports[PortCount] = new Port(portType, &HBA->Ports[i], PortCount);
+ dev_t ret = RegisterBlockDevice(ddt_SATA,
+ nullptr, nullptr,
+ drvRead, drvWrite,
+ nullptr);
+ if (ret != (dev_t)PortCount)
+ {
+ KPrint("Failed to register block device %d", ret);
+ return -EBADSLT;
+ }
+
+ PortCount++;
+ Ports[PortCount] = nullptr;
+ }
+ else
+ {
+ if (portType != PortType::None)
+ {
+ KPrint("Unsupported drive type %s found at port %d",
+ PortTypeName[portType], i);
+ }
+ }
+ }
+ }
+
+ ctx = (PCIArray *)ctx->Next;
+ }
+
+ Log("Initializing AHCI ports");
+ for (int i = 0; i < PortCount; i++)
+ Ports[i]->Configure();
+
+ return PortCount > 0 ? 0 : -ENODEV;
+}
+
+EXTERNC int cxx_Finalize()
+{
+ for (int i = 0; i < PortCount; i++)
+ {
+ Ports[i]->StopCMD();
+ delete Ports[i];
+ }
+
+ PortCount = 0;
+
+ do
+ {
+ UnregisterBlockDevice(PortCount, ddt_SATA);
+ PortCount--;
+ } while (PortCount >= 0);
+
+ PCIArray *ctx = Devices;
+
+ while (ctx != nullptr)
+ {
+ ctx->Device->Header->Command |= PCI_COMMAND_INTX_DISABLE;
+ ctx = (PCIArray *)ctx->Next;
+ }
+
+ // std::list Devices = PCIManager->FindPCIDevice(VendorIDs, DeviceIDs);
+ // foreach (auto dev in Devices)
+ // Interrupts::RemoveHandler(OnInterruptReceived, iLine(dev));
+ return 0;
+}
diff --git a/storage/ahci/ahci.hpp b/storage/ahci/ahci.hpp
new file mode 100644
index 0000000..99242b9
--- /dev/null
+++ b/storage/ahci/ahci.hpp
@@ -0,0 +1,25 @@
+/*
+ This file is part of Fennix Drivers.
+
+ Fennix Drivers is free software: you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation, either version 3 of
+ the License, or (at your option) any later version.
+
+ Fennix Drivers is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Fennix Drivers. If not, see .
+*/
+
+#pragma once
+
+#include
+
+EXTERNC int cxx_Panic();
+EXTERNC int cxx_Probe();
+EXTERNC int cxx_Initialize();
+EXTERNC int cxx_Finalize();
diff --git a/storage/ahci/main.c b/storage/ahci/main.c
new file mode 100644
index 0000000..8bac95a
--- /dev/null
+++ b/storage/ahci/main.c
@@ -0,0 +1,31 @@
+/*
+ This file is part of Fennix Drivers.
+
+ Fennix Drivers is free software: you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation, either version 3 of
+ the License, or (at your option) any later version.
+
+ Fennix Drivers is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Fennix Drivers. If not, see .
+*/
+
+#include
+
+#include "ahci.hpp"
+
+int DriverEntry() { return cxx_Initialize(); }
+int DriverFinal() { return cxx_Finalize(); }
+int DriverPanic() { return cxx_Panic(); }
+int DriverProbe() { return cxx_Probe(); }
+
+DriverInfo("ahci",
+ "Advanced Host Controller Interface Driver",
+ "EnderIce2",
+ "0.1",
+ "GPLv3");
diff --git a/storage/ata/Makefile b/storage/ata/Makefile
new file mode 100644
index 0000000..f712d0a
--- /dev/null
+++ b/storage/ata/Makefile
@@ -0,0 +1,83 @@
+# Config file
+include ../../../Makefile.conf
+
+FILENAME = ata.drv
+
+CC = ../../../$(COMPILER_PATH)/$(COMPILER_ARCH)gcc
+CPP = ../../../$(COMPILER_PATH)/$(COMPILER_ARCH)g++
+LD = ../../../$(COMPILER_PATH)/$(COMPILER_ARCH)ld
+AS = ../../../$(COMPILER_PATH)/$(COMPILER_ARCH)as
+OBJDUMP = ../../../$(COMPILER_PATH)/$(COMPILER_ARCH)objdump
+
+S_SOURCES = $(shell find ./ -type f -name '*.S')
+C_SOURCES = $(shell find ./ -type f -name '*.c')
+CPP_SOURCES = $(shell find ./ -type f -name '*.cpp')
+HEADERS = $(sort $(dir $(wildcard ../../include/*)))
+OBJ = $(C_SOURCES:.c=.o) $(CPP_SOURCES:.cpp=.o) $(ASM_SOURCES:.asm=.o) $(S_SOURCES:.S=.o) $(PSF_SOURCES:.psf=.o) $(BMP_SOURCES:.bmp=.o)
+STACK_USAGE_OBJ = $(C_SOURCES:.c=.su) $(CPP_SOURCES:.cpp=.su)
+INCLUDE_DIR = ../../include
+
+LIBS := ../../out/dcrt0.o -L../../out -ldriver
+
+LDFLAGS := \
+ -fPIC -fPIE -pie \
+ -Wl,--no-dynamic-linker,-ztext,--no-warn-rwx-segment \
+ -nostdlib -nodefaultlibs -nolibc \
+ -zmax-page-size=0x1000 \
+ -Wl,-Map file.map -shared -fvisibility=hidden
+
+WARNCFLAG = -Wall -Wextra
+
+CFLAGS := -I$(INCLUDE_DIR) -fvisibility=hidden
+
+ifeq ($(OSARCH), amd64)
+
+CFLAGS += -fPIC -fPIE -pie -mno-80387 -mno-mmx -mno-3dnow \
+ -mno-red-zone -mno-sse -mno-sse2 \
+ -march=x86-64 -pipe -ffunction-sections \
+ -msoft-float -fno-builtin
+
+else ifeq ($(OSARCH), i386)
+
+CFLAGS += -fPIC -fPIE -pie -mno-80387 -mno-mmx -mno-3dnow \
+ -mno-red-zone -mno-sse -mno-sse2 -ffunction-sections \
+ -march=i386 -pipe -msoft-float -fno-builtin
+
+else ifeq ($(OSARCH), aarch64)
+
+CFLAGS += -pipe -fno-builtin -fPIC
+
+endif
+
+ifeq ($(DEBUG), 1)
+ CFLAGS += -DDEBUG -ggdb3 -O0 -fdiagnostics-color=always -fstack-usage
+ifeq ($(OSARCH), amd64)
+ CFLAGS += -fverbose-asm
+endif
+ifneq ($(OSARCH), aarch64)
+ CFLAGS += -fstack-check
+endif
+ LDFLAGS += -ggdb3 -O0
+endif
+
+build: $(FILENAME)
+ mv $(FILENAME) ../../out/$(FILENAME)
+
+$(FILENAME): $(OBJ)
+ $(info Linking $@)
+ $(CC) $(LDFLAGS) $(OBJ) $(LIBS) -o $@
+
+%.o: %.c $(HEADERS)
+ $(info Compiling $<)
+ $(CC) $(CFLAGS) $(WARNCFLAG) -std=c17 -c $< -o $@
+
+%.o: %.cpp $(HEADERS)
+ $(info Compiling $<)
+ $(CPP) $(CFLAGS) $(WARNCFLAG) -std=c++20 -fno-exceptions -fno-rtti -c $< -o $@
+
+%.o: %.S
+ $(info Compiling $<)
+ $(AS) -o $@ $<
+
+clean:
+ rm -f file.map $(OBJ) $(STACK_USAGE_OBJ)
diff --git a/storage/ata/main.c b/storage/ata/main.c
new file mode 100644
index 0000000..300dab1
--- /dev/null
+++ b/storage/ata/main.c
@@ -0,0 +1,76 @@
+/*
+ This file is part of Fennix Drivers.
+
+ Fennix Drivers is free software: you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation, either version 3 of
+ the License, or (at your option) any later version.
+
+ Fennix Drivers is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Fennix Drivers. If not, see .
+*/
+
+#include
+#include
+#include
+#include
+
+bool IsATAPresent()
+{
+ outb(0x1F0 + 2, 0);
+ outb(0x1F0 + 3, 0);
+ outb(0x1F0 + 4, 0);
+ outb(0x1F0 + 5, 0);
+ outb(0x1F0 + 7, 0xEC);
+ if (inb(0x1F0 + 7) == 0 || inb(0x1F0 + 1) != 0)
+ return false;
+ return true;
+}
+
+void MasterInterruptHandler(TrapFrame *)
+{
+}
+
+void SlaveInterruptHandler(TrapFrame *)
+{
+}
+
+int DriverEntry()
+{
+ RegisterInterruptHandler(14, MasterInterruptHandler);
+ RegisterInterruptHandler(15, SlaveInterruptHandler);
+
+ return 0;
+}
+
+int DriverFinal()
+{
+ UnregisterInterruptHandler(14, MasterInterruptHandler);
+ UnregisterInterruptHandler(15, SlaveInterruptHandler);
+
+ return 0;
+}
+
+int DriverPanic()
+{
+ return 0;
+}
+
+int DriverProbe()
+{
+ if (!IsATAPresent())
+ return -ENODEV;
+
+ return 0;
+}
+
+DriverInfo("ata",
+ "Advanced Technology Attachment Driver",
+ "EnderIce2",
+ "0.1",
+ "GPLv3");