Design of a basic module loader

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
beyondsociety

Design of a basic module loader

Post by beyondsociety »

Im at the point where I want to start loading my system drivers as as modules and I am looking for some ideas on how to design a simple module loader. At this point Im not too concerned with different object formats, elf, coff, pe.

I have a few ideas but most of them require the use of a executable object format.

What steps do I need to take in order to write a basic module loader?

Thanks in advance.
User avatar
df
Member
Member
Posts: 1076
Joined: Fri Oct 22, 2004 11:00 pm
Contact:

Re:Design of a basic module loader

Post by df »

I dont know if it was the right way or not, but I always aproached this as doing a linker. I more or less post-linked/relocated objects in memory. my main exec format had imports/exports/relocs etc. so then there became no difference from loadong a binary or a module...

the hard bit was interfacing into the kernel and all that goes with that :)
-- Stu --
User avatar
Brendan
Member
Member
Posts: 8561
Joined: Sat Jan 15, 2005 12:00 am
Location: At his keyboard!
Contact:

Re:Design of a basic module loader

Post by Brendan »

Hi,
beyondsociety wrote: Im at the point where I want to start loading my system drivers as as modules and I am looking for some ideas on how to design a simple module loader. At this point Im not too concerned with different object formats, elf, coff, pe.

I have a few ideas but most of them require the use of a executable object format.

What steps do I need to take in order to write a basic module loader?
I do the opposite to "df". My modules are all loaded at fixed addresses, and I made up a simple binary file format for them (same as the DOS *.com format, except it's 32 bit and there's a simple header at the start).

To start a module the kernel uses normal file IO to load the first 128 bytes (enough for the header) and checks if it's a valid module (and that the OS has enough resources, the user has permission, etc to run it). Then the kernel creates a new process and spawns a thread within the new process. This spawned thread runs more kernel code that also uses file IO to load the binary file into the process's address space (or eventually, optionally memory maps the file - when I get time to write the code), and uses "retf" to jump to it's entry point. The new thread becomes the first thread for the process/module.


Cheers,

Brendan
For all things; perfection is, and will always remain, impossible to achieve in practice. However; by striving for perfection we create things that are as perfect as practically possible. Let the pursuit of perfection be our guide.
aladdin

Re:Design of a basic module loader

Post by aladdin »

I think module loader depends on your kernel architechture,
if you want to have a monolitic kernel you will use df methode
if you want a microkernel you have to do something like brendan methode

(correct me if i'm wrong)
User avatar
df
Member
Member
Posts: 1076
Joined: Fri Oct 22, 2004 11:00 pm
Contact:

Re:Design of a basic module loader

Post by df »

I didnt say anything about micro or monolithic.

whether each module gets its own task/process space or you load many inside a single address space or not doesnt alter what I said.
-- Stu --
User avatar
Pype.Clicker
Member
Member
Posts: 5964
Joined: Wed Oct 18, 2006 2:31 am
Location: In a galaxy, far, far away
Contact:

Re:Design of a basic module loader

Post by Pype.Clicker »

aladdin wrote: I think module loader depends on your kernel architechture,
if you want to have a monolitic kernel you will use df method
if you want a microkernel you have to do something like brendan method
hum. i don't think we should talk about "loading modules" for a microkernel system that loads a new service. Reason is the new service will only invoke the microkernel and will only do it through a collection of well-defined interrupts (or system traps or whatever).

Thus the "linkage" actually occurs in the "syscall.h" and in the system library or something where you will write the ASM stub and hardcode the parameters passing rules for the system calls.
User avatar
Pype.Clicker
Member
Member
Posts: 5964
Joined: Wed Oct 18, 2006 2:31 am
Location: In a galaxy, far, far away
Contact:

Re:Design of a basic module loader

Post by Pype.Clicker »

beyondsociety wrote: What steps do I need to take in order to write a basic module loader?
Knowing what you have to load: your module will have to include information about the size of the code to be loaded and the amount of space your module requires (e.g. don't forget the BSS section)

Knowing where you will load it: the easiest is to build your module so that it has a 'target address' that will be free at run-time. If you have enough virtual address, you can easily slice your kernel space so that each module has its own slice. However, this is not very eay-to-upgrade-later and thus i'd rather advocate for a relocation list, here. Check out the "Linkers and Loaders", it's not such a complex concept.

Knowing what you can use: your module is likely to need access to kernel (or other modules) functions. This is usually the symbol table. You can decide that there are N 'symbols' pointing towards structures/functions and pass the address of the table where those symbols are stored to your module's initialization function.

Code: Select all

  #define kprint kernelptrs[0]
  #define kalloc kernelptrs[1]
  ...
 
  function *kernelptrs=NULL;

  status init(function *imports) {
      kernelptrs=imports;
   }
That table could also be an associative array of name=>pointer that the module loader will use to patch the executable.

Telling what you can do: the last step is to be able to export features (such as open/close/read/write for a device). You can for instance return an "object" structure that will contain pointers to functions that will perform what is expected, etc.

Code: Select all


//-- module.h
struct itable {
   int id;
   void* vtable;
};

#define END_OF_INTERFACES 0

void* search_itable_for_id(int id);

//-- blockdev.h
struct block_device_interface {
    status (*open)(options);
    status (*close)();
    status (*read)(address, size, buffer);
    status (*write)(address, size, buffer);
};

#define BLOCK_DEVICE_INTERFACE 0xb10c

//-- module.c

status myOpen(...) {...}

...

struct block_device_interface myBlockDevice {
   open: myOpen,
   close: myClose,
   read: myRead,
   write: myWrite,
};

itable myInterfaces[]={
   { BLOCK_DEVICE_INTERFACE, &myBlockDevice },
   { END_OF_INTERFACES, NULL}
};

itable* init(functions* import) {
   ... do stuff ...
   return myInterfaces;
}
Post Reply