set time in kernel space - time

I apologize but I'm totally newbie...
I'm trying to write my own driver for custom hardware.
I need to read system time in kernel:
struct timeval time;
struct tm broken, mytime;
...
do_gettimeofday(&time);
time_to_tm(time.tv_sec, 0, &broken);
printk(KERN_INFO "Timer synced at %d:%d:%d:%ld\n", broken.tm_hour, broken.tm_min,broken.tm_sec, time.tv_usec);
...
and this works.
Then I manually set:
- broken.tm_hour
- broken.tm_min
...
- broken.tm_sec
- time.tv_usec
how can I now update system time with my values?
Thanks.

In user space there are couple functions: gettimeofday and settimeofday. May be do_settimeofday ?

There are many ways of fillings data into 'struct timespec', I am just keeping it simple:
$ sudo insmod .ko hh=2 mm=50 ss=10 nn=600
/*
=========================================================
Execute : sudo insmod <MODULENAME>.ko hh=2 mm=50 ss=10 nn=600
Output : dmesg
=========================================================
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/time.h>
static int hh, mm, ss, nn;
MODULE_LICENSE("GPL");
module_param(hh, int, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
MODULE_PARM_DESC(hr, "Hours");
module_param(mm, uint, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
MODULE_PARM_DESC(mm, "Minutes");
module_param(ss, uint, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
MODULE_PARM_DESC(ss, "Seconds");
module_param(nn, uint, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
MODULE_PARM_DESC(nn, "Nano seconds");
int __init ourinitmodule(void)
{
struct timeval time;
struct tm broken;
struct timespec tp;
printk(KERN_ALERT "\nWelcome to Module .... \n");
do_gettimeofday(&time);
time_to_tm(time.tv_sec, 0, &broken);
printk(KERN_INFO "Timer synced at %d:%d:%d:%ld\n", broken.tm_hour, broken.tm_min,broken.tm_sec, time.tv_usec);
// Iam trying to set time to 2:50:10:800 (HH:MM:SS:NN)
tp.tv_sec= 3600/*constant*/ * hh /*hours*/ + 60 * mm /*minutes*/ + ss /*seconds*/;
tp.tv_nsec=1000* nn /*nanosec*/;
do_settimeofday(&tp);
do_gettimeofday(&time);
time_to_tm(time.tv_sec, 0, &broken);
printk(KERN_INFO "Timer set to %d:%d:%d:%ld\n", broken.tm_hour, broken.tm_min,broken.tm_sec, time.tv_usec);
return 0;
}
void __exit ourcleanupmodule(void)
{
printk(KERN_ALERT "Thanks....Exiting Module. \n");
}
module_init(ourinitmodule);
module_exit(ourcleanupmodule);
Hope you got what you need.
Happy programming :)

Related

Linux Proc kernel hello world program

make -C /lib/modules/5.13.0-37-generic/build M=/home/a1085551/osc10e/ch2 modules
make[1]: Entering directory '/usr/src/linux-headers-5.13.0-37-generic'
CC [M] /home/a1085551/osc10e/ch2/hello.o
/home/a1085551/osc10e/ch2/hello.c: In function ‘proc_init’:
/home/a1085551/osc10e/ch2/hello.c:42:41: error: passing argument 4 of ‘proc_create’ from incompatible pointer type [-Werror=incompatible-pointer-types]
42 | proc_create(PROC_NAME, 0, NULL, &proc_ops);
| ^~~~~~~~~
| |
| struct file_operations *
In file included from /home/a1085551/osc10e/ch2/hello.c:16:
./include/linux/proc_fs.h:110:24: note: expected ‘const struct proc_ops *’ but argument is of type ‘struct file_operations *’
110 | struct proc_dir_entry *proc_create(const char *name, umode_t mode, struct proc_dir_entry *parent, const struct proc_ops *proc_ops);
| ^~~~~~~~~~~
/home/a1085551/osc10e/ch2/hello.c: In function ‘proc_read’:
/home/a1085551/osc10e/ch2/hello.c:89:9: warning: ignoring return value of ‘copy_to_user’, declared with attribute warn_unused_result [-Wunused-result]
89 | copy_to_user(usr_buf, buffer, rv);
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
cc1: some warnings being treated as errors
make[2]: *** [scripts/Makefile.build:281: /home/a1085551/osc10e/ch2/hello.o] Error 1
make[1]: *** [Makefile:1879: /home/a1085551/osc10e/ch2] Error 2
make[1]: Leaving directory '/usr/src/linux-headers-5.13.0-37-generic'
make: *** [Makefile:3: all] Error 2
https://github.com/greggagne/osc10e/tree/master/ch2
I try to make the hello kernel module from that link but ended up with this error.
As said in the comments from tsyvarev, in your kernel version "5.13.0-37", the prototype of proc_create() changed. You need to look at the header files of your kernel version. For example, under an Ubuntu distribution, you can find the header file in /usr/src/linux-headers-5.13.0-37-generic/include/linux/proc_fs.h:
$ cat /usr/src/linux-headers-5.13.0-37-generic/include/linux/proc_fs.h
[...]
struct proc_ops {
unsigned int proc_flags;
int (*proc_open)(struct inode *, struct file *);
ssize_t (*proc_read)(struct file *, char __user *, size_t, loff_t *);
ssize_t (*proc_read_iter)(struct kiocb *, struct iov_iter *);
ssize_t (*proc_write)(struct file *, const char __user *, size_t, loff_t *);
/* mandatory unless nonseekable_open() or equivalent is used */
loff_t (*proc_lseek)(struct file *, loff_t, int);
int (*proc_release)(struct inode *, struct file *);
__poll_t (*proc_poll)(struct file *, struct poll_table_struct *);
long (*proc_ioctl)(struct file *, unsigned int, unsigned long);
#ifdef CONFIG_COMPAT
long (*proc_compat_ioctl)(struct file *, unsigned int, unsigned long);
#endif
int (*proc_mmap)(struct file *, struct vm_area_struct *);
unsigned long (*proc_get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
} __randomize_layout;
[...]
struct proc_dir_entry *proc_create(const char *name, umode_t mode, struct proc_dir_entry *parent, const struct proc_ops *proc_ops);
[...]
Hence, you can modify the source code of hello.c as:
/**
* hello.c
*
* Kernel module that communicates with /proc file system.
*
* The makefile must be modified to compile this program.
* Change the line "simple.o" to "hello.o"
*
* Operating System Concepts - 10th Edition
* Copyright John Wiley & Sons - 2018
*/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/proc_fs.h>
#include <asm/uaccess.h>
#define BUFFER_SIZE 128
#define PROC_NAME "hello"
#define MESSAGE "Hello World\n"
/**
* Function prototypes
*/
static ssize_t proc_read(struct file *file, char *buf, size_t count, loff_t *pos);
static struct proc_ops proc_ops = {
.proc_read = proc_read,
};
/* This function is called when the module is loaded. */
static int proc_init(void)
{
// creates the /proc/hello entry
// the following function call is a wrapper for
// proc_create_data() passing NULL as the last argument
proc_create(PROC_NAME, 0, NULL, &proc_ops);
printk(KERN_INFO "/proc/%s created\n", PROC_NAME);
return 0;
}
/* This function is called when the module is removed. */
static void proc_exit(void) {
// removes the /proc/hello entry
remove_proc_entry(PROC_NAME, NULL);
printk( KERN_INFO "/proc/%s removed\n", PROC_NAME);
}
/**
* This function is called each time the /proc/hello is read.
*
* This function is called repeatedly until it returns 0, so
* there must be logic that ensures it ultimately returns 0
* once it has collected the data that is to go into the
* corresponding /proc file.
*
* params:
*
* file:
* buf: buffer in user space
* count:
* pos:
*/
static ssize_t proc_read(struct file *file, char __user *usr_buf, size_t count, loff_t *pos)
{
int rv = 0;
char buffer[BUFFER_SIZE];
static int completed = 0;
if (completed) {
completed = 0;
return 0;
}
completed = 1;
rv = sprintf(buffer, "Hello World\n");
// copies the contents of buffer to userspace usr_buf
copy_to_user(usr_buf, buffer, rv);
return rv;
}
/* Macros for registering module entry and exit points. */
module_init( proc_init );
module_exit( proc_exit );
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Hello Module");
MODULE_AUTHOR("SGG");
The compilation result is:
$ make
make -C /lib/modules/5.13.0-37-generic/build M=... modules
make[1]: Entering directory '/usr/src/linux-headers-5.13.0-37-generic'
LD [M] /.../hello.ko
BTF [M] /.../hello.ko
Skipping BTF generation for /.../hello.ko due to unavailability of vmlinux
make[1]: Leaving directory '/usr/src/linux-headers-5.13.0-37-generic'
The execution is:
$ sudo insmod hello.ko
$ lsmod | grep hello
hello 16384 0
$ cat /proc/hello
Hello World

Writing a custom nss hosts module

I'm seeking to implement a custom nss module for the getent hosts lookup. Based on glibc's resolv/nss-dns/dns-host.c and gnunet's src/gns/nss/nss_gns.c I wrote the following minimal implementation that I hoped at least should write something to syslog - which it sadly doesn't.
#include <netdb.h>
#include <nss.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <syslog.h>
#define _nss_lash_gethostbyname2_r _nss_lash_gethostbyname_r
#define _nss_lash_gethostbyname3_r _nss_lash_gethostbyname_r
#define _nss_lash_gethostbyname4_r _nss_lash_gethostbyname_r
#define _nss_lash_getcanonname_r _nss_lash_gethostbyaddr_r
#define _nss_lash_gethostbyaddr2_r _nss_lash_gethostbyaddr_r
#define _nss_lash_getnetbyname_r _nss_lash_gethostbyaddr_r
#define _nss_lash_getnetbyaddr_r _nss_lash_gethostbyaddr_r
typedef char addr[1];
const addr default_addrs[2] = {0x01, 0x00};
enum nss_status
_nss_lash_gethostbyname_r (const char *name, struct hostent *result,
char *buffer, size_t buflen, int *errnop,
int *h_errnop)
{
syslog(LOG_WARNING, name);
if (!strcmp(name, "lash")) {
return NSS_STATUS_UNAVAIL;
}
*(result->h_aliases) = 0x0;
result->h_addrtype = AF_INET;
result->h_length = 1;
*(result->h_addr_list) = (char *)default_addrs;
*errnop = 0;
*h_errnop = NETDB_SUCCESS;
return NSS_STATUS_SUCCESS;
}
enum nss_status
_nss_lash_gethostbyaddr_r (const char *name, struct hostent *result,
char *buffer, size_t buflen, int *errnop,
int *h_errnop)
{
syslog(LOG_ERR, name);
if (!strcmp(name, "lash")) {
return NSS_STATUS_UNAVAIL;
}
*(result->h_aliases) = 0x0;
result->h_addrtype = AF_INET;
result->h_length = 1;
*(result->h_addr_list) = (char *)default_addrs;
*errnop = 0;
*h_errnop = NETDB_SUCCESS;
return NSS_STATUS_SUCCESS;
}
I've added lash to /etc/nsswitch.conf. strace shows that the /lib/libnss_lash.so.2 file is being successfully opened. However the return value from the nss lookup is NSS_UNAVAIL / ENOENT. If I add [unavail=return] to /etc/nsswitch.conf after the lash entry, I get the same result.
Anyone have any clues to what I'm missing?
(the #define lines attempt to catch all symbols found in objdump -T /lib/libnss_dns.so, which seems to be the simpler implementation)
Using:
glibc 2.30
gnunet 0.11.6-ish
nss 3.49.2

Pass a big number parameter to kernel module

I want to pass a virtual address parameter (e.g. 0xf23fa44) to a small kernel module.
I obtain: Numerical result out of range error regardless of parameter type I use (int, long). Unsigned int & unsigned long gives a compilation error.
How can I solve this problem ?
Here as my source code:
#include <...headers...>
static long address = 0;
module_param(address, long, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
static int hello_init(void){
struct task_struct *task_struct = (struct task_struct*) address;
printk(KERN_ALERT "----BEGIN-------\n");
printk("pid: %x\n" task_struct->pid)
printk(KERN_ALERT "----END-------\n");
return 0;
}
static void hello_exit(void){
printk(KERN_ALERT "----EXIT---------\n");
}
module_init(hello_init);
module_exit(hello_exit);
From the description of macro module_param:
Standard types are:
byte, short, ushort, int, uint, long, ulong
charp: a character pointer
bool: a bool, values 0/1, y/n, Y/N.
invbool: the above, only sense-reversed (N = true).
For C type unsigned long corresponded value of type argument for module_param is ulong:
static unsigned long address = 0;
module_param(address, ulong, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
A potential solution; you could use a string instead
static char *str_name = "1231241233213213123123423";
module_param(str_name,charp,0000);
And parse the string into whatever type will fit the value.

insmod module param : invalid parameters

I'm developping sample kernel module driver.ko. I want to specify the block size of data_node structure with module parameter BlockSize. when I run insmod driver.ko alone, it works, but when I specify BlockSize insmod driver.ko BlockSize = 10 I get this eror :
Error: could not insert module driver.ko: Invalid parameters
modinfo -p ./driver.ko command give me this :
BlockSize: size of buffer (int)
driver.c
#include <linux/init.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
#include <linux/cdev.h>
#include <linux/kdev_t.h>
#include <linux/fs.h>
#include <asm/uaccess.h>
#include <linux/mutex.h>
#include <linux/device.h>
#include <linux/slab.h>
/* parametter */
static int BlockNumber = 8;
static int BlockSize = 512;
module_param( variable name, type, permission); */
module_param(BlockSize, int, S_IRUGO);
MODULE_PARM_DESC(BlockSize , " size of buffer");
/* using 'k' as magic number */
#define SAMPLE_IOC_MAGIC 'k'
#define SAMPLE_IOCRESET _IOWR(SAMPLE_IOC_MAGIC, 0, int)
#define SAMPLE_IOC_MAXNR 0
struct cdev* my_cdev;
dev_t dev;
static int size_to_read;
/* Macro used to compute the minimum */
#define MIN(a,b) (((a) < (b)) ? (a) : (b))
/* data buffer structure */
typedef struct dnode
{
int bufSize;
char *buffer;
struct dnode *next;
} data_node;
/* liste stucture */
typedef struct lnode
{
data_node *head;
data_node *cur_write_node;
data_node *cur_read_node;
int cur_read_offset;
int cur_write_offset;
}liste;
code ..........................
..
It appears that module parameters should be passed without a space between the name and value, ie you should use:
insmod driver.ko BlockSize=10
This makes some sense, as in the command line to insmod itself "BlockSize=10" is a single entry in *argv[] which can be handed off to the kernel as a chunk, while "BlockSize = 10" would be three distinct entries ("BlockSize", "=", "10") which someone would have to write code to re-join.

Windows Named Pipe is invalid

I have no idea why this pipe is invalid. everything seems fine to me. This is just a test, i don't write or read from it. Anyone can tell me what's wrong?
#include <windows.h>
#include <stdio.h>
#include <tchar.h>
#define BUFSIZE 4096
int main()
{
HANDLE hPipe;
LPTSTR Pipename = TEXT("\\\\.\\pipe\\mypipe");
printf("Start Server\n");
for(;;)
{
hPipe = CreateNamedPipe( Pipename,
PIPE_ACCESS_DUPLEX,
PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
PIPE_UNLIMITED_INSTANCES,
BUFSIZE,
BUFSIZE,
NMPWAIT_USE_DEFAULT_WAIT,
NULL );
if ( hPipe == INVALID_HANDLE_VALUE )
{
printf("CreatePipe failed");
return 0;
}
CloseHandle(hPipe);
}
return 1;
}
Without more detail about the error it is difficult to help. However, as a general rule create the server using CreateNamedPipe then use ConnectNamedPipe.
On the client side you can now use CreateFile, which ConnectNamedPipe is waiting for on the server side.

Resources