LxM. Linux Modules - JulTob/Ada GitHub Wiki

16.16 Writing Linux Modules

If you are writing kernel components, you'll have to use "GNORT" (pragma no_run_time). Without the run time components, you won't be able to use some Ada packages and features, including exceptions and the Text_IO library (which uses exceptions). You'll have to import the appropriate C functions to do I/O. Without the run time library, you're source code will also be much smaller, comparable with C.

If you have the time, you can always copy some of the standard Ada packages to a separate directory and compile them into your GNORT project, effectively creating your own small, custom run-time system.

The Gnat run-time system is described at http://www.iuma.ulpgc.es/users/jmiranda/.

For details on how to program for the Linux kernel, read Linux Kernel Module Programming Guide. To create a Linux kernel module in Ada, you will also need to register a license. In C, this is accomplised with the MODULE_LICENSE macro. The Linux kernel will expect init_module and cleanup_module subprograms to exist.

with Interfaces.C;

package SomeModule is

-- Module Variables

type Aliased_String is array (Positive range <>) of aliased Character; pragma Convention (C, Aliased_String);

Kernel_Version: constant Aliased_String:="2.4.18-5" & Character'Val(0); pragma Export (C, Kernel_Version, "kernel_version");

Mod_Use_Count: Integer; Pragma Export (C, Mod_Use_Count, "mod_use_count_");

-- Kernel Calls

procedure Printk( s : string ); pragma import( C, printk, "printk" );

-- Our Module Functions

function Init_Module return Interfaces.C.int; pragma Export (C, Init_Module, "init_module");

procedure Cleanup_Module; pragma Export (C, Cleanup_Module, "cleanup_module"); end SomeModule;

package body SomeModule is -- sample module layout

function Init_Module return Interfaces.C.int is begin Printk("Hello,World!" & Character'val(10) & character'val(0)); return 0; end Init_Module;

procedure Cleanup_Module is begin Printk("Goodbye , World!" & Character'val(10) & character'val(0)); end Cleanup_Module; end SomeModule;

Multiple object files must be combined into a single loadable module object file using the ld command. Never use -fPIC when working with the kernel. You may need the '-a' flag and '-s' flags so that Gnat will recompile the system package and related low-level Gnat files, or copy them by hand and compile them yourself (use the -gnatg switch).

Use insmod, lsmod and rmmod to install, test and uninstall your module.

$ insmod hello.o Hello, World!

For embedded systems, there is RTEMS, an embedded run time, and supports a more complete Ada runtime (with tasking) on some targets. See http://www.rtems.com/.

with Ada.Text_IO; use Ada.Text_IO;

procedure nrt2 is -- Simple Program begin put_line( "Hello World" ); end nrt2;

pragma no_run_time;

procedure nrt is -- Same as nrt2 but using no run time

type file_id is new integer;

-- No Ada.Text_IO possible, so we'll write our own -- that talks directly to the Linux kernel

procedure write_char( amount_written : out long_integer; id : file_id; buffer : in out character; amount2write : long_integer ); pragma import( C, write_char, "write" ); pragma import_valued_procedure( write_char, "write" );

procedure put( c : character ) is result : long_integer; buf : character := c; begin write_char( result, 1, buf, 1 ); end put;

procedure new_line is begin put( character'val( 10 ) ); end new_line;

procedure put_line( s : string ) is pragma suppress( index_check, s ); -- s(i) won't throw a range error, but Gnat checks for it -- by default. Exceptions are a part of the run time. begin for i in s'range loop put( s(i) ); end loop; new_line; end put_line;

begin put_line( "Hello World" ); end nrt;