Repository navigation
Writing my first driver
Hello, i think you read API of Depressure, if not, close this page and read it.
If you stay here, in this Tutorial we write your first driver for Depressure.
For start, we need to know what you have. Depressure uses System V ABI, compiling in ELF64.
At start check if you have downloaded Depressure in folder, unpacked BuildResources.zip in Depressure folder.
For example, you need to write at some address something, in QEMU you can use xp /2xg 0x........., for use at started QEMU, press Ctrl+Alt+2, now in compatmon0 enter command, you can replace in /2xg number 2 at any number, it's change how many adresses got readed and writed at screen. But you can read 000000000000000000, because this address is empty, for make it don't empty, you need to fill it, but how?
For this you write driver, now don't make thousands theories, go to work.
For start, check if you have installed VS Code, because its very good for writing code, also check if you have installed C/C++ Extension Pack (for check press Ctrl+Shift+X).
Now open folder where you unpack downloaded ZIP of Depressure, if you idk how to make that, open Depressure GitHub, found green button <> Code, click at it, and found Download ZIP, click to download ZIP, and unpack.
After opening folder, click at src/, now create file mydrv.h, and write this:
#ifndef MYDRV_H // Anti-error flag for usage in 1+ C/C++ files
#define MYDRV_H
#include "dtypes.h" // Need for u64/32/16/8, i64/32/16/8 and etc.
// Here you can make structures and macros (for example: #define ACPI_MAX_TABLES 64) and etc. for your driver
void mydrv_main(void *api, void *fb_info); // Need for starting driver.
#endif /* MYDRV_H */Now make mydrv_entry.asm, he need for start your driver:
BITS 64
DEFAULT REL
section .text.entry
global _mydrv_start
extern mydrv_main
_mydrv_start:
jmp mydrv_mainAfter make mydrv.c, is your driver code where you can do anything with PC and OS:
#include "dtypes.h" // Need for u64/32/16/8, i64/32/16/8 and etc.
#include "ddriver.h" // Need for making this driver visible for kernel
typedef struct dkernel_api {
u32 version;
u32 _pad;
int (*register_driver)(ddriver_t *drv);
} dkernel_api_t; // Need for register driver in kernel
typedef struct mydrv_api {
u32 version;
u32 _pad;
// Put here your api functions as: return_type (*name_of_func)(args...);
} mydrv_api_t;
static mydrv_api_t g_mydrv_api; // API of your driver
static ddriver_t mydrv_driver = {
.pattern = DDRIVER_PATTERN, // Don't change
.version = DDRIVER_VERSION, // You can change this
.next = 0, // Don't change
.type = DDRIVER_TYPE_OTHER,
.name = "mydrv", // Name of your driver (max 32 symbols)
.entry = 0, // Don't change
.api = 0, // Don't change
.data = 0, // Data of your driver
}; // Need for register
void mydrv_main(dkernel_api_t *api, void *fb_info) {
(void)fb_info;
g_mydrv_api.version = 0x00010000;
g_mydrv_api._pad = 0;
volatile u64 *dbg = (volatile u64 *)0x299998; // Address where you write something
dbg[1]=0x123456789;
// Here you link API functions to your as: g_mydrv_api.func_name = func_name_in_drv;
if (api && api->register_driver) {
mydrv_driver.api = (u64)&g_mydrv_api;
api->register_driver(&mydrv_driver);
}
}After creating of ths 3 files, go from src/ to root and make Linker Script (mydrv.ld), you can change _mydrv_start at other, but don't change other LD:
ENTRY(_mydrv_start)
SECTIONS
{
. = 0x400000 + SIZEOF_HEADERS;
.text : { *(.text.entry) *(.text*) }
.rodata : { *(.rodata*) }
.data : { *(.data*) }
.bss : { *(.bss*) *(COMMON) }
/DISCARD/ : { *(.eh_frame) *(.comment) *(.note*) }
}After open build.bat and add this commands:
Before echo [2/5] COMPILING C...:
nasm -f elf64 src/mydrv_entry.asm -o mydrv_entry.o
if %errorlevel% neq 0 goto :errBefore echo [4/5] LINKING...:
x86_64-elf-gcc -c src/mydrv.c -o mydrv.o %DFLAGS% -fPIC
if %errorlevel% neq 0 goto :errBefore echo [5/5] IMAGE + QEMU... (TIP: For other *.h files that displays interface of *.c files, add after mydrv.o he *****.o files):
x86_64-elf-ld -pie -z max-page-size=0x1000 -m elf_x86_64 -T mydrv.ld -o mydrv.elf ^
mydrv_entry.o mydrv.o
if %errorlevel% neq 0 goto :errDon't lost add copying command, after copy /Y acpi.elf image\Depressure\BOOT\acpi.elf > nul:
copy /Y mydrv.elf image\Depressure\BOOT\mydrv.elf > nulNow open VS Code Terminal (Ctrl+Shift+~ or or Ё). Check if you have installed QEMU, if you have, enterbuild.batand wait. After starting QEMU, wait before you seeDepressure Manager, now enter Ctrl+Alt+2, and enter xp /2xg 0x2999A0`, and you see 0000000123456789, if you see this, i congratulations you, you make own first driver for Depressure.
Also you can replace:
volatile u64 *dbg = (volatile u64 *)0x299998; // Address where you write something
dbg[1]=0x123456789;at:
__asm__ volatile ("ud2");And this is special instruction that makes #UD(Invalid Opcode) exception, and in VSCode terminal you can see (WARNING!: This log is Deprecated for Depressure v0.2, in v0.3 he difference, scroll down to see):
[kernel] exception Invalid Opcode vector=0x0000000000000006 error=0x0000000000000000
rip=0x000000000041813B cs=0x0000000000000048 rflags=0x0000000000010202
rax=0x0000000000418120 rbx=0x00000000CCCC0003 rcx=0x0000000000000479 rdx=0x000000000000000A
rsi=0x0000000000200000 rdi=0x0000000001009900 rbp=0x00000000013B4FF8 rsp=0x00000000013B4CD0 rsp_before_iretq=0x00000000013B4AF0
Also in v0.3, you can see this log (This is a example log of making ud2 in DepMgr at start of his poll):
[kernel] === EXCEPTION ===
[kernel] name: Invalid Opcode
[kernel] vector: 0x0000000000000006
[kernel] error: 0x0000000000000000
[kernel] task: DepMgr
[kernel] tick: 6
[kernel] rip: 0x0000000000425E92
[kernel] cs: 0x0000000000000048
[kernel] rflags: 0x0000000000010246
[kernel] rsp: 0x0000000001137828
[kernel] rax: 0x0000000000425E70
[kernel] rbx: 0x0000000000000000
[kernel] rcx: 0x0000000000000000
[kernel] rdx: 0x0000000000000000
[kernel] rsi: 0x0000000000000000
[kernel] rdi: 0x0000000000000000
[kernel] rbp: 0x0000000001137898
[kernel] ================
[kernel] killing task, resuming scheduler
[LHGC] scan start tick=1 slots=63 used=1
[LHGC] scan done, dead=0 -> compact phase
[LHGC] compact done: alive=1 reclaimed_total=0 free_slots=62
[LHGC] scan start tick=17 slots=63 used=1
[LHGC] scan done, dead=0 -> compact phase