libbsd.txt: Move initialization details

This commit is contained in:
Sebastian Huber 2022-05-23 15:59:58 +02:00
parent 3d36dc0239
commit 96c01bff09
2 changed files with 139 additions and 147 deletions

View File

@ -453,3 +453,142 @@ the priority inheritance protocol.
* `SYSINIT(9) <http://www.freebsd.org/cgi/man.cgi?query=sysinit&sektion=9>`_: A framework for dynamic kernel initialization
* `TASKQUEUE(9) <http://www.freebsd.org/cgi/man.cgi?query=taskqueue&sektion=9>`_: Asynchronous task execution
* `UMA(9) <http://www.freebsd.org/cgi/man.cgi?query=uma&sektion=9>`_: General-purpose kernel object allocator
LibBSD Initialization Details
=============================
The initialization of LibBSD is based on the FreeBSD
`SYSINIT(9) <http://www.freebsd.org/cgi/man.cgi?query=sysinit&sektion=9>`_
infrastructure. The key to initializing a system is to ensure that the desired
device drivers are explicitly pulled into the linked application. This plus
linking against the LibBSD (``libbsd.a``) will pull in the necessary FreeBSD
infrastructure.
The FreeBSD kernel is not a library like the RTEMS kernel. It is a bunch of
object files linked together. If we have a library, then creating the
executable is simple. We begin with a start symbol and recursively resolve all
references. With a bunch of object files linked together we need a different
mechanism. Most object files don't know each other. Lets say we have a driver
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!
This registration of independent components is performed by SYSINIT(9) and
specializations
The SYSINIT(9) uses some global data structures that are placed in a certain
section. In the linker command file we need this:
.. code-block:: none
.rtemsroset : {
KEEP (*(SORT(.rtemsroset.*)))
}
.rtemsrwset : {
KEEP (*(SORT(.rtemsrwset.*)))
}
This results for example in this executable layout:
.. code-block:: none
[...]
*(SORT(.rtemsroset.*))
.rtemsroset.bsd.modmetadata_set.begin
0x000000000025fe00 0x0 libbsd.a(rtems-bsd-init.o)
0x000000000025fe00 _bsd__start_set_modmetadata_set
.rtemsroset.bsd.modmetadata_set.content
0x000000000025fe00 0x8 libbsd.a(rtems-bsd-nexus.o)
.rtemsroset.bsd.modmetadata_set.content
0x000000000025fe08 0x4 libbsd.a(kern_module.o)
[...]
.rtemsroset.bsd.modmetadata_set.content
0x000000000025fe68 0x4 libbsd.a(mii.o)
.rtemsroset.bsd.modmetadata_set.content
0x000000000025fe6c 0x4 libbsd.a(mii_bitbang.o)
.rtemsroset.bsd.modmetadata_set.end
0x000000000025fe70 0x0 libbsd.a(rtems-bsd-init.o)
0x000000000025fe70 _bsd__stop_set_modmetadata_set
[...]
.rtemsrwset 0x000000000030bad0 0x290
*(SORT(.rtemsrwset.*))
.rtemsrwset.bsd.sysinit_set.begin
0x000000000030bad0 0x0 libbsd.a(rtems-bsd-init.o)
0x000000000030bad0 _bsd__start_set_sysinit_set
.rtemsrwset.bsd.sysinit_set.content
0x000000000030bad0 0x4 libbsd.a(rtems-bsd-nexus.o)
.rtemsrwset.bsd.sysinit_set.content
0x000000000030bad4 0x8 libbsd.a(rtems-bsd-thread.o)
.rtemsrwset.bsd.sysinit_set.content
0x000000000030badc 0x4 libbsd.a(init_main.o)
[...]
.rtemsrwset.bsd.sysinit_set.content
0x000000000030bd54 0x4 libbsd.a(frag6.o)
.rtemsrwset.bsd.sysinit_set.content
0x000000000030bd58 0x8 libbsd.a(uipc_accf.o)
.rtemsrwset.bsd.sysinit_set.end
0x000000000030bd60 0x0 libbsd.a(rtems-bsd-init.o)
0x000000000030bd60 _bsd__stop_set_sysinit_set
[...]
Here you can see, that some 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>``:
.. code-block:: none
#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) \
}; \
RWDATA_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)
#define SYSINIT_DOMAIN_REFERENCE(dom) \
SYSINIT_REFERENCE(domain_add_ ## dom)
#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.

View File

@ -104,153 +104,6 @@ be addressed.
- The ISA drivers require more BSD infrastructure to be addressed. This was
outside the scope of the initial porting effort.
== FreeBSD Source
You should be able to rely on FreebSD manual pages and documentation
for details on the code itself.
== BSD Library Source
== Initialization of the BSD Library
The initialization of the BSD library is based on the FreeBSD SYSINIT(9)
infrastructure. The key to initializing a system is to ensure that the desired
device drivers are explicitly pulled into the linked application. This plus
linking against the BSD library (`libbsd.a`) will pull in the necessary FreeBSD
infrastructure.
The FreeBSD kernel is not a library like the RTEMS kernel. It is a bunch of
object files linked together. If we have a library, then creating the
executable is simple. We begin with a start symbol and recursively resolve all
references. With a bunch of object files linked together we need a different
mechanism. Most object files don't know each other. Lets say we have a driver
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!
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:
-------------------------------------------------------------------------------
.rtemsroset : {
KEEP (*(SORT(.rtemsroset.*)))
}
.rtemsrwset : {
KEEP (*(SORT(.rtemsrwset.*)))
}
-------------------------------------------------------------------------------
This results for example in this executable layout:
-------------------------------------------------------------------------------
[...]
*(SORT(.rtemsroset.*))
.rtemsroset.bsd.modmetadata_set.begin
0x000000000025fe00 0x0 libbsd.a(rtems-bsd-init.o)
0x000000000025fe00 _bsd__start_set_modmetadata_set
.rtemsroset.bsd.modmetadata_set.content
0x000000000025fe00 0x8 libbsd.a(rtems-bsd-nexus.o)
.rtemsroset.bsd.modmetadata_set.content
0x000000000025fe08 0x4 libbsd.a(kern_module.o)
[...]
.rtemsroset.bsd.modmetadata_set.content
0x000000000025fe68 0x4 libbsd.a(mii.o)
.rtemsroset.bsd.modmetadata_set.content
0x000000000025fe6c 0x4 libbsd.a(mii_bitbang.o)
.rtemsroset.bsd.modmetadata_set.end
0x000000000025fe70 0x0 libbsd.a(rtems-bsd-init.o)
0x000000000025fe70 _bsd__stop_set_modmetadata_set
[...]
.rtemsrwset 0x000000000030bad0 0x290
*(SORT(.rtemsrwset.*))
.rtemsrwset.bsd.sysinit_set.begin
0x000000000030bad0 0x0 libbsd.a(rtems-bsd-init.o)
0x000000000030bad0 _bsd__start_set_sysinit_set
.rtemsrwset.bsd.sysinit_set.content
0x000000000030bad0 0x4 libbsd.a(rtems-bsd-nexus.o)
.rtemsrwset.bsd.sysinit_set.content
0x000000000030bad4 0x8 libbsd.a(rtems-bsd-thread.o)
.rtemsrwset.bsd.sysinit_set.content
0x000000000030badc 0x4 libbsd.a(init_main.o)
[...]
.rtemsrwset.bsd.sysinit_set.content
0x000000000030bd54 0x4 libbsd.a(frag6.o)
.rtemsrwset.bsd.sysinit_set.content
0x000000000030bd58 0x8 libbsd.a(uipc_accf.o)
.rtemsrwset.bsd.sysinit_set.end
0x000000000030bd60 0x0 libbsd.a(rtems-bsd-init.o)
0x000000000030bd60 _bsd__stop_set_sysinit_set
[...]
-------------------------------------------------------------------------------
Here you can see, that some 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>`:
-------------------------------------------------------------------------------
#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) \
}; \
RWDATA_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)
#define SYSINIT_DOMAIN_REFERENCE(dom) \
SYSINIT_REFERENCE(domain_add_ ## dom)
#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