FreeBSD kldload: can't load, No such file or directory - c

I am new to kernel and KLD programming. I am looking to modify the example file in FreeBSD for system call module. My question is, is it possible to fork or exec inside system call function? Like in the following example?
#include <sys/types.h>
#include <sys/param.h>
#include <sys/proc.h>
#include <sys/module.h>
#include <sys/sysent.h>
#include <sys/kernel.h>
#include <sys/systm.h>
/*
* The function for implementing the syscall.
*/
static int hello (struct thread *td, void *arg)
{
printf("Running...\n");
/******************************************************/
/*Something like this?*/
/******************************************************/
execl("/bin/pwd", "pwd", NULL);
return 0;
}
/*
* The `sysent' for the new syscall
*/
static struct sysent hello_sysent = {
0, /* sy_narg */
hello /* sy_call */
};
/*
* The offset in sysent where the syscall is allocated.
*/
static int offset = NO_SYSCALL;
/*
* The function called at load/unload.
*/
static int
load (struct module *module, int cmd, void *arg)
{
int error = 0;
switch (cmd) {
case MOD_LOAD :
uprintf ("syscall loaded at %d\n", offset);
break;
case MOD_UNLOAD :
uprintf ("syscall unloaded from %d\n", offset);
break;
default :
uprintf("There was some error!");
error = EINVAL;
break;
}
return error;
}
SYSCALL_MODULE(syscall, &offset, &hello_sysent, load, NULL);
There is no compilation error (syscall), but while loading it using kldload, it returns an error:
kldload: can't load ./syscall.ko: No such file or directory
Is there something I can read and know more about why is this happening and what can I do about it?

When kldload returns "No such file or directory", or some other weird error, first do "dmesg" and look for any errors at the bottom. In this case it's probably due to a missing symbol "execl". That's because execl is a userspace API (man 3 execl), and you're trying to use it in kernel.
What you're trying to do doesn't seem to be a good idea, but it's possible. Look at sys/kern/kern_exec.c:kern_execve().

Related

Callbacks in AIO asynchronous I/O

I have found discussion on using callbacks in AIO asynchronous I/O on the internet. However, what I have found has left me confused. An example code is listed below from a site on Linux AIO. In this code, AIO is being used to read in the contents of a file. My problem is that it seems to me that a code that actually processes the contents of that file must have some point where some kind of block is made to the execution until the read is completed. This code here has no block like that at all. I was expecting to see some kind of call analogous to pthread_mutex_lock in pthread programming. I suppose I could put in a dummy loop after the aio_read() call that would block execution until the read is completed. But that puts me right back to the simplest way of blocking the execution, and then I don't see what is gained by all the coding overhead that goes into establishing a callback. I am obviously missing something. Could someone tell me what it is?
Here is the code. (BTW, the original is in C++; I have adapted it to C.)
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <aio.h>
//#include <bits/stdc++.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <signal.h>
const int BUFSIZE = 1024;
void aio_completion_handler(sigval_t sigval)
{
struct aiocb *req;
req = (struct aiocb *)sigval.sival_ptr; //Pay attention here.
/*Check again if the asynchrony is complete?*/
if (aio_error(req) == 0)
{
int ret = aio_return(req);
printf("ret == %d\n", ret);
printf("%s\n", (char *)req->aio_buf);
}
close(req->aio_fildes);
free((void *)req->aio_buf);
while (1)
{
printf("The callback function is being executed...\n");
sleep(1);
}
}
int main(void)
{
struct aiocb my_aiocb;
int fd = open("file.txt", O_RDONLY);
if (fd < 0)
perror("open");
bzero((char *)&my_aiocb, sizeof(my_aiocb));
my_aiocb.aio_buf = malloc(BUFSIZE);
if (!my_aiocb.aio_buf)
perror("my_aiocb.aio_buf");
my_aiocb.aio_fildes = fd;
my_aiocb.aio_nbytes = BUFSIZE;
my_aiocb.aio_offset = 0;
//Fill in callback information
/*
Using SIGEV_THREAD to request a thread callback function as a notification method
*/
my_aiocb.aio_sigevent.sigev_notify = SIGEV_THREAD;
my_aiocb.aio_sigevent.sigev_notify_function = aio_completion_handler;
my_aiocb.aio_sigevent.sigev_notify_attributes = NULL;
/*
The context to be transmitted is loaded into the handler (in this case, a reference to the aiocb request itself).
In this handler, we simply refer to the arrived sigval pointer and use the AIO function to verify that the request has been completed.
*/
my_aiocb.aio_sigevent.sigev_value.sival_ptr = &my_aiocb;
int ret = aio_read(&my_aiocb);
if (ret < 0)
perror("aio_read");
/* <---- A real code would process the data read from the file.
* So execution needs to be blocked until it is clear that the
* read is complete. Right here I could put in:
* while (aio_error(%my_aiocb) == EINPROGRESS) {}
* But is there some other way involving a callback?
* If not, what has creating a callback done for me?
*/
//The calling process continues to execute
while (1)
{
printf("The main thread continues to execute...\n");
sleep(1);
}
return 0;
}

How could i send a message to another program, and output that it has been received?

In contiki, i need to have two files, sender and receiver, the sender sends packets to the receiver. My problem is, the receiver is not outputting that the packets have been received.
I tried a while loop inside the receiving packet, i even tried to create a function, but still nothing has worked.
My sender.c file
#include "contiki.h"
#include "net/rime.h"
#include "random.h"
#include "dev/button-sensor.h"
#include "dev/leds.h"
#include <stdio.h>
PROCESS(sendReceive, "Hello There");
AUTOSTART_PROCESSES(&sendReceive);
PROCESS_THREAD(sendReceive, ev, data)
{
PROCESS_BEGIN();
static struct abc_conn abc;
static struct etimer et;
static const struct abc_callbacks abc_call;
PROCESS_EXITHANDLER(abc_close(&abc);)
abc_open(&abc, 128, &abc_call);
while(1)
{
/* Delay 2-4 seconds */
etimer_set(&et, CLOCK_SECOND * 2 + random_rand() % (CLOCK_SECOND * 2));
PROCESS_WAIT_EVENT_UNTIL(etimer_expired(&et));
packetbuf_copyfrom("Hello", 6);
abc_send(&abc);
printf("Message sent\n");
}
PROCESS_END();
}
my receiver.c file
#include "contiki.h"
#include "net/rime.h"
#include "random.h"
#include "dev/button-sensor.h"
#include "dev/leds.h"
#include <stdio.h>
PROCESS(sendReceive, "Receiving Message");
AUTOSTART_PROCESSES(&sendReceive);
PROCESS_THREAD(sendReceive, ev, data)
{
PROCESS_BEGIN();
{
printf("Message received '%s'\n", (char *)packetbuf_dataptr());
}
PROCESS_END();
}
The sender.c file is working, it is sending the packets correctly, the problem is the receiver seems not to output that it has been received.
While sending is simple - you just need to call a function -, receiving data in embedded system is in general more complicated. There needs to be a way for the operating system to let your code know that new data has arrived from outside. In Contiki that is internally done with events, and from user's perspective with callbacks.
So, implement a callback function:
static void
recv_from_abc(struct abc_conn *bc)
{
printf("Message received '%s'\n", (char *)packetbuf_dataptr());
}
In your receiver process, create and open an connection, passing the callback function's pointer as a parameter:
static struct abc_conn c;
static const struct abc_callbacks callbacks =
{recv_from_abc, NULL};
uint16_t channel = 128; /* matching the sender code */
abc_open(&c, channel, &callbacks);

Writing to an I/O Address

I am using a VersaLogic Osprey Board and I am running Lubuntu 16.04 Xenial with GCC compiler 6.2.0. Writing in C, I cannot compile C++.
I am trying to read from the I/O address of the Watchdog timer, with the intent of later enabling it. According to the data sheet the I/O address is 1CA8 (WDT_CTL is the identifier of this address)
The code I have thus far is as follows:
#define WDT_CTL 0x1CA8
int main(void)
{
char *p_CTL = (char*) WDT_CTL;
printf("Attempting to print contents %c\n"),*p_CTL);
}
The code compiles, but I get a segmentation fault (core dumped) when I get to the important line, there are no other errors or warnings. As far as I know a seg fault is a "you can't access that memory location" error, but I am trying to read from the address that I found in the data sheet.
I have done some research and according to the datasheet the address I have is an I/O address, which seems to be different from a normal address. When I look at the address of a custom variable (char a) that address is 12 digits long as opposed to the four I am given for the watchdog timer.
Am I missing something? Is it a limitation of Lubuntu that I can no longer write directly to an I/O address? Do I need to use some specific command to do so? Do I need to enable something or change a setting?
Note that this thread is different from one with a similar title because that was done in Windows 7, not Lubuntu and that fix will not work here.
This is how I usually access the watchdog hardware:
This has worked on several different computers.
#include "watchdog.h"
#include <fcntl.h> /* open() */
#include <stdio.h> /* printf() */
#include <unistd.h> /* write() */
#include <string.h> /* strerror() */
#include <errno.h> /* errno */
#define APP_VERSION "1.1.0"
/* Look for the device in two places */
#define WD_KICK_DEV_NAME_1 "/dev/cs5535/gpio/5"
#define WD_KICK_DEV_NAME_2 "/dev/gpio/5"
#define WD_ENABLE_DEV_NAME_1 "/dev/cs5535/gpio/27"
#define WD_ENABLE_DEV_NAME_2 "/dev/gpio/27"
#define TEXT_WDOG_KICK "Ot0101"
#define TEXT_WDOG_ENABLE "1TO"
#define TEXT_WDOG_DISABLE "0TO"
static INT32 wd_kick_fd;
static INT32 wd_enable_fd;
/**
* Return the version
*/
const char *wd_get_version(void)
{
return(APP_VERSION);
}
/**
* Open GPIO-5 and GPIO-27
*/
INT32 wd_init(void)
{
if (((wd_kick_fd = open(WD_KICK_DEV_NAME_2, O_WRONLY)) < 0) &&
((wd_kick_fd = open(WD_KICK_DEV_NAME_1, O_WRONLY)) < 0))
{
printf("Failed to open '%s' or '%s': %s (%d)\n",
WD_KICK_DEV_NAME_1, WD_KICK_DEV_NAME_2, strerror(errno), errno);
return(FAILURE);
}
if (((wd_enable_fd = open(WD_ENABLE_DEV_NAME_2, O_WRONLY)) < 0) &&
((wd_enable_fd = open(WD_ENABLE_DEV_NAME_1, O_WRONLY)) < 0))
{
printf("Failed to open '%s' or '%s': %s (%d)\n",
WD_ENABLE_DEV_NAME_1, WD_ENABLE_DEV_NAME_2, strerror(errno), errno);
return(FAILURE);
}
return(SUCCESS);
}
/**
* Disabled via GPIO-27
*/
void wd_disable(void)
{
(void)write(wd_enable_fd, TEXT_WDOG_DISABLE, strlen(TEXT_WDOG_DISABLE));
}
/**
* Enabled via GPIO-27
*/
void wd_enable(void)
{
(void)write(wd_enable_fd, TEXT_WDOG_ENABLE, strlen(TEXT_WDOG_ENABLE));
}
/**
* Kick the watchdog by toggling GPIO 5
*/
void wd_kick(void)
{
(void)write(wd_kick_fd, TEXT_WDOG_KICK, strlen(TEXT_WDOG_KICK));
}
and the watchdog.h file contains:
#ifndef WATCHDOG_H_INCLUDED
#define WATCHDOG_H_INCLUDED
/**
* Grab the version of the kicker stuff
*/
const char *wd_get_version(void);
/**
* Do any initialization needed for the watchdog.
*
* #return SUCCESS or FAILURE
*/
INT32 wd_init(void);
/**
* Disables the watchdog.
* If watchdog cannot be disabled, then calls wd_kick()
*/
void wd_disable(void);
/**
* Enables the watchdog.
* If watchdog cannot be disabled, do nothing.
*/
void wd_enable(void);
/**
* Kicks the watchdog
*/
void wd_kick(void);
#endif /* WATCHDOG_H_INCLUDED */

Why does printk() work only in the init/exit method of a kernel module? (Priority should be fine)

My goal is to write a kernel-module. I am following the memory tutorial of the freesoftware magazine.
The tutorial works fine. I am able to compile the code. When loaded with insmod, the kernel prints <1>Inserting memory module as expected. When I remove the module using rmmod the kernel prints <1>Removing memory module.
For debugging purposes, I am trying to add printk() to the other methods. But they are never printed.
The priority of all the messages is <1>.
I write into the device by: echo -n test1234 > /dev/memory
And use cat /dev/memory to get back the data.
cat /var/log/messages and dmesg donĀ“t print anymore information
[ 5550.651221] <1>Inserting memory module
[ 5550.655396] <1>Inserting memory module !!!!!!!!!!!!!!!
[12230.130847] <1>Removing memory module
cat /proc/sys/kernel/printk
7 4 1 7
uname- a
Linux generic-armv7a-hf 3.14.0-163850-g775a3df-dirty #2 SMP Mon Jan 12 13:53:50 CET 2015 armv7l GNU/Linux
Why does printk() only work in the init and exit method?
Is there any (better) way to print variable values than printk()?
Here the code:
/* Necessary includes for device drivers */
#include <linux/init.h>
//#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h> /* printk() */
#include <linux/slab.h> /* kmalloc() */
#include <linux/fs.h> /* everything... */
#include <linux/errno.h> /* error codes */
#include <linux/types.h> /* size_t */
#include <linux/proc_fs.h>
#include <linux/fcntl.h> /* O_ACCMODE */
#include <asm/system.h> /* cli(), *_flags */
#include <asm/uaccess.h> /* copy_from/to_user */
MODULE_LICENSE("Dual BSD/GPL");
/* Declaration of memory.c functions */
int memory_open(struct inode *inode, struct file *filp);
int memory_release(struct inode *inode, struct file *filp);
ssize_t memory_read(struct file *filp, char *buf, size_t count, loff_t *f_pos);
ssize_t memory_write(struct file *filp, char *buf, size_t count, loff_t *f_pos);
void memory_exit(void);
int memory_init(void);
/* Structure that declares the usual file */
/* access functions */
struct file_operations memory_fops = {
read: memory_read,
write: memory_write,
open: memory_open,
release: memory_release
};
/* Declaration of the init and exit functions */
module_init(memory_init);
module_exit(memory_exit);
/* Global variables of the driver */
/* Major number */
int memory_major = 60;
/* Buffer to store data */
char *memory_buffer;
int memory_init(void) {
int result;
/* Registering device */
result = register_chrdev(memory_major, "memory", &memory_fops);
if (result < 0) {
printk(
"<1>memory: cannot obtain major number %d\n", memory_major);
return result;
}
/* Allocating memory for the buffer */
memory_buffer = kmalloc(1, GFP_KERNEL);
if (!memory_buffer) {
result = -ENOMEM;
goto fail;
}
memset(memory_buffer, 0, 1);
printk("<1>Inserting memory module\n"); ///this works fine
printk("<1>Inserting memory module !!!!!!!!!!!!!!!\n"); ///this works fine too
return 0;
fail:
memory_exit();
return result;
}
void memory_exit(void) {
/* Freeing the major number */
unregister_chrdev(memory_major, "memory");
/* Freeing buffer memory */
if (memory_buffer) {
kfree(memory_buffer);
}
printk("<1>Removing memory module\n"); //never printed
}
int memory_open(struct inode *inode, struct file *filp) {
printk("<1>memory open\n"); //never printed
/* Success */
return 0;
}
int memory_release(struct inode *inode, struct file *filp) {
printk("<1>memory_release\n"); //never printed
/* Success */
return 0;
}
ssize_t memory_read(struct file *filp, char *buf,
size_t count, loff_t *f_pos) {
printk("<1>mem read\n"); //never printed
/* Transfering data to user space */
copy_to_user(buf,memory_buffer,1);
/* Changing reading position as best suits */
if (*f_pos == 0) {
*f_pos+=1;
return 1;
} else {
return 0;
}
}
ssize_t memory_write( struct file *filp, char *buf,
size_t count, loff_t *f_pos) {
printk("<1>mem write\n"); //never printed
char *tmp;
tmp=buf+count-1;
copy_from_user(memory_buffer,tmp,1);
return 1;
}
Your driver seems fine, but you aren't actually talking to it with your test commands, so the functions with printks aren't being called. Once the module is loaded, it registers a major and minor number, 60 and 0 in your case. (Down the road you should update the module to request an available major number instead of using a hard-coded one.)
You need to create a file system node with mknod in order to actually use the driver. This will create the /dev/memory node and connect it to the module you have loaded. Then when it is opened, closed, read from, or written to, the file_operations in your module will be called, and the printks will work.
For your module, you should be able to use
mknod /dev/memory c 60 0
You can also chmod 666 /dev/memory to allow any user to use the device, rather than running as root all the time.
Here's a script based on the one I use with modules I develop:
#!/bin/sh
device="memory"
mode="666"
major=$(awk "\$2==\"$device\" {print \$1}" /proc/devices}
mknod /dev/${device} c $major 0
chmod $mode /dev/${device}
It will look up the major number associated with your module and create a file system node for it automatically.
Once you have loaded the module and run mknod or the script, you should be able to use the driver. You will know that it is working becase cat will only return the last character written to the device - your driver only has a one character buffer, and it is automatically overwritten each time a new character comes in. Then dmesg should show the printk's associated with the functions in your module.
The reason your driver seemed to work is because you were creating a regular file with your echo command, which cat happily printed right back to you. It's the same thing that would have happened if you ran those commands on a file in your home directory, you just happened to be in /dev instead.

Passing Arguments wrongly? C Question

When my TimerExpire function is finally called when the timer ticks out, it prints out gibberish. Anyone know why? But my printk function in IOCTL_MAKE_TIMER prints out correctly, so I think it's because I'm passing in the data wrong.
setup_timer() works by setting up the timer in the first argument, telling it to call the function specified by the second argument, and passes the data (which is the third argument), to that function.
In my case, it is calling the TimerExpire(char* data) function, passing to it final_arg, which is a char* to kern_arg. I even tried passing kern_arg directly to the function... also gave me gibberish.
Previously (yesterday), I had char* kern_arg, instead of char kern_arg[], and that worked out perfectly, but I think it was unsafe.
If anyone could provide some insight, that would be amazing! Thanks!
//Necessary Includes For Device Drivers.
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/proc_fs.h>
#include <asm/uaccess.h>
#include <linux/timer.h>
#include <linux/ioctl.h>
#define DEVICE_NAME "mytimer"
#define DEVICE_FILE_NAME "mytimer"
#define MAJOR_NUM 61
#define MINOR_NUM 0
#define SUCCESS 0
#define IOCTL_MAKE_TIMER _IOWR(MAJOR_NUM, 0, int)
#define IOCTL_SET_TIMER _IOWR(MAJOR_NUM, 1, int)
#define IOCTL_GET_TIMER _IOWR(MAJOR_NUM, 2, int)
//Module License
MODULE_LICENSE("Dual BSD/GPL");
//Initialize timer structure.
static struct timer_list my_timer;
//Forward Declarations for File Operation Functions and Other Functions.
static int mytimer_open(struct inode *inode, struct file *file);
static int mytimer_release(struct inode *inode, struct file *file);
int mytimer_ioctl(struct inode *inode, struct file *file, unsigned int ioctl_num, unsigned long args);
void TimerExpire(char* data);
//Syscall Operations for the module.
struct file_operations FileOps =
{
.owner = THIS_MODULE,
.open = mytimer_open,
.release = mytimer_release,
.ioctl = mytimer_ioctl
};
//Syscall function for opening the module.
static int mytimer_open(struct inode *inode, struct file *file)
{
try_module_get(THIS_MODULE);
return SUCCESS;
}
//Syscall function for releasing the module.
static int mytimer_release(struct inode *inode, struct file *file)
{
module_put(THIS_MODULE);
return SUCCESS;
}
//Syscall function for controlling the module through IOCTLs.
int mytimer_ioctl(struct inode *inode, struct file *file, unsigned int fcn, unsigned long args)
{
//Copies the function parameters from userspace to kernel space in order to use them in the kernel module.
char* user_arg = args;
char kern_arg[strlen_user(user_arg)];
copy_from_user(kern_arg, user_arg, strlen_user(user_arg));
char* final_arg = kern_arg;
//If there is a timer, and the command is to make a new one, the old timer will be removed so a new one can be setup.
if (timer_pending(&my_timer) && fcn == IOCTL_MAKE_TIMER)
{
del_timer_sync(&my_timer);
printk("Timer already exists. Deleting old timer and setting new timer.\n");
}
//Switch function that serves the function that is called.
//Note that the make and set timer functions are separate. This is because only 1 arg is passed via ioctl at a time, so I had to make two different ioctl calls.
switch (fcn)
{
//Make a new timer.
case IOCTL_MAKE_TIMER:
setup_timer(&my_timer, TimerExpire, final_arg);
printk("Made timer with message: %s\n", final_arg);
break;
//Set the timer made above.
case IOCTL_SET_TIMER:
mod_timer(&my_timer, jiffies + msecs_to_jiffies(args * 1000));
printk("Armed timer for %d seconds.\n", args);
break;
//Print the current timer, if any.
case IOCTL_GET_TIMER:
if (!timer_pending(&my_timer))
{
printk("No timer currently set.\n");
}
else
{
printk("Time left in timer: %u seconds\n", jiffies_to_msecs(my_timer.expires - jiffies)/1000);
printk("Message in timer is: %s\n", my_timer.data);
}
break;
}
return SUCCESS;
}
//Function to perform when timer expires.
void TimerExpire(char* data)
{
printk("%s\n", data);
}
//Module Init and Exit Functions.
int init_module(void)
{
printk("Loading MyTimer Kernel Module...\n");
//Register the device with the system to obtain the major number and register the file operations for syscall functionality.
int initResult = register_chrdev(MAJOR_NUM, "mytimer", &FileOps);
//If we couldn't register the device, print the error.
if (initResult < 0)
{
printk("Cannot obtain major number %d\n", MAJOR_NUM);
return initResult;
}
printk("Please create device file using:\n\tmknod /dev/mytimer c 61 0\n");
return SUCCESS;
}
void cleanup_module(void)
{
//Unregister the device with the system to free the major number.
printk("Unloading MyTimer Kernel Module...\n");
unregister_chrdev(MAJOR_NUM, "mytimer");
printk("MyTimer Kernel Module Unloaded.\n");
}
In this code, a call to ioctl(fd,IOCTL_MAKE_TIMER,...) passes setup_timer() a pointer to an array located on the kernel stack, then returns. By the point that the timer expires, the memory that used to hold that array has probably been reused.
You need to keep the memory around until after the timer expires. You could do this by allocating a buffer on the kernel heap (e.g. kmalloc()) or using static/global data.

Resources