josecm wrote:Hello, I would like your opinion on how to organize a kernel source tree taking in mind portability, especially in embedded environments. What directories do you define and with which sort of code for this intent? Also, a related question would be how do you tackle this from the build system point of view and what sort of configuration do you like to offer in this regard?
Thank you in advance
First off, you need to work out what features you consider to be 'core' to the design of your OS. Are you going to relying on there always being some kind of paging / MMU? Are you going to assume that the architecture is interrupt-driven? Unless you define strict boundaries for systems that your OS is permitted to run on, it's hard to organise your project. Making assumptions like "there will always be an MMU" or "the system will always be interrupt-driven" may sacrifice a small amount of portability for a huge gain in ease of development and a more coherent codebase structure.
Secondly, keep architecture-dependent stuff separate to architecture-independent stuff. Put the architecture-dependent code in an arch/myarch directory, where myarch is something like "x86" or "x86/amd64".
There are two ways of interfacing with the architecture-dependent code. The first is to provide implementations for low-level function definitions (things like enabling or disabling interrupts) within the arch/ directory. The second is to use #ifdef barriers to conditionally compile code within your main source tree. I always opt for the former wherever possible, opting only for the latter in very specific places. It keeps the structure of your code much nicer. Personally, I think too many #ifdef barriers are ugly and confusing.
Remember that a lot of hardware is architecture-independent. The driver for a PS/2 keyboard, for example, should be part of any architecture that defines access to a PS/2 controller. It is not specific to x86. For this reason, it's a good idea to keep peripheral drivers outside of the arch/ directory and to build them in a way that makes them dependent on your arch-independent low-level API (i.e: your PS/2 driver should NOT be making direct use of instructions such as 'outb', but should instead hook into a low-level interface that provides things like serial I/O).
The aim throughout all of this is to build a source structure whereby building for another platform is as simple as flipping a switch in your build system.
Good luck!