Skip to content

Writing my first driver

RedstoneShell edited this page Oct 12, 2026 · 5 revisions

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.

First: Check what we have

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.

Second: Let's Write driver

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.

2.1: Making ready to writing driver

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.

2.2: Writing driver code

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_main

After 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 :err

Before echo [4/5] LINKING...:

x86_64-elf-gcc -c src/mydrv.c -o mydrv.o %DFLAGS% -fPIC
if %errorlevel% neq 0 goto :err

Before 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 :err

Don'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 > nul

2.3: Check work of driver

Now 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.

2.4: Experiments with crash and some info from Depressure Author

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

Clone this wiki locally