N00b trying to write a kernel in C++

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.
Cjmovie

Re:N00b trying to write a kernel in C++

Post by Cjmovie »

I figure you know this, but just in case:
Remember the calling conventions of your C++ compiler when interfacing with the all-required Misc. ASM code.
amee2000

Re:N00b trying to write kernel module handler in C++

Post by amee2000 »

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!
AR

Re:N00b trying to write a kernel in C++

Post by AR »

The obvious problem here is that GRUB doesn't care what the modules are or what order they are in, it will therefore not take the base link address into account when it loads them into memory.

The start address can be found by reading the executable's headers, in flat binary executables the start address is at the start of the file. Make sure you are actually linking the modules, object files cannot be executed. You will most likely want to make the modules into executables (rather than libraries) and make them relocatable, you will then be able to relocate the module wherever you like, you will need an interface for the executable to give you its function table though.

You can produce libraries if you want but you will need to write a dynamic linker to link the modules against the kernel (although you would have probably needed this anyway) and get it to record the export addresses in the kernel's link table. IIRC, libraries do not have entry points but that isn't a problem as ELF libraries can have .init (initaliser) and .fini (finaliser/destructor) which can fulfill those roles. The libraries will still need to be relocatable as well, you are going to have to write some reasonably complex code to get all this stuff to work...
amee2000

Re:N00b trying to write a kernel in C++

Post by amee2000 »

Hi all!

Since my last post I discovered the need to have something like malloc and decided to do that first, delaying the interfacing problem again (and the dynamic linker).

Currently I'm using a bitmap to keep track of which pages are used and which are free. This works slow but sufficient for now. Now I need to find out how much memory is usable and how much of that is already occupied. I could piece that together from what I know about my modules and my kernel and probe the memory at every page but that seems to be a quite bad idea because GRUB provides me with a "memory map". So I did a loop to show me the contents of that memory map (type, the start and end addresses and the length(in brackets) of each entry):

Code: Select all

MEMORY MAP: 0x2bde8->0x2bef0
    type=0x01;   L:0x0->0x9f7ff(0x9f800)
    type=0x02;   L:0x9f800->0x9ffff(0x800)
    type=0x02;   L:0xdc000->0xdffff(0x4000)
    type=0x02;   L:0xe4000->0xfffff(0x1c000)
    type=0x01;   L:0x100000->0x1eeffff(0x1df0000)
    type=0x03;   L:0x1ef0000->0x1efefff(0xf000)
    type=0x04;   L:0x1eff000->0x1efffff(0x1000)
    type=0x01;   L:0x1f00000->0x1ffffff(0x100000)
    type=0x02;   L:0xfec00000->0xfec0ffff(0x10000)
    type=0x02;   L:0xfee00000->0xfee00fff(0x1000)
    type=0x02;   L:0xfffe0000->0xffffffff(0x20000)
Now I have three questions:
1) Because my test machine only has 32M (0x2000000), there is no physical memory at 0xFFFE0000. The multiboot specs only say:
type is the variety of address range represented, where a value of 1 indicates available RAM, and all other values currently indicated a reserved area.

The map provided is guaranteed to list all standard RAM that should be available for normal use.
Where can I find a list of type numbers and their describtion?
2) Can I safely omit the high part on an only-32-bit-system?
3) GRUB is supposed to load my kernel to 0x100000 but why is this location marked as free(0x1)?? It seems like GRUB doesn't mark the memory occupied by the kernel/modules and I need to complete the above list myself anyway?
User avatar
Solar
Member
Member
Posts: 7615
Joined: Thu Nov 16, 2006 12:01 pm
Location: Germany
Contact:

Re:N00b trying to write a kernel in C++

Post by Solar »

amee2000 wrote: 1) Because my test machine only has 32M (0x2000000), there is no physical memory at 0xFFFE0000.
Yes there is. ;)

Who ever said that all memory has to be RAM? There's BIOS, video mem, memory-mapped devices...

And the RAM you have doesn't have to be one continuous block starting at lowest possible address, either. ;)
The multiboot specs only say:
type is the variety of address range represented, where a value of 1 indicates available RAM, and all other values currently indicated a reserved area.
Where can I find a list of type numbers and their describtion?
You have it, above. 0x01 is available, all other is reserved (read: hands off unless you already know what you're doing).
3) GRUB is supposed to load my kernel to 0x100000 but why is this location marked as free(0x1)?? It seems like GRUB doesn't mark the memory occupied by the kernel/modules and I need to complete the above list myself anyway?
Your kernel is of course free to overwrite itself. (Imagine it's only a third-stage bootloader?) Thus the RAM isn't reserved.
Every good solution is obvious once you've found it.
amee2000

Re:N00b trying to write a kernel in C++

Post by amee2000 »

all other is reserved (read: hands off unless you already know what you're doing)
To know what I can do with it, I need to know what it is reserved for and the type in the GRUB memory map seems to give me at least a hint.
Thus the RAM isn't reserved.
GRUB doesn't consider it reserved but overwriting my kernel is quite not what I want. So I need to mark all memory from 0x100000 to (the last module's address + it's length) as 'used' to prevent it being allocated by my memory manager. Correct?
AR

Re:N00b trying to write a kernel in C++

Post by AR »

amee2000 wrote:
all other is reserved (read: hands off unless you already know what you're doing)
To know what I can do with it, I need to know what it is reserved for and the type in the GRUB memory map seems to give me at least a hint.
Reserved = Reserved. It means the memory is not RAM and cannot be used for storage (ie. there is no memory there and it's merely an empty gap or there is a memory mapped device there [where writing will change the devices registers which will probably screw up the system if you write random values like program code to it]). The ACPI stuff can be interpreted if your kernel supports ACPI and then those spaces can be overridden.
amee2000 wrote:
Thus the RAM isn't reserved.
GRUB doesn't consider it reserved but overwriting my kernel is quite not what I want. So I need to mark all memory from 0x100000 to (the last module's address + it's length) as 'used' to prevent it being allocated by my memory manager. Correct?
Yes, marking the kernel reserved is very easy since the link script can be used to store the kernel's position and length. Modules are more of a problem though.
User avatar
Solar
Member
Member
Posts: 7615
Joined: Thu Nov 16, 2006 12:01 pm
Location: Germany
Contact:

Re:N00b trying to write a kernel in C++

Post by Solar »

Modules aren't that much of a problem since GRUB gives the starting addresses of each, and your linker scripts can give you their sizes.

Full ACK on the "reserved" though. Either you're writing a driver for whatever is located there (in which case the hardware documentation of the corresponding device / feature will tell you what it is), or you don't touch it.
Every good solution is obvious once you've found it.
Post Reply