104 lines
2.7 KiB
Markdown
104 lines
2.7 KiB
Markdown
layout: post
|
|
title: "The debug file system"
|
|
subtitle: "It's still in the kernel!"
|
|
tags: [osdev, filesystems]
|
|
|
|
This far in my vfs rewrite, I've made a [vfs mount tree](/blog/2013/12/Virtual-File-System2/) and written some [file operation syscalls](/blog/2013/12/VFS-syscalls/). Now it's time to actually use this, by writing a filesystem that can be mounted and then manipulated through the syscall interface.
|
|
|
|
The filesystem I want to start with is what I call the `debug` file.
|
|
|
|
It is a single file, which mounts to `/` for now (later `/dev/debug`)
|
|
and cannot be read from. Writing to it will print the written text on
|
|
the screen.
|
|
|
|
Three functions are needed for newlib `fprintf` to be able to write to
|
|
it: `stat`, `isatty` and `write`. Those are all rather simple, since
|
|
they won't need to keep track of which file we're referencing.
|
|
|
|
:::c
|
|
uint32_t debug_stat(INODE node, struct stat *st)
|
|
{
|
|
memset(st, 0, sizeof(struct stat));
|
|
st->st_mode = S_IFCHR;
|
|
return 0;
|
|
}
|
|
|
|
I don't care much about the stat for the debug file. Maybe I'll add some
|
|
creation time or so later...
|
|
|
|
:::c
|
|
uint32_t debug_isatty(INODE node)
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
The debug output is a terminal.
|
|
|
|
:::c
|
|
uint32_t debug_write(INODE node, void *buffer, uint32_t size, uint32_t offset)
|
|
{
|
|
char *buf = calloc(size + 1, 1);
|
|
memcpy(buf, buffer, size);
|
|
kdbg_puts(buf);
|
|
free(buf);
|
|
return size;
|
|
}
|
|
|
|
`kdbg_puts` is a function I wrote
|
|
[a long time ago](/blog/2012/06/Kernel-Debug-Functions/) which prints a
|
|
string to the screen. The first two lines are just to make sure that the
|
|
data is null-terminated.
|
|
|
|
With this, I can define a driver for the "debug device":
|
|
|
|
:::c
|
|
vfs_driver_t debug_driver =
|
|
{
|
|
0, // open
|
|
0, // close
|
|
0, // read
|
|
debug_write, // write
|
|
0, // link
|
|
0, // unlink
|
|
debug_stat, // stat
|
|
debug_isatty, // isatty
|
|
0, // mkdir
|
|
0, // readdir
|
|
0 // finddir
|
|
};
|
|
|
|
And then write a function to setup the device:
|
|
|
|
:::c
|
|
INODE debug_dev_init()
|
|
{
|
|
INODE node = calloc(1, sizeof(vfs_node_t));
|
|
strcpy(node->name, "debug");
|
|
node->d = &debug_driver;
|
|
node->type = FS_CHARDEV;
|
|
return node;
|
|
}
|
|
|
|
Then, to activate it, all I need to do is add
|
|
|
|
:::c
|
|
vfs_init();
|
|
vfs_mount("/", debug_dev_init());
|
|
|
|
in my kernel boot code. After that I can use the standard library
|
|
functions:
|
|
|
|
:::c
|
|
FILE *dbg = fopen("/", "w");
|
|
fprintf(dbg, "Hello, world!\n");
|
|
|
|
or even:
|
|
|
|
:::c
|
|
fopen("/", "r");
|
|
fopen("/", "w");
|
|
printf("Hello, world!\n");
|
|
|
|
That's it for this time. Next time, we'll do some piping!
|
|
|