Elaborate RTEMS libbsd initialization

This commit is contained in:
Sebastian Huber 2012-04-16 12:23:55 +02:00
parent a3d2498e49
commit 8a4f070701

View File

@ -261,20 +261,135 @@ Generating into /home/joel/newbsd/git/libbsd-8.2
The script may also be used to generate a diff in either forward or reverse The script may also be used to generate a diff in either forward or reverse
direction. direction.
== Initialization of RTEMS Libbsd == Initialization of RTEMS libbsd
The initialization of the RTEMS Libbsd is based on the FreeBSD SYSINIT The initialization of the RTEMS libbsd is based on the FreeBSD SYSINIT(9)
infrastructure. This is simply because we are initializing a subset of infrastructure. The key to initializing a system is to ensure that the desired
FreeBSD. For details refer to http://www.freebsd.org/cgi/man.cgi?query=SYSINIT&sektion=9&apropos=0&manpath=FreeBSD+9-current device drivers are explicitly pulled into the linked application. This plus
linking against the libbsd library will pull in the necessary FreeBSD
infrastructure.
The key to initializing a system is to ensure that the desired device The FreeBSD kernel is not a library like the RTEMS kernel. It is a bunch of
drivers are explicitly pulled into the linked application. This plus object files linked together. If we have a library, then creating the
linking against the Libsd library will pull in the necessary FreeBSD executable is simple. We begin with a start symbol and recursively resolve all
infrastructure. The SYSINIT structures are automatically built at link references. With a bunch of object files linked together we need a different
time and the various initialization routines will thus be executed in' mechanism. Most object files don't know each other. Lets say we have a driver
the correct order. module. The rest of the system has no references to this driver module. The
driver module needs a way to tell the rest of the system: Hey, kernel I am
here, please use my services!
XXX This needs more details. This registration of independent components is performed by SYSINIT(9) and
specializations:
http://www.freebsd.org/cgi/man.cgi?query=SYSINIT
The SYSINIT(9) uses some global data structures that are placed in a certain
section. In the linker command file we need this:
[listing]
----
.robsdsets : {
_bsd__start_set_modmetadata_set = .;
*(_bsd_set_modmetadata_set);
_bsd__stop_set_modmetadata_set = .;
_bsd__start_set_sysctl_set = .;
*(_bsd_set_sysctl_set);
_bsd__stop_set_sysctl_set = .;
} > REGION_RODATA AT > REGION_RODATA_LOAD
.rwbsdsets : {
_bsd__start_set_sysinit_set = .;
*(_bsd_set_sysinit_set);
_bsd__stop_set_sysinit_set = .;
} > REGION_DATA AT > REGION_DATA_LOAD
----
Here you can see, that these global data structures are collected into
continuous memory areas. This memory area can be identified by start and stop
symbols. This constructs a table of uniform items.
The low level FreeBSD code calls at some time during the initialization the
mi_startup() function (machine independent startup). This function will sort
the SYSINIT(9) set and call handler functions which perform further
initialization. The last step is the scheduler invocation.
The SYSINIT(9) routines are run in mi_startup() which is called by
rtems_bsd_initialize().
This is also explained in "The Design and Implementation of the FreeBSD
Operating System" section 14.3 "Kernel Initialization".
In RTEMS we have a library and not a bunch of object files. Thus we need a way
to pull-in the desired services out of the libbsd. Here the
"rtems-bsd-sysinit.h" comes into play. The SYSINIT(9) macros have been
modified and extended for RTEMS in "sys/kernel.h":
[listing]
----
#ifndef __rtems__
#define C_SYSINIT(uniquifier, subsystem, order, func, ident) \
static struct sysinit uniquifier ## _sys_init = { \
subsystem, \
order, \
func, \
(ident) \
}; \
DATA_SET(sysinit_set,uniquifier ## _sys_init)
#else /* __rtems__ */
#define SYSINIT_ENTRY_NAME(uniquifier) \
_bsd_ ## uniquifier ## _sys_init
#define SYSINIT_REFERENCE_NAME(uniquifier) \
_bsd_ ## uniquifier ## _sys_init_ref
#define C_SYSINIT(uniquifier, subsystem, order, func, ident) \
struct sysinit SYSINIT_ENTRY_NAME(uniquifier) = { \
subsystem, \
order, \
func, \
(ident) \
}; \
DATA_SET(sysinit_set,SYSINIT_ENTRY_NAME(uniquifier))
#define SYSINIT_REFERENCE(uniquifier) \
extern struct sysinit SYSINIT_ENTRY_NAME(uniquifier); \
static struct sysinit const * const \
SYSINIT_REFERENCE_NAME(uniquifier) __used \
= &SYSINIT_ENTRY_NAME(uniquifier)
#define SYSINIT_MODULE_REFERENCE(mod) \
SYSINIT_REFERENCE(mod ## module)
#define SYSINIT_DRIVER_REFERENCE(driver, bus) \
SYSINIT_MODULE_REFERENCE(driver ## _ ## bus)
#endif /* __rtems__ */
----
Here you see that the SYSINIT(9) entries are no longer static. The
*_REFERENCE() macros will create references to the corresponding modules which
are later resolved by the linker. The application has to provide an object
file with references to all required FreeBSD modules.
The FreeBSD device model is quite elaborated (with follow-ups):
http://www.freebsd.org/cgi/man.cgi?query=driver
The devices form a tree with the Nexus device at a high-level. This Nexus
device is architecture specific in FreeBSD. In RTEMS we have our own Nexus
device, see "rtems-bsd-nexus.c". It uses a table to add child devices:
[listing]
----
const char *const _bsd_nexus_devices [] = {
#ifdef NEED_USB_OHCI
"ohci",
#endif
#ifdef NEED_USB_EHCI
"ehci",
#endif
#ifdef NEED_SDHC
"sdhci",
#endif
NULL
};
----
This table must be provided by the application.
=== SYSCTL_NODE Example === SYSCTL_NODE Example