linux/kernel/module development

From Free Pascal wiki
Revision as of 10:29, 5 October 2007 by Mazen (talk | contribs)
Jump to navigationJump to search

overview

The purpose of this page is to give basic material to write Linux kernel modules using FPC. As Linux distributions may differ, most actions on installing packages are described for Debian distribution, on with author of this article is working. However, it may be very simple to translate this for other Linux distributions.

Requirements

1) First of all, you need to have FPC installed

apt-get install fp-compiler

Please notice that this will install fp-compiler and fp-units-rtl. The author of this page is using 2.2.0, but 2.0.4 is also working. However other versions were not tested an my not work, especially previous releases. 2) you need to have kernel headers packages installed

apt-get install linux-headers-$(uname -r)

3) Then you need make utility

apt-get install make

Please note that installing linux-headers-* will install automatically the required version of GCC and binutils.

Kernel RTL

It is obvious that when programming Linux kernel modules, one can not use the standard FPC RTL. As nos standard kernel RTL is provided, you have to write your own one. This is not very easy. A good start point could be the following unit system; {$TYPEINFO OFF} interface {Paѕcal common type aliases} type {Basic embedded types} u8 = Byte; u16 = Word; u32 = LongWord; u64 = QWord; s8 = ShortInt; s16 = SmallInt; s32 = LongInt; s64 = Int64; {Integer types} DWord = LongWord; Cardinal = LongWord; Integer = SmallInt; UInt64 = QWord; {$ifdef CPU64} SizeInt = Int64; SizeUInt = QWord; PtrInt = Int64; PtrUInt = QWord; ValSInt = int64; ValUInt = qword; {$endif CPU64} {$ifdef CPU32} SizeInt = Longint; SizeUInt = DWord; PtrInt = Longint; PtrUInt = DWord; ValSInt = Longint; ValUInt = Cardinal; {$endif CPU32} {Zero - terminated strings } PChar = ^Char; PPChar = ^PChar; {Pointers} PSmallInt = ^Smallint; PShortInt = ^Shortint; PInteger = ^Integer; PByte = ^Byte; PWord = ^word; PDWord = ^DWord; PLongWord = ^LongWord; PLongint = ^Longint; PCardinal = ^Cardinal; PQWord = ^QWord; PInt64 = ^Int64; PPtrInt = ^PtrInt; PPtrUInt = ^PtrUInt; PSizeInt = ^SizeInt; PPointer = ^Pointer; PPPointer = ^PPointer; PBoolean = ^Boolean; PWordBool = ^WordBool; PLongBool = ^LongBool; {Other types} HRESULT = type Longint; TDateTime = type Double; TError = type Longint; const KERN_INFO='KERNEL:INFO:'; KERN_ALERT='KERNEL:ALERT:'; DEVICE_NAME='kpmod'; PROCFS_MAX_SIZE=1024; PROCFS_NAME='kpmod'; EPERM = 1;{Operation not permitted} ENOENT = 2;{No such file or directory} ESRCH = 3;{No such process} EINTR = 4;{Interrupted system call} EIO = 5;{I/O error} ENXIO = 6;{No such device or address} E2BIG = 7;{Argument list too long} ENOEXEC = 8;{Exec format error} EBADF = 9;{Bad file number} ECHILD = 10;{No child processes} EAGAIN = 11;{Try again} ENOMEM = 12;{Out of memory} EACCES = 13;{Permission denied} EFAULT = 14;{Bad address} ENOTBLK = 15;{Block device required} EBUSY = 16;{Device or resource busy} EEXIST = 17;{File exists} EXDEV = 18;{Cross-device link} ENODEV = 19;{No such device} ENOTDIR = 20;{Not a directory} EISDIR = 21;{Is a directory} EINVAL = 22;{Invalid argument} ENFILE = 23;{File table overflow} EMFILE = 24;{Too many open files} ENOTTY = 25;{Not a typewriter} ETXTBSY = 26;{Text file busy} EFBIG = 27;{File too large} ENOSPC = 28;{No space left on device} ESPIPE = 29;{Illegal seek} EROFS = 30;{Read-only file system} EMLINK = 31;{Too many links} EPIPE = 32;{Broken pipe} EDOM = 33;{Math argument out of domain of func} ERANGE = 34;{Math result not representable} type {Kernel types} mode_t = Word; nlink_t = DWord; uid_t = Word; fl_owner_t = ^files_struct; gid_t = Word; off_t = LongInt; loff_t = Int64; Ploff_t = ^loff_t; size_t = DWord; ssize_t = LongInt; {$PACKRECORDS C} atomic_t = record counter:LongInt; end; files_struct = record

 		{read mostly part}

count:atomic_t; //struct fdtable *fdt; //struct fdtable fdtab;

 		{written part on a separate cache line in SMP}

//spinlock_t file_lock ____cacheline_aligned_in_smp; //int next_fd; //struct embedded_fd_set close_on_exec_init; //struct embedded_fd_set open_fds_init; //struct file * fd_array[NR_OPEN_DEFAULT]; end; filldir_t = function(arg1:Pointer; arg2:PChar; arg3:LongInt; arg4:loff_t; arg5:u64; arg6:DWord):LongInt; cdecl; read_actor_t = function(arg1:Pointer{read_descriptor_t *}; arg2:Pointer{struct page *}; arg3:DWord; arg4:DWord):LongInt; cdecl; Pfile_operations = ^file_operations; file_operations = record owner:Pointer;{struct module *} llseek:function(filp:Pointer{struct file *}; offset:loff_t; whence:LongInt):loff_t; cdecl; read:function(filp:Pointer{struct file *}; buf:PChar; count:size_t; offset:Ploff_t):ssize_t; cdecl; write:function(filp:Pointer{struct file *}; buf:PChar; count:size_t; offset:Ploff_t):ssize_t; cdecl; aio_read:function(kiocb:Pointer{struct kiocb *}; iovec:Pointer{const struct iovec *}; count:DWord; offset:loff_t):ssize_t; cdecl; aio_write:function(kiocb:Pointer{struct kiocb *}; iovec:Pointer{const struct iovec *}; count:DWord; offset:loff_t):ssize_t; cdecl; readdir:function(filp:Pointer{struct file *}; buf:Pointer; filldir:filldir_t):LongInt; cdecl; poll:function(filp:Pointer{struct file *}; poll_table:Pointer{struct poll_table_struct *}):DWord; cdecl; ioctl:function(inode:Pointer{struct inode *}; filp:Pointer{struct file *}; arg1:DWord; arg2:DWord):LongInt; cdecl; unlocked_ioctl:function(filp:Pointer{struct file *}; arg1:DWord; arg2:DWord):LongInt; cdecl; compat_ioctl:function(filp:Pointer{struct file *}; arg1:DWord; arg2:DWord):LongInt; cdecl; mmap:function(filp:Pointer{struct file *}; vm_area_struct:Pointer{ struct vm_area_struct *}):LongInt; cdecl; open:function(inode:Pointer{struct inode *}; filp:Pointer{struct file *}):LongInt; cdecl; flush:function(filp:Pointer{struct file *}; id:fl_owner_t):LongInt; cdecl; release:function(inode:Pointer{struct inode *}; filp:Pointer{struct file *}):LongInt; cdecl; fsync:function(filp:Pointer{struct file *}; arg1:Pointer{ struct dentry *}; datasync:LongInt):LongInt; cdecl; aio_fsync:function(kiocb:Pointer{struct kiocb *}; datasync:LongInt):LongInt; cdecl; fasync:function(arg1:LongInt; filp:Pointer{struct file *}; arg2:LongInt):LongInt; cdecl; lock:function(filp:Pointer{struct file *}; arg1:LongInt; arg2:Pointer{ struct file_lock *}):LongInt; cdecl; sendfile:function(filp:Pointer{struct file *}; arg1:Pointer{ loff_t *}; arg2:size_t; arg3:read_actor_t; arg4:Pointer{ void *}):ssize_t; cdecl; sendpage:function(filp:Pointer{struct file *}; arg1:Pointer{ struct page *}; arg2:LongInt; arg3:size_t; arg4:Pointer{ loff_t *}; arg5:LongInt):ssize_t; cdecl; get_unmapped_area:function(filp:Pointer{struct file *}; arg1:DWord; arg2:DWord; arg3:DWord; arg4:DWord):DWord; cdecl; check_flags:function(falgs:LongInt):LongInt; cdecl; dir_notify:function(filp:Pointer{struct file *}; arg:DWord):LongInt; cdecl; flock:function(filp:Pointer{struct file *}; arg1:LongInt; arg2:Pointer{ struct file_lock *}):LongInt; cdecl; splice_write:function(arg1:Pointer{struct pipe_inode_info *}; filp:Pointer{struct file *}; arg2:Pointer{ loff_t *}; arg3:size_t; arg4:DWord):ssize_t; cdecl; splice_read:function(filp:Pointer{struct file *}; arg1:Pointer{ loff_t *}; arg2:Pointer{ struct pipe_inode_info *}; arg3:size_t; arg4:DWord):ssize_t; cdecl; end; Pproc_dir_entry = ^proc_dir_entry; proc_dir_entry = record low_ino:Cardinal; namelen:Integer; name:PChar; mode:mode_t; nlink:nlink_t; uid:uid_t; gid:gid_t; size:loff_t; proc_iops:Pointer;{const struct inode_operations *} proc_fops:Pfile_operations;{const struct file_operations *} get_info:Pointer;{get_info_t *} owner:Pointer;{struct module *} next, parent, subdir:Pproc_dir_entry; data:Pointer; read_proc:Pointer;{read_proc_t *} write_proc:Pointer;{write_proc_t *} count:atomic_t;{use count} deleted:LongInt;{delete flag} _set:Pointer; end; var proc_root:proc_dir_entry; cvar; external; //function copy_from_user(_to:Pointer; _from:Pointer; count:Cardinal):Cardinal; cdecl; function create_proc_entry(name:PChar; mode:mode_t; parent:Pproc_dir_entry):Pproc_dir_entry; cdecl; procedure remove_proc_entry(name:PChar; parent:Pproc_dir_entry); cdecl; procedure printk(fmt:PChar); cdecl; procedure printk(fmt:PChar; param:LongInt); cdecl; procedure printk(fmt:PChar; param1:PChar); cdecl; procedure printk(fmt:PChar; param1:PChar; param2:LongInt); cdecl; function register_chrdev(devMajor:LongInt; devName:PChar; fops:Pfile_operations):LongInt; cdecl; function unregister_chrdev(devMajor:LongInt; devName:PChar):LongInt; cdecl;

implementation {$LINK kernel_module_info}

//function copy_from_user(_to:Pointer; _from:Pointer; count:Cardinal):Cardinal; cdecl; external; function create_proc_entry(name:PChar; mode:mode_t; parent:Pproc_dir_entry):Pproc_dir_entry; cdecl; external; procedure remove_proc_entry(name:PChar; parent:Pproc_dir_entry); cdecl; external; procedure printk(fmt:PChar); cdecl; external; procedure printk(fmt:PChar; param:LongInt); cdecl; external; procedure printk(fmt:PChar; param1:PChar); cdecl; external; procedure printk(fmt:PChar; param1:PChar; param2:LongInt); cdecl; external; function register_chrdev(devMajor:LongInt; devName:PChar; fops:Pfile_operations):LongInt; cdecl; external; function unregister_chrdev(devMajor:LongInt; devName:PChar):LongInt; cdecl; external; end.