Drivers
Functions
Section titled “Functions”gint_world_alloc
Section titled “gint_world_alloc”Allocate a new world buffer (single block), returns NULL on error
gint_world_t gint_world_alloc(void)gint_world_free
Section titled “gint_world_free”Free a world buffer
void gint_world_free(gint_world_t world)gint_world_switch_in
Section titled “gint_world_switch_in”Switch from the OS world to a gint-managed world
void gint_world_switch_in(gint_world_t world_os, gint_world_t world_addin)gint_world_switch_out
Section titled “gint_world_switch_out”Switch from a gint-managed world to the OS world
void gint_world_switch_out(gint_world_t world_addin, gint_world_t world_os)Macros
Section titled “Macros”GINT_DECLARE_DRIVER
Section titled “GINT_DECLARE_DRIVER”GINT_DECLARE_DRIVER(): Declare a driver to the kernel
Use this macro to declare a driver by passing it the name of a gint_driver_t structure. This macro moves the structure to the .gint.drivers.* sections, which are automatically traversed at startup.
The level argument represents the priority level: lower numbers mean that drivers will be loaded sooner. This numbering allows a primitive form of dependency for drivers. You need to specify a level which is strictly higher than the level of all the drivers you depend on.
The level number MUST HAVE EXACTLY 2 DIGITS, as it is used as a string in the section name and the linker then sorts by name. If your driver has a level lower than 10, you must add a leading 0.
#define GINT_DECLARE_DRIVER ((level, name)) \ GSECTION(".gint.drivers." #level) GVISIBLE extern gint_driver_t name;gint_driver_count
Section titled “gint_driver_count”Number of drivers in the (gint_drivers) array
#define gint_driver_count (()) \ ((gint_driver_t *)&gint_drivers_end - (gint_driver_t *)&gint_drivers)typedef struct{ /* Driver name */ char const *name; /* General constructor, is called before any interaction with the driver. This can be used to adjust settings based on detected hardware. */ void (*constructor)(void); // Foreign calls /* Foreign unbind: separate the hardware from the OS driver. If NULL, the OS driver is always considered idle. */ void (*funbind)(void); // "Hypervisor" calls /* Determine whether the device is powered. If NULL, the device is assumed to be permanently powered. */ bool (*hpowered)(void); /* Power on the device; this should allow register access to save the peripheral state, with minimal state changes. Cannot be NULL if hpowered() can return false. */ void (*hpoweron)(void); /* Power off the device; cannot be NULL if hpowered() can return false. */ void (*hpoweroff)(void); /* Save the hardware state; the (state) pointer points to a 4-aligned region of (state_size) bytes. */ void (*hsave)(void *state); /* Restore a hardware state previously saved by hsave(). */ void (*hrestore)(void const *state); // Standard calls /* Bind the driver to acquire control of the device. May be NULL. */ void (*bind)(void); /* Unbind the driver from the hardware. Usually sleeps until processes that block world switches terminate, like bind(). May be NULL. */ void (*unbind)(void); /* Initialize the hardware for the driver to work in gint. Usually installs interrupt handlers and configures registers. May be NULL. */ void (*configure)(void); /* Size of the peripheral's hardware state (assumed 4-aligned) */ uint16_t state_size; /* Initial flags */ uint8_t flags;}gint_driver_tgint_world_t: World state capture
The world state is a copy of the (almost) complete hardware state, which can be used to switch between several kernels running in parallel on the same machine. gint runs in a different world than the OS, allowing it to control peripheral modules in ways incompatible with the OS without compromising the stability of either program.
The world state is a sequence of 4-aligned buffers each holding a copy of a module’s state, as saved (and restored) by a driver. It is prefixed with an array of pointers, one for each driver, specifying the driver’s spot within the sequence.
The layout is as follows: An array of (void *), with one entry per driver, in priority order. Each pointer is to a buffer in the sequence. A sequence of buffers of size (state_size), rounded up to a multiple of 4 bytes, for each driver in priority order.
The world is returned as a (void *) array but allocated in one block.
typedef void **gint_world_tData structures
Section titled “Data structures”enum{ /* Driver is clean (needs to be configured before running) */ GINT_DRV_CLEAN = 0x01, /* Device was powered during the last foreign unbind */ GINT_DRV_FOREIGN_POWERED = 0x02, /* Driver does not require hardware state saves during world switches */ GINT_DRV_SHARED = 0x10, /* Flags that can be set in the (flags) attribute of the driver struct */ GINT_DRV_INIT_ = 0x10,}