Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions 01_hello/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
SRCS=hello.c
KMOD=hello

# Uncomment the following lines to cross compile to ARM64 architecture for the Raspberry Pi
#CC=clang --target=aarch64-unknown-freebsd
#MACHINE_ARCH=aarch64
#MACHINE=arm64

.include <bsd.kmod.mk>

42 changes: 42 additions & 0 deletions 01_hello/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# 01_hello (FreeBSD version)

A simple hello world style FreeBSD kernel module.

This example can be compiled and run on a Raspberry Pi running FreeBSD or on an x86 computer.

## Commands to manage the module

Follow the kernel's log for new lines (recommended to do so in a separate terminal or tmux)
```shell
$ tail -F /var/log/messages
```

Loading the kernel module
```shell
# kldload ./hello.ko
```

Unloading the kernel module
```shell
# kldunload ./hello.ko
```

## Cross Compiling From x86 FreeBSD to AArch64 FreeBSD

It is possible to cross compile the kernel module from an x86 version of FreeBSD to the Raspberry Pi version. Edit your Makefile as follows:

```Make
KMOD=hello
SRCS=hello.c

CC=clang --target=aarch64-unknown-freebsd

CFLAGS+= -I/usr/src/sys/arm64/include

MACHINE_ARCH=aarch64
MACHINE=arm64

.include <bsd.kmod.mk>
```

The file hello.ko can then be copied to the Raspberry Pi and loaded into the kernel with kldload command.
38 changes: 38 additions & 0 deletions 01_hello/hello.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*
* Copyright [2025] John Holloway
* Learning exercise. Use at your own risk
*/

#include <sys/types.h>
#include <sys/errno.h>
#include <sys/param.h>
#include <sys/module.h>
#include <sys/kernel.h>
#include <sys/systm.h>

static int loader(struct module *module, int what, void *arg) {
int error = 0;

switch (what) {
case MOD_LOAD:
printf("Module loaded into FreeBSD kernel\n");
break;
case MOD_UNLOAD:
printf("Module removed from the FreeBSD kernel\n");
break;
default:
error = EOPNOTSUPP;
break;
}
return (error);
}

static moduledata_t mod = {
"hello",
loader,
NULL
};

DECLARE_MODULE(hello, mod, SI_SUB_KLD, SI_ORDER_ANY
);

10 changes: 10 additions & 0 deletions 02_better_hello/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
SRCS=better_hello.c
KMOD=better_hello

# Uncomment the following lines to cross compile to ARM64 architecture for the Raspberry Pi
#CC=clang --target=aarch64-unknown-freebsd
#MACHINE_ARCH=aarch64
#MACHINE=arm64

.include <bsd.kmod.mk>

57 changes: 57 additions & 0 deletions 02_better_hello/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# 02 better_hello (FreeBSD version)

A simple hello world style FreeBSD kernel module.

This example can be compiled and run on a Raspberry Pi running FreeBSD or on an x86 computer.

## Commands to manage the module

Follow the kernel's log for new lines (recommended to do so in a separate terminal or tmux)
```shell
$ tail -F /var/log/messages
```

Loading the kernel module
```shell
# kldload ./better_hello.ko
```

To get the metadata from the sysctrl use the following commands:

```shell
$ sysctl kern.better_hello
kern.better_hello.version: 1.0
kern.better_hello.license: BSD
kern.better_hello.description: A simple Hello World kernel module
kern.better_hello.author: John Holloway
```

To get more specific information, you can enter the child node in the sysctl command.
```shell
$ sysctl kern.better_hello.author
kern.better_hello.author: John Holloway
```

Unloading the kernel module
```shell
# kldunload better_hello
```

## Cross Compiling From x86 FreeBSD to AArch64 FreeBSD

It is possible to cross compile the kernel module from an x86 version of FreeBSD to the Raspberry Pi version. Edit your Makefile as follows:

```Make
KMOD=better_hello
SRCS=better_hello.c

CC=clang --target=aarch64-unknown-freebsd
CFLAGS+= -I/usr/src/sys/arm64/include

MACHINE_ARCH=aarch64
MACHINE=arm64

.include <bsd.kmod.mk>
```

The file hello.ko can then be copied to the Raspberry Pi and loaded into the kernel with kldload command.
88 changes: 88 additions & 0 deletions 02_better_hello/better_hello.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
/*
* Copyright [2025] John Holloway
* Learning exercise. Use at your own risk
*/

#include <sys/types.h>
#include <sys/errno.h>
#include <sys/param.h>
#include <sys/module.h>
#include <sys/kernel.h>
#include <sys/systm.h>
#include <sys/sysctl.h> // required for the metadata

static struct sysctl_ctx_list sysctl_ctx;
static struct sysctl_oid *sysctl_tree;

static int load_metadata(void) {
// Add a sysctrl context and object identifier to the system control tree
if (sysctl_ctx_init(&sysctl_ctx)) {
return ENOMEM;
}

sysctl_tree = SYSCTL_ADD_NODE(&sysctl_ctx,
SYSCTL_STATIC_CHILDREN(_kern),
OID_AUTO,
"better_hello",
CTLFLAG_RW,
0,
"better_hello metadata");

// Add metadata entries
SYSCTL_ADD_STRING(&sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree),
OID_AUTO, "author", CTLFLAG_RD,
"John Holloway", 0, "Module author");

SYSCTL_ADD_STRING(&sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree),
OID_AUTO, "description", CTLFLAG_RD,
"A simple Hello World kernel module",
0, "Module description");

SYSCTL_ADD_STRING(&sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree),
OID_AUTO, "license", CTLFLAG_RD,
"GPL", 0, "Module license");

SYSCTL_ADD_STRING(&sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree),
OID_AUTO, "version", CTLFLAG_RD,
"1.0", 0, "Module version");
return 0;
}

static int loader(struct module *module, int what, void *arg) {
int error = 0;

switch (what) {
case MOD_LOAD:
printf("Module loaded into FreeBSD kernel\n"
"Use sysctl to get the kernel metadata\n");
error = load_metadata();
break;

case MOD_UNLOAD:
printf("Module removed from the FreeBSD kernel\n");

// If we do not free the system call context
// we end up with dangling pointers in the kernel
if (sysctl_ctx_free(&sysctl_ctx)) {
printf("Can't free the system call context\n");
error = ENOTEMPTY;
} else {
printf("Metadata has been removed from sysctl tree\n");
}

break;
default:
error = EOPNOTSUPP;
break;
}
return(error);
}

static moduledata_t mod = {
"better_hello",
loader,
NULL
};

DECLARE_MODULE(hello, mod, SI_SUB_KLD, SI_ORDER_ANY);

11 changes: 11 additions & 0 deletions 03_gpioctrl/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
SRCS=gpioctrl.c
KMOD=gpioctrl

CFLAGS+= -I/usr/obj/usr/src/arm64.aarch64/sys/GENERIC

# Uncomment the following lines to cross compile to ARM64 architecture for the Raspberry Pi
#CC=clang --target=aarch64-unknown-freebsd
#MACHINE_ARCH=aarch64
#MACHINE=arm64

.include <bsd.kmod.mk>
73 changes: 73 additions & 0 deletions 03_gpioctrl/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
# 03_gpioctrl (FreeBSD version)

A style FreeBSD kernel module that can both turn a GPIO pin ON and read from another pin. It will be using the [gpiobus -- GPIO bus system](https://man.freebsd.org/cgi/man.cgi?gpiobus(4)) kernel interface.

This example can be compiled and run on a Raspberry Pi running FreeBSD or on an x86 computer.

Unlike the 01_hello, this kernel module requires building the kernel headers and artifacts for FreeBSD. If you have not already done so, you can build them with the following commands:
```shell
# cd /usr/src
# make -j$(sysctl -n hw.ncpu) buildkernel
```

## Hardware Setup
![Raspberry Pi Wiring](led_button_Steckplatine.png)

## Commands to manage the module

Follow the kernel's log for new lines (recommended to do so in a separate terminal or tmux)
```shell
$ tail -F /var/log/messages
```

Loading the kernel module
```shell
# kldload ./gpioctrl.ko
```

Unloading the kernel module
```shell
# kldunload gpioctrl
```

## Finding the Correct GPIO Numbers
Check your pins at [pinout.xyz](https://www.pinout.xyz)

Using the `devinfo` command to find information regarding the gpio chips on the board:

```shell
$ devinfo -rv | grep gpio
gpio0 pnpinfo name=gpio@7e200000 compat=brcm,bcm2711-gpio
gpiobus0
gpioc0
gpio1 pnpinfo name=gpio compat=raspberrypi,firmware-gpio
gpiobus1
gpioc1
unknown pnpinfo name=gpiomem compat=brcm,bcm2835-gpiomem
gpioled0 pnpinfo name=leds compat=gpio-leds
gpioregulator0 pnpinfo name=sd_io_1v8_reg compat=regulator-gpio
```

We know that _bcm2711-gpio_ is the main GPIO controller on the Raspberry Pi, so we will use the GPIO with Offset 0.

## Cross Compiling From x86 FreeBSD to AArch64 FreeBSD

It is possible to cross compile the kernel module from an x86 version of FreeBSD to the Raspberry Pi version. Edit your Makefile as follows:

```shell
KMOD=gpioctrl

SRCS=gpioctrl.c device_if.h bus_if.h

CC=clang --target=aarch64-unknown-freebsd

CFLAGS+= -I/usr/src/sys/arm64/include

MACHINE_ARCH=aarch64

MACHINE=arm64

.include <bsd.kmod.mk>
```

The file gpio.ko can then be copied to the Raspberry Pi and loaded into the kernel with kldload command.
Loading