kernel: firmware loading

This commit is contained in:
Matheus
2026-09-09 16:37:15 -03:00
parent de0d5cb8f9
commit 2328f889ef
6 changed files with 160 additions and 0 deletions
+11
View File
@@ -0,0 +1,11 @@
#ifndef _FIRMWARE_H
#define _FIRMWARE_H
#include <stddef.h>
typedef void (*firmware_callback_t)(void *ctx, void *data, size_t size);
// firmware data is only valid only for the duration of the callback
int firmware_load(const char *name, firmware_callback_t callback, void *ctx);
#endif
+99
View File
@@ -0,0 +1,99 @@
#include <kernel/firmware.h>
#include <kernel/vfs.h>
#include <kernel/alloc.h>
#include <errno.h>
#define FIRMWARE_SIZE_LIMIT (16 * 1024)
#define FIRMWARE_PATH "/usr/lib/firmware/"
typedef struct {
const char *name;
firmware_callback_t callback;
void *ctx;
} firmware_ctx_t;
static void do_load(void *ctx) {
firmware_ctx_t *fc = ctx;
printf("firmware: loading \"%s\"\n", fc->name);
vnode_t *firmware_dir;
int error = vfs_lookup(&firmware_dir, vfsroot, FIRMWARE_PATH, NULL, 0);
if (error) {
printf("firmware: loading \"%s\" failed: failed to open %s (%s)\n",
fc->name, FIRMWARE_PATH, strerror(error));
goto leave;
}
VOP_UNLOCK(firmware_dir); // vfs_lookup returns vnode locked
vnode_t *firmware_file;
error = vfs_lookup(&firmware_file, firmware_dir, fc->name, NULL, 0);
VOP_RELEASE(firmware_dir);
if (error) {
printf("firmware: loading \"%s\" failed: failed to open file (%s)\n",
fc->name, strerror(error));
goto leave;
}
vattr_t vattr;
error = VOP_GETATTR(firmware_file, &vattr, NULL);
VOP_UNLOCK(firmware_file);
if (error)
goto leave_release;
if (vattr.size >= FIRMWARE_SIZE_LIMIT) {
error = EINVAL;
goto leave_release;
}
void *buffer = alloc(vattr.size);
if (buffer == NULL) {
error = ENOMEM;
goto leave_release;
}
size_t bytes_read;
error = vfs_read(firmware_file, buffer, vattr.size, 0, &bytes_read, 0);
if (error)
goto leave_free;
if (bytes_read != vattr.size) {
error = EINVAL;
goto leave_free;
}
printf("firmware: \"%s\" loaded\n", fc->name);
fc->callback(fc->ctx, buffer, vattr.size);
leave_free:
free(buffer);
leave_release:
if (error) {
printf("firmware: loading \"%s\" failed: %s\n",
fc->name, strerror(error));
}
VOP_RELEASE(firmware_file);
leave:
free(fc);
}
int firmware_load(const char *name, firmware_callback_t callback, void *ctx) {
// TODO: support kernel embedded firmware
firmware_ctx_t *fc = alloc(sizeof(firmware_ctx_t));
if (fc == NULL)
return ENOMEM;
fc->name = name;
fc->callback = callback;
fc->ctx = ctx;
int error = vfs_root_event_attach(do_load, fc);
if (error && error != EBUSY) {
free(fc);
return error;
} else if (error == EBUSY) {
do_load(fc);
}
return 0;
}