Kernel Module development

From Nekochan
Jump to: navigation, search

Commands

ml list
ml ld
ml reg
ml unld
ml unreg
ml debug

MACROs

  • _KERNEL Compile for a kernel module, not a user program.
  • MP Compile for a multiprocessor.
  • _MP_NETLOCKS Compile network driver (only) for multiprocessor TCP/IP
  • STATIC=static Use of pseudo-declarator STATIC is converted to real static.
  • _PAGESZ=16384 Compile for a kernel using 16K memory pages.
  • _PAGESZ=4096 Compile for a kernel using 4K memory pages.
  • _MIPS3_ADDRSPACE Kernel for a MIPS3 machine.
  • R10000 Target machine is the R10000.
  • TFP R4000 Target machine is the R4000.
  • IPnn Target machine uses the IPnn CPU module, one of IP19, IP20, IP21, IP22, IP25, IP26, IP27, IP28, IP30, and IP35 are currently supported.
  • EVEREST Compile for a Challenge or Onyx system.
  • BADVA_WAR, JUMP_WAR, PROBE_WAR Compile workaround code for bugs in certain R4x00 revisions.
  • _IP26_SYNC_WAR, Compile workaround code for IP26 bugs.
  • _NO_UNCCHED_MEM_WAR Compile workaround code for IP26 bugs.
  • R10000_SPECULATION_WAR Compile workaround code for bug in certain R10000 revisions.
  • USE_PCI_PIO Compile workaround for IP32 PIO bug (see sys/PCI/pciio.h).

Compiler Options

  • -non_shared
  • -elf
  • -64
  • -mips4 , -mips2
  • -G 8
  • -G 0
  • -r
  • -d
  • -Wc,-pic0
  • -jalr
  • -TARG:t5_no_spec_stores
  • -TENV:kernel -TENV:misalignment=1
  • -OPT:space
  • -OPT:quad_align_branch_targets=FALSE
  • -OPT:quad_align_with_memops=FALSE
  • -OPT:unroll_times=0


Configuring a Loadable Driver

  • You provide an additional global variable with the public name pfxmversion.
  • You use a few different compile options.
  • You decide when the driver should be loaded, and use appropriate flags in the descriptive line in the master file.

For more background on loadable modules, see the mload(4) and ml(1) reference pages.


Public Global Variables

To be loadable, a driver must specify a pfxdevflag entry point containing the D_MP or D_MT flag. Any loadable module must define a public name pfxmversion, declared as follows:

  #include <sys/mload.h>
  char *pfxmversion = M_VERSION;

Note the exact spelling of the variable; it is easy to overlook the letter “m” after the prefix. If the variable does not exist or is incorrectly spelled, an attempt to load the driver will fail.


Compile Options for Loadable Drivers

Use the -G 0 option when compiling and linking a loadable driver, since the global option table is not available to a loadable driver. You must also use the -jalr option in a loadable driver. In a loadable driver, link using the -r and -d options to retain the symbol table yet generate a bss segment.


Master File for Loadable Drivers

The file in /var/sysgen/master.d for a loadable driver has different flags. In the flags field of the descriptive line of the master file, you specify that the driver is loadable, and when it should be loaded. The possible flags are listed below.

Flag Values for Loadable Drivers Letter Meaning b or c Block (b) or character (c) device. One or the other is essential for any device driver. f or m STREAMS driver (f) or STREAMS module (m). Omit for device driver. s Software driver, either a pseudo-device or a SCSI driver. d Specifies that this is a loadable driver. R Auto-register the module (discussed in text). D Load, then unload, at boot time, in order to let the driver initialize the hardware inventory. N Prevent this module from being automatically unloaded even when it has a pfxunload() entry point.


When the d flag is given for an included module, lboot parses the master file for the driver. Global variables defined in the variables section of the master file are defined and included in the kernel. However, object code of the driver is not included in the kernel, and the names of its entry points are not entered into the kernel switch table. Such a driver has to be manually loaded with the ml or lboot command before it can be used; and it cannot be used from the miniroot.

Loading

A loadable driver can be loaded by the lboot command at boot time, and by the ml command while the system is running. The following steps occur when a driver is loaded:

1.      The object file header is read.
2.      Memory is allocated for the driver’s text, data, and bss segments.
3.      The driver’s text and data are read.
4.      The text and data are relocated. References to kernel names and to global variables named in the master file are resolved.
5.      Entry points are noted in the appropriate kernel switch table.
6.      The pfxinit() entry point is called if one is defined.
7.      If the driver is named in a VECTOR statement and has a pfxedtinit() entry point, 
        then that entry point is called for each VECTOR statement that names the driver.
8.      The pfxstart() entry point, if any, is called.
9.      The pfxreg() entry point, if any, is called.

Space allocated for the module’s text, data, and bss is located in node 0 of an Origin2000 system. Static buffers in loadable modules are not necessarily physically contiguous in memory. A variety of errors can occur when a module is loaded. See the mload(4) reference page for a list of possible causes.


Effect of ‘D’ Flag

Normally a loadable driver is not loaded at boot time. It must be loaded sometime after boot using the ml command. When the D flag is included in the descriptive line in the descriptive file, lboot loads the driver at boot time, and immediately after calling pfxstart(), unloads the driver. This permits the driver to test the hardware and set up the hwgraph and hardware inventory.


Registration

A loadable module is “registered” by loading it, then placing a stub entry in the pfxopen() and pfxattach() column of its row of the switch table, and unloading it again. The stub entry points are invoked when the driver is needed, and the code of the entry points initiates a load of the driver. Registration of this kind can be done automatically during bootstrap, or later using the ml command. Once it has been registered, a driver is loaded automatically the first time the kernel needs to attach a device supported by this driver, or the first time a process attempts to open a device special file managed by this driver. You can also load a registered driver in advance of any use with the ml command—loading implies registration. Note: Try not to confuse this “registration” with a driver’s registration with the kernel to handle a particular type of device. Registration is done automatically for each master descriptive file that contains the d (loadable) and R (register) flags. Autoregistration is done at bootstrap phase 2. It is initiated by the script /etc/rc2/S23autoconfig. Registration can be initiated manually at any time after bootstrap by using the ml or lboot command with the reg option (see the ml(1M) and lboot(1M) reference pages).

Reloading

When a registered driver is reloaded, the sequence of events listed under “Loading” occurs again. There is one exception: the pfxreg() entry point is not called when a registered driver is reloaded from a stub. (The complete sequence occurs when an unregistered driver is explicitly loaded by the ml command.)


Unloading

A module can be unloaded only when it provides an pfxunload() entry point (see “Entry Point unload()”. The N flag can be specified in the master file to prevent automatic unloading in any case. A loaded module is automatically unloaded following a delay after the last close of a device it supports. The delay is configurable using systune, as the module_unld_delay variable (see the systune(1) reference page). You can use ml to specify an unloading delay for a particular module. The lboot or ml command can be used to unload a module before the delay expires, or to manually override the N flag. The unload sequence is as follows:

The kernel verifies that all opens of the driver’s devices have been closed. The driver cannot be unloaded if it has open devices or active mmaps. The pfxunreg() entry point is called, if one exists. This gives the driver a chance to unregister as a provider of service for a particular device type. If pfxunreg() returns nonzero, the process stops. The pfxunload() entry point is called. If it returns nonzero, the process stops. The module is removed from memory. If it had been registered (R flag), stubs are again placed in the pfxopen() and pfxattach() column of its row of the switch table. Experience has shown that most of the problems with loadable drivers arise from unloading and reloading. The precautions to take are described under “Entry Point unload()”.

deploy (IRIX 6.5)

# cp my_mod.o /var/sysgen/boot
# autogen

(reboot, not the TV series)

# ml reg -m my_mod.o -p ''module name''
# ml ld -m my_mod.o -p ''module name''

Example load and unload (including syslog messags)