Page 1 of 1
Most important things for portability
Posted: Thu May 21, 2009 1:25 pm
by NickJohnson
I'm nearly done writing my kernel, but my current implementation is somewhat x86 bound. I know that I will probably want to port it to different processor architectures in the future (specifically ARM). My implementation is still quite small, only 800-900 SLOC, so I think I still have time to refactor the less portable pieces. What are the most important rules to follow in order to make OS level code that is easy to port to other architectures? And will size-mismatched casts break when using a big-endian machine (because I have quite a few of those
) ?
Re: Most important things for portability
Posted: Thu May 21, 2009 4:25 pm
by mathematician
The obvious thing would be to write a hardware abstraction layer - a kind of bios for protected mode. You would most likely need to write some C callable libraries, containing software interrupts which trap into the kernel, but once that is done you should be able to keep assembly language to a minimum, and to access the hard disk the Kernel would call something like abswrite(.....), instead of becoming involved with the intricasies of the IDE controller. When the time comes to port your OS, the HAL would need rewriting, but not much else.
So far as possible, keep the assembly language in separate files, so you know where to find it, instead of using inline assembly language.
Re: Most important things for portability
Posted: Thu May 21, 2009 4:37 pm
by NickJohnson
Well, I have a sort of microkernel design - I'm already expecting to rewrite driver programs. I'm talking about the stuff in the kernel itself, which for me means the memory manager, process manager, interrupts, and IPC code.
Edit: Maybe a more clear question would be: what are the main differences between the x86 architecture and other architectures that someone porting a kernel has to know about?
Re: Most important things for portability
Posted: Thu May 21, 2009 4:49 pm
by mathematician
Well by definition, if something directly programs the hardware, or if it sets up page tables which are directly dependent upon the Intel architecture, then it is hardware dependent. The only thing you can do is to confine the hardware dependent stuff to C callable functions, and keep it in seperate (source code) files from the rest of the kernel.
You are not going to avoid having to rewrite the hardware dependent stuff. But whereas the details of paging are hardware dependent, the concept isn't, so you should be able to write some functions which look generic to the caller.
Re: Most important things for portability
Posted: Thu May 21, 2009 5:25 pm
by NickJohnson
I see what you mean. At least in my design, the kernel is responsible for handling everything related to the processor, and nothing outside it. It has a simple interface, and there shouldn't be any additional features past the basic functionality. So I think I'll just fork the kernel source for different architecture ports, and use the old code as a framework. ~1000 SLOC doesn't sound bad, and then I can avoid unnecessary glue code.
Re: Most important things for portability
Posted: Thu May 21, 2009 6:01 pm
by Love4Boobies
NickJohnson wrote:Well, I have a sort of microkernel design - I'm already expecting to rewrite driver programs. I'm talking about the stuff in the kernel itself, which for me means the memory manager, process manager, interrupts, and IPC code.
That doesn't sound like a microkernel to me.
Re: Most important things for portability
Posted: Thu May 21, 2009 6:07 pm
by NickJohnson
That's why I said a *sort* of microkernel design. The point is that the I/O drivers are in userspace, which means I already sort of have a HAL. I think it doesn't make much sense to have memory and process management outside of the kernel - it makes things much more complex and slower; when have you ever needed to hot swap your scheduler?
Re: Most important things for portability
Posted: Fri May 22, 2009 12:37 am
by Tomaka17
NickJohnson wrote:Edit: Maybe a more clear question would be: what are the main differences between the x86 architecture and other architectures that someone porting a kernel has to know about?
- big/little endian
- the size of the memory bus
- memory management (paging) and preemptive multitasking may not be possible (but you could simply ignore these old platforms)
- 'short' may not be 16 bits long, 'int' not 32 bits long, etc. note that 'char' is always one byte long (that's written in ISO C) but a byte may not be 8 bits
- on the ARM there are four types of interrupts : software (syscalls), IRQs, fast interrupts for things like PIO transfers, and exceptions ; all of them are handled differently by the kernel
What is usually common to all platforms is: registers, memory, stack, interrupts
So you have to write a high-level interface between your platform-specific stuff and the rest of your O/S
Your platform-specific stuff should be rewritten for each different CPU
The rest of your O/S should use the types defined in stdint.h (or something similar) if necessary. For example it should not copy a 'void*' to an 'int' because the int may not be large enough on some platforms
Re: Most important things for portability
Posted: Fri May 22, 2009 2:22 am
by Brendan
Hi,
If you put all the architecture specific stuff into one binary, then you'd call that binary a HAL, and you'd port the OS by rewriting the HAL.
Alternatively, if you put a little bit more code into that binary, then you'd call it a micro-kernel, and you'd port the OS by rewriting the micro-kernel. The advantage here is that you avoid an entire abstraction layer (and any inefficiency that the abstraction layer causes). The disadvantage is that it's a little more work to port the OS (as a micro-kernel includes more than a HAL would); but I really don't think it's very much extra.
Here's a list of things I'd consider to be "architecture specific":
- All the boot code (unless you're using EFI perhaps)
- CPU detection, AP CPU startup and CPU initialization
- memory detection and most of the memory management (e.g. MTRRs, PAT, page tables)
- half the scheduler (the code that does the actual task switch, and the code that creates new tasks)
- some timers (e.g. PIT, local APIC) that the scheduler relies on
- primitives for re-entrancy locks and lockless/wait-free algorithms (special CPU instructions)
- debugging and performance/profiling facilities
- IPC is typically optimized by using "page table tricks" (for large messages) or CPU specific tricks (for small messages), so that's at least partly architecture specific
- IRQ handling and exception handling is architecture specific (PICs, I/O APICs, IDT, etc)
- I/O port protection
- the low-level mechanics of the kernel API (different registers, different ways of invoking the kernel API)
If you shifted all of this (plus anything I forgot) into a HAL, you'd probably only have a few hundred lines of code left in the micro-kernel anyway...
Cheers,
Brendan
Re: Most important things for portability
Posted: Fri May 22, 2009 9:20 am
by skyking
I would call it more a CPU abstraction layer than a hardware abstraction layer. You will of course need other device drivers because you have other hardware present, but that's not because it's a different CPU.
Much of the differences are hidden by clean use of C features (and use typedefs to get the intended integral types). Endianness is then not much of a problem since you normally shouldn't cast between pointers to different types, and of course other processors are much less forgiving if you violate alignment requrirements. Typecast from char* to int* and you may be doomed (unaligned read's on ARM does not mean quite the same thing as on intel, and on other CPU's you may get an unforgiving exception).
Preemptive multitasking requires only a interrupt that alow you to preempt a process. The CPU abstraction layer need to contain the code to manage interrupt service routines and the context switch. If you wan't to use MMU you also have to use some abstraction for managing the MMU tables (and you should probably avoid using intels segmented memory model).
Basically the things that differ between CPUs is, given you make clean use of C, the code that's need to be written in assembler.