-
Notifications
You must be signed in to change notification settings - Fork 63
Development Guide
Learn how to add new programs and features to MentOS.
Create a new .c file in userspace/bin/ (or userspace/tests/ for tests):
cd userspace/binCreate hello.c:
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
printf("Hello from MentOS!\n");
if (argc > 1) {
printf("Arguments:\n");
for (int i = 1; i < argc; i++) {
printf(" argv[%d] = %s\n", i, argv[i]);
}
}
return 0;
}Edit userspace/bin/CMakeLists.txt and add your program to the list:
# Add the executables (manually).
set(PROGRAM_LIST
cat.c
chmod.c
# ... existing programs ...
hello.c ← Add your program here
)For tests, edit userspace/tests/CMakeLists.txt instead.
cd build
make
make filesystemmake qemu
# At shell prompt:
hello
hello arg1 arg2System calls allow userspace programs to request kernel services.
Edit lib/inc/system/syscall_types.h:
#define __NR_fork 2
#define __NR_read 3
// ... existing syscalls ...
#define __NR_myfunction 100 ← Add new syscall numberCreate kernel/src/system/my_function.c:
#include "process/scheduler.h"
#include "system/printk.h"
long sys_myfunction(int arg1, int arg2)
{
// Your kernel code here
printk("sys_myfunction called with %d, %d\n", arg1, arg2);
// Access current process
task_struct *task = scheduler_get_current_process();
// Return value
return arg1 + arg2;
}Edit kernel/src/system/syscall.c:
long sys_myfunction(int arg1, int arg2); // Declare
// In syscall_init():
sys_call_table[__NR_myfunction] = (SystemCall)sys_myfunction;Create lib/src/unistd/myfunction.c:
#include "errno.h"
#include "system/syscall_types.h"
#include "unistd.h"
int myfunction(int arg1, int arg2)
{
long __res;
__inline_syscall_2(__res, myfunction, arg1, arg2);
__syscall_return(int, __res);
}Edit lib/inc/unistd.h (or appropriate header):
int myfunction(int arg1, int arg2);Create test program userspace/tests/t_myfunction.c:
#include <stdio.h>
#include <unistd.h>
int main(void)
{
int result = myfunction(10, 20);
printf("myfunction(10, 20) = %d\n", result);
return 0;
}Build and test:
make
make filesystem
make qemu
# At shell:
/bin/tests/t_myfunctionCreate kernel/src/drivers/mydevice.c:
#include <io/port_io.h>
#include <system/printk.h>
#define MYDEVICE_PORT 0x3F8 // Example I/O port
void mydevice_init(void)
{
pr_info("Initializing mydevice driver\n");
// Initialize hardware
outportb(MYDEVICE_PORT, 0x00);
}
int mydevice_read(void)
{
return inportb(MYDEVICE_PORT);
}
void mydevice_write(uint8_t data)
{
outportb(MYDEVICE_PORT, data);
}Create kernel/inc/drivers/mydevice.h:
#pragma once
void mydevice_init(void);
int mydevice_read(void);
void mydevice_write(uint8_t data);Edit kernel/src/kernel.c in kmain():
#include <drivers/mydevice.h>
void kmain(/* ... */)
{
// ... existing initialization ...
mydevice_init(); ← Initialize your driver
// ... rest of kernel init ...
}Create syscalls to interact with the device from userspace (follow "Adding a System Call" steps).
See Scheduling for details on scheduler algorithms.
cd build
cmake .. -DSCHEDULER_TYPE=SCHEDULER_CFS
make-
Create
kernel/src/process/sched_custom.c -
Implement scheduler interface:
void scheduler_custom_init(void); task_struct *scheduler_custom_pick_next(void); void scheduler_custom_enqueue(task_struct *task);
-
Register in
kernel/CMakeLists.txt(add a new entry toSCHEDULER_TYPES) -
Add your implementation to
kernel/src/process/(sources are picked up automatically)
Create kernel/src/fs/myfs.c:
#include <fs/vfs.h>
#include <fs/vfs_types.h>
static vfs_file_t *myfs_mount_callback(const char *path, const char *device);
static file_system_type_t myfs_file_system_type = {
.name = "myfs",
.fs_flags = 0,
.mount = myfs_mount_callback,
};
int myfs_init(void)
{
return vfs_register_filesystem(&myfs_file_system_type);
}static vfs_file_t *myfs_open(const char *path, int flags, mode_t mode)
{
// Open file logic
}
static int myfs_read(vfs_file_t *file, char *buf, off_t offset, size_t nbyte)
{
// Read logic
}
// ... etcIn kernel/src/kernel.c:
myfs_init();Create tests in userspace/tests/:
// t_myfeature.c
#include <stdio.h>
#include <assert.h>
int main(void)
{
int result = myfunction(5, 10);
assert(result == 15);
printf("Test passed!\n");
return 0;
}Run full test suite:
make qemu-testmake qemu
# Manually test featurespr_debug("Value = %d\n", value);
pr_info("Function called\n");
pr_err("Error occurred: %d\n", errno);printf("Debug: x=%d, y=%d\n", x, y);make qemu-gdb
# In another terminal (from build/):
gdb --quiet --command=gdb.runKernel messages appear in terminal running make qemu.
Follow the C coding guidelines from .github/copilot-instructions.md:
-
Functions/variables:
snake_case -
Types/structs:
CamelCaseorsnake_case_t -
Constants:
UPPER_CASE - Initialization: Always initialize variables
- Error handling: Use return codes or errno
- Comments: Document non-obvious code
Example:
// Good
int calculate_sum(int a, int b)
{
int result = a + b; // Initialize variables
return result;
}
// Bad
int CalculateSum(int a, int b)
{
int result; // Uninitialized
result = a + b;
return result;
}#include <process/scheduler.h>
task_struct *current = scheduler_get_current_process();
pid_t pid = current->pid;#include <mem/alloc/slab.h>
void *ptr = kmalloc(size);
// Use ptr
kfree(ptr);#include <mem/mm/vmem.h>
// Copy between address spaces (src/dst are mm_struct_t* + virtual addrs)
vmem_memcpy(dst_mm, dst_vaddr, src_mm, src_vaddr, size);#include <fs/vfs.h>
// Open file
vfs_file_t *file = vfs_open("/path/to/file", O_RDONLY, 0);
// Read
char buf[256];
ssize_t bytes = vfs_read(file, buf, 0, sizeof(buf));
// Close
vfs_close(file);# Kernel change
make kernel.bin
make bootloader.bin
# Userspace program
make programs
make filesystem
# Library change
make libc
make programs
make filesystem
# CMake config change
cd build
cmake ..
makemake -j$(nproc)make clean
# or
rm -rf build && mkdir build && cd build && cmake .. && make- Kernel - Understand kernel internals
- System Calls - Syscall interface details
- Debugging - Advanced debugging techniques
- Contributing - Submit your changes
Previous: Running MentOS | Next: Debugging →