Update drivers

This commit is contained in:
EnderIce2 2024-01-19 06:44:00 +02:00
parent 2ee57b9756
commit da4a6317ea
Signed by untrusted user who does not match committer: enderice2
GPG Key ID: EACC3AD603BAB4DD
83 changed files with 9425 additions and 598 deletions

2
.gitignore vendored
View File

@ -1,4 +1,6 @@
out out
*.map *.map
*.o *.o
*.a
*.su
.dccache .dccache

View File

@ -24,5 +24,29 @@
"/** @brief $0 */" "/** @brief $0 */"
], ],
"description": "Create documentation brief." "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 <https://www.gnu.org/licenses/>.",
"*/"
],
"description": "Create kernel license."
} }
} }

View File

@ -1,3 +0,0 @@
build:
clean:

View File

@ -32,7 +32,7 @@ DOXYFILE_ENCODING = UTF-8
# title of most generated pages and in a few other places. # title of most generated pages and in a few other places.
# The default value is: My Project. # 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 # 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 # 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 # 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. # 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 # 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 # 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 # spaces. See also FILE_PATTERNS and EXTENSION_MAPPING
# Note: If this tag is empty the current directory is searched. # 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 # 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 # 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 # (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. # 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 # Configuration options related to source browsing
@ -1224,7 +1224,7 @@ GENERATE_HTML = YES
# The default directory is: html. # The default directory is: html.
# This tag requires that the tag GENERATE_HTML is set to YES. # 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 # The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
# generated HTML page (for example: .htm, .php, .asp). # generated HTML page (for example: .htm, .php, .asp).

View File

@ -1,3 +0,0 @@
build:
clean:

View File

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

View File

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

View File

@ -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.*)
}
}

View File

@ -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.*)
}
}

View File

@ -1,5 +0,0 @@
build:
make -C ExampleDriver build
clean:
make -C ExampleDriver clean

View File

@ -1,3 +0,0 @@
build:
clean:

View File

@ -1,22 +1,21 @@
build: build:
cp -f ../Kernel/driver.h include/driver.h
mkdir -p out mkdir -p out
make -C Input build make -C library build
make -C Storage build make -C audio build
make -C Audio build make -C input build
make -C FileSystem build make -C misc build
make -C Generic build make -C network build
make -C Network build make -C storage build
make -C Video build
prepare: prepare:
$(info Nothing to prepare) $(info Nothing to prepare)
clean: clean:
rm -rf out rm -rf out
make -C Input clean make -C library clean
make -C Storage clean make -C audio clean
make -C Audio clean make -C input clean
make -C FileSystem clean make -C misc clean
make -C Generic clean make -C network clean
make -C Network clean make -C storage clean
make -C Video clean

View File

@ -1,3 +0,0 @@
build:
clean:

View File

@ -1,6 +1,6 @@
# Modules # Drivers
Modules for [Fennix](https://github.com/Fennix-Project/Fennix). Drivers for [Fennix](https://github.com/Fennix-Project/Fennix).
--- ---

View File

@ -1,3 +0,0 @@
build:
clean:

View File

@ -1,3 +0,0 @@
build:
clean:

7
audio/Makefile Normal file
View File

@ -0,0 +1,7 @@
build:
make -C ac97 build
make -C hda build
clean:
make -C ac97 clean
make -C hda clean

83
audio/ac97/Makefile Normal file
View File

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

857
audio/ac97/ac97.cpp Normal file
View File

@ -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 <https://www.gnu.org/licenses/>.
*/
#include <errno.h>
#include <audio.h>
#include <regs.h>
#include <base.h>
#include <pci.h>
#include <io.h>
#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;
}

25
audio/ac97/ac97.hpp Normal file
View File

@ -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 <https://www.gnu.org/licenses/>.
*/
#pragma once
#include <types.h>
EXTERNC int cxx_Panic();
EXTERNC int cxx_Probe();
EXTERNC int cxx_Initialize();
EXTERNC int cxx_Finalize();

31
audio/ac97/main.c Normal file
View File

@ -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 <https://www.gnu.org/licenses/>.
*/
#include <base.h>
#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");

83
audio/hda/Makefile Normal file
View File

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

239
audio/hda/hda.cpp Normal file
View File

@ -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 <https://www.gnu.org/licenses/>.
*/
#include <errno.h>
#include <audio.h>
#include <regs.h>
#include <base.h>
#include <pci.h>
#include <io.h>
#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;
}

635
audio/hda/hda.hpp Normal file
View File

@ -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 <https://www.gnu.org/licenses/>.
*/
#pragma once
#include <types.h>
#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();

31
audio/hda/main.c Normal file
View File

@ -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 <https://www.gnu.org/licenses/>.
*/
#include <base.h>
#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");

50
driver.template Normal file
View File

@ -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 <https://www.gnu.org/licenses/>.
*/
#include <errno.h>
#include <regs.h>
#include <base.h>
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");

123
include/aip.h Normal file
View File

@ -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 <https://www.gnu.org/licenses/>.
*/
#ifndef __FENNIX_API_AIP_H__
#define __FENNIX_API_AIP_H__
#include <types.h>
#include <aip/kbd.h>
#include <aip/mouse.h>
#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__

93
include/aip/kbd.h Normal file
View File

@ -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 <https://www.gnu.org/licenses/>.
*/
#ifndef __FENNIX_API_AIP_KBD_H__
#define __FENNIX_API_AIP_KBD_H__
#include <types.h>
#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__

89
include/aip/mouse.h Normal file
View File

@ -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 <https://www.gnu.org/licenses/>.
*/
#ifndef __FENNIX_API_AIP_MOUSE_H__
#define __FENNIX_API_AIP_MOUSE_H__
#include <types.h>
#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__

45
include/audio.h Normal file
View File

@ -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 <https://www.gnu.org/licenses/>.
*/
#ifndef __FENNIX_API_AUDIO_H__
#define __FENNIX_API_AUDIO_H__
#include <types.h>
#include <driver.h>
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__

277
include/base.h Normal file
View File

@ -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 <https://www.gnu.org/licenses/>.
*/
#ifndef __FENNIX_API_BASE_H__
#define __FENNIX_API_BASE_H__
#include <driver.h>
#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__

45
include/block.h Normal file
View File

@ -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 <https://www.gnu.org/licenses/>.
*/
#ifndef __FENNIX_API_BLOCK_H__
#define __FENNIX_API_BLOCK_H__
#include <types.h>
#include <driver.h>
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__

326
include/driver.h Normal file
View File

@ -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 <https://www.gnu.org/licenses/>.
*/
#ifndef __FENNIX_API_DRIVER_FUNCTIONS_H__
#define __FENNIX_API_DRIVER_FUNCTIONS_H__
#include <types.h>
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__

408
include/errno.h Normal file
View File

@ -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 <https://www.gnu.org/licenses/>.
*/
#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

66
include/input.h Normal file
View File

@ -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 <https://www.gnu.org/licenses/>.
*/
#ifndef __FENNIX_API_INPUT_H__
#define __FENNIX_API_INPUT_H__
#include <types.h>
#include <driver.h>
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__

View File

@ -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 <https://www.gnu.org/licenses/>.
*/
#ifndef __FENNIX_API_IO_H__ #ifndef __FENNIX_API_IO_H__
#define __FENNIX_API_IO_H__ #define __FENNIX_API_IO_H__
@ -9,201 +26,203 @@
extern "C" extern "C"
{ {
#endif #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) static inline uint8_t inportb(uint16_t Port)
{ {
uint16_t Result; uint8_t Result;
__asm__("in %%dx, %%ax" __asm__("in %%dx, %%al"
: "=a"(Result) : "=a"(Result)
: "d"(Port)); : "d"(Port));
return Result; return Result;
} }
static inline uint32_t inportl(uint16_t Port) static inline uint16_t inportw(uint16_t Port)
{ {
uint32_t Result; uint16_t Result;
__asm__ volatile("inl %1, %0" __asm__("in %%dx, %%ax"
: "=a"(Result) : "=a"(Result)
: "dN"(Port)); : "d"(Port));
return Result; return Result;
} }
static inline void outportb(uint16_t Port, uint8_t Data) static inline uint32_t inportl(uint16_t Port)
{ {
__asm__ volatile("out %%al, %%dx" uint32_t Result;
: __asm__ volatile("inl %1, %0"
: "a"(Data), "d"(Port)); : "=a"(Result)
} : "dN"(Port));
return Result;
}
static inline void outportw(uint16_t Port, uint16_t Data) static inline void outportb(uint16_t Port, uint8_t Data)
{ {
__asm__ volatile("out %%ax, %%dx" __asm__ volatile("out %%al, %%dx"
: :
: "a"(Data), "d"(Port)); : "a"(Data), "d"(Port));
} }
static inline void outportl(uint16_t Port, uint32_t Data) static inline void outportw(uint16_t Port, uint16_t Data)
{ {
__asm__ volatile("outl %1, %0" __asm__ volatile("out %%ax, %%dx"
: :
: "dN"(Port), "a"(Data)); : "a"(Data), "d"(Port));
} }
static inline uint8_t mmioin8(uint64_t Address) static inline void outportl(uint16_t Port, uint32_t Data)
{ {
__asm__ volatile("" :: __asm__ volatile("outl %1, %0"
: "memory"); :
uint8_t Result = *(volatile uint8_t *)Address; : "dN"(Port), "a"(Data));
__asm__ volatile("" :: }
: "memory");
return Result;
}
static inline uint16_t mmioin16(uint64_t Address) static inline uint8_t mmioin8(uint64_t Address)
{ {
__asm__ volatile("" :: __asm__ volatile("" ::
: "memory"); : "memory");
uint16_t Result = *(volatile uint16_t *)Address; uint8_t Result = *(volatile uint8_t *)Address;
__asm__ volatile("" :: __asm__ volatile("" ::
: "memory"); : "memory");
return Result; return Result;
} }
static inline uint32_t mmioin32(uint64_t Address) static inline uint16_t mmioin16(uint64_t Address)
{ {
__asm__ volatile("" :: __asm__ volatile("" ::
: "memory"); : "memory");
uint32_t Result = *(volatile uint32_t *)Address; uint16_t Result = *(volatile uint16_t *)Address;
__asm__ volatile("" :: __asm__ volatile("" ::
: "memory"); : "memory");
return Result; return Result;
} }
static inline uint64_t mmioin64(uint64_t Address) static inline uint32_t mmioin32(uint64_t Address)
{ {
__asm__ volatile("" :: __asm__ volatile("" ::
: "memory"); : "memory");
uint64_t Result = *(volatile uint64_t *)Address; uint32_t Result = *(volatile uint32_t *)Address;
__asm__ volatile("" :: __asm__ volatile("" ::
: "memory"); : "memory");
return Result; return Result;
} }
static inline void mmioout8(uint64_t Address, uint8_t Data) static inline uint64_t mmioin64(uint64_t Address)
{ {
__asm__ volatile("" :: __asm__ volatile("" ::
: "memory"); : "memory");
*(volatile uint8_t *)Address = Data; uint64_t Result = *(volatile uint64_t *)Address;
__asm__ volatile("" :: __asm__ volatile("" ::
: "memory"); : "memory");
} return Result;
}
static inline void mmioout16(uint64_t Address, uint16_t Data) static inline void mmioout8(uint64_t Address, uint8_t Data)
{ {
__asm__ volatile("" :: __asm__ volatile("" ::
: "memory"); : "memory");
*(volatile uint16_t *)Address = Data; *(volatile uint8_t *)Address = Data;
__asm__ volatile("" :: __asm__ volatile("" ::
: "memory"); : "memory");
} }
static inline void mmioout32(uint64_t Address, uint32_t Data) static inline void mmioout16(uint64_t Address, uint16_t Data)
{ {
__asm__ volatile("" :: __asm__ volatile("" ::
: "memory"); : "memory");
*(volatile uint32_t *)Address = Data; *(volatile uint16_t *)Address = Data;
__asm__ volatile("" :: __asm__ volatile("" ::
: "memory"); : "memory");
} }
static inline void mmioout64(uint64_t Address, uint64_t Data) static inline void mmioout32(uint64_t Address, uint32_t Data)
{ {
__asm__ volatile("" :: __asm__ volatile("" ::
: "memory"); : "memory");
*(volatile uint64_t *)Address = Data; *(volatile uint32_t *)Address = Data;
__asm__ volatile("" :: __asm__ volatile("" ::
: "memory"); : "memory");
} }
static inline void mmoutb(void *Address, uint8_t Value) static inline void mmioout64(uint64_t Address, uint64_t Data)
{ {
__asm__ volatile("mov %1, %0" __asm__ volatile("" ::
: "=m"((*(uint8_t *)(Address))) : "memory");
: "r"(Value) *(volatile uint64_t *)Address = Data;
: "memory"); __asm__ volatile("" ::
} : "memory");
}
static inline void mmoutw(void *Address, uint16_t Value) static inline void mmoutb(void *Address, uint8_t Value)
{ {
__asm__ volatile("mov %1, %0" __asm__ volatile("mov %1, %0"
: "=m"((*(uint16_t *)(Address))) : "=m"((*(uint8_t *)(Address)))
: "r"(Value) : "r"(Value)
: "memory"); : "memory");
} }
static inline void mmoutl(void *Address, uint32_t Value) static inline void mmoutw(void *Address, uint16_t Value)
{ {
__asm__ volatile("mov %1, %0" __asm__ volatile("mov %1, %0"
: "=m"((*(uint32_t *)(Address))) : "=m"((*(uint16_t *)(Address)))
: "r"(Value) : "r"(Value)
: "memory"); : "memory");
} }
static inline void mmoutq(void *Address, uint64_t Value) static inline void mmoutl(void *Address, uint32_t Value)
{ {
__asm__ volatile("mov %1, %0" __asm__ volatile("mov %1, %0"
: "=m"((*(uint64_t *)(Address))) : "=m"((*(uint32_t *)(Address)))
: "r"(Value) : "r"(Value)
: "memory"); : "memory");
} }
static inline uint8_t mminb(void *Address) static inline void mmoutq(void *Address, uint64_t Value)
{ {
uint8_t Result; __asm__ volatile("mov %1, %0"
__asm__ volatile("mov %1, %0" : "=m"((*(uint64_t *)(Address)))
: "=r"(Result) : "r"(Value)
: "m"((*(uint8_t *)(Address))) : "memory");
: "memory"); }
return Result;
}
static inline uint16_t mminw(void *Address) static inline uint8_t mminb(void *Address)
{ {
uint16_t Result; uint8_t Result;
__asm__ volatile("mov %1, %0" __asm__ volatile("mov %1, %0"
: "=r"(Result) : "=r"(Result)
: "m"((*(uint16_t *)(Address))) : "m"((*(uint8_t *)(Address)))
: "memory"); : "memory");
return Result; return Result;
} }
static inline uint32_t mminl(void *Address) static inline uint16_t mminw(void *Address)
{ {
uint32_t Result; uint16_t Result;
__asm__ volatile("mov %1, %0" __asm__ volatile("mov %1, %0"
: "=r"(Result) : "=r"(Result)
: "m"((*(uint32_t *)(Address))) : "m"((*(uint16_t *)(Address)))
: "memory"); : "memory");
return Result; 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 #ifdef __cplusplus
} }
#endif #endif

47
include/net.h Normal file
View File

@ -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 <https://www.gnu.org/licenses/>.
*/
#ifndef __FENNIX_API_AUDIO_H__
#define __FENNIX_API_AUDIO_H__
#include <types.h>
#include <driver.h>
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__

View File

@ -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 <https://www.gnu.org/licenses/>.
*/
#ifndef __FENNIX_API_NETWORK_UTILS_H__ #ifndef __FENNIX_API_NETWORK_UTILS_H__
#define __FENNIX_API_NETWORK_UTILS_H__ #define __FENNIX_API_NETWORK_UTILS_H__

View File

@ -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 <https://www.gnu.org/licenses/>.
*/
#ifndef __FENNIX_API_PCI_H__ #ifndef __FENNIX_API_PCI_H__
#define __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 */ /* https://sites.uclouvain.be/SystInfo/usr/include/linux/pci_regs.h.html */
enum PCICommands enum PCICommands
{ {
/** @brief Enable response in I/O space */ /** @brief Enable response in I/O space */
PCI_COMMAND_IO = 0x1, PCI_COMMAND_IO = 0x1,
/** @brief Enable response in Memory space */ /** @brief Enable response in Memory space */
PCI_COMMAND_MEMORY = 0x2, PCI_COMMAND_MEMORY = 0x2,
/** @brief Enable bus mastering */ /** @brief Enable bus mastering */
PCI_COMMAND_MASTER = 0x4, PCI_COMMAND_MASTER = 0x4,
/** @brief Enable response to special cycles */ /** @brief Enable response to special cycles */
PCI_COMMAND_SPECIAL = 0x8, PCI_COMMAND_SPECIAL = 0x8,
/** @brief Use memory write and invalidate */ /** @brief Use memory write and invalidate */
PCI_COMMAND_INVALIDATE = 0x10, PCI_COMMAND_INVALIDATE = 0x10,
/** @brief Enable palette snooping */ /** @brief Enable palette snooping */
PCI_COMMAND_VGA_PALETTE = 0x20, PCI_COMMAND_VGA_PALETTE = 0x20,
/** @brief Enable parity checking */ /** @brief Enable parity checking */
PCI_COMMAND_PARITY = 0x40, PCI_COMMAND_PARITY = 0x40,
/** @brief Enable address/data stepping */ /** @brief Enable address/data stepping */
PCI_COMMAND_WAIT = 0x80, PCI_COMMAND_WAIT = 0x80,
/** @brief Enable SERR */ /** @brief Enable SERR */
PCI_COMMAND_SERR = 0x100, PCI_COMMAND_SERR = 0x100,
/** @brief Enable back-to-back writes */ /** @brief Enable back-to-back writes */
PCI_COMMAND_FAST_BACK = 0x200, PCI_COMMAND_FAST_BACK = 0x200,
/** @brief INTx Emulation Disable */ /** @brief INTx Emulation Disable */
PCI_COMMAND_INTX_DISABLE = 0x400 PCI_COMMAND_INTX_DISABLE = 0x400
}; };
struct PCIDeviceHeader typedef struct
{ {
uint16_t VendorID; uint16_t VendorID;
uint16_t DeviceID; uint16_t DeviceID;
uint16_t Command; uint16_t Command;
uint16_t Status; uint16_t Status;
uint8_t RevisionID; uint8_t RevisionID;
uint8_t ProgIF; uint8_t ProgIF;
uint8_t Subclass; uint8_t Subclass;
uint8_t Class; uint8_t Class;
uint8_t CacheLineSize; uint8_t CacheLineSize;
uint8_t LatencyTimer; uint8_t LatencyTimer;
uint8_t HeaderType; uint8_t HeaderType;
uint8_t BIST; uint8_t BIST;
}; } __attribute__((packed)) PCIDeviceHeader;
struct PCIHeader0 typedef struct
{ {
PCIDeviceHeader Header; PCIDeviceHeader Header;
uint32_t BAR0; uint32_t BAR0;
uint32_t BAR1; uint32_t BAR1;
uint32_t BAR2; uint32_t BAR2;
uint32_t BAR3; uint32_t BAR3;
uint32_t BAR4; uint32_t BAR4;
uint32_t BAR5; uint32_t BAR5;
uint32_t CardbusCISPointer; uint32_t CardbusCISPointer;
uint16_t SubsystemVendorID; uint16_t SubsystemVendorID;
uint16_t SubsystemID; uint16_t SubsystemID;
uint32_t ExpansionROMBaseAddress; uint32_t ExpansionROMBaseAddress;
uint8_t CapabilitiesPointer; uint8_t CapabilitiesPointer;
uint8_t Reserved0; uint8_t Reserved0;
uint16_t Reserved1; uint16_t Reserved1;
uint32_t Reserved2; uint32_t Reserved2;
uint8_t InterruptLine; uint8_t InterruptLine;
uint8_t InterruptPin; uint8_t InterruptPin;
uint8_t MinGrant; uint8_t MinGrant;
uint8_t MaxLatency; uint8_t MaxLatency;
}; } __attribute__((packed)) PCIHeader0;
struct PCIHeader1 typedef struct
{ {
PCIDeviceHeader Header; PCIDeviceHeader Header;
uint32_t BAR0; uint32_t BAR0;
uint32_t BAR1; uint32_t BAR1;
uint8_t PrimaryBusNumber; uint8_t PrimaryBusNumber;
uint8_t SecondaryBusNumber; uint8_t SecondaryBusNumber;
uint8_t SubordinateBusNumber; uint8_t SubordinateBusNumber;
uint8_t SecondaryLatencyTimer; uint8_t SecondaryLatencyTimer;
uint8_t IOBase; uint8_t IOBase;
uint8_t IOLimit; uint8_t IOLimit;
uint16_t SecondaryStatus; uint16_t SecondaryStatus;
uint16_t MemoryBase; uint16_t MemoryBase;
uint16_t MemoryLimit; uint16_t MemoryLimit;
uint16_t PrefetchableMemoryBase; uint16_t PrefetchableMemoryBase;
uint16_t PrefetchableMemoryLimit; uint16_t PrefetchableMemoryLimit;
uint32_t PrefetchableMemoryBaseUpper32; uint32_t PrefetchableMemoryBaseUpper32;
uint32_t PrefetchableMemoryLimitUpper32; uint32_t PrefetchableMemoryLimitUpper32;
uint16_t IOBaseUpper16; uint16_t IOBaseUpper16;
uint16_t IOLimitUpper16; uint16_t IOLimitUpper16;
uint8_t CapabilitiesPointer; uint8_t CapabilitiesPointer;
uint8_t Reserved0; uint8_t Reserved0;
uint16_t Reserved1; uint16_t Reserved1;
uint32_t ExpansionROMBaseAddress; uint32_t ExpansionROMBaseAddress;
uint8_t InterruptLine; uint8_t InterruptLine;
uint8_t InterruptPin; uint8_t InterruptPin;
uint16_t BridgeControl; uint16_t BridgeControl;
}; } __attribute__((packed)) PCIHeader1;
struct PCIHeader2 typedef struct
{ {
PCIDeviceHeader Header; PCIDeviceHeader Header;
uint32_t CardbusSocketRegistersBaseAddress; uint32_t CardbusSocketRegistersBaseAddress;
uint8_t CapabilitiesPointer; uint8_t CapabilitiesPointer;
uint8_t Reserved0; uint8_t Reserved0;
uint16_t SecondaryStatus; uint16_t SecondaryStatus;
uint8_t PCIbusNumber; uint8_t PCIbusNumber;
uint8_t CardbusBusNumber; uint8_t CardbusBusNumber;
uint8_t SubordinateBusNumber; uint8_t SubordinateBusNumber;
uint8_t CardbusLatencyTimer; uint8_t CardbusLatencyTimer;
uint32_t MemoryBase0; uint32_t MemoryBase0;
uint32_t MemoryLimit0; uint32_t MemoryLimit0;
uint32_t MemoryBase1; uint32_t MemoryBase1;
uint32_t MemoryLimit1; uint32_t MemoryLimit1;
uint32_t IOBase0; uint32_t IOBase0;
uint32_t IOLimit0; uint32_t IOLimit0;
uint32_t IOBase1; uint32_t IOBase1;
uint32_t IOLimit1; uint32_t IOLimit1;
uint8_t InterruptLine; uint8_t InterruptLine;
uint8_t InterruptPin; uint8_t InterruptPin;
uint16_t BridgeControl; uint16_t BridgeControl;
uint16_t SubsystemVendorID; uint16_t SubsystemVendorID;
uint16_t SubsystemID; uint16_t SubsystemID;
uint32_t LegacyBaseAddress; 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__ #endif // !__FENNIX_API_PCI_H__

100
include/regs.h Normal file
View File

@ -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 <https://www.gnu.org/licenses/>.
*/
#ifndef __FENNIX_API_REGISTERS_H__
#define __FENNIX_API_REGISTERS_H__
#include <types.h>
#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__

231
include/syscall.h Normal file
View File

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

View File

@ -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 <https://www.gnu.org/licenses/>.
*/
#ifndef __FENNIX_API_TYPES_H__ #ifndef __FENNIX_API_TYPES_H__
#define __FENNIX_API_TYPES_H__ #define __FENNIX_API_TYPES_H__
@ -37,6 +54,58 @@ typedef __UINTMAX_TYPE__ uintmax_t;
typedef __PTRDIFF_TYPE__ ptrdiff_t; typedef __PTRDIFF_TYPE__ ptrdiff_t;
typedef __SIZE_TYPE__ size_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) #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__ #endif // !__FENNIX_API_TYPES_H__

25
include/vm.h Normal file
View File

@ -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 <https://www.gnu.org/licenses/>.
*/
#ifndef __FENNIX_API_VM_H__
#define __FENNIX_API_VM_H__
#include <types.h>
bool IsVMwareBackdoorAvailable();
#endif // !__FENNIX_API_VM_H__

5
input/Makefile Normal file
View File

@ -0,0 +1,5 @@
build:
make -C aip build
clean:
make -C aip clean

83
input/aip/Makefile Normal file
View File

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

38
input/aip/aip.h Normal file
View File

@ -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 <https://www.gnu.org/licenses/>.
*/
#ifndef __FENNIX_DRIVER_AIP_H__
#define __FENNIX_DRIVER_AIP_H__
#include <types.h>
#include <aip.h>
#include <regs.h>
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__

309
input/aip/keyboard.c Normal file
View File

@ -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 <https://www.gnu.org/licenses/>.
*/
#include "aip.h"
#include <driver.h>
#include <errno.h>
#include <input.h>
#include <base.h>
#include <io.h>
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;
}

234
input/aip/main.c Normal file
View File

@ -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 <https://www.gnu.org/licenses/>.
*/
#include "aip.h"
#include <errno.h>
#include <base.h>
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");

233
input/aip/mouse.c Normal file
View File

@ -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 <https://www.gnu.org/licenses/>.
*/
#include "aip.h"
#include <errno.h>
#include <input.h>
#include <base.h>
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;
}

82
library/Makefile Normal file
View File

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

146
library/aip.c Normal file
View File

@ -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 <https://www.gnu.org/licenses/>.
*/
#include <aip.h>
#include <errno.h>
#include <io.h>
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;
}

31
library/audio.c Normal file
View File

@ -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 <https://www.gnu.org/licenses/>.
*/
#include <audio.h>
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);
}

182
library/base.c Normal file
View File

@ -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 <https://www.gnu.org/licenses/>.
*/
#include <base.h>
#include <driver.h>
#include <errno.h>
__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
}

31
library/block.c Normal file
View File

@ -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 <https://www.gnu.org/licenses/>.
*/
#include <block.h>
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);
}

85
library/crt/crt0.c Normal file
View File

@ -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 <https://www.gnu.org/licenses/>.
*/
#include <driver.h>
#include <errno.h>
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;
}

61
library/input.c Normal file
View File

@ -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 <https://www.gnu.org/licenses/>.
*/
#include <input.h>
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);
}

36
library/net.c Normal file
View File

@ -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 <https://www.gnu.org/licenses/>.
*/
#include <net.h>
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);
}

57
library/pci.c Normal file
View File

@ -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 <https://www.gnu.org/licenses/>.
*/
#include <pci.h>
#include <driver.h>
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;
}

51
library/std.c Normal file
View File

@ -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 <https://www.gnu.org/licenses/>.
*/
#include <base.h>
#include <driver.h>
#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);
}

73
library/stdcpp.cpp Normal file
View File

@ -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 <https://www.gnu.org/licenses/>.
*/
#include <base.h>
#include <driver.h>
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);
}

59
library/task.c Normal file
View File

@ -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 <https://www.gnu.org/licenses/>.
*/
#include <driver.h>
#include <base.h>
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);
}

114
library/vm.c Normal file
View File

@ -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 <https://www.gnu.org/licenses/>.
*/
#include <vm.h>
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;
}

7
misc/Makefile Normal file
View File

@ -0,0 +1,7 @@
build:
make -C example build
make -C vmware build
clean:
make -C example clean
make -C vmware clean

83
misc/example/Makefile Normal file
View File

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

87
misc/example/main.c Normal file
View File

@ -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 <https://www.gnu.org/licenses/>.
*/
#include <base.h>
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");

83
misc/vmware/Makefile Normal file
View File

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

753
misc/vmware/main.c Normal file
View File

@ -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 <https://www.gnu.org/licenses/>.
*/
#include <driver.h>
#include <errno.h>
#include <input.h>
#include <regs.h>
#include <base.h>
#include <aip.h>
#include <vm.h>
#include <io.h>
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");

7
network/Makefile Normal file
View File

@ -0,0 +1,7 @@
build:
make -C e1000 build
make -C rtl8139 build
clean:
make -C e1000 clean
make -C rtl8139 clean

83
network/e1000/Makefile Normal file
View File

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

485
network/e1000/e1000.cpp Normal file
View File

@ -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 <https://www.gnu.org/licenses/>.
*/
#include <netools.h>
#include <errno.h>
#include <regs.h>
#include <base.h>
#include <pci.h>
#include <net.h>
#include <io.h>
#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;
}

163
network/e1000/e1000.hpp Normal file
View File

@ -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 <https://www.gnu.org/licenses/>.
*/
#pragma once
#include <types.h>
#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();

31
network/e1000/main.c Normal file
View File

@ -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 <https://www.gnu.org/licenses/>.
*/
#include <base.h>
#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");

83
network/rtl8139/Makefile Normal file
View File

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

31
network/rtl8139/main.c Normal file
View File

@ -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 <https://www.gnu.org/licenses/>.
*/
#include <base.h>
#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");

298
network/rtl8139/rtl8139.cpp Normal file
View File

@ -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 <https://www.gnu.org/licenses/>.
*/
#include <netools.h>
#include <errno.h>
#include <regs.h>
#include <base.h>
#include <pci.h>
#include <net.h>
#include <io.h>
#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<uint64_t>(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<uintptr_t>(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;
}

View File

@ -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 <https://www.gnu.org/licenses/>.
*/
#pragma once
#include <types.h>
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();

7
storage/Makefile Normal file
View File

@ -0,0 +1,7 @@
build:
make -C ahci build
make -C ata build
clean:
make -C ahci clean
make -C ata clean

83
storage/ahci/Makefile Normal file
View File

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

517
storage/ahci/ahci.cpp Normal file
View File

@ -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 <https://www.gnu.org/licenses/>.
*/
#include <errno.h>
#include <block.h>
#include <regs.h>
#include <base.h>
#include <pci.h>
#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<uint8_t *>(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<void *>(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<HBACommandHeader *>(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<HBACommandTable *>(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<PCI::PCIDevice> Devices = PCIManager->FindPCIDevice(VendorIDs, DeviceIDs);
// foreach (auto dev in Devices)
// Interrupts::RemoveHandler(OnInterruptReceived, iLine(dev));
return 0;
}

25
storage/ahci/ahci.hpp Normal file
View File

@ -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 <https://www.gnu.org/licenses/>.
*/
#pragma once
#include <types.h>
EXTERNC int cxx_Panic();
EXTERNC int cxx_Probe();
EXTERNC int cxx_Initialize();
EXTERNC int cxx_Finalize();

31
storage/ahci/main.c Normal file
View File

@ -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 <https://www.gnu.org/licenses/>.
*/
#include <base.h>
#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");

83
storage/ata/Makefile Normal file
View File

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

76
storage/ata/main.c Normal file
View File

@ -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 <https://www.gnu.org/licenses/>.
*/
#include <errno.h>
#include <regs.h>
#include <base.h>
#include <io.h>
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");