by now to make things easier I compiled the modules seperately but linked them all together into one kernel image.
While working on the interfaces between them, I came by accident across the GRUB manual again. This time I fully recogized its module support and thought it is a good thing and would buy me some time to think about the interfacing problem. Well, after some time I threw all I had away (the concepts, not the code
in favour of the following: I use GRUB (or any other multiboot compilant boot loader would do it as well) not only as a bootloader but as an actual part of my system to load the few kernel modules I have at boot time.
Grub first loads the kernel and then the modules at subsequent page aligned locations above the kernel, passing me an array with (among other things) all the start addresses of the modules.
A module may need to initialize itself before it can be used (register signal handers, interrupts, ...) so I need to call something like a constructor at startup. Because at this stage my module is just a big bunch of code to the kernel, the easiest to find location where to place the initialization code is at the beginning of the module (the start address).
To get the module address called like a function I tried the following:
- try to convert the data pointer into a function pointer and call it -> forbidden by ISO C (see below)
- define a pointer to a function pointer and let the first one point to where my data pointer(I don't like that word) is (which btw is unsigned long) -> either my brain is too small to get it done or it is impossible
- using
Code: Select all
asm("call %%eax" : : "a"(modi->mod_start) );
takes me where i want to be but it trashes the stack and makes returning impossible, even when I override the functions entry and exit code with some black magic ( asm("/*"); ... asm("*/"); I compiled with -s to check that only the right parts are commented out)
- encapsulating the module like the kernel image with ASM (I tried several different ways) -> the same, trashed stack, no way back
- someone at
http://public.activestate.com/gsar/APC/ ... ent/perl.h suggests:
Code: Select all
#if (IVSIZE == PTRSIZE) && (UVSIZE == PTRSIZE)
# define PTRV UV
# define INT2PTR(any,d) (any)(d)
#else
# if PTRSIZE == LONGSIZE
# define PTRV unsigned long
# define PTR2ul(p) (unsigned long)(p)
# else
# define PTRV unsigned
# endif
#endif
...
#define PTR2nat(p) (PTRV)(p) /* pointer to integer of PTRSIZE */
...
/* According to strict ANSI C89 one cannot freely cast between
* data pointers and function (code) pointers. There are at least
* two ways around this. One (used below) is to do two casts,
* first the other pointer to an (unsigned) integer, and then
* the integer to the other pointer. The other way would be
* to use unions to "overlay" the pointers. For an example of
* the latter technique, see union dirpu in struct xpvio in sv.h.
* The only feasible use is probably temporarily storing
* function pointers in a data pointer (such as a void pointer). */
#define DPTR2FPTR(t,p) ((t)PTR2nat(p)) /* data pointer to function pointer */
#define FPTR2DPTR(t,p) ((t)PTR2nat(p)) /* function pointer to data pointer */
-> doesn't compile
Additionally I just noted that GRUB doesn't enter the kernel at 0x100000 but at 0x10000c. That can be an(-other?) explanation why all of the above that compiles doesn't really work. how can I find out where I need to enter the module code?
Can anyone provide a pointer?
Thanks to you all for taking the time to answer my questions!