l4re-base-25.08.0

This commit is contained in:
2025-09-12 15:55:45 +02:00
commit d959eaab98
37938 changed files with 9382688 additions and 0 deletions

1
src/l4/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
/conf/Makeconf.boot

13
src/l4/BENCHMARKING Normal file
View File

@@ -0,0 +1,13 @@
IMPORTANT NOTE ON BENCHMARKING Fiasco.OC/L4RE SOFTWARE
======================================================
Owing to the flexibility of configurations possible with this software we
urge you to send any benchmarking results for review prior to publication to
benchmarking@os.inf.tu-dresden.de
to get feedback and an 'OK' from our side that the presented figures are
plausible.
Thanks.

349
src/l4/COPYING-GPL-2 Normal file
View File

@@ -0,0 +1,349 @@
NOTE! This License shall not affect user programs that use the micro-kernel
API to invoke kernel-operations or services provided in other address
spaces - this is merely considered normal use of the kernel or
accompanying user-level services, and does not fall under the heading of
"derivative work".
-----------------------------------------------------------------------
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License.

510
src/l4/COPYING-LGPL-2.1 Normal file
View File

@@ -0,0 +1,510 @@
GNU LESSER GENERAL PUBLIC LICENSE
Version 2.1, February 1999
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
[This is the first released version of the Lesser GPL. It also counts
as the successor of the GNU Library Public License, version 2, hence
the version number 2.1.]
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
Licenses are intended to guarantee your freedom to share and change
free software--to make sure the software is free for all its users.
This license, the Lesser General Public License, applies to some
specially designated software packages--typically libraries--of the
Free Software Foundation and other authors who decide to use it. You
can use it too, but we suggest you first think carefully about whether
this license or the ordinary General Public License is the better
strategy to use in any particular case, based on the explanations
below.
When we speak of free software, we are referring to freedom of use,
not price. Our General Public Licenses are designed to make sure that
you have the freedom to distribute copies of free software (and charge
for this service if you wish); that you receive source code or can get
it if you want it; that you can change the software and use pieces of
it in new free programs; and that you are informed that you can do
these things.
To protect your rights, we need to make restrictions that forbid
distributors to deny you these rights or to ask you to surrender these
rights. These restrictions translate to certain responsibilities for
you if you distribute copies of the library or if you modify it.
For example, if you distribute copies of the library, whether gratis
or for a fee, you must give the recipients all the rights that we gave
you. You must make sure that they, too, receive or can get the source
code. If you link other code with the library, you must provide
complete object files to the recipients, so that they can relink them
with the library after making changes to the library and recompiling
it. And you must show them these terms so they know their rights.
We protect your rights with a two-step method: (1) we copyright the
library, and (2) we offer you this license, which gives you legal
permission to copy, distribute and/or modify the library.
To protect each distributor, we want to make it very clear that
there is no warranty for the free library. Also, if the library is
modified by someone else and passed on, the recipients should know
that what they have is not the original version, so that the original
author's reputation will not be affected by problems that might be
introduced by others.
Finally, software patents pose a constant threat to the existence of
any free program. We wish to make sure that a company cannot
effectively restrict the users of a free program by obtaining a
restrictive license from a patent holder. Therefore, we insist that
any patent license obtained for a version of the library must be
consistent with the full freedom of use specified in this license.
Most GNU software, including some libraries, is covered by the
ordinary GNU General Public License. This license, the GNU Lesser
General Public License, applies to certain designated libraries, and
is quite different from the ordinary General Public License. We use
this license for certain libraries in order to permit linking those
libraries into non-free programs.
When a program is linked with a library, whether statically or using
a shared library, the combination of the two is legally speaking a
combined work, a derivative of the original library. The ordinary
General Public License therefore permits such linking only if the
entire combination fits its criteria of freedom. The Lesser General
Public License permits more lax criteria for linking other code with
the library.
We call this license the "Lesser" General Public License because it
does Less to protect the user's freedom than the ordinary General
Public License. It also provides other free software developers Less
of an advantage over competing non-free programs. These disadvantages
are the reason we use the ordinary General Public License for many
libraries. However, the Lesser license provides advantages in certain
special circumstances.
For example, on rare occasions, there may be a special need to
encourage the widest possible use of a certain library, so that it
becomes a de-facto standard. To achieve this, non-free programs must
be allowed to use the library. A more frequent case is that a free
library does the same job as widely used non-free libraries. In this
case, there is little to gain by limiting the free library to free
software only, so we use the Lesser General Public License.
In other cases, permission to use a particular library in non-free
programs enables a greater number of people to use a large body of
free software. For example, permission to use the GNU C Library in
non-free programs enables many more people to use the whole GNU
operating system, as well as its variant, the GNU/Linux operating
system.
Although the Lesser General Public License is Less protective of the
users' freedom, it does ensure that the user of a program that is
linked with the Library has the freedom and the wherewithal to run
that program using a modified version of the Library.
The precise terms and conditions for copying, distribution and
modification follow. Pay close attention to the difference between a
"work based on the library" and a "work that uses the library". The
former contains code derived from the library, whereas the latter must
be combined with the library in order to run.
GNU LESSER GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License Agreement applies to any software library or other
program which contains a notice placed by the copyright holder or
other authorized party saying it may be distributed under the terms of
this Lesser General Public License (also called "this License").
Each licensee is addressed as "you".
A "library" means a collection of software functions and/or data
prepared so as to be conveniently linked with application programs
(which use some of those functions and data) to form executables.
The "Library", below, refers to any such software library or work
which has been distributed under these terms. A "work based on the
Library" means either the Library or any derivative work under
copyright law: that is to say, a work containing the Library or a
portion of it, either verbatim or with modifications and/or translated
straightforwardly into another language. (Hereinafter, translation is
included without limitation in the term "modification".)
"Source code" for a work means the preferred form of the work for
making modifications to it. For a library, complete source code means
all the source code for all modules it contains, plus any associated
interface definition files, plus the scripts used to control
compilation and installation of the library.
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running a program using the Library is not restricted, and output from
such a program is covered only if its contents constitute a work based
on the Library (independent of the use of the Library in a tool for
writing it). Whether that is true depends on what the Library does
and what the program that uses the Library does.
1. You may copy and distribute verbatim copies of the Library's
complete source code as you receive it, in any medium, provided that
you conspicuously and appropriately publish on each copy an
appropriate copyright notice and disclaimer of warranty; keep intact
all the notices that refer to this License and to the absence of any
warranty; and distribute a copy of this License along with the
Library.
You may charge a fee for the physical act of transferring a copy,
and you may at your option offer warranty protection in exchange for a
fee.
2. You may modify your copy or copies of the Library or any portion
of it, thus forming a work based on the Library, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) The modified work must itself be a software library.
b) You must cause the files modified to carry prominent notices
stating that you changed the files and the date of any change.
c) You must cause the whole of the work to be licensed at no
charge to all third parties under the terms of this License.
d) If a facility in the modified Library refers to a function or a
table of data to be supplied by an application program that uses
the facility, other than as an argument passed when the facility
is invoked, then you must make a good faith effort to ensure that,
in the event an application does not supply such function or
table, the facility still operates, and performs whatever part of
its purpose remains meaningful.
(For example, a function in a library to compute square roots has
a purpose that is entirely well-defined independent of the
application. Therefore, Subsection 2d requires that any
application-supplied function or table used by this function must
be optional: if the application does not supply it, the square
root function must still compute square roots.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Library,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Library, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote
it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Library.
In addition, mere aggregation of another work not based on the Library
with the Library (or with a work based on the Library) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may opt to apply the terms of the ordinary GNU General Public
License instead of this License to a given copy of the Library. To do
this, you must alter all the notices that refer to this License, so
that they refer to the ordinary GNU General Public License, version 2,
instead of to this License. (If a newer version than version 2 of the
ordinary GNU General Public License has appeared, then you can specify
that version instead if you wish.) Do not make any other change in
these notices.
Once this change is made in a given copy, it is irreversible for
that copy, so the ordinary GNU General Public License applies to all
subsequent copies and derivative works made from that copy.
This option is useful when you wish to copy part of the code of
the Library into a program that is not a library.
4. You may copy and distribute the Library (or a portion or
derivative of it, under Section 2) in object code or executable form
under the terms of Sections 1 and 2 above provided that you accompany
it with the complete corresponding machine-readable source code, which
must be distributed under the terms of Sections 1 and 2 above on a
medium customarily used for software interchange.
If distribution of object code is made by offering access to copy
from a designated place, then offering equivalent access to copy the
source code from the same place satisfies the requirement to
distribute the source code, even though third parties are not
compelled to copy the source along with the object code.
5. A program that contains no derivative of any portion of the
Library, but is designed to work with the Library by being compiled or
linked with it, is called a "work that uses the Library". Such a
work, in isolation, is not a derivative work of the Library, and
therefore falls outside the scope of this License.
However, linking a "work that uses the Library" with the Library
creates an executable that is a derivative of the Library (because it
contains portions of the Library), rather than a "work that uses the
library". The executable is therefore covered by this License.
Section 6 states terms for distribution of such executables.
When a "work that uses the Library" uses material from a header file
that is part of the Library, the object code for the work may be a
derivative work of the Library even though the source code is not.
Whether this is true is especially significant if the work can be
linked without the Library, or if the work is itself a library. The
threshold for this to be true is not precisely defined by law.
If such an object file uses only numerical parameters, data
structure layouts and accessors, and small macros and small inline
functions (ten lines or less in length), then the use of the object
file is unrestricted, regardless of whether it is legally a derivative
work. (Executables containing this object code plus portions of the
Library will still fall under Section 6.)
Otherwise, if the work is a derivative of the Library, you may
distribute the object code for the work under the terms of Section 6.
Any executables containing that work also fall under Section 6,
whether or not they are linked directly with the Library itself.
6. As an exception to the Sections above, you may also combine or
link a "work that uses the Library" with the Library to produce a
work containing portions of the Library, and distribute that work
under terms of your choice, provided that the terms permit
modification of the work for the customer's own use and reverse
engineering for debugging such modifications.
You must give prominent notice with each copy of the work that the
Library is used in it and that the Library and its use are covered by
this License. You must supply a copy of this License. If the work
during execution displays copyright notices, you must include the
copyright notice for the Library among them, as well as a reference
directing the user to the copy of this License. Also, you must do one
of these things:
a) Accompany the work with the complete corresponding
machine-readable source code for the Library including whatever
changes were used in the work (which must be distributed under
Sections 1 and 2 above); and, if the work is an executable linked
with the Library, with the complete machine-readable "work that
uses the Library", as object code and/or source code, so that the
user can modify the Library and then relink to produce a modified
executable containing the modified Library. (It is understood
that the user who changes the contents of definitions files in the
Library will not necessarily be able to recompile the application
to use the modified definitions.)
b) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (1) uses at run time a
copy of the library already present on the user's computer system,
rather than copying library functions into the executable, and (2)
will operate properly with a modified version of the library, if
the user installs one, as long as the modified version is
interface-compatible with the version that the work was made with.
c) Accompany the work with a written offer, valid for at least
three years, to give the same user the materials specified in
Subsection 6a, above, for a charge no more than the cost of
performing this distribution.
d) If distribution of the work is made by offering access to copy
from a designated place, offer equivalent access to copy the above
specified materials from the same place.
e) Verify that the user has already received a copy of these
materials or that you have already sent this user a copy.
For an executable, the required form of the "work that uses the
Library" must include any data and utility programs needed for
reproducing the executable from it. However, as a special exception,
the materials to be distributed need not include anything that is
normally distributed (in either source or binary form) with the major
components (compiler, kernel, and so on) of the operating system on
which the executable runs, unless that component itself accompanies
the executable.
It may happen that this requirement contradicts the license
restrictions of other proprietary libraries that do not normally
accompany the operating system. Such a contradiction means you cannot
use both them and the Library together in an executable that you
distribute.
7. You may place library facilities that are a work based on the
Library side-by-side in a single library together with other library
facilities not covered by this License, and distribute such a combined
library, provided that the separate distribution of the work based on
the Library and of the other library facilities is otherwise
permitted, and provided that you do these two things:
a) Accompany the combined library with a copy of the same work
based on the Library, uncombined with any other library
facilities. This must be distributed under the terms of the
Sections above.
b) Give prominent notice with the combined library of the fact
that part of it is a work based on the Library, and explaining
where to find the accompanying uncombined form of the same work.
8. You may not copy, modify, sublicense, link with, or distribute
the Library except as expressly provided under this License. Any
attempt otherwise to copy, modify, sublicense, link with, or
distribute the Library is void, and will automatically terminate your
rights under this License. However, parties who have received copies,
or rights, from you under this License will not have their licenses
terminated so long as such parties remain in full compliance.
9. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Library or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Library (or any work based on the
Library), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Library or works based on it.
10. Each time you redistribute the Library (or any work based on the
Library), the recipient automatically receives a license from the
original licensor to copy, distribute, link with or modify the Library
subject to these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties with
this License.
11. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Library at all. For example, if a patent
license would not permit royalty-free redistribution of the Library by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Library.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply, and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
12. If the distribution and/or use of the Library is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Library under this License
may add an explicit geographical distribution limitation excluding those
countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
13. The Free Software Foundation may publish revised and/or new
versions of the Lesser General Public License from time to time.
Such new versions will be similar in spirit to the present version,
but may differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the Library
specifies a version number of this License which applies to it and
"any later version", you have the option of following the terms and
conditions either of that version or of any later version published by
the Free Software Foundation. If the Library does not specify a
license version number, you may choose any version ever published by
the Free Software Foundation.
14. If you wish to incorporate parts of the Library into other free
programs whose distribution conditions are incompatible with these,
write to the author to ask for permission. For software which is
copyrighted by the Free Software Foundation, write to the Free
Software Foundation; we sometimes make exceptions for this. Our
decision will be guided by the two goals of preserving the free status
of all derivatives of our free software and of promoting the sharing
and reuse of software generally.
NO WARRANTY
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Libraries
If you develop a new library, and you want it to be of the greatest
possible use to the public, we recommend making it free software that
everyone can redistribute and change. You can do so by permitting
redistribution under these terms (or, alternatively, under the terms
of the ordinary General Public License).
To apply these terms, attach the following notices to the library.
It is safest to attach them to the start of each source file to most
effectively convey the exclusion of warranty; and each file should
have at least the "copyright" line and a pointer to where the full
notice is found.
<one line to give the library's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Also add information on how to contact you by electronic and paper mail.
You should also get your employer (if you work as a programmer) or
your school, if any, to sign a "copyright disclaimer" for the library,
if necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the
library `Frob' (a library for tweaking knobs) written by James
Random Hacker.
<signature of Ty Coon>, 1 April 1990
Ty Coon, President of Vice
That's all there is to it!

1097
src/l4/Makefile Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,150 @@
# This file is an example for defining configurations for different boot
# methods:
# - QEMU (qemu)
# - Image mode (image)
# - ISO images (grub1iso, grub2iso)
# - VirtualBox
# - Fastboot
#
# This is a 'make' file.
#
# Copy this example file to Makeconf.boot in the same directory.
#
# Generic options:
#
# Search path for modules, such as binaries, libraries, kernel, configuration
# files or any other data file you might want to load. Note that the bin and
# lib directories of the build-tree are automatically added to the search
# path.
# MODULE_SEARCH_PATH = /path/to/cfgs:/path/to/foo:..
#
# For additional image building options see the header of
# pkg/bootstrap/server/src/Make.rules
# Add fiasco build directory to MODULE_SEARCH_PATH
MODULE_SEARCH_PATH += /path/to/fiasco-build
# For use with multiple platforms and architectures:
FIASCO_PATH-arm-integrator = /path/to/fiasco-build-arm-integrator
FIASCO_PATH-arm-rv_vexpress = /path/to/fiasco-build-arm-rv_vexpress
FIASCO_PATH-arm-rv_vexpress_a15 = /path/to/fiasco-build-arm-rv_vexpress_a15
FIASCO_PATH-arm-arm_virt = /path/to/fiasco-build-arm-arm_virt
FIASCO_PATH-arm64-arm_virt = /path/to/fiasco-build-arm64-arm_virt
FIASCO_PATH-mips-malta = /path/to/fiasco-build-mips-malta
FIASCO_PATH-x86 = /path/to/fiasco-build-x86
FIASCO_PATH-amd64 = /path/to/fiasco-build-amd64
MODULE_SEARCH_PATH += $(FIASCO_PATH-$(ARCH)-$(PLATFORM_TYPE))
MODULE_SEARCH_PATH += $(FIASCO_PATH-$(ARCH))
# QEMU: Specific configuration for 'qemu' target (make qemu E=xxx'):
# Optional options for QEMU, but setting '-serial stdio' is recommended
QEMU_OPTIONS += -serial stdio
#QEMU_OPTIONS += -nographic
#QEMU_OPTIONS += -monitor none
QEMU_OPTIONS-arm-rv += -M realview-eb -m 256
#QEMU_OPTIONS-arm-rv += -cpu arm926
QEMU_OPTIONS-arm-rv += -cpu arm1176
#QEMU_OPTIONS-arm-rv += -cpu cortex-a8
#QEMU_OPTIONS-arm-rv += -cpu cortex-a9
QEMU_OPTIONS-arm-integrator += -M integratorcp -m 256
#QEMU_OPTIONS-arm-integrator += -cpu arm1176
QEMU_OPTIONS-arm-rv_vexpress += -M vexpress-a9 -m 1024 -cpu cortex-a9 -smp 4
QEMU_OPTIONS-arm-rv_vexpress_a15 += -M vexpress-a15 -m 2047 -cpu cortex-a15 \
-smp 4
QEMU_OPTIONS-arm-rv_pbx += realview-pbx-a9 -m 512 -cpu cortex-a9 -smp 4
QEMU_OPTIONS-arm-arm_virt += -M virt,virtualization=true -cpu cortex-a15 -m 1024
QEMU_OPTIONS-arm-arm_mps3_an536 += -M mps3-an536 -smp 2
# Have to add additional serial devices to see output of UARTs other than UART0.
# UART0: Exclusively accessible to CPU0.
# UART1: Exclusively accessible to CPU1.
# UART2/3/4/5: Shared between CPU0 and CPU1.
# The following adds serial devices for UART0-3 and muxes them all into stdio.
# Must not be combined with the usual "-serial stdio".
# QEMU_OPTIONS-arm-arm_mps3_an536 += -chardev stdio,mux=on,id=stdio-mux -serial chardev:stdio-mux -serial chardev:stdio-mux -serial chardev:stdio-mux -serial chardev:stdio-mux
QEMU_OPTIONS-arm64-arm_virt += -M virt,virtualization=true,iommu=smmuv3 -cpu cortex-a57 -m 1024
QEMU_OPTIONS-mips-malta += -M malta -m 1024 -cpu P5600
QEMU_OPTIONS-riscv-riscv_virt += -bios default -M virt -m 1024 -smp 4
QEMU_OPTIONS-riscv-sifive_u += -bios default -M sifive_u -m 1024 -smp 4
QEMU_OPTIONS-arm += $(QEMU_OPTIONS-arm-$(PLATFORM_TYPE))
QEMU_OPTIONS-arm64 += $(QEMU_OPTIONS-arm64-$(PLATFORM_TYPE))
QEMU_OPTIONS-mips += $(QEMU_OPTIONS-mips-$(PLATFORM_TYPE))
QEMU_OPTIONS-riscv += $(QEMU_OPTIONS-riscv-$(PLATFORM_TYPE))
QEMU_OPTIONS-x86 += -m 512 -M q35
QEMU_OPTIONS-amd64 += -m 512 -M q35
#QEMU_OPTIONS-amd64 += -m 1024 -enable-kvm -M q35,kernel_irqchip=split -cpu host -device intel-iommu,intremap=on,eim=on
QEMU_OPTIONS += $(QEMU_OPTIONS-$(ARCH))
# The path to the QEMU binary - optional
#QEMU_PATH-x86 = /path/to/qemu
#QEMU_PATH-amd64 = /path/to/qemu-system-x86_64
#QEMU_PATH = $(QEMU_PATH-$(ARCH))
# Arm FVP: Specific configuration for 'fvp' target (make fvp E=xxx' PT=arm_fvp_base):
FVP_OPTIONS += -C cluster0.NUM_CORES=1 -C pctl.startup=0.0.*.*
# Basic settings for bare-metal boot without an ATF
FVP_OPTIONS += -C bp.refcounter.non_arch_start_at_default=1
FVP_OPTIONS += -C gic_distributor.has-two-security-states=0
# Speed up simulation
FVP_OPTIONS += -C cache_state_modelled=0
FVP_OPTIONS += -C bp.vis.disable_visualisation=1
# UART output. You probably want to disable telnet when running tests...
FVP_OPTIONS += -C bp.pl011_uart0.out_file=-
#FVP_OPTIONS += -C bp.terminal_0.start_telnet=0
# A-profile specific settings. Required because we boot witout ATF.
FVP_OPTIONS-arm_fvp_base += -C bp.secure_memory=false
FVP_OPTIONS-arm_fvp_base += -C cluster0.has_el3=0 -C cluster0.has_secure_el2=0
# R-profile specific settings.
FVP_OPTIONS-arm_fvp_base_r += -C gic_distributor.GICD_CTLR-DS-1-means-secure-only=1
FVP_OPTIONS-arm_fvp_base_r += -C gic_distributor.has-two-security-states=0
FVP_OPTIONS-arm_fvp_base_r += -C cci400.force_on_from_start=1
FVP_OPTIONS-arm_fvp_base_r += -C bp.exclusive_monitor.monitor_access_level=1
# Armv8-R VMSA is only supported on AArch64
FVP_OPTIONS-arm-arm_fvp_base_r += -C cluster0.VMSA_supported=0
FVP_OPTIONS-arm64-arm_fvp_base_r += -C cluster0.VMSA_supported=1
FVP_OPTIONS-arm += -C cluster0.has_aarch64=0
FVP_OPTIONS-arm64 += -C cluster0.has_aarch64=1
FVP_OPTIONS += $(FVP_OPTIONS-$(ARCH))
FVP_OPTIONS += $(FVP_OPTIONS-$(PLATFORM_TYPE))
FVP_OPTIONS += $(FVP_OPTIONS-$(ARCH)-$(PLATFORM_TYPE))
# Set path to FVP binary if model is not in $PATH - optional
#FVP_PATH = /path/to/FVP_Base_RevC-2xAEMvA
# VirtualBox
#
# To use VirtualBox create a VM in VirtualBox and set the name of the VM in
# 'VBOX_VM'. The 'vbox' target uses an ISO image generating target to generate
# an ISO and use that with VirtualBox.
#
# Required variables:
# VBOX_VM: Name of the VM to use.
#
# Additional (optional) variables:
# VBOX_ISOTARGET: grub1iso or grub2iso (grub2iso is the default)
# VBOX_OPTIONS: Additional options (see VBoxSDL --help)
VBOX_VM = L4
VBOX_ISOTARGET = grub1iso
#VBOX_OPTIONS += --memory 256
# Fastboot
# FASTBOOT_BOOT_CMD = path/to/fastboot boot

View File

@@ -0,0 +1,69 @@
-- vim:set ft=lua:
-- This script shall start mag. For that we need a frame-buffer and io to
-- get access to the required hardware resources. Target platform is ARM
-- Real-View as used with QEmu.
local L4 = require("L4");
local l = L4.default_loader;
local io_buses =
{
gui = l:new_channel();
fbdrv = l:new_channel();
};
l:start({
caps = {
gui = io_buses.gui:svr(),
fbdrv = io_buses.fbdrv:svr(),
icu = L4.Env.icu,
sigma0 = L4.Env.sigma0,
},
log = { "IO", "y" },
l4re_dbg = L4.Dbg.Warn,
},
"rom/io rom/hw_devices.io rom/arm-rv-lcd.io");
local fbdrv_fb = l:new_channel();
l:startv({
caps = {
vbus = io_buses.fbdrv,
fb = fbdrv_fb:svr(),
},
log = { "fbdrv", "r" },
l4re_dbg = L4.Dbg.Warn,
},
"rom/fb-drv", "-c", "1024 565 bgr");
local mag_caps = {
mag = l:new_channel(),
svc = l:new_channel(),
};
l:start({
caps = {
vbus = io_buses.gui,
fb = fbdrv_fb,
mag = mag_caps.mag:svr(),
svc = mag_caps.svc:svr(),
},
log = { "mag", "g" },
l4re_dbg = L4.Dbg.Warn,
-- scheduler = L4.Env.user_factory:create(L4.Proto.Scheduler, 0xa0, 0x80),
},
"rom/mag");
e = l:start({ caps = {
fb = mag_caps.svc:create(L4.Proto.Goos, "g=640x480"),
},
log = { "spectrum", "b" },
l4re_dbg = L4.Dbg.Warn,
-- scheduler = L4.Env.user_factory:create(L4.Proto.Scheduler, 0x18, 0x8),
},
"rom/ex_fb_spectrum_cc");
print("ex_fb_spectrum exited with: " .. e:wait());

View File

@@ -0,0 +1,15 @@
-- vi:ft=lua
-- configuration file for io
local hw = Io.system_bus()
Io.add_vbus("gui", Io.Vi.System_bus
{
INPUT = wrap(hw:match("arm,pl050"));
})
Io.add_vbus("fbdrv", Io.Vi.System_bus
{
CTRL = wrap(hw:match("arm,sysctl"));
LCD = wrap(hw:match("arm,pl111"));
})

View File

@@ -0,0 +1,16 @@
modaddr 0x1100000
entry arm-lcd-example
bootstrap bootstrap -serial
kernel fiasco -serial_esc
roottask moe rom/arm-rv-lcd.cfg
module arm-rv-lcd.cfg
module arm-rv-lcd.io
module plat-rv/hw_devices.io
module l4re
module io
module ned
module fb-drv
module mag
module ex_fb_spectrum_cc

View File

@@ -0,0 +1,11 @@
-- vi:ft=lua
local hw = Io.system_bus()
-- create a virtual bus 'l4lx'
Io.add_vbus("l4lx", Io.Vi.System_bus
{
-- add device which matches the compatibility ID (CID)
-- 'smsc,lan9118'
NIC = wrap(hw:match("smsc,lan9118"));
})

View File

@@ -0,0 +1,32 @@
-- vi:ft=lua
Io.Dt.add_children(Io.system_bus(), function()
pciec0 = Io.Hw.Ecam_pcie_bridge(function()
Property.regs_base = 0x10000000
Property.regs_size = 0x2eff0000
Property.cfg_base = 0x4010000000
Property.cfg_size = 0x0010000000 -- 256 buses x 256 devs x 4KB
Property.ioport_base = 0x3eff0000
Property.ioport_size = 0x10000 -- 64KB (for port I/O access)
Property.mmio_base = 0x10000000
Property.mmio_size = 0x2eff0000 -- ~750MB (for memory I/O access)
Property.mmio_base_64 = 0x8000000000
Property.mmio_size_64 = 0x8000000000 -- 512GB (for memory I/O access)
Property.int_a = 32 + 3
Property.int_b = 32 + 4
Property.int_c = 32 + 5
Property.int_d = 32 + 6
Property.flags = Io.Hw_device_DF_dma_supported
end);
end);
local hw = Io.system_bus()
Io.add_vbusses
{
vbus = Io.Vi.System_bus(function ()
Property.num_msis = 26
PCI = Io.Vi.PCI_bus(function ()
pci_bus = wrap(hw:match("PCI/network", "PCI/storage", "PCI/media"));
end)
end);
}

View File

@@ -0,0 +1,9 @@
-- vim:ft=lua
-- This is a configuration to start two 'hello's,
-- showing the colored prefix made by the system to securely differentiate
-- the two applications.
local L4 = require("L4");
L4.default_loader:start({ log = { "hello-1", "red" } }, "rom/hello");
L4.default_loader:start({ log = { "hello-2", "cyan" } }, "rom/hello");

View File

@@ -0,0 +1,6 @@
-- vim:ft=lua
-- this is a configuration to start 'hello'
local L4 = require("L4");
L4.default_loader:start({}, "rom/hello");

View File

@@ -0,0 +1,66 @@
-- vim:set ft=lua:
local L4 = require("L4");
loader = L4.default_loader;
local lxname = "vmlinuz";
-- Start io
vbus_l4linux = loader:new_channel();
vbus_input = loader:new_channel();
vbus_fbdrv = loader:new_channel();
loader:start(
{
caps = {
sigma0 = L4.Env.sigma0,
icu = L4.Env.icu,
input = vbus_input:svr(),
l4linux = vbus_l4linux:svr(),
fbdrv = vbus_fbdrv:svr(),
},
}, "rom/io rom/x86-legacy.devs rom/l4lx-x86.io");
-- Start fb-drv (but only if we need to)
local fb = L4.Env.vesa;
if (not fb) then
fb = loader:new_channel();
loader:start(
{
caps = {
fb = fb:svr(),
vbus = vbus_fbdrv
}
}, "rom/fb-drv -m 0x117");
end
local mag_mag = loader:new_channel();
local mag_svc = loader:new_channel();
-- Start mag
loader:start(
{
caps = {
vbus = vbus_input;
mag = mag_mag:svr();
svc = mag_svc:svr();
fb = fb;
},
}, "rom/mag");
-- Start Linux
loader:start(
{
caps = {
fb = mag_svc:create(L4.Proto.Goos, "g=640x480");
vbus = vbus_l4linux;
},
l4re_dbg = L4.Dbg.Warn,
log = L4.Env.log,
},
"rom/vmlinuz mem=64M console=tty0 "
.. "l4x_rd=rom/ramdisk-" .. L4.Info.arch() .. ".rd "
.. "root=1:0 ramdisk_size=5000");

View File

@@ -0,0 +1,33 @@
-- vi:ft=lua
local hw = Io.system_bus()
Io.add_vbusses
{
input = Io.Vi.System_bus
{
ps2dev = wrap(hw:match("PNP0[3F]??"));
};
fbdrv = Io.Vi.System_bus
{
PCI0 = Io.Vi.PCI_bus_ident
{
dummy = Io.Vi.PCI_dummy_device();
pci_gfx = wrap(hw:match("PCI/display"));
};
x1 = wrap(hw:match("BIOS"));
x2 = wrap(hw:match("PNP0900"));
x3 = wrap(hw:match("PNP0100"));
};
l4linux = Io.Vi.System_bus
{
-- Add a new virtual PCI root bridge
PCI0 = Io.Vi.PCI_bus
{
pci_l4x = wrap(hw:match("PCI/network", "PCI/storage", "PCI/media"));
};
};
}

View File

@@ -0,0 +1,11 @@
-- vim:set ft=lua:
local L4 = require("L4");
L4.default_loader:start(
{
log = L4.Env.log,
}, "rom/vmlinuz mem=64M console=ttyLv0 "
.. "l4x_rd=rom/ramdisk-" .. L4.Info.arch() .. ".rd "
.. (L4.Info.arch() == "arm64" and "l4x_dtb=rom/simple.dtb " or "")
.. "root=1:0 ramdisk_size=5000");

View File

@@ -0,0 +1,13 @@
-- vi:ft=lua
local hw = Io.system_bus()
Io.add_vbusses
{
vbus = Io.Vi.System_bus(function ()
Property.num_msis = 26
PCI = Io.Vi.PCI_bus(function ()
pci_bus = wrap(hw:match("PCI/network", "PCI/storage", "PCI/media"));
end)
end)
}

View File

@@ -0,0 +1,61 @@
-- vim:set ft=lua:
local L4 = require("L4");
local l = L4.default_loader;
-- start console server
local cons = l:new_channel();
l:start({ caps = { cons = cons:svr(); },
log = L4.Env.log
},
"rom/cons -a");
l.log_fab = cons;
-- start io server
local vbus = l:new_channel();
l:start({
caps = {
vbus = vbus:svr(),
icu = L4.Env.icu,
iommu = L4.Env.iommu,
sigma0 = L4.Env.sigma0,
},
log = { "IO", "y" },
l4re_dbg = L4.Dbg.Warn,
},
"rom/io rom/pci.io");
local flags = L4.Mem_alloc_flags.Continuous
| L4.Mem_alloc_flags.Pinned
| L4.Mem_alloc_flags.Super_pages;
local align = 28;
local dt;
local overlay
if (L4.Info.arch() == "arm64") then
dt = "-drom/.fdt"
overlay = "-drom/virt-pci.dtb"
else
dt = "-drom/virt-pci.dtb"
end
local serialdev = { arm = "ttyAMA0", arm64 = "ttyAMA0", amd64 = "ttyS0" };
l:startv({
caps = {
ram = L4.Env.user_factory:create(L4.Proto.Dataspace,
256 * 1024 * 1024,
flags, align):m("rw"),
vbus = vbus
},
log = { "vm", "Blue" },
},
"rom/uvmm", "-v",
"-krom/linux",
"-rrom/ramdisk.cpio.gz",
dt, overlay,
"-cconsole=" .. serialdev[L4.Info.arch()] .. " rw");

View File

@@ -0,0 +1,26 @@
-- vim:set ft=lua:
local L4 = require("L4");
local l = L4.default_loader;
local flags = L4.Mem_alloc_flags.Continuous
| L4.Mem_alloc_flags.Pinned
| L4.Mem_alloc_flags.Super_pages;
local align = 21;
local serialdev = { arm = "ttyAMA0", arm64 = "ttyAMA0", amd64 = "ttyS0", riscv = "ttyS0" };
l:startv({
caps = {
ram = L4.Env.user_factory:create(L4.Proto.Dataspace,
128 * 1024 * 1024,
flags, align):m("rw"),
},
log = L4.Env.log,
},
"rom/uvmm", "-v",
"-krom/linux",
"-rrom/ramdisk.cpio.gz",
"-drom/virt.dtb",
"-cconsole=" .. serialdev[L4.Info.arch()] .. " rw");

View File

@@ -0,0 +1,51 @@
-- vim:set ft=lua:
local L4 = require("L4");
local l = L4.default_loader;
local cons = l:new_channel();
l:start({ caps = { cons = cons:svr(); },
log = L4.Env.log
},
"rom/cons -a");
l.log_fab = cons;
local p2p = l:new_channel();
l:start({
caps = { svr = p2p:svr() },
log = { "p2p", "Blue" }
},
"rom/l4vio_net_p2p" );
local ports = {}
ports[1] = p2p:create(0, "ds-max=4")
ports[2] = p2p:create(0, "ds-max=4")
local serialdev = { arm = "ttyAMA0", arm64 = "ttyAMA0", amd64 = "ttyS0", riscv = "ttyS0" };
function start_vm(num, port)
local flags = L4.Mem_alloc_flags.Continuous
| L4.Mem_alloc_flags.Pinned
| L4.Mem_alloc_flags.Super_pages;
local align = 21;
l:startv({
caps = {
ram = L4.Env.user_factory:create(L4.Proto.Dataspace,
128 * 1024 * 1024,
flags, align):m("rw"),
net = port
},
log = { "vm-" .. num, "", "key=" .. num },
},
"rom/uvmm", "-v",
"-krom/linux",
"-rrom/ramdisk.cpio.gz",
"-drom/virt.dtb",
"-cconsole=" .. serialdev[L4.Info.arch()] .. " rw");
end
start_vm(1, ports[1])
start_vm(2, ports[2])

View File

@@ -0,0 +1,40 @@
-- vim:set ft=lua:
local L4 = require("L4");
local l = L4.default_loader;
local cons = l:new_channel();
l:start({ caps = { cons = cons:svr(); },
log = L4.Env.log
},
"rom/cons -a");
l.log_fab = cons;
local serialdev = { arm = "ttyAMA0", arm64 = "ttyAMA0", amd64 = "ttyS0", riscv = "ttyS0" };
function start_vm(num)
local flags = L4.Mem_alloc_flags.Continuous
| L4.Mem_alloc_flags.Pinned
| L4.Mem_alloc_flags.Super_pages;
local align = 21;
l:startv({
caps = {
ram = L4.Env.user_factory:create(L4.Proto.Dataspace,
128 * 1024 * 1024,
flags, align):m("rw"),
},
log = { "vm-" .. num, "", "key=" .. num },
},
"rom/uvmm", "-v",
"-krom/linux",
"-rrom/ramdisk.cpio.gz",
"-drom/virt.dtb",
"-cconsole=" .. serialdev[L4.Info.arch()] .. " rw");
end
start_vm(1)
start_vm(2)
start_vm(3)

View File

@@ -0,0 +1,69 @@
-- vim:set ft=lua:
-- This script shall start mag. For that we need a frame-buffer and io to
-- get access to the required hardware resources. Target platform is x86.
local L4 = require("L4");
local l = L4.default_loader;
local io_buses =
{
gui = l:new_channel();
fbdrv = l:new_channel();
};
l:start({
caps = {
icu = L4.Env.icu,
sigma0 = L4.Env.sigma0,
gui = io_buses.gui:svr(),
fbdrv = io_buses.fbdrv:svr(),
},
log = { "IO", "y" },
l4re_dbg = L4.Dbg.Warn,
},
"rom/io rom/x86-legacy.devs rom/x86-fb.io");
-- Start fb-drv (but only if we need to)
local fbdrv_fb = L4.Env.vesa;
if (not fbdrv_fb) then
fbdrv_fb = l:new_channel();
l:start({
caps = {
vbus = io_buses.fbdrv,
fb = fbdrv_fb:svr(),
},
log = { "fbdrv", "r" },
},
"rom/fb-drv");
end
local mag_caps = {
mag = l:new_channel(),
svc = l:new_channel(),
};
l:start({
caps = {
vbus = io_buses.gui,
fb = fbdrv_fb,
mag = mag_caps.mag:svr(),
svc = mag_caps.svc:svr(),
},
log = { "mag", "g" },
l4re_dbg = L4.Dbg.Warn,
-- scheduler = L4.Env.user_factory:create(L4.Proto.Scheduler, 0xa0, 0x80),
},
"rom/mag");
e = l:start({ caps = {
fb = mag_caps.svc:create(L4.Proto.Goos, "g=640x480"),
},
log = { "spectrum", "b" },
l4re_dbg = L4.Dbg.Warn,
-- scheduler = L4.Env.user_factory:create(L4.Proto.Scheduler, 0x18, 0x8),
},
"rom/ex_fb_spectrum_cc");
print("ex_fb_spectrum exited with: " .. e:wait());

View File

@@ -0,0 +1,23 @@
-- vim:set ft=lua:
-- configuration file for io
local hw = Io.system_bus()
Io.add_vbus("gui", Io.Vi.System_bus
{
ps2 = wrap(hw:match("PNP0[3F]??"));
})
Io.add_vbus("fbdrv", Io.Vi.System_bus
{
PCI0 = Io.Vi.PCI_bus_ident
{
dummy = Io.Vi.PCI_dummy_device();
pci = wrap(hw:match("PCI/display"));
};
bios = wrap(hw:match("BIOS"));
dev1 = wrap(hw:match("PNP0900"));
dev2 = wrap(hw:match("PNP0100"));
})

209
src/l4/conf/modules.list Normal file
View File

@@ -0,0 +1,209 @@
# vim:set ft=l4mods:
# Module configuration file for single image mode
#
# kernel, sigma0 and moe are always loaded automatically
#
# add kernel command line arguments with
# kernel fiasco arguments...
# the second argument (here 'fiasco') is the binary name
#
# add sigma command line arguments with
# sigma0 sigma0 arguments...
# the second argument (here 'sigma0') is the binary name
#
# add roottask command line arguments with
# roottask moe arguments...
# the second argument (here 'moe') is the binary name
#
# modaddr: address where modules start, relative to begin of RAM
# this statement is either global (before first entry statement)
# or per entry
#
# 'module' variants
# - module file: add file
# - module[uncompress] module name: uncompress module (gzip) before adding it
# - module[glob] /some/path/*.foo: add all file matching
# - module[perl] perl-code: Perl code returns array of files to include
# - module[shell] shell-code: Return list of files to include
# - module[fname=FOO] /some/path/bar: The file 'bar' will be added as the
# module named 'FOO'.
# - moe file.cfg: expands to
# roottask moe rom/file.cfg
# module file.cfg
#
# Modules can have an arbitrary number of attributes (key-value-pairs). The
# attribute key must be prefixed by 'attr:':
# - module[attr:nodes=0-3]: The attribute 'nodes' with the value '0-3'
#
# Define a module group:
# group oftenneedthose
# module one
# module two
# module ...
#
# Use a module group:
# entry someentry
# module-group oftenneedthose
#
# Include other module list files:
# include /path/to/other.list
#
# Set defaults:
# - default-kernel: set default kernel including arguments
# - default-sigma0: set default sigma0 including arguments
# - default-roottask: set default roottask including arguments
modaddr 0x01100000
default-kernel fiasco -serial_esc
default-bootstrap bootstrap
entry hello
roottask moe --init=rom/hello
module l4re
module hello
entry hello-cfg
kernel fiasco -serial_esc
roottask moe rom/hello.cfg
module l4re
module ned
module hello.cfg
module hello
entry hello-2
kernel fiasco -serial_esc
roottask moe rom/hello-2.cfg
module l4re
module ned
module hello-2.cfg
module hello
entry hello-shared
roottask moe --init=rom/ex_hello_shared
module l4re
module ex_hello_shared
entry[arch=x86|amd64] framebuffer-example
roottask moe rom/x86-fb.cfg
module x86-fb.cfg
module l4re
module ned
module io
module io/x86-legacy.devs
module x86-fb.io
module fb-drv
module mag
module ex_fb_spectrum_cc
entry[arch=x86|amd64|arm|arm64] L4Linux-basic
roottask moe rom/l4lx.cfg
module l4lx.cfg
module l4re
module ned
module[arch=arm64] arch/l4/boot/dts/simple.dtb
module[uncompress] vmlinuz
module[perl] "ramdisk-$ENV{ARCH}.rd"
entry[arch=x86|amd64] L4Linux-mag
moe l4lx-gfx.cfg
module l4re
module ned
module io
module fb-drv
module mag
module io/x86-legacy.devs
module l4lx-x86.io
module[uncompress] vmlinuz
module[perl] "ramdisk-$ENV{ARCH}.rd"
entry[arch=arm|arm64|amd64|riscv] VM-basic
moe vm-basic.cfg
module l4re
module ned
module uvmm
module[arch=arm,fname=virt.dtb] dtb/virt-arm_virt-32.dtb
module[arch=arm64,fname=virt.dtb] dtb/virt-arm_virt-64.dtb
module[arch=amd64,fname=virt.dtb] dtb/virt-pc.dtb
module[arch=riscv,bits=32,fname=virt.dtb] dtb/virt-riscv32.dtb
module[arch=riscv,bits=64,fname=virt.dtb] dtb/virt-riscv64.dtb
module[arch=arm,fname=linux,nostrip] https://l4re.org/download/Linux-kernel/arm32/zImage-6.6.8
module[arch=arm64,fname=linux,nostrip] https://l4re.org/download/Linux-kernel/arm64/Image-6.6.8
module[arch=amd64,fname=linux,nostrip] https://l4re.org/download/Linux-kernel/x86-64/bzImage-6.6.8
module[arch=riscv,bits=64,fname=linux,nostrip] https://l4re.org/download/Linux-kernel/riscv64/Image-6.11.4.gz
module[arch=arm,fname=ramdisk.cpio.gz] https://l4re.org/download/ramdisks/ramdisk-armv7.cpio.gz
module[arch=arm64,fname=ramdisk.cpio.gz] https://l4re.org/download/ramdisks/ramdisk-armv8-64.cpio.gz
module[arch=amd64,fname=ramdisk.cpio.gz] https://l4re.org/download/ramdisks/ramdisk-amd64.cpio.gz
module[arch=riscv,bits=64,fname=ramdisk.cpio.gz] https://l4re.org/download/ramdisks/ramdisk-riscv64.cpio.gz
entry[arch=arm|arm64|amd64|riscv] VM-multi
moe vm-multi.cfg
module l4re
module ned
module cons
module uvmm
module[arch=arm,fname=virt.dtb] dtb/virt-arm_virt-32.dtb
module[arch=arm64,fname=virt.dtb] dtb/virt-arm_virt-64.dtb
module[arch=amd64,fname=virt.dtb] dtb/virt-pc.dtb
module[arch=riscv,bits=32,fname=virt.dtb] dtb/virt-riscv32.dtb
module[arch=riscv,bits=64,fname=virt.dtb] dtb/virt-riscv64.dtb
module[arch=arm,fname=linux,nostrip] https://l4re.org/download/Linux-kernel/arm32/zImage-6.6.8
module[arch=arm64,fname=linux,nostrip] https://l4re.org/download/Linux-kernel/arm64/Image-6.6.8
module[arch=amd64,fname=linux,nostrip] https://l4re.org/download/Linux-kernel/x86-64/bzImage-6.6.8
module[arch=riscv,bits=64,fname=linux,nostrip] https://l4re.org/download/Linux-kernel/riscv64/Image-6.11.4.gz
module[arch=arm,fname=ramdisk.cpio.gz] https://l4re.org/download/ramdisks/ramdisk-armv7.cpio.gz
module[arch=arm64,fname=ramdisk.cpio.gz] https://l4re.org/download/ramdisks/ramdisk-armv8-64.cpio.gz
module[arch=amd64,fname=ramdisk.cpio.gz] https://l4re.org/download/ramdisks/ramdisk-amd64.cpio.gz
module[arch=riscv,bits=64,fname=ramdisk.cpio.gz] https://l4re.org/download/ramdisks/ramdisk-riscv64.cpio.gz
entry[arch=arm|arm64|amd64|riscv] VM-multi-p2p
moe vm-multi-p2p.cfg
module l4re
module ned
module cons
module l4vio_net_p2p
module uvmm
module[arch=arm,fname=virt.dtb] dtb/virt-arm_virt-32.dtb
module[arch=arm64,fname=virt.dtb] dtb/virt-arm_virt-64.dtb
module[arch=amd64,fname=virt.dtb] dtb/virt-pc.dtb
module[arch=riscv,bits=32,fname=virt.dtb] dtb/virt-riscv32.dtb
module[arch=riscv,bits=64,fname=virt.dtb] dtb/virt-riscv64.dtb
module[arch=arm,fname=linux,nostrip] https://l4re.org/download/Linux-kernel/arm32/zImage-6.6.8
module[arch=arm64,fname=linux,nostrip] https://l4re.org/download/Linux-kernel/arm64/Image-6.6.8
module[arch=amd64,fname=linux,nostrip] https://l4re.org/download/Linux-kernel/x86-64/bzImage-6.6.8
module[arch=riscv,bits=64,fname=linux,nostrip] https://l4re.org/download/Linux-kernel/riscv64/Image-6.11.4.gz
module[arch=arm,fname=ramdisk.cpio.gz] https://l4re.org/download/ramdisks/ramdisk-armv7.cpio.gz
module[arch=arm64,fname=ramdisk.cpio.gz] https://l4re.org/download/ramdisks/ramdisk-armv8-64.cpio.gz
module[arch=amd64,fname=ramdisk.cpio.gz] https://l4re.org/download/ramdisks/ramdisk-amd64.cpio.gz
module[arch=riscv,bits=64,fname=ramdisk.cpio.gz] https://l4re.org/download/ramdisks/ramdisk-riscv64.cpio.gz
entry[arch=arm|arm64|amd64] VM-basic-pci
moe vm-basic-pci.cfg
module l4re
module ned
module cons
module io
module[arch=arm|arm64,fname=pci.io] arm-virt64.io
module[arch=amd64] pci.io
module uvmm
module[arch=arm, fname=virt-pci.dtb] dtb/virt-arm_virt-64_pci.dtb
module[arch=arm64,fname=virt-pci.dtb] dtb/virt-arm_virt-64_pci.dtb
module[arch=amd64,fname=virt-pci.dtb] dtb/virt-pc.dtb
module[arch=arm,fname=linux,nostrip] https://l4re.org/download/Linux-kernel/arm32/zImage-6.6.8
module[arch=arm64,fname=linux,nostrip] https://l4re.org/download/Linux-kernel/arm64/Image-6.6.8
module[arch=amd64,fname=linux,nostrip] https://l4re.org/download/Linux-kernel/x86-64/bzImage-6.6.8
module[arch=arm,fname=ramdisk.cpio.gz] https://l4re.org/download/ramdisks/ramdisk-armv7.cpio.gz
module[arch=arm64,fname=ramdisk.cpio.gz] https://l4re.org/download/ramdisks/ramdisk-armv8-64.cpio.gz
module[arch=amd64,fname=ramdisk.cpio.gz] https://l4re.org/download/ramdisks/ramdisk-amd64.cpio.gz
entry ipcbench
roottask moe rom/ipcbench.cfg
module l4re
module ned
module ipcbench
module ipcbench_client
module ipcbench_server
module ipcbench_parallel
module syscallbench
module syscallbench_parallel
module ned/ipcbench/ipcbench.cfg

View File

@@ -0,0 +1 @@
Put your own local platform configuration files in this directory.

10
src/l4/conf/test/README Normal file
View File

@@ -0,0 +1,10 @@
Standard configuration files for test setups.
Test configurations expect a number of environment variables to be set up.
Within the test framework this is done by the test execution script,
which creates a second lua config with the variables.
The following variables are defined:
TEST_PROG - name of executable containing test
REQUIRED_MODULES - list of additional modules loaded (filename only)

View File

@@ -0,0 +1,209 @@
-- SPDX-License-Identifier: GPL-2.0-only or License-Ref-kk-custom
-- Copyright (C) 2020 Kernkonzept GmbH.
-- Author: Philipp Eppelt <philipp.eppelt@kernkonzept.com>
--
--
-- Usage note:
-- If you use this library you must abort further program startup if any of the
-- used functions return false.
-- In this case the library already printed a TAP TEST START - TAP TEST FINISH
-- block, which a) can lead to program termination from the outside, b)
-- further TAP blocks will be ignored by the infrastructure, c) additional
-- messages are likely not picked up by the infrastructure.
--
-- Errors during usage of this library will print a TAP block containing a
-- 'not ok' line with the error message.
-- A failure of a HWconfig check will print a TAP block containing an 'ok-skip'
-- line with the failed check.
local t = require("rom/test_env")
local conf = t.FULLCONFIG
local function print_tap_start()
print "TAP TEST START"
end
local function print_tap_finish()
print "TAP TEST FINISH"
end
local function print_tap_skip_line(reason)
skip_msg = "1..0 # SKIP"
if type(reason) == "string" then
skip_msg = skip_msg .. " - " .. reason
end
print(skip_msg)
end
-- Print a failure message in TAP format. Use this instead of error().
--
-- error() terminates the program and leaves the TAP infrastructure waiting
-- until the timeout hits. Instead of waiting, we print a failure message in
-- TAP format, such that other tests can progress and the failure is recorded.
local function print_tap_failure(reason)
local failure_msg = "1..1\nnot ok lib-test-setup - "
if type(reason) == "string" then
failure_msg = failure_msg .. reason
end
print_tap_start()
print(failure_msg)
print_tap_finish()
end
-- print the reason to skip the test in TAP format
local function print_tap_skip(msg)
print_tap_start()
print_tap_skip_line(msg)
print_tap_finish()
end
-- Check for HWconfig and print default TAP messages if not.
local function conf_present()
if conf == nil then
print_tap_skip("Hardware configuration unknown (see TEST_HWCONFIG)")
return false
end
return true
end
local function conf_prop(prop, val)
if type(prop) ~= "string" or type(val) ~= "boolean" then
print_tap_failure("conf_prop: Property must be of type string.")
return false
end
-- convention with HWconfig: every property is upper case
prop = string.upper(prop)
if val and conf[prop] ~= "y" then
print_tap_skip("Hardware does not support property " .. prop .. " (see TEST_HWCONFIG)")
return false
elseif not val and conf[prop] == "y" then
print_tap_skip("Hardware supports property " .. prop .. " (see TEST_HWCONFIG)")
return false;
end
return true
end
-- A property `prop` is set to "y".
-- pre: present() == true
-- param: prop = string
local function conf_prop_set(prop)
return conf_prop(prop, true)
end
-- A property `prop` is set to "n".
-- pre: present() == true
-- param: prop = string
local function conf_prop_unset(prop)
return conf_prop(prop, false)
end
-- All of the passed properties are set to "y".
-- pre: present() == true
-- param: ... = string
local function conf_props_set(...)
for _, prop in pairs({...}) do
if not conf_prop_set(prop) then
return false
end
end
return true
end
-- All of the passed properties are set to "n".
-- pre: present() == true
-- param: ... = string
local function conf_props_unset(...)
for _, prop in pairs({...}) do
if not conf_prop_unset(prop) then
return false
end
end
return true
end
-- A property `prop` compares to value used in `prop_test_fn`.
-- pre: present() == true
-- param: prop = string
-- param: prop_test_fn = function testing the property
--
-- returns: comparison result and error_msg.
local function prop_val_cmp(prop, prop_test_fn)
if type(prop) ~= "string" then
print_tap_failure("prop_val_cmp: Property must be of type string.")
return false
end
if type(prop_test_fn) ~= "function" then
print_tap_failure("prop_val_cmp: Compare function must be of type function.")
return false
end
-- convention with HWconfig: every property is upper case
prop = string.upper(prop)
if (conf[prop] == nil) then
print_tap_skip("Hardware does not feature property " .. prop .. " (see TEST_HWCONFIG)")
return false
end
if not prop_test_fn(conf[prop]) then
print_tap_skip("Hardware provides " .. prop .. " = " .. conf[prop] .. ". "
.. "This does not satisfy the requested property value (see TEST_HWCONFIG)")
return false
end
return true
end
-- A property `prop` compares to value used in `prop_test_fn`.
-- pre: present() == true
-- param: prop = string
-- param: prop_test_fn = function testing the property
--
-- usage:
-- ret = conf_prop_val_cmp(num_cpus, function (v1) return v1 > 1 end)
local function conf_prop_val_cmp(prop, prop_test_fn)
return prop_val_cmp(prop, prop_test_fn)
end
-- All of the passed property-comparator-pairs are satisfied.
--
-- usage:
-- conf_props_values_cmp({ ["num_cpus"] = function (v) return v == 1 end,
-- ["FOO"] = prop_test_fnB })
local function conf_props_values_cmp(...)
local _, tbl = pairs({...})
if type(tbl) ~= "table" then
print_tap_failure("conf_props_values_cmp: Parameter must be of type table.")
return false
end
for prop, fn in pairs(tbl) do
if not prop_val_cmp(prop, fn) then
return false
end
end
return true
end
return {
print_tap_start = print_tap_start,
print_tap_finish = print_tap_start,
print_tap_skip_line = print_tap_skip_line,
print_tap_skip = print_tap_skip,
conf_prop_set = conf_prop_set,
conf_prop_unset = conf_prop_unset,
conf_props_set = conf_props_set,
conf_props_unset = conf_props_unset,
conf_present = conf_present,
conf_prop_val = conf_prop_val_cmp,
conf_props_vals = conf_props_values_cmp
}

View File

@@ -0,0 +1,17 @@
-- vim:set ft=lua:
-- Starts the test program and all applications from the required modules list
-- independently without creating any communication channels.
local t = require("rom/test_env")
local L4 = require("L4");
for k,v in ipairs(t.REQUIRED_MODULES) do
L4.default_loader:start({}, "rom/" .. v);
end
-- The pfc cap is passed in to allow the test to reboot the machine once it
-- finishes. Rebooting only happens if the test arguments contain the -b switch.
L4.default_loader:start({ caps = {pfc = L4.Env.icu} }, "rom/" .. t.TEST_PROG);

View File

@@ -0,0 +1,13 @@
-- vim:set ft=lua:
-- Simple configuration that starts exactly one server.
-- load the test_env module which provides additional test environment variables
local t = require("rom/test_env")
local L4 = require("L4");
-- The pfc cap is passed in to allow the test to reboot the machine once it
-- finishes. Rebooting only happens if the test arguments contain the -b switch.
L4.default_loader:start({ caps = {pfc = L4.Env.icu, jdb = L4.Env.jdb} },
"rom/" .. t.TEST_PROG);

View File

@@ -0,0 +1 @@
.*TAP TEST FINISHED

9
src/l4/doc/Makefile Normal file
View File

@@ -0,0 +1,9 @@
L4DIR ?= ..
TARGET = bid-spec bid-tut building-howto dev-overview l4env-concept html
TARGET = source
doc: $(TARGET)
html: bid-spec bid-tut building-howto dev-overview
include $(L4DIR)/mk/subdir.mk

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

@@ -0,0 +1,22 @@
PKGDIR = .
L4DIR ?= ../..
SRC_DOX_REF = l4re.cfg
ADD_FILES_TO_HTML = $(SRC_DIR)/images/header-bg.png
include $(L4DIR)/mk/doc.mk
export L4DIR
export OBJ_BASE
PHONY += regen regen_cfg regen_html
regen: regen_cfg regen_html
regen_cfg:
doxygen -u l4re.cfg
rm -f l4re.cfg.bak
regen_html: regen_cfg
doxygen -w html l4re-header.html l4re-footer.html l4re.css l4re.cfg
rm -r l4re-footer.html.bak l4re-header.html.bak l4re.css.bak

View File

@@ -0,0 +1,664 @@
// vi:ft=c
/**
\page l4re_build_system L4Re Build System
L4Re uses a custom make-based build system, often simply referred to as *BID*.
This section explains how to use BID when writing applications and libraries
for L4Re.
\section l4re_build_system_using Building L4Re
Setting up the Build Directory
------------------------------
L4Re must be built out-of-source. Therefore the first mandatory step is
creating and populating a build directory. From the root of the
L4Re source tree run
make B=<builddir>
Other targets that can be executed in the source directory are
\par update
Update the source directory from svn. Only makes sense when you have
downloaded L4Re from the official subversion repository.
\par help
Show a short help with the most important targets.
Invoking Make
-------------
Once the build directory is set up, BID make can be invoked in one of two ways:
1. Go to the build directory and invoke make without special options.
2. Go to a source directory with a BID make file and invoke
`make O=<builddir> ...`.
The default target builds the source (as you would expect),
other targets that are available in build mode are
\par cleanfast
Quickly cleans the build directory by removing all subdirectories that
contain generated files. The configuration will remain untouched.
\par clean
Remove generated files. Slower than `make cleanfast` but can be used
on selected packages. Use `S=...` to select the target package.
In addition to these targets, there are a number of targets to
generate images which are explained elsewhere.
\section l4re_build_system_writing Writing BID Make Files
The BID build system exports different roles that define what should
be done in the subdirectory. So a BID make file essentially consists
of defining the role and a number of role-dependent make
variables. The basic layout should look like this:
~~~
PKGDIR ?= <path to package's root directory> # e.g., '.' or '..'
L4DIR ?= <path to L4Re source directory> # e.g. '$(PKGDIR)/../..'
<various definitions>
include $(L4DIR)/mk/<role>.mk
~~~
`PKGDIR` in the first line defines the root directory of the current
package. `L4DIR` in the next line must be pointed to the root of the
L4Re source tree the package should be built against. After this
custom variable definitions for the role follow. In the final line
of the file, the make file with the role-specific rules must be sourced.
The following roles are currently defined:
- project.mk - Sub-project Role
- subdir.mk - Directory Role
- \subpage bid_role_prog "prog.mk - Application Role"
- lib.mk - Library Role
- \subpage bid_role_include "include.mk - Header File Role"
- doc.mk - Documentation Role
- \subpage bid_role_test "test.mk - Test Application Role"
- idl.mk - IDL File Role (currently unused)
- runux.mk - Tests in FiascoUX Role
BID-global Variables
--------------------
This section lists variables that configure how the BID build system
behaves. They are applicable for all roles.
Variable | Description
---------|----------------------
CC | C compiler for target
CXX | C++ compiler for target
HOST_CC | C compiler for host
HOST_CXX | C++ compiler for host
*/
/** \page bid_role_prog prog.mk - Application Role
The prog role is used to build executable programs.
General Configuration Variables
-------------------------------
The following variables can only be set globally for the Makefile:
\par `MODE`
Kind of target to build for. The following values are possible:
- `static` - build a statically linked binary (default)
- `shared` - build a dynamically linked binary
- `l4linux` - build a binary for running on L4Linux on the target platform
- `host` - build for host system
- `targetsys` - build a binary for the target platform with the compiler's
default settings
\par `SYSTEMS`
List of architectures the target can be built for. The entries must be
space-separated entries either naming an architecture (e.g. amd64) or
an architecture and ABI (e.g, arm-l4f). When not defined, the target
will be built for all possible platforms.
\par `TARGET`
Name or names of the binaries to compile. This variable may also be
postfixed with a specific architecture.
Target-specific Configuration Variables
---------------------------------------
The following variables may either be used with or without a description
suffix. Without suffix they will be used for all operations. With a
specific description their use is restricted to a subset.
These specifications include a target file and
the architecture, both optional but in this order, separated by
underscores. The specific variables will be used in addition to the
more general ones.
\par `SRC_C` / `SRC_CC` / `SRC_F` / `SRC_S`
.c, .cc, .f90, .S source files.
\par `REQUIRES_LIBS`
List of libraries the binary depends on. This works only with libraries
that export a pkg_config configuration file. Automatically adds any required
include and link options.
\par `DEPENDS_PKGS`
List of packages this binary depends on. If one these packages is missing
then building of the binary will be skipped.
\par `CPPFLAGS` / `CFLAGS` / `CXXFLAGS` / `FFLAGS` / `ASFLAGS`
Options for the C preprocessor, C compiler, C++ compiler, Fortran compiler
and assembler. When used with suffix, the referred element is the source file,
not the target file.
\par `LDFLAGS`
Options for the linker ld.
\par `LIBS`
Additional libraries to link against (with -l).
\par `PRIVATE_LIBDIR`
Additional directories to search for libraries.
\par `CRT0` / `CRTN`
(expert use only) Files containing custom startup and finish code.
\par `LDSCRIPT`
(expert use only) Custom link script to use.
*/
/** \page bid_role_include include.mk - Header File Role
The header file role is responsible for installing header file at the
appropriate location. The following variables can be used for customizing
the process:
\par `INCSRC_DIR`
Source directory where the headers can be found. Default is the directory
where the Makefile resides.
\par `TARGET`
List of header files to install. If left undefined, then `INCSRC_DIR` will
be scanned for files with suffix `.h` or `.i`.
Supports the specification of special filenames to allow for different source
and target filenames to be installed. The syntax is `TARGET<SRC`, where a
filename including the path of `SRC` is installed as `TARGET`. An example is
`libfoo.h<contrib/libfoo_linux.h`
which installs the header from the contrib directory under the name without that
contrib directory and without the platform specific suffix.
\par `EXTRA_TARGET`
When TARGET is undefined, then add these files to the headers found by
scanning the source directory. Has no effect if `TARGET` has been defined.
The filenames specified allow for the same rule specifications as supported by
`TARGET`.
\par `CONTRIB_HEADERS`
When set, the headers will be installed in
`${BUILDDIR}/include/contrib/${PKGNAME}`
rather than `${BUILDDIR}/include/l4/${PKGNAME}`.
\par `INSTALL_INC_PREFIX`
Base directory where to install the headers. Overwrites `CONTRIB_HEADERS`.
The headers will then be found under
`${BUILDDIR}/include/${INSTALL_INC_PREFIX}`.
\par `PC_FILENAME`
When set, a pkg_config configuration file is created with the given name.
*/
/** \page bid_role_test test.mk - Test Application Role
The test role is very similar to the application role, it also builds an
executable binary. The difference is that is also builds for each target
a test script that executes the test target either on the host (MODE=host)
or a target platform (currently only qemu).
The role accepts all make variables that are accepted by the
application role. The only difference
is that the `TARGET` variable is not required. If it is missing, the
source directory will be scanned for source files that fit the pattern
`test_*.c[c]` and create one target for each of them.
\note It is possible to still use SRC_C[C] when targets are determined
automatically. In that case the specified sources will be used
*in addition* to the main `test_*.c[c]` source.
In addition to the variables above, there are a number of variables that
control how the test is executed. All these variables may be used as
a global variable that applies to all test or, if the target name is
added as a suffix, set for a specific target only.
\par `TEST_TARGET`
Name of binary containing the test (default: same as `TARGET`).
\par `TARGET_$(ARCH)`
When TARGET is undefined, these targets are added to the list of targets for
the specified architecture. For all targets `SRC_C[C]` files must be
defined separately.
\par `TEST_KERNEL_ARGS`
Arguments to append to the kernel command line. These are also appended when
specifying custom ones via a .t-file's -f parameter or when using -d.
\par `TEST_EXPECTED`
File containing expected output.
By default the variable is empty, which means the test binary
is expected to produce TAP test output, that can be directly
processed.
When the `TEST_TAP_PLUGINS` variable is given, `TEST_EXPECTED` is ignored.
\par `TEST_EXPECTED_REPEAT`
Number of times the expected output should be repeated, by default 1.
When set to 0 then output is expected to repeat forever. This is particularly
useful to make sure that stress tests that are meant to run in an endless
loop are still alive. Note that such endless tests can only be run by
directly executing the test script. They will be skipped when run in a
test harness like `prove`.
\par `TEST_TAP_PLUGINS`
Specify the plugins that are used to process the output of the test run.
The syntax is of the values is:
plugin1:arg1=a,arg2=b plugin2:arg=foo
Multiple plugins separated by a space are loaded in order. Spaces are not
allowed inside a plugin specification. One or more arguments are optionally
passed to the plugin separated by commas and delimited by a colon.
If the variable is not specified the plugins for TAPOutput and OutputMatching
(depending on the TEST_EXPECTED variable) are automatically loaded.
For the supported plugins and their options please refer to their in-line
documentation in tool/lib/L4/TapWrapper/Plugin/. The plugin name corresponds to
the file stem name in that directory.
\par `TEST_TIMEOUT`
Non-standard timeout after which the test run is aborted
(useful for tests involving sleep).
\par `NED_CFG`
LUA configuration file for startup to give to Ned
\par `REQUIRED_MODULES`
Additional modules needed to run the test. By adding `[opts]` to the name of a
module you can add module options that are reflected in the generated
modules.list.
\par `BOOTSTRAP_ARGS`
Additional parameters to supply to bootstrap.
\par `QEMU_ARGS`
Additional parameters to supply to QEMU.
\par `MOE_ARGS`
Additional parameters to supply to moe.
\par `TEST_ARGS`
Additional arguments for the `TEST_STARTER` (tapper-wrapper per default).
\par `TEST_ROOT_TASK`
Alternative root task to be used during a test instead of moe.
\par `TEST_ROOT_TASK_ARGS`
Arguments passed to `TEST_ROOT_TASK` if `TEST_ROOT_TASK` is different from moe.
\par `KERNEL_CONF`
Features the L4Re Microkernel must have been compiled with.
A space-separated list of config options as used by
Kconfig. `run_test` looks for a `globalconfig.out` file
in the same directory as the kernel and checks that all
options are enabled. If not, the test is skipped.
Has only an effect if the `globalconfig.out` file is present.
\par `L4RE_CONF`
Features the L4Re userland must have been compiled with. A
space-separated list of config options as used by Kconfig. `run_test`
will look for these in the `.kconfig` file in the L4Re build
directory.
\par `L4LINUX_CONF`
Features the L4Linux kernel must have been compiled with.
Similar to `KERNEL_CONF` but checks for a `.config` file
in the directory of the L4Linux kernel.
\par `TEST_SETUP`
Command to execute before the test is run.
The test will only be executed if the command returns 0.
If the exit code is 69, the test is marked as skipped
with the reason provided in the final line of stdout.
\par `TEST_LOGFILE`
Append output of test execution to the given file unless
TEST_WORKDIR is given.
\par `TEST_WORKDIR`
Create logs, temp and other files below the given directory. That
directory is taken as base dir for more automatically created subdir
levels using the current test path, in order to guarantee conflict-free
usage when running many different tests with a common workdir. When
TEST_WORKDIR is provided then TEST_LOGFILE is ignored as it is
organized below workdir.
\par `TEST_TAGS`
\parblock
List of conditions for tags provided during execution of a test. A tag
can be set to 1, set to 0 or be unspecified via TEST_RUN_TAGS during
execution. Therefore there are 4 possible conditions for a tag that can
be specified in TEST_TAGS: tag, !tag, +tag and -tag. The following table
shows the conditions they represent.
|TEST_RUN_TAGS \ TEST_TAGS | tag | !tag | +tag | -tag|
|--------------------------|-----|------|------|-----|
|tag or tag=1 | y | | y | |
|unspecified | | y | y | |
|tag=0 | | y | | y|
_Example usage:_
The tag `long-running` is used by tests which take a long time and should
be skipped by default. These tests are marked with the tag long-running
unprefixed.
The tag `hardware` is set to 1 at runtime when the tests will run on real
hardware. Tests that must not run on real hardware are marked with
`!hardware`.
The tag `+impl-def` is used by tests that test implementation details.
Due to the nature of this flag we require the "+" prefix to be used, so
they are run by default but can be excluded from execution by setting
TEST_RUN_TAGS to impl-def=0 at runtime.
If you want to specify multiple tag conditions they need to be separated
with a comma.
\endparblock
\par `TEST_PLATFORM_ALLOW` and `TEST_PLATFORM_DENY`
\parblock
Deny and allow lists of platforms a test is banned from or limited to.
If you list platforms in the TEST_PLATFORM_ALLOW variable the test will
only be run on these listed platforms and will be skipped on any other
platform. If you list platforms in the TEST_PLATFORM_DENY variable the
test will be skipped on the listed platforms and will be run on any other
platform. You can only use one of these variables per test, not both.
See mk/platforms/ for the various identifiers.
_Example usage:_
# Do not run this test on the Raspberry Pi platform
TEST_PLATFORM_DENY_test_xyz := rpi
# Only run this test on this test on the RCar3 platform.
TEST_PLATFORM_ALLOW_test_abc := rcar3
\endparblock
\par `TAPARCHIVE`
Filename for an archive file to store the resulting TAP output.
In addition to compiled tests, it is also possible to create tests
where the test binary or script comes from a different source. These
tests must be listed in `EXTRA_TARGET` and for each target a
custom `TEST_TARGET` must be provided.
Running Tests
-------------
The make role creates a test script which can be found in
`<builddir>/test/t/<arch>/<api>`. It is possible to organise
the tests further in subdirectories below by specifying a
TEST_GROUP.
To be able to execute the test, a minimal test environment needs
to be set up by exporting the following environment variables:
\par `KERNEL_<arch>`, `KERNEL`
L4Re Microkernel binary to use. The test runner is able to check if the
kernel has all features necessary for the test and skip tests accordingly.
In order for this to work, the `globalconfig.out` config file from the
build directory needs to be available in the same directory as the
kernel.
\par `L4LX_KERNEL_<arch>`, `L4LX_KERNEL`
L4Linux binary to use. This is only required to run tests in
`mode=l4linux`. If no L4Linux kernel is set then these tests
will simply be skipped.
The test runner is also able to check if the kernel has all features
compiled in that are required to run the test successfully (see make
variable `L4LINUX_CONF` above). For this to work, the `.config` configuration
file from the build directory needs to be available in the same
directory as the kernel.
\par `LINUX_RAMDISK_<arch>`, `LINUX_RAMDISK`
Ramdisk to mount as root in L4Linux. This is only required to run tests in
`mode=l4linux`. If not supplied, L4Linux tests will be skipped.
The ramdisk must be set up to start the test directly after the
initial startup is finished. The name of the test binary is supplied
via the kernel command line option `l4re_testprog`. The `tool/test`
directory contains an example script `launch-l4linux-test`. which can
be copied onto the ramdisk and started by the init script.
\par `TEST_HWCONFIG` and `TEST_FIASCOCONFIG`
\parblock
Some userland tests rely on external information about the underlying platform
and the configuration of the L4Re Microkernel to decide whether or not to test
specific features or to determine which and how much resources are available.
Some examples for this are whether or not virtualization is supported by the
platform, how many cores the platform has, how many cores the kernel supports or
how much memory the platform provides. To convey this information to these tests
you can set the two environment variables `TEST_HWCONFIG` and
`TEST_FIASCOCONFIG`.
Using `TEST_HWCONFIG` requires a plain text document containing key-value
pairs separated by a `=` symbol. On top of that comment lines starting with `#`
are supported. Simply create a plain text file such as the following and set
`TEST_HWCONFIG` to its absolute path.
VIRTUALIZATION=y
MP=y
NUM_CORES=4
MEMORY=2048
Using `TEST_FIASCOCONFIG` is easier since it only needs to contain the absolute
path of the globalconfig.out file in the L4Re Microkernel's build directory. The
build system will then extract the information when a test is started.
When starting a test the build system will read both files and provide their
content as a lua table to the test. A ned script can then make decisions based
on them. To simplify some decisions the build system merges some information by
itself, e.g. virtualization is only available if both the platform and the L4Re
Microkernel support this feature. More details can be obtain from the perl
module in `tool/lib/L4/TestEnvLua.pm`.
\endparblock
In addition to these variables, the following BID variables can be
overwritten at runtime: `PT` (for the plaform type) and `TEST_TIMEOUT`.
You may also supply `QEMU_ARGS` and `MOE_ARGS` which will be appended
to the parameters specified in the BID test make file.
Once the environment is set up, the tests can be run either by simply
executing all of them from the build directory with
make test
or executing them directly, like
test/t/amd64_amdfam10/l4f/l4re-core/moe/test_namespace.t
or running one or more tests through the test harness
[prove](http://perldoc.perl.org/prove.html), like
prove test/t/amd64_amdfam10/l4f/l4re-core/moe/test_namespace.t
prove -r test/t/amd64_amdfam10/l4f/l4re-core/
prove -rv test/t/amd64_amdfam10/l4f/l4re-core/
TEST_TAGS allow for a way to include or exclude whole groups of tests
during execution, primarily with prove. You can specify which tests to
run at runtime using one of the following ways:
$ test/t/amd64_amdfam10/l4f/l4re-core/test_one.t --run-tags slow,gtest-shuffle=0
$ test/t/amd64_amdfam10/l4f/l4re-core/test_one.t -T slow,gtest-shuffle=0
$ prove -r test/t/amd64_amdfam10/l4f/l4re-core/ :: -T slow,gtest-shuffle=0
$ TEST_RUN_TAGS=slow,gtest-shuffle=0 prove -r test/t/amd64_amdfam10/l4f/l4re-core/
For each test tag requirements defined in the corresponding TEST_TAGS
Makefile variable are tested. If the requirements for tags do not match
the test is skipped. The SKIP message will provide insight why the test
was skipped:
$ make test
...
test/t/amd64_amdfam10/test_one.t .... ok
test/t/amd64_amdfam10/test_two.t .... skipped: Running this test requires tag slow to be set to 1.
test/t/amd64_amdfam10/test_three.t .. ok
When tags are provided, the tests requiring those tags are now also
executed while the tests that forbid them are skipped:
$ TEST_RUN_TAGS=slow,gtest-shuffle
$ make test
...
test/t/amd64_amdfam10/test_one.t .... ok
test/t/amd64_amdfam10/test_two.t .... ok
test/t/amd64_amdfam10/test_three.t .. skipped: Running this test requires tag gtest-shuffle to be set to 0 or not specified.
For further details on how values in TEST_TAGS and TEST_RUN_TAGS interact, see the help text for TEST_TAGS.
Running Tests in External Programs
----------------------------------
You can hand-over test execution to an external program by setting the
environment variable `EXTERNAL_TEST_STARTER` to the full path of that
program:
export EXTERNAL_TEST_STARTER=/path/to/external/test-starter
make test
\par `EXTERNAL_TEST_STARTER`
This variable is evaluated by `tool/bin/run_test` (the backend behind
`make test`) and contains the full path to the tool which actually
starts the test instead of the test itself.
The `EXTERNAL_TEST_STARTER` can be any program instead of the default
execution via `make qemu E=maketest`. Its output is taken by
`run_test` as the test output.
Usually it is just a bridge to prepare the test execution, e.g., it
could create the test as image and start that image via a simulator.
### Running Tests in a Simulator
Based on above mechanism there is a dedicated external test starter
`tool/bin/teststarter-image-telnet.pl` shipped in BID which assumes an
image to be started with another program which provides test execution
output on a network port.
This can be used to execute tests in a simulator, like this:
export EXTERNAL_TEST_STARTER=$L4RE_SRC/tool/bin/teststarter-image-telnet.pl
export SIMULATOR_START=/path/to/configured/simulator-exe
make test
After building the image and starting the simulator it contacts the
simulator via a network port (sometimes called "telnet" port) to
pass-through its execution output as its own output so it gets
captured by `run_test` as usual.
The following variables control `teststarter-image-telnet.pl`:
\par `SIMULATOR_START`
This points to the full path of the program that actually starts the
prepared test image. Most often this is the frontend script of your
simulator environment which is pre-configured so that it actually
works in the way that `teststarter-image-telnet.pl` expects from the
following settings.
\par `SIMULATOR_IMAGETYPE`
The image type to be generated via `make $SIMULATOR_IMAGETYPE
E=maketest`. Default is `elfimage`.
\par `SIMULATOR_HOST`
The simulator will be contacted via socket on that host to read its
output. Default is `localhost`.
\par `SIMULATOR_PORT`
The simulator will be contacted via socket on that port to read its
output. Default is `11111`.
\par `SIMULATOR_START_SLEEPTIME`
After starting the simulator it waits that many seconds before reading
from the port. Default is `1` (second).
Running tests without tapper-wrapper
------------------------------------
In case you want to replace the tapper-wrapper test starter, you can
replace the default one by setting the environment variable
`TEST_STARTER` to the path of your test starter. Then your test starter
can use the same environment which is normally set up for the default
starter, which includes environment variables provided by the build
system as well as the test itself. Among these are `SEARCHPATH`, `MODE`,
`ARCH`, `MOE_CFG`, `MOE_ARGS`, `TEST_TIMEOUT`, `TEST_TARGET`,
`TEST_EXPECTED`, `QEMU_ARGS` and many more.
Debugging Tests
---------------
The test script is only a thin wrapper that sets up the test
environment as it was defined in the make file and then executes
two scripts: `tapper-wrapper` and `run_test`.
The main work horse of the two is `tool/bin/run_test`. It collects
the necessary files and starts qemu to execute the test. This script
is always required.
There is then a second script wrapped around the test runner:
`tool/bin/tapper-wrapper`. This tool inspects the output of the test
runner and reformats it, so that it can be read by tools like `prove`.
If the test produces tap output, then the script scans for this output
and filters away all the debug output. If `TEST_EXPECTED` was defined,
then the script scans the output for the expected lines and prints a
suitable TAP message with success or failure. It also makes sure that
qemu is killed as soon as the test is finished.
There are a number of command-line parameters that allow to quickly
change test parameters for debugging purposes. Run the test with
'--help' for more information about available parameters.
*/

View File

@@ -0,0 +1,417 @@
// vi:ft=c
/**
\page l4re_concepts Programming for L4Re
This part of the documentation discusses the concept of microkernel-based
programming in more detail. You should already have a basic understanding
of the L4Re programming environment from the tutorial.
\todo All subpages need cleaning. Level of detail here?
- \subpage l4re_concepts_ipc
- \subpage l4re_concepts_abi
- \subpage l4re_concepts_naming
- \subpage l4re_concepts_mapping
- \subpage l4re_concepts_env_and_start
- \subpage l4re_concepts_ds_rm
- \subpage l4re_concepts_stdio
- \subpage l4re_concepts_memalloc
- \subpage l4re_concepts_apps_svr
- \subpage l4re_pthreads
- tasks and threads
- communication channels
- server loops
- \subpage l4_cxx_ipc_iface
- hardware access
- \subpage l4re_build_system
\page l4re_concepts_ds_rm Memory management - Data Spaces and the Region Map
\section l4re_concept_pagers User-level paging
Memory management in L4-based systems is done by user-level applications, the
role is usually called \em pager. Tasks can give other tasks full or
restricted access rights to parts of their own memory. The kernel offers means
to give access to memory in a secure way, often referred to as *memory* mapping.
The mapping mechanism allows one task to resolve page faults of another: A
thread usually has a pager assigned to it. When the thread causes a page fault,
the kernel sends an IPC message to the pager with information about the page
fault. The pager answers this IPC by either providing a backing page, or with an
error. The kernel will map the backing page into the address space of the
faulting thread's task.
These mechanisms can be used to construct a memory and paging hierarchy among
tasks. The root of the hierarchy is `sigma0`, which initially gets all
system resources and hands them out once on a first-come-first-served basis.
Memory resources can be mapped between tasks at a page-size granularity. This
size is predetermined by the CPU's memory management unit and is commonly set
to 4 kB.
\subsection l4re_concept_data_spaces Data spaces
A data space is the L4Re abstraction for objects which may be
accessed in a memory mapped fashion (i.e., using normal memory
read and write instructions). Examples include the sections of a
binary which the loader attaches to the application's address
space, files in the ROM or on disk provided by a file server, the
registers of memory-mapped devices and anonymous memory such as
the heap or the stack.
Anonymous memory data spaces in particular (but in general all
data spaces except memory mapped IO) can either be constructed
entirely from a portion of the RAM or the current working set may
be multiplexed on some portion of the RAM. In the first case it
is possible to eagerly insert all pages (more precisely
page-frame capabilities) into the application's address space
such that no further page faults occur when this data space is
accessed. In general, however, only the pages for some
portion are provided and further pages are inserted by the pager
as a result of page faults.
\subsection l4re_concept_regions Virtual Memory Handling
The virtual memory of each task is constructed from data spaces backing
virtual memory regions (VMRs). The management of the VMRs is provided by an
object called *region map*. A dedicated region-map object is associated
with each task; it allows attaching and detaching data spaces to an address space
as well as reserving areas of virtual memory. Since the region-map object
possesses all knowledge about the virtual memory layout of a task, it also serves
as an application's default pager.
\subsection l4re_concept_mem_alloc Memory Allocation
Operating systems commonly use anonymous memory for implementing dynamic
memory allocation (e.g., using `malloc` or `new`). In an
L4Re-based system, each task gets assigned a memory allocator providing
anonymous memory using data spaces.
\see L4Re::Dataspace and L4Re::Rm.
\page l4re_concepts_naming Capabilities and Naming
The L4Re system is a capability based system which uses and offers
capabilities to implement fine-grained access control.
Generally, owning a capability means to be allowed to communicate with the
object the capability points to. All user-visible kernel objects, such as
tasks, threads, and IRQs, can only be accessed through a capability.
Please refer to the \ref l4_kernel_object_api
documentation for details. Capabilities are stored in per-task capability
tables (the object space) and are referenced by capability selectors or
object flexpages. In a simplified view, a capability selector is a natural
number indexing into the capability table of the current task.
As a matter of fact, a system designed solely based on capabilities uses
so-called 'local names' because each task can only access those objects made
available to this task. Other objects are not visible to and accessible by the
task.
\image html l4-caps-basic.png "Capabilities and Local Naming in L4"
\image latex l4-caps-basic.pdf "Capabilities and Local Naming in L4
So how does an application get access to a service?
In general all applications are started with an initial set of available
objects. This set of objects is predetermined by the creator of a new
application process and granted directly to the new task before starting
the first application thread. The application can then use these initial objects
to request access to further objects or to transfer capabilities to its own objects
to other applications. A central L4Re object for exchanging capabilities at
runtime is the name-space object, implementing a store of named capabilities.
From a security perspective, the set of initial capabilities (access rights to
objects) completely define the execution environment of an application.
Mandatory security policies can be defined by well known properties of the
initial objects and carefully handled access rights to them.
\page l4re_concepts_mapping Spaces and Mappings
Each task in the L4Re system has access to two resource spaces (three on IA32)
which are maintained by the kernel. These are the
-# object space,
-# memory space, and
-# IO-port space (only on IA32).
The entities addressed in each space are capabilities to objects, virtual memory
pages, and IO ports. The addresses are unsigned integers and the largest valid
address depends on which space is referenced, the hardware, and the
configuration of the kernel. Although a program can access memory at byte
granularity, from the kernel's point of view the address granularity in the
memory space is not bytes but pages, as determined by the hardware. The address
of a capability is also called its "capability slot".
Flexpages describe a range in any of the spaces that has a power-of-two length
and is also aligned to this length. They additionally hold access rights
information and further space specific information.
When a resource is present at some address in a task's corresponding resource
space, then we say that resource is mapped to that task. For example, a
capability to the task's main thread may be mapped to capability slot 5, or the
first page of the code segment a thread executes is mapped to virtual memory
page 12345. However, there need not be any resource mapped to an address.
Tasks can exchange resources through a process called "mapping" during IPC and
using the L4::Task::map() method. The sending task specifies a send flexpage and
the receiving task a receive flexpage. The resources mapped to the send flexpage
will then be mapped to the receive flexpage by the kernel.
Memory mappings and IO port mappings are hierarchical: If a resource of such a
type is subject of a map operation, the received mapping is a child mapping of
the corresponding mapping in the sending task (parent mapping). The kernel
usually respects the relationship between these two mappings (granting is an
exception; see below): If rights of a parent mapping are revoked using
L4::Task::unmap(), these rights are also removed from its child mappings. Also,
if a mapping is completely removed (via L4::Task::unmap() or by mapping
something else at its place), then also all child mappings are removed. In
contrast, revoking rights of a child mapping leaves the rights of its parent
mapping untouched.
The mapping of a resource can be performed as \em grant operation (see
#L4_MAP_ITEM_GRANT): Such an operation includes the removal of all involved
mappings from the send flexpage (basically a move operation). While with a map
operation without grant the mapping in the send flexpage remains the parent of
all child mappings (including the new child mapping in the receive flexpage), a
grant operation moves the mappings covered by the send flexpage to the
corresponding addresses from the receive flexpage while leaving the
parent/child relationship of the moved mappings with other mappings untouched.
During a map operation at most the access rights of the source mapping(s) can
be transferred but no additional rights can be added. So only rights that are
present in the source mapping and that are specified in the send item/flexpage
are transferred. This also holds for grant mappings, however, rights revocation
is *not* guaranteed to be applied to descendant mappings in case of grant.
There are cases where a grant operation is not or cannot be performed as
requested; see #L4_MAP_ITEM_GRANT for details.
Object capabilities are not hierarchical -- they have no children. The result
of the map operation on an object capability is a copy of that capability in
the object space of the destination task.
\page l4re_concepts_env_and_start Initial Environment and Application Bootstrapping
New applications that are started by a loader conforming to L4Re get
provided an \ref api_l4re_env. This environment
comprises a set of capabilities to initial L4Re objects that are
required to bootstrap and run this application. These
capabilities include:
- A capability to an initial memory allocator for obtaining memory in the
form of data spaces
- A capability to a factory which can be used to create additional kernel
objects
- A capability to a Vcon object for debugging output and maybe input
- A set of named capabilities to application specific objects
During the bootstrapping of the application, the loader establishes data
spaces for each individual region in the ELF binary. These include data spaces
for the code and data sections, and a data space backed with RAM for the stack
of the program's first thread.
One loader implementation is the `moe` root task. Moe usually starts an *init*
process that is responsible for coordinating the further boot
process. The default *init* process is `ned`, which implements a
script-based configuration and startup of other processes. Ned uses Lua
(http://www.lua.org) as its scripting language, see \ref l4re_servers_ned
"Ned Script example" for more details.
\section l4re_ns_config Configuring an application before startup
The default L4Re init process (Ned) provides a Lua script based configuration
of initial capabilities and application startup. Ned itself also has a set of
initial objects available that can be used to create the environment for an
application. The most important object is a kernel object factory that allows
creation of kernel objects such as IPC gates (communication channels), tasks,
threads, etc. Ned uses Lua tables (associative arrays) to represent sets of
capabilities that shall be granted to application processes.
~~~
local caps = {
name = some_capability
}
~~~
The L4 Lua package in Ned also has support functions to create application
tasks, region-map objects, etc. to start an ELF binary in a new task.
The package also contains Lua bindings for basic L4Re objects, for example, to
generic factory objects, which are used to create kernel objects and also
user-level objects provided by user-level servers.
~~~
L4.default_loader:start({ caps = { some_service = service } }, "rom/program --arg");
~~~
\section l4re_config_connection Connecting clients and servers
In general, a connection between a client and a server is represented by a
communication channel (IPC gate) that is available to both of them.
You can see the simplest connection between a client and a server
in the following example.
~~~
local loader = L4.default_loader; -- which is Moe
local svc = loader:new_channel(); -- create an IPC gate
loader:start({ caps = { service = svc:svr() }}, "rom/my_server");
loader:start({ caps = { service = svc:m("rw") }}, "rom/my_client");
~~~
As you can see in the snippet, the first action is to create a new channel
(IPC gate) using `loader:new_channel()`. The capability to the gate is stored
in the variable `svc`. Then the binary `my_server` is started in a new task,
and full (`:svr()`) access to the IPC gate is granted to the server as initial
object. The gate is accessible to the server application as "service" in the set of
its initial capabilities. Virtually in parallel a second task, running the client
application, is started and also given access to the IPC gate with less rights
(`:m("rw")`, note, this is essential). The server can now receive messages via the
IPC gate and provide some service and the client can call operations on the IPC gate
to communicate with the server.
Services that keep client specific state need to implement per-client server
objects. Usually it is the responsibility of some authority (e.g., Ned) to
request such an object from the service via a generic factory object that the
service provides initially.
~~~
local loader = L4.default_loader; -- which is Moe
local svc = loader:new_channel():m("rws"); -- create an IPC gate with rws rights
loader:start({ caps = { service = svc:svr() } }, "rom/my-service");
loader:start({ caps = { foo_service = svc:create(object_to_create, "param") }}, "rom/client");
~~~
This example is quite similar to the first one, however, the difference is that
Ned itself calls the create method on the factory object provided by the server and
passes the returned capability of that request as "foo_service" to the client process.
\note The `svc:create(..)` call blocks on the server. This means the script execution
blocks until the my-service application handles the create request.
\page l4re_concepts_stdio Program Input and Output
The initial environment provides a Vcon capability used as the standard
input/output stream. Output is usually connected to the parent of the
program and displayed as debugging output. The standard output is also used
as a back end to the C-style printf functions and the C++ streams.
Vcon services are implemented in Moe and the loader as well as by the L4Re
Microkernel and connected either to the serial line or to the screen if
available.
\see \ref l4_vcon_api
\page l4re_concepts_memalloc Initial Memory Allocator and Factory
The purpose of the memory allocator and of the factory is to provide
the application with the means to allocate memory (in the form of data spaces)
and kernel objects respectively.
An initial memory allocator and an initial factory are accessible via the
initial L4Re environment.
\see L4Re::Mem_alloc
The factory is a kernel object that provides the ability to create new
kernel objects dynamically. A factory imposes a resource limit for
kernel memory, and is thus a means to prevent denial of service attacks on
kernel resources. A factory can also be used to create new factory objects.
\see \ref l4_factory_api
\page l4re_concepts_apps_svr Application and Server Building Blocks
So far we have discussed the environment of applications in which a single
thread runs and which may invoke services provided through their initial objects.
In the following we describe some building blocks to extend the
application in various dimensions and to eventually implement a server which
implements user-level objects that may in turn be accessed by other
applications and servers.
\section l4re_concepts_app_thread Creating Additional Application Threads
To create application threads, one must allocate a stack on which
this thread may execute, create a thread kernel object and setup
the information required at startup time (instruction pointer,
stack pointer, etc.). In L4Re this functionality is encapsulated in the
pthread library.
\section l4re_concepts_service Providing a Service
In capability systems, services are typically provided by
transferring a capability to those applications that are
authorised to access the object to which the capability refers to.
Let us discuss an example to illustrate how two parties can communicate with
each other:
Assume a simple file server, which implements an interface for accessing
individual files: read(pos, buf, length) and write(pos, data, length).
L4Re provides support for building servers based on the class
L4::Server_object. L4::Server_object provides an abstract interface to be
used with the L4::Server class. Specific server objects such as, in our
case, files inherit from L4::Server_object. Let us call this class
File_object. When invoked upon receiving a message, the L4::Server will
automatically identify the corresponding server object based on the
capability that has been provided to its clients and invoke this object's
\em dispatch function with the incoming message as a parameter. Based on
this message, the server must then decide which of the protocols it
implements was invoked (if any). Usually, it will evaluate a protocol
specific opcode that clients are required to transmit as one of the first
words in the message. For example, assume our server assigns the following
opcodes: Read = 0 and Write = 1. The `dispatch` function calls the
corresponding server function (i.e., `File_object::read()` or
`File_object::write()`), which will in turn parse additional
parameters given to the function. In our case, this would be the position
and the amount of data to be read or written. In case the write function was
called the server will now update the contents of the file with the data
supplied. In case of a read it will store the requested part of the file in
the message buffer. A reply to the client finishes the client request.
*/
/* This is some text we currently do not use:
\link api_l4re_dataspace Data spaces\endlink and the purpose of the \link
api_l4re_rm Region Map\endlink are explained in more detail in the following
section.
In the L4Re Microkernel capabilities are addressed in two different
ways.
A capability can be addressed with the help of a capability
descriptor \XXX Ref which identifies the position of one single
capability in the application's address space.
The second means to address a bunch of capabilities at once are
flexpages. A flexpage describes a region of the application's
address space that is of a power 2 size and size aligned. Thus
the name flexpage. When capabilities are to be transferred (see
IPC / MapItem) the flexpage declared by the sender --- the send
flexpage --- specifies which capabilities are to be transferred.
These are at most those capabilities that are located within the
region described by the flexpage and precisely those in the
region that results from adjusting the flexpage with a possibly
smaller flexpage on the receiver side (see \XXX for more details
on how sender and receiver declared flexpages are adjusted). The
receiver declared flexpage --- the receive flexpage --- defines
where in the address space of the application capabilities are to
be received.
The key insight here is that applications are able to restrict
an invoked server such that it can only modify a part of the
applications address space --- the receive flexpage.
When invoking servers and when creating new objects one is faced
with the task to find not yet used parts in the address space of
the application at which the kernel or other servers may insert
capabilities. L4Re assists this task with the help of a capability
allocator.
*/

View File

@@ -0,0 +1,157 @@
/**
Doxygen Awesome
https://github.com/jothepro/doxygen-awesome-css
MIT License
Copyright (c) 2021 - 2023 jothepro
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
class DoxygenAwesomeDarkModeToggle extends HTMLElement {
// SVG icons from https://fonts.google.com/icons
// Licensed under the Apache 2.0 license:
// https://www.apache.org/licenses/LICENSE-2.0.html
static lightModeIcon = `<svg xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 24 24" height="24px" viewBox="0 0 24 24" width="24px" fill="#FCBF00"><rect fill="none" height="24" width="24"/><circle cx="12" cy="12" opacity=".3" r="3"/><path d="M12,9c1.65,0,3,1.35,3,3s-1.35,3-3,3s-3-1.35-3-3S10.35,9,12,9 M12,7c-2.76,0-5,2.24-5,5s2.24,5,5,5s5-2.24,5-5 S14.76,7,12,7L12,7z M2,13l2,0c0.55,0,1-0.45,1-1s-0.45-1-1-1l-2,0c-0.55,0-1,0.45-1,1S1.45,13,2,13z M20,13l2,0c0.55,0,1-0.45,1-1 s-0.45-1-1-1l-2,0c-0.55,0-1,0.45-1,1S19.45,13,20,13z M11,2v2c0,0.55,0.45,1,1,1s1-0.45,1-1V2c0-0.55-0.45-1-1-1S11,1.45,11,2z M11,20v2c0,0.55,0.45,1,1,1s1-0.45,1-1v-2c0-0.55-0.45-1-1-1C11.45,19,11,19.45,11,20z M5.99,4.58c-0.39-0.39-1.03-0.39-1.41,0 c-0.39,0.39-0.39,1.03,0,1.41l1.06,1.06c0.39,0.39,1.03,0.39,1.41,0s0.39-1.03,0-1.41L5.99,4.58z M18.36,16.95 c-0.39-0.39-1.03-0.39-1.41,0c-0.39,0.39-0.39,1.03,0,1.41l1.06,1.06c0.39,0.39,1.03,0.39,1.41,0c0.39-0.39,0.39-1.03,0-1.41 L18.36,16.95z M19.42,5.99c0.39-0.39,0.39-1.03,0-1.41c-0.39-0.39-1.03-0.39-1.41,0l-1.06,1.06c-0.39,0.39-0.39,1.03,0,1.41 s1.03,0.39,1.41,0L19.42,5.99z M7.05,18.36c0.39-0.39,0.39-1.03,0-1.41c-0.39-0.39-1.03-0.39-1.41,0l-1.06,1.06 c-0.39,0.39-0.39,1.03,0,1.41s1.03,0.39,1.41,0L7.05,18.36z"/></svg>`
static darkModeIcon = `<svg xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 24 24" height="24px" viewBox="0 0 24 24" width="24px" fill="#FE9700"><rect fill="none" height="24" width="24"/><path d="M9.37,5.51C9.19,6.15,9.1,6.82,9.1,7.5c0,4.08,3.32,7.4,7.4,7.4c0.68,0,1.35-0.09,1.99-0.27 C17.45,17.19,14.93,19,12,19c-3.86,0-7-3.14-7-7C5,9.07,6.81,6.55,9.37,5.51z" opacity=".3"/><path d="M9.37,5.51C9.19,6.15,9.1,6.82,9.1,7.5c0,4.08,3.32,7.4,7.4,7.4c0.68,0,1.35-0.09,1.99-0.27C17.45,17.19,14.93,19,12,19 c-3.86,0-7-3.14-7-7C5,9.07,6.81,6.55,9.37,5.51z M12,3c-4.97,0-9,4.03-9,9s4.03,9,9,9s9-4.03,9-9c0-0.46-0.04-0.92-0.1-1.36 c-0.98,1.37-2.58,2.26-4.4,2.26c-2.98,0-5.4-2.42-5.4-5.4c0-1.81,0.89-3.42,2.26-4.4C12.92,3.04,12.46,3,12,3L12,3z"/></svg>`
static title = "Toggle Light/Dark Mode"
static prefersLightModeInDarkModeKey = "prefers-light-mode-in-dark-mode"
static prefersDarkModeInLightModeKey = "prefers-dark-mode-in-light-mode"
static _staticConstructor = function() {
DoxygenAwesomeDarkModeToggle.enableDarkMode(DoxygenAwesomeDarkModeToggle.userPreference)
// Update the color scheme when the browsers preference changes
// without user interaction on the website.
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', event => {
DoxygenAwesomeDarkModeToggle.onSystemPreferenceChanged()
})
// Update the color scheme when the tab is made visible again.
// It is possible that the appearance was changed in another tab
// while this tab was in the background.
document.addEventListener("visibilitychange", visibilityState => {
if (document.visibilityState === 'visible') {
DoxygenAwesomeDarkModeToggle.onSystemPreferenceChanged()
}
});
}()
static init() {
$(function() {
$(document).ready(function() {
const toggleButton = document.createElement('doxygen-awesome-dark-mode-toggle')
toggleButton.title = DoxygenAwesomeDarkModeToggle.title
toggleButton.updateIcon()
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', event => {
toggleButton.updateIcon()
})
document.addEventListener("visibilitychange", visibilityState => {
if (document.visibilityState === 'visible') {
toggleButton.updateIcon()
}
});
$(document).ready(function(){
document.getElementById("MSearchBox").parentNode.appendChild(toggleButton)
})
$(window).resize(function(){
document.getElementById("MSearchBox").parentNode.appendChild(toggleButton)
})
})
})
}
constructor() {
super();
this.onclick=this.toggleDarkMode
}
/**
* @returns `true` for dark-mode, `false` for light-mode system preference
*/
static get systemPreference() {
return window.matchMedia('(prefers-color-scheme: dark)').matches
}
/**
* @returns `true` for dark-mode, `false` for light-mode user preference
*/
static get userPreference() {
return (!DoxygenAwesomeDarkModeToggle.systemPreference && localStorage.getItem(DoxygenAwesomeDarkModeToggle.prefersDarkModeInLightModeKey)) ||
(DoxygenAwesomeDarkModeToggle.systemPreference && !localStorage.getItem(DoxygenAwesomeDarkModeToggle.prefersLightModeInDarkModeKey))
}
static set userPreference(userPreference) {
DoxygenAwesomeDarkModeToggle.darkModeEnabled = userPreference
if(!userPreference) {
if(DoxygenAwesomeDarkModeToggle.systemPreference) {
localStorage.setItem(DoxygenAwesomeDarkModeToggle.prefersLightModeInDarkModeKey, true)
} else {
localStorage.removeItem(DoxygenAwesomeDarkModeToggle.prefersDarkModeInLightModeKey)
}
} else {
if(!DoxygenAwesomeDarkModeToggle.systemPreference) {
localStorage.setItem(DoxygenAwesomeDarkModeToggle.prefersDarkModeInLightModeKey, true)
} else {
localStorage.removeItem(DoxygenAwesomeDarkModeToggle.prefersLightModeInDarkModeKey)
}
}
DoxygenAwesomeDarkModeToggle.onUserPreferenceChanged()
}
static enableDarkMode(enable) {
if(enable) {
DoxygenAwesomeDarkModeToggle.darkModeEnabled = true
document.documentElement.classList.add("dark-mode")
document.documentElement.classList.remove("light-mode")
} else {
DoxygenAwesomeDarkModeToggle.darkModeEnabled = false
document.documentElement.classList.remove("dark-mode")
document.documentElement.classList.add("light-mode")
}
}
static onSystemPreferenceChanged() {
DoxygenAwesomeDarkModeToggle.darkModeEnabled = DoxygenAwesomeDarkModeToggle.userPreference
DoxygenAwesomeDarkModeToggle.enableDarkMode(DoxygenAwesomeDarkModeToggle.darkModeEnabled)
}
static onUserPreferenceChanged() {
DoxygenAwesomeDarkModeToggle.enableDarkMode(DoxygenAwesomeDarkModeToggle.darkModeEnabled)
}
toggleDarkMode() {
DoxygenAwesomeDarkModeToggle.userPreference = !DoxygenAwesomeDarkModeToggle.userPreference
this.updateIcon()
}
updateIcon() {
if(DoxygenAwesomeDarkModeToggle.darkModeEnabled) {
this.innerHTML = DoxygenAwesomeDarkModeToggle.darkModeIcon
} else {
this.innerHTML = DoxygenAwesomeDarkModeToggle.lightModeIcon
}
}
}
customElements.define("doxygen-awesome-dark-mode-toggle", DoxygenAwesomeDarkModeToggle);

View File

@@ -0,0 +1,85 @@
/**
Doxygen Awesome
https://github.com/jothepro/doxygen-awesome-css
MIT License
Copyright (c) 2022 - 2023 jothepro
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
class DoxygenAwesomeFragmentCopyButton extends HTMLElement {
constructor() {
super();
this.onclick=this.copyContent
}
static title = "Copy to clipboard"
static copyIcon = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><path d="M0 0h24v24H0V0z" fill="none"/><path d="M16 1H4c-1.1 0-2 .9-2 2v14h2V3h12V1zm3 4H8c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h11c1.1 0 2-.9 2-2V7c0-1.1-.9-2-2-2zm0 16H8V7h11v14z"/></svg>`
static successIcon = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><path d="M0 0h24v24H0V0z" fill="none"/><path d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41L9 16.17z"/></svg>`
static successDuration = 980
static init() {
$(function() {
$(document).ready(function() {
if(navigator.clipboard) {
const fragments = document.getElementsByClassName("fragment")
for(const fragment of fragments) {
const fragmentWrapper = document.createElement("div")
fragmentWrapper.className = "doxygen-awesome-fragment-wrapper"
const fragmentCopyButton = document.createElement("doxygen-awesome-fragment-copy-button")
fragmentCopyButton.innerHTML = DoxygenAwesomeFragmentCopyButton.copyIcon
fragmentCopyButton.title = DoxygenAwesomeFragmentCopyButton.title
fragment.parentNode.replaceChild(fragmentWrapper, fragment)
fragmentWrapper.appendChild(fragment)
fragmentWrapper.appendChild(fragmentCopyButton)
}
}
})
})
}
copyContent() {
const content = this.previousSibling.cloneNode(true)
// filter out line number from file listings
content.querySelectorAll(".lineno, .ttc").forEach((node) => {
node.remove()
})
let textContent = content.textContent
// remove trailing newlines that appear in file listings
let numberOfTrailingNewlines = 0
while(textContent.charAt(textContent.length - (numberOfTrailingNewlines + 1)) == '\n') {
numberOfTrailingNewlines++;
}
textContent = textContent.substring(0, textContent.length - numberOfTrailingNewlines)
navigator.clipboard.writeText(textContent);
this.classList.add("success")
this.innerHTML = DoxygenAwesomeFragmentCopyButton.successIcon
window.setTimeout(() => {
this.classList.remove("success")
this.innerHTML = DoxygenAwesomeFragmentCopyButton.copyIcon
}, DoxygenAwesomeFragmentCopyButton.successDuration);
}
}
customElements.define("doxygen-awesome-fragment-copy-button", DoxygenAwesomeFragmentCopyButton)

View File

@@ -0,0 +1,81 @@
/**
Doxygen Awesome
https://github.com/jothepro/doxygen-awesome-css
MIT License
Copyright (c) 2022 - 2023 jothepro
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
class DoxygenAwesomeInteractiveToc {
static topOffset = 38
static hideMobileMenu = true
static headers = []
static init() {
window.addEventListener("load", () => {
let toc = document.querySelector(".contents > .toc")
if(toc) {
toc.classList.add("interactive")
if(!DoxygenAwesomeInteractiveToc.hideMobileMenu) {
toc.classList.add("open")
}
document.querySelector(".contents > .toc > h3")?.addEventListener("click", () => {
if(toc.classList.contains("open")) {
toc.classList.remove("open")
} else {
toc.classList.add("open")
}
})
document.querySelectorAll(".contents > .toc > ul a").forEach((node) => {
let id = node.getAttribute("href").substring(1)
DoxygenAwesomeInteractiveToc.headers.push({
node: node,
headerNode: document.getElementById(id)
})
document.getElementById("doc-content")?.addEventListener("scroll", () => {
DoxygenAwesomeInteractiveToc.update()
})
})
DoxygenAwesomeInteractiveToc.update()
}
})
}
static update() {
let active = DoxygenAwesomeInteractiveToc.headers[0]?.node
DoxygenAwesomeInteractiveToc.headers.forEach((header) => {
let position = header.headerNode.getBoundingClientRect().top
header.node.classList.remove("active")
header.node.classList.remove("aboveActive")
if(position < DoxygenAwesomeInteractiveToc.topOffset) {
active = header.node
active?.classList.add("aboveActive")
}
})
active?.classList.add("active")
active?.classList.remove("aboveActive")
}
}

View File

@@ -0,0 +1,51 @@
/**
Doxygen Awesome
https://github.com/jothepro/doxygen-awesome-css
MIT License
Copyright (c) 2022 - 2023 jothepro
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
class DoxygenAwesomeParagraphLink {
// Icon from https://fonts.google.com/icons
// Licensed under the Apache 2.0 license:
// https://www.apache.org/licenses/LICENSE-2.0.html
static icon = `<svg xmlns="http://www.w3.org/2000/svg" height="20px" viewBox="0 0 24 24" width="20px"><path d="M0 0h24v24H0V0z" fill="none"/><path d="M17 7h-4v2h4c1.65 0 3 1.35 3 3s-1.35 3-3 3h-4v2h4c2.76 0 5-2.24 5-5s-2.24-5-5-5zm-6 8H7c-1.65 0-3-1.35-3-3s1.35-3 3-3h4V7H7c-2.76 0-5 2.24-5 5s2.24 5 5 5h4v-2zm-3-4h8v2H8z"/></svg>`
static title = "Permanent Link"
static init() {
$(function() {
$(document).ready(function() {
document.querySelectorAll(".contents a.anchor[id], .contents .groupheader > a[id]").forEach((node) => {
let anchorlink = document.createElement("a")
anchorlink.setAttribute("href", `#${node.getAttribute("id")}`)
anchorlink.setAttribute("title", DoxygenAwesomeParagraphLink.title)
anchorlink.classList.add("anchorlink")
node.classList.add("anchor")
anchorlink.innerHTML = DoxygenAwesomeParagraphLink.icon
node.parentElement.appendChild(anchorlink)
})
})
})
}
}

View File

@@ -0,0 +1,40 @@
/**
Doxygen Awesome
https://github.com/jothepro/doxygen-awesome-css
MIT License
Copyright (c) 2021 - 2023 jothepro
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
@media screen and (min-width: 768px) {
#MSearchBox {
width: calc(var(--side-nav-fixed-width) - calc(2 * var(--spacing-medium)) - var(--searchbar-height) - 1px);
}
#MSearchField {
width: calc(var(--side-nav-fixed-width) - calc(2 * var(--spacing-medium)) - 66px - var(--searchbar-height));
}
}

View File

@@ -0,0 +1,116 @@
/**
Doxygen Awesome
https://github.com/jothepro/doxygen-awesome-css
MIT License
Copyright (c) 2021 - 2023 jothepro
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
html {
/* side nav width. MUST be = `TREEVIEW_WIDTH`.
* Make sure it is wide enough to contain the page title (logo + title + version)
*/
--side-nav-fixed-width: 335px;
--menu-display: none;
--top-height: 120px;
--toc-sticky-top: -25px;
--toc-max-height: calc(100vh - 2 * var(--spacing-medium) - 25px);
}
#projectname {
white-space: nowrap;
}
@media screen and (min-width: 768px) {
html {
--searchbar-background: var(--page-background-color);
}
#side-nav {
min-width: var(--side-nav-fixed-width);
max-width: var(--side-nav-fixed-width);
top: var(--top-height);
overflow: visible;
}
#nav-tree, #side-nav {
height: calc(100vh - var(--top-height)) !important;
}
#nav-tree {
padding: 0;
}
#top {
display: block;
border-bottom: none;
height: var(--top-height);
margin-bottom: calc(0px - var(--top-height));
max-width: var(--side-nav-fixed-width);
overflow: hidden;
background: var(--side-nav-background);
}
#main-nav {
float: left;
padding-right: 0;
}
.ui-resizable-handle {
cursor: default;
width: 1px !important;
background: var(--separator-color);
box-shadow: 0 calc(-2 * var(--top-height)) 0 0 var(--separator-color);
}
#nav-path {
position: fixed;
right: 0;
left: var(--side-nav-fixed-width);
bottom: 0;
width: auto;
}
#doc-content {
height: calc(100vh - 31px) !important;
padding-bottom: calc(3 * var(--spacing-large));
padding-top: calc(var(--top-height) - 80px);
box-sizing: border-box;
margin-left: var(--side-nav-fixed-width) !important;
}
#MSearchBox {
width: calc(var(--side-nav-fixed-width) - calc(2 * var(--spacing-medium)));
}
#MSearchField {
width: calc(var(--side-nav-fixed-width) - calc(2 * var(--spacing-medium)) - 65px);
}
#MSearchResultsWindow {
left: var(--spacing-medium) !important;
right: auto;
}
}

View File

@@ -0,0 +1,90 @@
/**
Doxygen Awesome
https://github.com/jothepro/doxygen-awesome-css
MIT License
Copyright (c) 2023 jothepro
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
class DoxygenAwesomeTabs {
static init() {
window.addEventListener("load", () => {
document.querySelectorAll(".tabbed:not(:empty)").forEach((tabbed, tabbedIndex) => {
let tabLinkList = []
tabbed.querySelectorAll(":scope > ul > li").forEach((tab, tabIndex) => {
tab.id = "tab_" + tabbedIndex + "_" + tabIndex
let header = tab.querySelector(".tab-title")
let tabLink = document.createElement("button")
tabLink.classList.add("tab-button")
tabLink.appendChild(header)
header.title = header.textContent
tabLink.addEventListener("click", () => {
tabbed.querySelectorAll(":scope > ul > li").forEach((tab) => {
tab.classList.remove("selected")
})
tabLinkList.forEach((tabLink) => {
tabLink.classList.remove("active")
})
tab.classList.add("selected")
tabLink.classList.add("active")
})
tabLinkList.push(tabLink)
if(tabIndex == 0) {
tab.classList.add("selected")
tabLink.classList.add("active")
}
})
let tabsOverview = document.createElement("div")
tabsOverview.classList.add("tabs-overview")
let tabsOverviewContainer = document.createElement("div")
tabsOverviewContainer.classList.add("tabs-overview-container")
tabLinkList.forEach((tabLink) => {
tabsOverview.appendChild(tabLink)
})
tabsOverviewContainer.appendChild(tabsOverview)
tabbed.before(tabsOverviewContainer)
function resize() {
let maxTabHeight = 0
tabbed.querySelectorAll(":scope > ul > li").forEach((tab, tabIndex) => {
let visibility = tab.style.display
tab.style.display = "block"
maxTabHeight = Math.max(tab.offsetHeight, maxTabHeight)
tab.style.display = visibility
})
tabbed.style.height = `${maxTabHeight + 10}px`
}
resize()
new ResizeObserver(resize).observe(tabbed)
})
})
}
static resize(tabbed) {
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,23 @@
INKSCAPE ?= inkscape
PNGWIDTH ?= 640
PNGOPTS ?= --export-area-drawing
PDFOPTS ?= --export-text-to-path
IMAGES := l4-caps-basic l4re-basic io-overview
SVG_PATH ?= ../../../../doc/l4-clipart
vpath %.svg $(SVG_PATH)
PDF_IMAGES := $(addsuffix .pdf,$(IMAGES))
PNG_IMAGES := $(addsuffix .png,$(IMAGES))
all: $(PDF_IMAGES) $(PNG_IMAGES)
%.png: %.svg
$(INKSCAPE) $(PNGOPTS) --export-width=$(PNGWIDTH) --export-png=$@ -f $<
%.pdf: %.svg
$(INKSCAPE) $(PDFOPTS) -A $@ -f $<

Binary file not shown.

After

Width:  |  Height:  |  Size: 715 B

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

165
src/l4/doc/source/intro.dox Normal file
View File

@@ -0,0 +1,165 @@
// vi:set ft=c: -*- Mode: C -*-
/**
\mainpage Overview
Welcome to the documentation of the %L4Re Operating System Framework, or %L4Re
for short. There are two parts to this documentation: a user manual, which
provides a birds eye view of %L4Re and its environment, and a reference
section which documents the complete programming API.
### User Manual #####
1. \ref l4re_intro shortly explains the concept of microkernels and
introduces the basic terminology.
2. \ref l4re_tutorial helps you getting started with setting up
the development environment and writing your own first %L4Re application.
3. \ref l4re_concepts explains in detail the most important
programming concepts.
4. \ref l4re_servers provides a quick overview over standard services running
on the %L4Re operating system.
### Reference #####
The second part provides the complete reference of all classes and functions
of the %L4Re Operating System Framework as well as a list of example code.
*/
/**
\page l4re_intro Introduction
The intention of this section is to provide a short overview about the
L4Re Operating System Framework. The general structure of a
microkernel-based system will be introduced and the principal functionality
of the servers in the basic environment outlined.
\section fiasco_intro L4Re Microkernel
The L4Re Microkernel is the lowest-level component of software running in an
L4Re-based system. The microkernel is the only component that runs in privileged
processor mode. It does not include complex services such as program loading,
device drivers, or file systems; those are implemented in user-level programs on
top of it (a basic set of these services and abstractions is provided by the L4
Runtime Environment).
Microkernel services are implemented in kernel objects. Tasks hold
references to kernel objects in their respective \em "object space", which is a
kernel-protected table.
These references are called \em capabilities. System calls to the microkernel are function
invocations on kernel objects through the corresponding capabilities. These
can be thought of as function invocations on object references in an
object-oriented programming environment. Furthermore, if a task owns a
capability, it may grant other tasks the same (or fewer) rights on this object
by passing the capability from its own to the other task's object space.
From a design perspective, capabilities are a concept that enables flexibility
in the system structure. A thread that invokes an object through a capability
does not need to care about where this object is implemented. In fact, it is
possible to implement all objects either in the kernel or in a user-level
server and replace one implementation with the other transparently for clients.
\subsection l4re_concepts_fiasco_ipc Communication
The basic communication mechanism in L4-based systems is called
\em "Inter Process Communication (IPC)". It is always synchronous, i.e. both
communication partners need to actively rendezvous for IPC. In addition to
transmitting arbitrary data between threads, IPC is also used to resolve
hardware exceptions, faults and for virtual memory management.
\subsection l4re_concepts_fiasco_kobjects Kernel Objects
The following list gives a short overview of the kernel objects provided by
the L4Re Microkernel:
\li <b>Task</b> A task comprises a memory address space (represented by the
task's page table), an object space (holding the kernel protected
capabilities), and on x86 an IO-port address space.
\li <b>Thread</b> A thread is bound to a task and executes code. Multiple
threads can coexist in one task and are scheduled by the microkernel's scheduler.
\li <b>Factory</b> A factory is used by applications to create new kernel
objects. Access to a factory is required to create any new kernel object.
Factories can control and restrict object creation.
\li <b>IPC Gate</b> An IPC gate is used to create a secure communication
channel between different tasks. It embeds a label (kernel protected payload)
that securely identifies the gate through which a message is received.
The gate label is not visible to and cannot be altered by the sender.
\li <b>IRQ</b> IRQ objects provide access to hardware interrupts. Additionally,
programs can create new virtual interrupt objects and trigger them. This
allows to implement a signaling mechanism. The receiver cannot decide whether
the interrupt is a physical or virtual one.
\li <b>Vcon</b> Provides access to the in-kernel debugging console (input and output).
There is only one such object in the kernel and it is only available, if the
kernel is built with debugging enabled. This object is typically interposed
through a user-level service or without debugging in the kernel can be
completely based on user-level services.
\li <b>Scheduler</b> Implements scheduling policy and assignment of threads
to CPUs, including CPU statistics.
\section l4re_system_structure L4Re System Structure
The system has a multi-tier architecture consisting of the
following layers depicted in the figure below:
\li <b>Microkernel</b> The microkernel is the component at the lowest level of
the software stack. It is the only piece of software that is running in the
privileged mode of the processor.
\li <b>Tasks</b> Tasks are the basic containers (address spaces) in which system
services and applications are executed. They run in the processor's deprivileged
user mode.
\image html l4re-basic.png "Basic Structure of an L4Re based system"
\image latex l4re-basic.pdf "Basic Structure of an L4Re based system"
In terms of functionality, the system is structured as follows:
\li <b>Microkernel</b> The kernel provides primitives to execute programs in tasks,
to enforce isolation among them, and to provide means of secure communication in
order to let them cooperate. As the kernel is the most privileged, security-critical
software component in the system, it is a general design goal to make it as small
as possible in order to reduce its attack surface. It provides only a minimal set of
mechanisms that are necessary to support applications.
\li <b>Runtime Environment</b> The small kernel offers a concise set of interfaces,
but these are not necessarily suited for building applications directly on top of
it. The L4Re Runtime Environment aims at providing more convenient abstractions for
application development. It comprises low-level software components that interface
directly with the microkernel. The root pager \em sigma0 and the root task \em Moe
are the most basic components of the L4Re Runtime Environment. Other
services (e.g., for device enumeration) use interfaces provided by them.
\li \b Applications Applications run on top of the system and use services
provided by the runtime environment -- or by other applications. There may be
several types of applications in the system and even virtual machine monitors
and device drivers are considered applications in the terminology used in this
document. They are running alongside other applications on the system.
Lending terminology from the distributed systems area, applications offering
services to other applications are usually called \em servers, whereas
applications using those services are named \em clients. Being in both
roles is also common, for instance, a file system server may be viewed as a
server with respect to clients using the file system, while the server itself
may also act as a client of a hard disk driver.
\section main_l4re_sec L4Re Runtime Environment
The L4Re Runtime Environment provides a basic set of services and
abstractions, which are useful to implement and run user-level applications on
top of the L4Re Microkernel. They form the L4Re Operating System Framework.
The L4Re Operating System Framework consists of a set of libraries and
servers. L4Re follows an object-oriented design. Server interfaces are
object-oriented, and the implementation is also object-oriented.
A minimal L4Re-based application needs 3 components to be booted beforehand:
the L4Re Microkernel, the root pager (Sigma0), and the root task (Moe). The
Sigma0 root pager initially owns all system resources, but is usually used
only to resolve page faults for the Moe root task. Moe provides the essential
services to normal user applications such as an initial program loader, a
region-map service for virtual memory management, and a memory (data space)
allocator.
*/

View File

@@ -0,0 +1,444 @@
// vi:set ft=c: -*- Mode: C -*-
/**
\page l4re_concepts_abi Kernel ABI
This section details the binary representation of the IPC interface of the
kernel. It accompanies the [L4 Inter-Process Communication
(IPC)](#l4re_concepts_ipc) section. The details presented here are usually not
relevant when developing %L4Re applications and can therefore be skipped by many
readers.
\note The kernel ABI is subject to change. Please use the API instead of relying
on particular binary representations.
The following notation is used to indicate how particular data fields are used:
- [in]: The kernel reads and interprets this field.
- [out]: The kernel writes this field with information provided by the kernel.
- [cpy]: The kernel copies this field from sender to receiver (without
interpretation if [in] is not listed as well).
The above indications may be combined.
\section l4re_concepts_abi_capsel Capability selector and flags
See [partner capability selector](#l4re_concepts_descr_capidx) and [IPC
flags](#l4re_concepts_descr_flags).
The kernel reads and interprets all the fields ([in]).
MSB 12 11 10 [7] 4 3 2 1 0 bits
┌───────────┬─────────┬─────────┬─────────┬─────────┬─────────┬─────────┐
│ [in] │ [in] │ │ [in] │ [in] │ [in] │ [in] │
│(see below)│ special │ SBZ │ reply │open wait│ recv │ send │
└───────────┴─────────┴─────────┴─────────┴─────────┴─────────┴─────────┘
┌───────────┬─────────┬─
│ cap idx │ 0 │ if special is 0
└───────────┴─────────┴─
┌───────────┬─────────┬─
│ 1...1 │ 1 │ if special is 1
└───────────┴─────────┴─
- Bits 0…3 [in]: These bits correspond to the flags defined in
#l4_syscall_flags_t. The individual bits correspond to #L4_SYSF_REPLY,
#L4_SYSF_OPEN_WAIT, #L4_SYSF_RECV, #L4_SYSF_SEND. Note that not all
combinations of those bits are defined; see #l4_syscall_flags_t.
- Bits 4…10 [in] `SBZ`: should be zero
- Bit 11 [in] `special`: Set when using #L4_INVALID_CAP, otherwise unset.
- Bits 12…MSB [in]: Capability index if `special` is unset, otherwise all those
bits should be one (see #L4_INVALID_CAP, [partner capability
selector](#l4re_concepts_descr_capidx) and #l4_cap_idx_t).
\section l4re_concepts_abi_label Label
See [IPC label](#l4re_concepts_descr_label).
When IPC is sent via a thread capability, the label is copied to the receiver
unchanged ([cpy]).
When IPC is sent via an IPC gate, the sent label is ignored and the kernel
provides the bitwise OR (`|`) of the IPC gate label and the senders write and
special permissions (see #L4_CAP_FPAGE_W and #L4_CAP_FPAGE_S) of the used
capability ([out]):
MSB 2 1 0 bits
┌───────────────────┬─────────────────┬─────────────────┐
│ [out] │ [out] │ [out] │
│ label │ label | special │ label | write │
│ │ right │ right │
└───────────────────┴─────────────────┴─────────────────┘
\section l4re_concepts_abi_msgtag Message tag
See [IPC message tag](#l4re_concepts_descr_msgtag). Note that, for a message tag
returned by the kernel, if the error flag is set, all other contents of the
message tag is undefined.
MSB 16 15 14 13 12 11 [6] 6 5 [6] 0 bits
┌─────────────────┬──────────┬──────────┬──────────┬──────────┬─────────────┬─────────────┐
│ [cpy] │ [out] │ │ [in,cpy] │ [in,cpy] │ [in,cpy] │ [in,cpy] │
│ payload │ error │ SBZ │ schedule │ transfer │ items │ words │
│ │ flag │ │ flag │ FPU flag │ │ │
└─────────────────┴──────────┴──────────┴──────────┴──────────┴─────────────┴─────────────┘
- Bits 0…5 [in,cpy] `words`: Number of (untyped) message words in the UTCBs
message registers. See #l4_msgtag_words() and #l4_msgtag_t::words().
- Bits 6…11 [in,cpy] `items`: Number of typed message items in the UTCBs
message registers. See #l4_msgtag_items() and #l4_msgtag_t::items().
- Bit 12 [in,cpy] `transfer FPU flag`: See #L4_MSGTAG_TRANSFER_FPU.
- Bit 13 [in,cpy] `schedule flag`: See #L4_MSGTAG_SCHEDULE.
- Bit 14 `SBZ`: should be zero
- Bit 15 [out] `error`: See #L4_MSGTAG_ERROR, #l4_msgtag_has_error() and
#l4_msgtag_t::has_error().
- Bits 16…MSB [cpy] `payload`: Transferred to receiver unchanged; not
interpreted by kernel (unless it is the communication partner). For IPC calls
or send-only IPC, this is usually the protocol. For replies, this is usually
used for return values and server error signaling. See #l4_msgtag_label() and
#l4_msgtag_t::label().
\section l4re_concepts_abi_timeouts Timeouts
See [IPC timeouts](#l4re_concepts_descr_timeouts) and #l4_timeout_t.
The kernel reads and interprets all the fields ([in]).
31 [16] 16 15 [16] 0 bits
┌─────────────────┬─────────────────┐
│ [in] │ [in] │
│ send timeout │ receive timeout │
└─────────────────┴─────────────────┘
A timeout has the following format. There are two special timeout values:
- *Zero timeout:* Only bit 10 is set. See #L4_IPC_TIMEOUT_0.
15 [5] 11 10 9 [10] 0 bits
┌───────────┬─────┬──────────────────────┐
│ 0 │ 1 │ 0 │
└───────────┴─────┴──────────────────────┘
- *Infinite timeout:* All bits are unset. See #L4_IPC_TIMEOUT_NEVER.
15 [16] 0 bits
┌────────────────────────────────────────┐
│ 0 │
└────────────────────────────────────────┘
Otherwise, the timeout is either relative or absolute, which is specified by
bit 15.
- *Relative timeout:* If bit 15 is unset, the timeout is `mantissa * 2 ^
exponent` micro seconds relative to the current time. The `mantissa` must not
be zero:
15 14 [5] 10 9 [10] 0 bits
┌─────┬───────────┬──────────────────────┐
│ 0 │ exponent │ mantissa ≠ 0 │
└─────┴───────────┴──────────────────────┘
- *Absolute timeout:* If bit 15 is set, an absolute timeout is specified in the
UTCBs buffer registers starting at `buf reg idx` (the particular number of
registers depends on the architecture; see #l4_timeout_s):
15 14 [9] 6 5 [6] 0 bits
┌─────┬────────────────────┬─────────────┐
│ 1 │ SBZ │ buf reg idx │
└─────┴────────────────────┴─────────────┘
\section l4re_concepts_abi_utcb User-level thread control block (UTCB)
See [User-level thread control block (UTCB)](#l4re_concepts_descr_utcb).
l4_utcb_mr() l4_utcb_br() l4_utcb_tcr()
l4_msg_regs_t l4_buf_regs_t l4_thread_regs_t
┌─────────────────┐ ┌────────┐ ┌───────────────────────────┐ ┌───────────────────────────────────┐
0 [63] 62 63 64 65 [58] 122 123 124 125 [3] 128 words
┌───────────────────┬──────────┬──────────┬──────────────────┬──────────┬──────────┬───────────────┐
│ │ [(out)] │ [in] │ [in] │ [out] │ [(out)] │ │
│ message registers │ arch │ BDR │ buffer registers │ error │ free │ threadlocal │
│ (MRs) │ specific │ │ (BRs) │ code │ marker │ storage (TLS) │
└───────────────────┴──────────┴──────────┴──────────────────┴──────────┴──────────┴───────────────┘
│ └────────────────────┐
│0 [words] [2 * items] 62│ words
┌───────────────┬───────────────┬────────┐
│ [cpy] │ [in,out] │ │
│ (untyped) │ typed │ unused │
│ message words │ message items │ │
└───────────────┴───────────────┴────────┘
- Words 0…62 `MRs`: See [IPC Message registers](#l4re_concepts_descr_mrs) and
#l4_utcb_mr(). The number of message registers is defined by
#L4_UTCB_GENERIC_DATA_SIZE. The actually used message registers are defined by
`words` and `items` in the [message tag](#l4re_concepts_abi_msgtag). The
layout of a typed message item varies depending on being an input or output
value, see [typed message items](#l4re_concepts_abi_items).
- Word 63 [(out)]: Depending on the architecture, this word may be used by the
kernel to signify the position of a threads UTCB in memory. See
architecture-specific implementation of #l4_utcb(). If at all, the kernel
writes this word when kernel-user memory is set up as UTCB while binding a
thread to a task; see #l4_thread_control_bind(), #L4::Thread::Attr::bind().
- Word 64 [in] `BDR`: See [buffer descriptor
register](#l4re_concepts_abi_utcb_bdr).
- Words 65…122 [in] `BRs`: See [IPC Buffer Registers](#l4re_concepts_descr_brs),
[receive items](#l4re_concepts_abi_items_receive) and
#l4_utcb_br()->[br](#l4_buf_regs_t::br). The number of buffer registers is
defined by #L4_UTCB_GENERIC_BUFFERS_SIZE.
- Word 123 [out] `error code`: See [IPC Thread Control
Registers](#l4re_concepts_descr_tcrs) and
#l4_utcb_tcr()->[error](#l4_thread_regs_t::error).
- Word 124 [(out)] `free marker`: Written by the kernel, but not necessarily
during IPC. See [IPC Thread Control Registers](#l4re_concepts_descr_tcrs) and
#l4_utcb_tcr()->[free_marker](#l4_thread_regs_t::free_marker).
- Word 125…128 `TLS`: Ignored and left untouched by the kernel. See [IPC Thread
Control Registers](#l4re_concepts_descr_tcrs) and
#l4_utcb_tcr()->[user](#l4_thread_regs_t::user).
\subsection l4re_concepts_abi_utcb_bdr Buffer descriptor register
See [IPC Buffer Descriptor Register](#l4re_concepts_descr_bdr) and
#l4_utcb_br()->[bdr](#l4_buf_regs_t::bdr).
MSB 25 24 23 [9] 15 14 [5] 10 9 [5] 5 4 [5] 0 bits
┌───────────┬──────────┬───────────┬────────────────┬────────────────┬────────────────┐
│ SBZ │ inherit │ SBZ │ index of first │ index of first │ index of first │
│ │ FPU flag │ │ obj cap buffer │ io buffer │ memory buffer │
└───────────┴──────────┴───────────┴────────────────┴────────────────┴────────────────┘
\section l4re_concepts_abi_items Typed message items
The number of words in a typed message item varies depending on the particular
kind of item. However, for the first word, the following properties are shared:
- *Void item:* If all bits of the first word of a typed message item are zero,
then it is a void item.
- *Non-void item:* The first word of a non-void typed message item has the
following binary layout:
MSB 4 3 2 0 bits
┌────────────────────────────┬───┬────────┐
│ │ t │ │
└────────────────────────────┴───┴────────┘
Bit 3 (`t`) is the type bit. If `t` is set, the item is a map item. Currently,
map item is the only supported type. Hence, this bit must be set for all items
except for void items.
There are three sub-types of typed message items: *send items*, *receive items*,
and *return items*; see [Message Items](#l4_msgitem_api).
Many typed items make use of flexpages, therefore, these are described before
the various kinds of typed items. Note that flexpages are also used outside of
typed message items, e.g., for #L4::Task::unmap().
\subsection l4re_concepts_abi_items_flexpages Flexpages
A flexpage consists of a single word and, except for some special values,
describes a range in an address space, see [flex pages](#l4_fpage_api).
The general layout is defined as follows:
MSB 6 5 [2] 4 3 [4] 0 bits
┌───────────────────────────────────┬─────────┬─────────────┐
│ │ type │ │
└───────────────────────────────────┴─────────┴─────────────┘
- Bits 4…5 `type`: See #l4_fpage_type() and #L4_fpage_type.
The type #L4_FPAGE_SPECIAL only supports some selected values, which are only
supported for selected interfaces; see #L4_FPAGE_SPECIAL.
The other types share the same layout:
MSB 12 11 [6] 6 5 [2] 4 3 [4] 0 bits
┌─────────────────┬─────────────────┬─────────┬─────────────┐
│ start │ order │ type │ permissions │
└─────────────────┴─────────────────┴─────────┴─────────────┘
- Bits 0…3 `permissions`: See #l4_fpage_rights(), #L4_fpage_rights (memory space)
and #L4_cap_fpage_rights (object space). Should be zero for I/O port space.
- Bits 6…11 `order`: The log₂ size of the flexpage. See #l4_fpage_size.
- Bits 12…MSB `start`: The starting page number / I/O port number / capability
index of the flexpage. Must be aligned to the flexpage size. See
#l4_fpage_page(), #l4_fpage_memaddr(), #l4_fpage_ioport() and #l4_fpage_obj().
Also see #l4_fpage() (memory space), #l4_iofpage() (I/O port space) and
#l4_fpage_obj() (object space).
\subsection l4re_concepts_abi_items_send Send items
A send item consists of two words. The second word of a non-void send item is a
[flexpage](#l4re_concepts_abi_items_flexpages). The type of the flexpage
determines the interpretation of the `attr` bits in the first word (see below).
If not void, the layout of the first word is defined as follows:
first word second word
MSB 12 11 8 7 4 3 2 1 0 bits
┌──────────┬─────┬──────┬───┬─────┬───────┬──────────┐┌───────────────┐
│ hot_spot │ SBZ │ attr │ 1 │ SBZ │ grant │ compound ││ send flexpage │
└──────────┴─────┴──────┴───┴─────┴───────┴──────────┘└───────────────┘
`SBZ` means “should be zero”.
- Bit 0 (`compound`): Compound bit. See #L4_ITEM_CONT and
#L4::Ipc::Snd_fpage::is_compound().
- Bit 1 (`grant`): Grant flag. See #L4_ITEM_MAP, #L4_MAP_ITEM_GRANT and
#L4::Ipc::Snd_fpage::Map_type.
- Bits 7..4 (`attr`): Attributes. See #L4_obj_fpage_ctl and
#l4_fpage_cacheability_opt_t, #L4::Ipc::Snd_fpage::Cacheopt.
- Bits MSB­..12 (`hot_spot`): Send base (also called hot spot). See
#L4::Ipc::Snd_fpage::snd_base().
For details, see [IPC Message registers](#l4re_concepts_descr_mrs).
\subsection l4re_concepts_abi_items_receive Receive items
A non-void receive item consists of up to three words.
If not void, the general layout of the first word is defined as follows:
MSB 4 3 2 1 0 bits
┌──────────────────────────┬───┬────────┬───────┬─────┐
│ │ 1 │ rcv_id │ small │ fwd │
└──────────────────────────┴───┴────────┴───────┴─────┘
The `small` and `fwd` bits determine the details of the layout of the whole
message item.
If `small` is unset, then also `rcv_id` must be unset, and the most
significant bits should be zero:
┌──────────────────────────┬───┬────────┬───────┬─────┐
│ SBZ (should be zero) │ 1 │ 0 │ 0 │ fwd │
└──────────────────────────┴───┴────────┴───────┴─────┘
If `small` is set, the most significant bits are layouted as follows:
MSB 12 11 4 3 2 1 0 bits
┌─────────────┬────────────┬───┬────────┬───────┬─────┐
│ rcv cap idx │ SBZ │ 1 │ rcv_id │ 1 │ fwd │
└─────────────┴────────────┴───┴────────┴───────┴─────┘
At most one of `rcv_id` and `fwd` may be set.
The number and meaning of the words in the whole item are determined by the
`small` and `fwd` bits:
first word second word third word
rcv_id small fwd
─┬─────┬─────┬─────┐┌───────────────────┐
│ 0 │ 0 │ 0 ││ rcv flexpage │
─┴─────┴─────┴─────┘└───────────────────┘ 12 11 0
─┬─────┬─────┬─────┐┌───────────────────┐┌─────────────┬─────┐
│ 0 │ 0 │ 1 ││ rcv flexpage ││ fwd cap idx │ SBZ │
─┴─────┴─────┴─────┘└───────────────────┘└─────────────┴─────┘
─┬─────┬─────┬─────┐
│ 0/1 │ 1 │ 0 │
─┴─────┴─────┴─────┘ 12 11 0
─┬─────┬─────┬─────┐┌─────────────┬─────┐
│ 0 │ 1 │ 1 ││ fwd cap idx │ SBZ │
─┴─────┴─────┴─────┘└─────────────┴─────┘
The meaning of the bits in detail:
- Bit 0 (`fwd`): See #L4_RCV_ITEM_FORWARD_MAPPINGS and
#L4::Ipc::Rcv_fpage::forward_mappings(). For `fwd cap idx` see
#L4::Ipc::Rcv_fpage::rcv_task().
- Bit 1 (`small`): See #L4_RCV_ITEM_SINGLE_CAP and #L4::Ipc::Small_buf vs.
#L4::Ipc::Rcv_fpage.
- Bit 2 (`rcv_id`): See #L4_RCV_ITEM_LOCAL_ID.
\subsection l4re_concepts_abi_items_return Return items
A return item always consists of two words. The general layout of a non-void
return item is defined as follows:
first word second word
MSB 12 11 6 5 4 3 2 1 0 bits
┌──────────┬───────┬──────┬───┬──────────┬───┐┌───────────────────┐
│ hot_spot │ order │ type │ 1 │ rcv_type │ c ││ payload │
└──────────┴───────┴──────┴───┴──────────┴───┘└───────────────────┘
└──────────┘ └───┘ └───┘ from send items first word
└──────────────┘ from send items flexpage
└──────────┘ initially zero
As indicated above, the `hot_spot`, `1`, and `c` (`compound`) are copied from
the senders send items first word, and `order` and `type` are copied from the
senders send items flexpage. The `rcv_type` and `payload` are determined by
what is actually transferred, which is also affected by the `rcv_id` bit in the
receivers receive item. The `rcv_type` determines the content and layout of the
payload.
There are four cases for `rcv_type`:
`00`: Used if at least one mapping was actually transferred for
the corresponding send item. The payload is undefined:
(also see #L4::Ipc::Snd_fpage::cap_received()):
┌──────────┬───────┬──────┬───┬──────────┬───┐┌───────────────────┐
│ hot_spot │ order │ type │ 1 │ 00 │ c ││ undefined │
└──────────┴───────┴──────┴───┴──────────┴───┘└───────────────────┘
`01`: Used if transfer of mappings was attempted, but actually
nothing was transferred, because nothing was mapped on the senders side for
the corresponding send item. The payload is undefined:
┌──────────┬───────┬──────┬───┬──────────┬───┐┌───────────────────┐
│ hot_spot │ order │ type │ 1 │ 01 │ c ││ undefined │
└──────────┴───────┴──────┴───┴──────────┴───┘└───────────────────┘
`10`: Used if the receive items `rcv_id` bit was set and the conditions for
transferring an IPC gate label were fulfilled. In that case, no mapping is done
for this item and the payload consists of the bitwise OR (`|`) of the IPC gate
label and the write and special permissions (see #L4_CAP_FPAGE_W and
#L4_CAP_FPAGE_S) that would have been mapped (also see
#L4::Ipc::Snd_fpage::id_received()):
2 1 0 bits
┌──────────┬───────┬──────┬───┬──────────┬───┐┌──────────┬────────┐
│ hot_spot │ order │ type │ 1 │ 10 │ c ││ label │ rights │
└──────────┴───────┴──────┴───┴──────────┴───┘└──────────┴────────┘
`11`: Used if the receive items `rcv_id` bit was set and the conditions for
transferring the senders flexpage word were fulfilled. In that case, no mapping
is done for this item and the payload is a copy of the senders flexpage word
(also see #L4::Ipc::Snd_fpage::local_id_received()):
┌──────────┬───────┬──────┬───┬──────────┬───┐┌───────────────────┐
│ hot_spot │ order │ type │ 1 │ 11 │ c ││ send flexpage │
└──────────┴───────┴──────┴───┴──────────┴───┘└───────────────────┘
*/

View File

@@ -0,0 +1,593 @@
// vi:ft=c
/* -*- c -*- */
/**
\page l4re_concepts_ipc %L4 Inter-Process Communication (IPC)
Inter-process communication (IPC) is the fundamental communication mechanism in
the L4Re Microkernel.
Basically IPC invokes a subroutine in a different context using input and
output parameters. It is used to communicate between userland threads and, as a
special case, to communicate between a userland thread and a kernel object. IPC
provides the only (non-debugging) way of doing system calls.
\section l4re_concepts_ipc_mechanism IPC mechanism
When using this API, an IPC operation can be conducted using the l4_ipc()
function (or one of its related \ref l4_ipc_api "helpers"). In general it
causes a method to be invoked on the called kernel object. An IPC operation
consists of a send and receive phase, but either of them can be skipped, that
is, an IPC operation can consist of only either a send or a receive phase. IPC
is always synchronous and blocking and can be given a timeout. Timeouts can be
specified separately for each phase. Invoking the IPC syscall without any phase
is deprecated.
On the lowest abstraction level, IPC operations need the following arguments:
- \ref l4re_concepts_descr_flags "flags" describing the IPC mode,
- the \ref l4re_concepts_descr_capidx "capability selector" of the
communication partner,
- a \ref l4re_concepts_descr_label "label",
- a \ref l4re_concepts_descr_msgtag "message tag", and
- a pair of \ref l4re_concepts_descr_timeouts "timeout" values.
During an IPC operation the kernel accesses the UTCB of the current thread to
read parameters which are not passed as direct arguments.
As result of an IPC operation the kernel returns a message tag and a label and
the kernel also changes UTCB content. For the detailed call signature, refer to
l4_ipc(). Furthermore, depending on the IPC parameters, the kernel might have
transferred the FPU state and capabilities (memory, I/O ports, and/or object
capabilities) from the sender to the receiving thread.
The transition between the IPC send phase and the IPC receive phase is atomic,
that is, as soon as the send phase has finished, the thread receive phase
starts. A relative receive timeout does not start before the send phase has
finished (see also below) and a thread which received an IPC call from another
thread can assume that the other thread is ready to receive the reply message
and the replying thread can therefore reply with a timeout of zero, see
\ref l4re_concepts_descr_timeouts.
For performance optimization and under certain conditions, the kernel may
perform a context switch from the IPC sender to the IPC receiver without
consulting the scheduler after the send phase finished. For instance, a client
performing an IPC call to a server has to wait for the server anyway. Hence,
after the client request was sent to the server, the kernel switches directly
to the server thread. This behavior can be disabled by setting the
#L4_MSGTAG_SCHEDULE flag in the sender message tag (see below).
\subsection l4re_concepts_descr_flags IPC Flags
The *flags* defined in #l4_syscall_flags_t are used by the invoking thread to
define the intended IPC operation. The variants of l4_ipc() (see \ref
l4_ipc_api) use the flags
- to request the IPC phases (send-only IPC, receive-only IPC, IPC with send
and receive phase), and
- to decide, if the reply capability (see \ref l4re_concepts_descr_capidx
"below") should be used instead of the capability of a dedicated kernel
object as target for the send phase (*reply*), and
- to decide, if receiving should wait for an incoming message from any
possible sender (*open wait*) instead of a message from a dedicated
sender (*closed wait*).
\subsection l4re_concepts_descr_capidx Partner capability selector
The *partner capability selector* defines a kernel object as partner of the IPC
operation. Some kernel objects forward IPC to a userland thread.
Basically an object capability is represented by #l4_cap_idx_t where the bits
starting from #L4_CAP_SHIFT are used as index into the local capability table
of the current address space.
Specifying #L4_INVALID_CAP as target for an IPC operation is equivalent to
specifying a thread capability of the current thread with full permissions.
As a result, the userland thread either communicates with its corresponding
kernel thread object (if #L4_PROTO_THREAD is specified as protocol value,
see the description of the message tag \ref l4re_concepts_descr_msgtag "below")
or the IPC target is the current userland thread. In the latter case, no IPC
will be performed and the send phase and the receive phase will block until the
corresponding timeout has expired, see \ref l4re_concepts_descr_timeouts
"below".
A special partner is defined by the *reply capability*. Since it would
be impractical (and a security flaw) to always pass an explicit object
capability to reply to for each IPC, the kernel generates an implicit one that
can be used for just that purpose if the IPC contains an **open wait** phase.
The reply capability is valid after a receive phase and points to the kernel
object that sent the IPC just received. It can be used only once. The reply
capability is selected by setting the #L4_SYSF_REPLY flag, see \ref
l4re_concepts_descr_flags "above".
\subsection l4re_concepts_descr_label IPC Label
The IPC label is a machine word which is transferred unchanged from the IPC
sender to the IPC receiver when directly sending to a userland thread. However,
the primary purpose of the label is to create a relationship between an
L4::Rcv_endpoint (L4::Ipc_gate or L4::Irq) and the bound thread.
During L4::Rcv_endpoint::bind_thread(), a label is specified. If the thread
receives an IPC message through the endpoint, that label is delivered to the
receiving thread as output parameter of l4_ipc() instead of the label specified
during the corresponding IPC send operation (see the detailed description of
L4::Ipc_gate for more details on the label with IPC gates). The label is
usually used by the receiving thread to invoke the object which is responsible
for handling the IPC request of the corresponding endpoint. This mechanism is
used by the L4::Epiface mechanism for server loops.
\subsection l4re_concepts_descr_msgtag IPC Message Tag
The *message tag* (#l4_msgtag_t) describes the payload of the IPC and
can also be used to enable certain features. It contains:
- a *protocol value* (cf. l4_msgtag_t::label(), also called the tag's
_label_),
- the number of items in \ref l4re_concepts_descr_mrs
"UTCB message registers" to transfer (cg. l4_msgtag_t::words() and
l4_msgtag_t::items()), and
- flags (cf. l4_msgtag_t::flags() and #L4_msgtag_flags, may be 0).
The information from the message tag is required by the kernel to transfer the
message. The IPC system call returns a message tag as result of the IPC
operation. On success, a copy of the message tag specified by the sender is
returned if there is a receive phase. Without receive phase, a successful IPC
syscall returns the message tag specified as input parameter.
Failures during IPC are signalled using the #L4_MSGTAG_ERROR flag in the
message tag. If this bit is set by the kernel, the content of the returned
message tag apart from that bit is undefined and the kernel wrote the actual
error code into the l4_thread_regs_t::error register of the UTCB (see also
\ref l4re_concepts_descr_tcrs). When an IPC error occurs after the rendezvous
of the IPC partners, both partners observe the same error information. If, for
instance, the IPC was aborted using L4::Thread::ex_regs(), the sender gets an
#L4_IPC_SECANCELED error while the receiver gets an #L4_IPC_RECANCELED error.
The function L4Re::chkipc() can be used to verify that an IPC operation
finished successfully: It throws an error if the IPC failed.
\internal
See kk-all chat from 2022-04-11: Alex says that the message tag is undefined in
case of an error (only the error bit is set).
\endinternal
The *protocol value* is usually used to distinguish between different
protocols of the same interface. Certain protocol IDs are pre-defined when
talking to kernel objects, see #L4_msgtag_protocol. From IPC point of view, the
protocol value is just payload that is transferred from sender to receiver and
hence doesn't have a dedicated meaning.
By convention, during IPC calls, the protocol value is used for return values,
where negative values signify errors. See the
\ref l4_cxx_ipc_iface_return_types "section" about %L4 RPC return types for
further information. The function L4Re::chksys() can be used to verify that an
RPC call using IPC was successful: It throws an error if the IPC failed or if
the returned protocol value is negative.
\subsection l4re_concepts_descr_timeouts IPC Timeouts
As written above, IPC *timeouts* are specified separately for the send phase
(IPC send timeout) and the receive phase (IPC receive timeout). The timeout of
one phase is encapsulated by #l4_timeout_s. Both timeouts are combined into a
single #l4_timeout_t parameter. Timeouts are either relative to the current
time of the invoking thread or absolute. In the latter case, the absolute time
of the deadline of the respective phase is written into a UTCB buffer register
(see l4_timeout_abs()). The relative timeout of the receive phase starts
immediately after the send phase has finished.
Two specific timeout values are sufficient for most IPC operations:
- #L4_IPC_TIMEOUT_NEVER is used if the IPC partner might not yet be ready.
Usually a client trusting a server will perform an IPC call with an
infinite timeout for both phases. The send phase will take some time if the
IPC receiver is currently not ready. The receive phase will take some time
as the server needs time to serve the request. Also, a server will usually
wait with an infinite receive timeout for the next request (see below for
a possible exception).
- #L4_IPC_TIMEOUT_0 is used when it is either certain that the IPC receiver
is currently ready or if the IPC sender doesn't want to wait if the IPC
receiver is not ready. The former case applies to a thread which was called
with an IPC call, for example a server got a client request. The reply to
the IPC call should use a timeout of zero to ensure that a client doesn't
block a server (server could not deliver the result of the request).
See also L4::Ipc_svr::Default_timeout.
Another case is an IPC send operation for waking up another thread from an
IPC receive operation. If the other thread is not ready to receive, then it
might be already woken up and it does not make sense to wait any longer.
Also triggering an IRQ is usually done with a send timeout of 0, see
L4::Triggerable::trigger().
In certain cases it also makes sense to specify an IPC timeout different from
"never" or "zero":
- A server might leave the server loop after some time to perform idle work
(see L4::Ipc_svr::Server_iface::add_timeout()).
- A thread does not want to wait for an infinite time if the partner is not
ready. This could be also some safety measure.
- A thread wants to block for a certain amount of time without consuming CPU
time. The l4_ipc_sleep() function specifies the #L4_INVALID_CAP as target
for an IPC receive operation and specifies the intended relative waiting
period as IPC timeout. Waiting for an absolute timeout would be possible
with similar code.
\note The kernel IPC path is optimized for the two special cases using
#L4_IPC_TIMEOUT_NEVER and #L4_IPC_TIMEOUT_0. Specifying a different
timeout causes more maintenance effort for the kernel.
\note Special care is required if a finite timeout for the receive phase of an
IPC call is specified: The IPC receive operation could abort before the
partner was able to send the reply message. Under certain circumstances
the partner may still have the temporary reply capability to the calling
thread and may use this capability to reply to the caller at a later,
unexpected time specifying an arbitrary IPC label. This case is relevant
for servers which call another, possibly untrusted, server while serving a
client request.
\subsection l4re_concepts_descr_utcb User-level Thread Control Block
The \ref l4_utcb_api "UTCB" is located on a power-of-2-sized and
power-of-2-aligned memory area shared between userland and the kernel
(L4::Task::add_ku_mem()). The UTCB is bound to a thread during the
L4::Thread::control() operation with the L4::Thread::Attr parameters set up
using L4::Thread::Attr::bind(). The UTCB is used for IPC-related data exchange
and is set up before invoking l4_ipc(). To access certain parts of the UTCB,
the corresponding functions have to be used (there is no data type L4_utcb or
similar). The UTCB consists of:
- the \ref l4re_concepts_descr_mrs "message registers"
`MR[0]`, `MR[1]`, ..., `MR[n-1]` with n = #L4_UTCB_GENERIC_DATA_SIZE
(access using l4_utcb_mr()),
- the \ref l4re_concepts_descr_bdr "buffer descriptor register" `BDR`
(access using l4_utcb_br(), see l4_buf_regs_t::bdr),
- the \ref l4re_concepts_descr_brs "buffer registers"
`BR[0]`, `BR[1]`, ..., `BR[m-1]` with m = #L4_UTCB_GENERIC_BUFFERS_SIZE
(access using l4_utcb_br()),
- the \ref l4re_concepts_descr_tcrs "thread control registers" (access using
l4_utcb_tcr(), includes the IPC error code), and
- in case of an exception IPC, the register state of the thread which
triggered the exception (access using l4_utcb_exc()).
IPC to a kernel object requires the setup of the UTCB of the corresponding
userlevel thread. IPC between userlevel threads requires the setup of UTCBs
of both partners.
The kernel changes only the following UTCB content:
- The message registers of the UTCB of the receiver of an IPC, and
- the IPC error field of the thread invoking l4_ipc() if there was an error
during IPC.
\internal
Another exception: See Ic7e8aa98d8f782b684445cc6f866df3bffae2c37 / #CD-518.
\endinternal
\subsubsection l4re_concepts_descr_mrs IPC Message registers
The *message registers* contain *untyped items* and *typed items*. The sender's
typed items are interpreted by the kernel in conjunction with the receiver's
_receive items_. Each typed send item occupies two message registers.
The untyped items, on the other hand, are free to be used by the communication
partners to exchange data: The content of all message registers used for
untyped items (l4_msgtag_t::words()) is copied from the UTCB of the IPC sender
to the UTCB of the IPC receiver.
A typed send item consists of a *flexpage* (see l4_fpage(), l4_obj_fpage(), and
l4_iofpage()) of the to be transferred capabilities (*flexpage word*) and a
_message word_. There are two types of send items: *map items* and *void
items*. For a void item, the message word is all zero. For a map item, the
message word contains:
- the *compound bit* allowing to use the same receive buffer for the
subsequent typed send item (scatter-gather behavior,
see #L4_ITEM_CONT of #l4_msg_item_consts_t),
- the *type bit* defining this typed send item as a *map item*,
- the *grant flag* for delegating the access to the flexpage from the
sender to the receiver and atomically removing the rights from the sender
(see #l4_msg_item_consts_t),
- *attributes* with semantics depending on the item type; for memory
mappings, they contain cacheability information
(see #l4_fpage_cacheability_opt_t); for objects, they contain additional
rights (see #L4_obj_fpage_ctl),
- the *send base* (also called *hot spot*) defining what is actually mapped
when send and receive flexpages have a different size.
A typed send item can be created using l4_sndfpage_add(). This function sets
the compound bit unconditionally. Alternatively, the functions l4_map_control()
and l4_map_obj_control() can be used to set up the message word of a map item
for a memory flexpage respective for objects.
See \ref l4re_concepts_descr_transfer "below" for a description how typed items
are transferred.
\subsubsection l4re_concepts_descr_brs IPC Buffer Registers
The *buffer registers* and *buffer descriptor register* are
interpreted by the kernel during the receive phase (if any). Buffer registers
define *receive items* which are required to receive typed send items (memory,
I/O ports or object capabilities). To specify a receive item, up to three buffer
registers are required:
- A *small receive item* (L4::Ipc::Small_buf) occupying one buffer
register is sufficient to receive one object capability.
- A *receive item* (L4::Ipc::Rcv_fpage) occupying two or three buffer
registers (*message word*, a *flexpage*, and an optional destination task
capability index) is required to receive memory flexpages, I/O ports, or
multiple object capabilities.
\subsubsection l4re_concepts_descr_bdr IPC Buffer Descriptor Register
The buffer descriptor register defines indices of buffer registers used to
receive dedicated types of send items and also contains a flag:
- 5 bits starting at #L4_BDR_MEM_SHIFT define the index of the first receive
item used for memory flexpages.
- 5 bits starting at #L4_BDR_IO_SHIFT define the index of the first receive
item used for I/O flexpages.
- 5 bits starting at #L4_BDR_OBJ_SHIFT define the index of the first receive
item used for object flexpages.
- The #L4_UTCB_INHERIT_FPU can be set using l4_utcb_inherit_fpu() and allows
to receive the FPU state from the IPC sender. This is only relevant if the
sender set #L4_MSGTAG_TRANSFER_FPU in the message tag.
For most use cases, a BDR value of zero is sufficient. In that case, if `BR[0]`
contains a void item, no capabilities are received. Otherwise, only one type of
capabilities (memory, I/O ports or objects) can be received even if there are
several receive items. For more complex setups that require receiving different
types of capabilities in one receive operation, other BDR values are necessary.
The BDR of the receiving thread is only used by the kernel if at least one
typed item is transferred during the IPC or if #L4_MSGTAG_TRANSFER_FPU is set
in the UTCB of the sending thread.
\subsubsection l4re_concepts_descr_tcrs IPC Thread Control Registers
The l4_thread_regs_t::error register contains the IPC error code in case the
#L4_MSGTAG_ERROR flag is set in the message tag returned by an IPC syscall.
Otherwise this register is not touched by the kernel. See
#l4_ipc_tcr_error_t for a detailed enumeration of all possible error codes
during an IPC operation.
The l4_thread_regs_t::free_marker is set by the kernel to zero immediately
before a thread is destroyed. This value indicates that the kernel does not
longer use the UTCB and it can be re-used by other threads.
The other members of l4_thread_regs_t are never touched by the kernel.
\subsection l4re_concepts_descr_transfer Transfer of Typed Send Items
The kernel interprets all typed items in the sender UTCB (l4_msgtag_t::items())
and performs the following operations while modifying the corresponding typed
items in the receiver UTCB:
- If the message item of the sender is void, this item is ignored and the
message word of the corresponding typed item in the receiver UTCB is set to
zero (making it a void item). The flexpage word of this item is not
changed.
- Otherwise, if the type bit of the message item of the sender is not set,
the IPC is aborted with #L4_IPC_SEMSGCUT / #L4_IPC_REMSGCUT.
- Otherwise, if there is a receive item corresponding to the flexpage type of
the send item available (see \ref l4re_concepts_descr_bdr), information
described by the flexpage is transferred to the receiver.
In the last case, the message word of the typed item in the receiver UTCB is
modified to contain the send base, the type and the size of the transferred
flexpage, as well as a copy of the compound bit and the type bit of the send
item. If the receiver ordered a local ID in the corresponding receive item, the
kernel attempts to apply special rules, see #L4_RCV_ITEM_LOCAL_ID. Otherwise,
regular mappings as described by the flexpage of the send item are created in
the receiver space.
A receive item forms a *receive window* of a specific address and size in the
receiver space. Each typed send item that is a map item requires a
corresponding receive item. By default, there is a one-to-one mapping (one
receive item per typed send item) but it is also possible to use one receive
item to receive several typed send items: The compound bit (see
#l4_msg_item_consts_t) of a send item defines if the following typed send item
shall use the same receive item as the current one for receiving the flexpage.
If the compound bit is set, proper values of the send base shall be used to
prevent overlapping of addresses in the receiver space.
The send base is relevant when the size of the receive flexpage differs from
the size of the transferred resource. As a typical example, triggering a memory
page fault opens a receive window covering the entire memory address space of
the faulting thread. The pager will usually reply a memory flexpage smaller
than the entire address space of the faulting thread. Hence, the pager has to
specify a proper base which is used as offset of the sent object in the receive
flexpage in the *receiver space*. If the sender flexpage is bigger than the
receive window, a flexpage of the size of the receive window starting at the
send base in the *sender space* is transferred to the receiver.
\internal
See Fiasco's source code: map_util.cpp / free_constraint().
\endinternal
The kernel will stop transmission of typed items before l4_msgtag_t::items() is
reached either if it finds a void item as receive buffer or if the flexpage
type of the send item does not match the flexpage type of the corresponding
receive item. Under both conditions, the IPC is aborted with #L4_IPC_SEMSGCUT /
#L4_IPC_REMSGCUT.
\note The kernel ignores the flexpage access rights of the receive items. The
actual rights for a transferred resource in the target address space are
defined by the access rights to that resource of the IPC sender address
space and the flexpage access rights in the typed send item.
Additionally, when transferring object capabilities, the transferred
rights also depend on the senders rights on the capability invoked for
IPC.
The kernel does not unmap capabilities in the receive window when there is no
capability present at the corresponding index at the sender. Further, the
receiver cannot reliably detect at which capability indices it received
capabilities in its receive windows. Therefore, before receiving from an
untrusted source, all receive windows should be cleared. Otherwise the receiver
may erroneously associate a capability in one of its receive windows with his
last IPC partner although it was actually received in an earlier IPC.
However, the kernel indicates if at least one object capability was received or
not, see #L4::Ipc::Snd_fpage::cap_received().
\section l4re_concepts_ipc_examples Examples
A number of examples show the interplay of the concepts introduced so far.
\subsection l4re_concepts_ipc_examples_1 User Thread to Kernel Object
The L4::Scheduler kernel object has a method L4::Scheduler.idle_time(). It
takes a set of CPUs to query, represented by two machine words.
In user space, the function L4::Cap<L4::Scheduler>->idle_time() is called,
which does the following:
- Fill `MR[0]` with a constant identifying the method being called
(#L4_SCHEDULER_IDLE_TIME_OP).
- Fill `MR[1]` and `MR[2]` with the two words making up the CPU set.
- Set up the message tag with the protocol value (#L4_PROTO_SCHEDULER), the
number of untyped and typed items (3 and 0), and some flags.
- Call l4_ipc() with the partner capability ID, the tag, the pointer to the
filled UTCB, infinite timeouts, and with flags indicating a send and
receive phase. (The label does not matter in this case.)
This function traps into kernel space using standard platform specific
mechanisms. The kernel reads the protocol value on the message tag, checks that
the partner capability ID refers to a valid object that speaks that protocol,
and dispatches the message to the appropriate handler. The handler fills the
first 64 bits of the message registers with the computed time value. This will
cover `MR[0]` on 64-bit architectures and `MR[0]` and `MR[1]` on 32-bit
architectures.
It then sets up the return message tag:
- The number of untyped items is 1 or 2.
- The number of typed items is 0.
- The protocol value contains the return value and is set to 0.
- An error would be signalled as a negative protocol value. Under certain
conditions (e.g. wrong kernel object capability specified), the error is
signalled as IPC error (see #L4_MSGTAG_ERROR in the description of the
\ref l4re_concepts_descr_msgtag).
- (The return label is as irrelevant in this case as the send label.)
This reply is received by the receive phase of the original l4_ipc() call from
userland. Finally the l4_ipc() function copies the time value out of the
message registers and forwards it with a possible error from the message tag
flags to its caller.
\subsection l4re_concepts_ipc_examples_2 User Thread to User Thread
When the target kernel object is of type L4::Thread (or L4::Ipc_gate, but we
will cover this in the example \ref l4re_concepts_ipc_examples_3 "below") and
the message tag's protocol value is not #L4_PROTO_THREAD, the kernel will
forward the IPC message to the userland thread represented by the kernel
object. There it can be received by a call to l4_ipc(). The restriction of the
protocol number is necessary because one also wants to invoke L4::Thread's
control methods such as L4::Thread.switch_to() or L4::Thread.ex_regs(). Besides
this restriction, the interpretation of all the IPC parameters and the untyped
items of the UTCB is up to the communication partners.
\subsubsection l4re_concepts_ipc_examples_2_1 Simple Messages
A simple example is a client calling a server to have a computation performed
on a value: Similar to IPC from a userland thread to a kernel object, the
client writes the value to `MR[0]`. It sets up the message tag with some agreed
upon protocol value (which, as explained above, must be different from
#L4_PROTO_THREAD), number of untyped items to 1, typed items to 0, and no flags
set. The client may want to pass a label that identifies itself, as many
clients can use the server. In this context, the identifier might also be
passed via the message registers, but the label is the proper place for this,
as it gets a special treatment by the kernel for IPC gates (covered by the
example \ref l4re_concepts_ipc_examples_3 "below"). The client then calls
l4_ipc() with the tag, label and flags indicating it wants a send phase and a
receive phase (as it wants a result back). The target is the capability index
referring to a capability for the L4::Thread kernel object of the server.
To be able to receive an IPC message, the server has set up a UTCB of its own
and called l4_ipc() with flags indicating it only wants to enter a receive
phase and it accepts IPCs from any partner. This is called an **open wait**.
(The alternative would be to specify a capability index referring to a
L4::Thread capability to exclusively receive from.)
Both system calls (the send IPC initiated by the client and the receive IPC
initiated by the server) may be seen by the kernel in any order but the IPC
will not start before sender and receiver are ready. In that case the kernel
will copy the relevant message registers the client specified in the message
tag from the client's UTCB to the server's UTCB, in the current example just
`MR[0]`. It will then switch the client to the receive phase of its call (which
cannot yet be executed) and return the server's call with the message tag and
label.
The server inspects the tag for the correct protocol value and number of
untyped items passed, inspect the label to decide whether it maybe wants
special treatment of this particular client, performs the computation on
`MR[0]` and writes the result back to `MR[0]` (or to more words, depending on
what exactly it computes). It sets up the tag in the usual way, but probably
needs to pass no label, as the client knows who it is talking to.
For the reply, the server makes use the reply capability (see
\ref l4re_concepts_descr_capidx "above"). Since the client sent the last IPC to
the server, the reply capability will point to it. So when the server calls
l4_ipc() with the computed result in the message registers and using the reply
capability as target, the kernel knows to forward this to the client's thread.
The kernel copies the message registers from the server's UTCB to the client's
UTCB, and the client's l4_ipc() system call, which is still stuck in the
receive phase, is returned with the tag.
The client looks at the tag and then the message registers for its wanted
result and the example is concluded.
\subsubsection l4re_concepts_ipc_examples_2_2 Send Items
IPC between userland threads is also used to transfer typed items: Memory, I/O
ports, and objects, all represented as flexpages. Typed items and untyped
items can be part of the same IPC. As general rule, the sender specifies what
he wants to send, the receiver where and how much it wants to receive, and the
kernel checks the required permissions before doing the actual transfer. As
written before, this mechanism is synchronous and the receiver cannot be
transferred items against its will. \see l4_fpage_api
Suppose a client wants a server to have read only access to a page of its
memory. The client sets up a flexpage covering the page and with only the
#L4_FPAGE_RO right set. The server sets up a flexpage of a memory region where
it will receive the mapping. This may be larger than one page, suppose for our
case four pages, in which case the exact position of the mapping will be
resolved by the send base provided by the sender. The client combines the hot
spot and some flags into a machine word and writes it to `MR[0]` (see also
l4_map_control()). At `MR[1]` follows the flexpage it wants to send (see also
l4_fpage()). The server does almost the same but writes the words to `BR[0]`
and `BR[1]`. (The server could also specify a hot spot, but it is currently
ignored by the kernel.) The client specifies 1 typed and 0 untyped items in the
message tag. The server writes 0 to `BDR` to specify that the first receive
item starts at the first buffer register.
Both client and server initiate their IPC, the client with only a send phase to
the server, and the server with an open wait receive phase. The kernel checks
the compatibility of the send items and the receive buffers (e.g. that no
object capability flexpage is sent to a receive buffer describing a memory
mapping flexpage) and updates its internal structures to reflect the change. In
our case, the sender's hot spot indicates to which of the four pages that make
up the receive buffer the sent page should be mapped. The kernel also
translates the typed send item to the server's address space and stores it in
the server's UTCB at `MR[0]` and `MR[1]`.
Once the server returns from its syscall, it will have read access to the
client's shared page.
\subsection l4re_concepts_ipc_examples_3 User Thread to User Object
A common use case for thread to thread communication is when a server
implements a number of object interfaces and a client wants to invoke methods
on them. For security reasons, the server does not want to hand out its thread
capability to everyone it nonetheless wants to serve. It also may not want to
allow every client access to everyone of its interfaces. For this purpose,
IPC gates implemented by the kernel object L4::Ipc_gate can be used.
An IPC gate can be bound to a thread and forwards IPC to it. In doing so it
applies two transformations
1. It sets the label to a predefined value.
2. It changes the rights of transferred items (see #L4_CAP_FPAGE_S).
For each object of every interface the server implements, it creates an IPC
gate and binds it to itself (see L4::Ipc_gate::bind_thread()). It sets the
gate's label to a unique value identifying the object. Then it hands the gate
out to clients. Several clients can be handed the same gate and will all end up
invoking methods on the same object.
Instead of setting the target as the server's thread kernel object, the client
uses the IPC gate's instead. The label the client sends is irrelevant, as the
gate will overwrite it with the value the server has set during the bind
operation. The server executes an open wait, and the kernel performs the same
operation as in the above \ref l4re_concepts_ipc_examples_2_2 "example" with
the transformed IPC finally ending up in the server's thread.
The server checks that the received label refers to one of its objects. It then
checks if the protocol value in the message tag matches the interface the
object implements. Then it invokes the method specified in `MR[0]` with the
rest of the arguments. Finally it returns the results via UTCB and message tag
to the reply capability and waits for the next IPC.
*/

View File

@@ -0,0 +1,24 @@
/* Disable animation when showing search results. */
#MSearchResultsWindow {
animation: none;
}
/* more visually responsive sidebar */
html {
--side-nav-arrow-opacity: 0.4;
--side-nav-arrow-hover-opacity: 1;
--side-nav-hover-background: #f0f0f0;
}
#nav-tree div.item:hover .arrow {
opacity: var(--side-nav-arrow-opacity);
}
#nav-tree div.item a:hover .arrow {
opacity: var(--side-nav-arrow-hover-opacity);
}
#nav-tree div.item:has(a:hover), #nav-tree div.item:has(a:focus) {
background-color: var(--side-nav-hover-background);
}

View File

@@ -0,0 +1,17 @@
<!-- HTML footer for doxygen 1.9.1-->
<!-- start footer part -->
<!--BEGIN GENERATE_TREEVIEW-->
<div id="nav-path" class="navpath"><!-- id is needed for treeview function! -->
<ul>
$navpath
<li class="footer">$generatedby <a href="https://www.doxygen.org/index.html"><img class="footer" src="$relpath^doxygen.svg" width="104" height="31" alt="doxygen"/></a> $doxygenversion </li>
</ul>
</div>
<!--END GENERATE_TREEVIEW-->
<!--BEGIN !GENERATE_TREEVIEW-->
<hr class="footer"/><address class="footer"><small>
$generatedby&#160;<a href="https://www.doxygen.org/index.html"><img class="footer" src="$relpath^doxygen.svg" width="104" height="31" alt="doxygen"/></a> $doxygenversion
</small></address>
<!--END !GENERATE_TREEVIEW-->
</body>
</html>

View File

@@ -0,0 +1,56 @@
<!-- HTML header for doxygen 1.9.1-->
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=9"/>
<meta name="generator" content="Doxygen $doxygenversion"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<!--BEGIN PROJECT_NAME--><title>$projectname: $title</title><!--END PROJECT_NAME-->
<!--BEGIN !PROJECT_NAME--><title>$title</title><!--END !PROJECT_NAME-->
<link href="$relpath^tabs.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="$relpath^jquery.js"></script>
<script type="text/javascript" src="$relpath^dynsections.js"></script>
$treeview
$search
$mathjax
<link href="$relpath^$stylesheet" rel="stylesheet" type="text/css" />
$extrastylesheet
</head>
<body>
<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
<!--BEGIN TITLEAREA-->
<div id="titlearea">
<table cellspacing="0" cellpadding="0">
<tbody>
<tr style="height: 56px;">
<!--BEGIN PROJECT_LOGO-->
<td id="projectlogo"><img alt="Logo" src="$relpath^$projectlogo"/></td>
<!--END PROJECT_LOGO-->
<!--BEGIN PROJECT_NAME-->
<td id="projectalign" style="padding-left: 0.5em;">
<div id="projectname">$projectname
<!--BEGIN PROJECT_NUMBER-->&#160;<span id="projectnumber">$projectnumber</span><!--END PROJECT_NUMBER-->
</div>
<!--BEGIN PROJECT_BRIEF--><div id="projectbrief">$projectbrief</div><!--END PROJECT_BRIEF-->
</td>
<!--END PROJECT_NAME-->
<!--BEGIN !PROJECT_NAME-->
<!--BEGIN PROJECT_BRIEF-->
<td style="padding-left: 0.5em;">
<div id="projectbrief">$projectbrief</div>
</td>
<!--END PROJECT_BRIEF-->
<!--END !PROJECT_NAME-->
<!--BEGIN DISABLE_INDEX-->
<!--BEGIN SEARCHENGINE-->
<td>$searchbox</td>
<!--END SEARCHENGINE-->
<!--END DISABLE_INDEX-->
</tr>
</tbody>
</table>
</div>
<!--END TITLEAREA-->
<!-- end header part -->

2847
src/l4/doc/source/l4re.cfg Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,80 @@
/* vim:set ft=c: */
/**
* \example hello/server/src/main.c
* This is the famous "Hello World!" program.
*
* \example examples/sys/ipc/ipc_example.c
* This example shows how two threads can exchange data using the L4 IPC
* mechanism. One thread is sending an integer to the other thread which
* is returning the square of the integer. Both values are printed.
*
* \example examples/sys/ipc/ipc.cfg
* Sample configuration file for the IPC example.
*
* \example examples/sys/start-with-exc/main.c
* This example shows how to start a newly created thread with a defined set
* of CPU registers.
*
* \example examples/sys/singlestep/main.c
* This example shows how a thread can be single stepped on the x86
* architecture.
*
* \example examples/sys/aliens/main.c
* This example shows how system call tracing can be done.
*
* \example examples/sys/utcb-ipc/main.c
* This example shows how to send IPC using the UTCB to store payload.
*
* \example examples/sys/isr/main.c
* Example of an interrupt service routine.
*
* \example examples/clntsrv/src/server.cc
* Client/Server example using C++ infrastructure -- Server implementation.
* \example examples/clntsrv/src/client.cc
* Client/Server example using C++ infrastructure -- Client implementation.
* \example examples/clntsrv/src/shared.h
* Client/Server example using C++ infrastructure -- Shared header file.
* \example examples/clntsrv/configs/clntsrv.cfg
* Sample configuration file for the client/server example.
*
* \example examples/libs/l4re/c/ma+rm.c
* Coarse grained memory allocation, in C.
* \example examples/libs/l4re/c++/mem_alloc/ma+rm.cc
* Coarse grained memory allocation, in C++.
*
* \example examples/libs/l4re/c++/shared_ds/ds_clnt.cc
* Sharing memory between applications, client side.
* \example examples/libs/l4re/c++/shared_ds/ds_srv.cc
* Sharing memory between applications, server/creator side.
* \example examples/libs/l4re/c++/shared_ds/shared_ds.cfg
* Sharing memory between applications, configuration file.
*
* \example examples/libs/l4re/streammap/server.cc
* Client/Server example showing how to map a page to another task -- Server
* implementation. Note that there's also a shared memory library that
* supplies this functionality in more convenient way.
* \example examples/libs/l4re/streammap/client.cc
* Client/Server example showing how to map a page to another task -- Client
* implementation. Note that there's also a shared memory library that
* supplies this functionality in more convenient way.
* \example examples/libs/l4re/streammap/streammap.cfg
* Sample configuration file for the client/server map example.
*
*
* \example examples/libs/libirq/loop.c
* libirq usage example using a self-created thread.
*
* \example examples/libs/libirq/async_isr.c
* libirq usage example using asynchronous ISR handler functionality.
*
* \example examples/sys/migrate/thread_migrate.cc
* Thread migration example.
*
* \example examples/sys/migrate/thread_migrate.cfg
* Sample configuration file for the thread migration example.
*
* \example tmpfs/lib/src/fs.cc
* Example file system for L4Re::Vfs.
*/

View File

@@ -0,0 +1,16 @@
\DeclareUnicodeCharacter{2264}{$\leq$}
\DeclareUnicodeCharacter{2212}{-}
\DeclareUnicodeCharacter{2500}{-}
\DeclareUnicodeCharacter{2502}{|}
\DeclareUnicodeCharacter{250C}{|-} % \ulcorner
\DeclareUnicodeCharacter{2510}{-|} % \urcorner
\DeclareUnicodeCharacter{252C}{-|-}
\DeclareUnicodeCharacter{2514}{|\_} % \llcorner
\DeclareUnicodeCharacter{2518}{\_|} % \lrcorner
\DeclareUnicodeCharacter{2534}{\_|\_}
\DeclareUnicodeCharacter{2082}{$_{2}$}
\AtBeginDocument{%
\fancyfoot[RE]{\fancyplain{}{\bfseries\scriptsize Generated for L4Re by Doxygen }}
\fancyfoot[LO]{\fancyplain{}{\bfseries\scriptsize Generated for L4Re by Doxygen }}
}

View File

@@ -0,0 +1,146 @@
// vi:ft=c
/**
\page l4re_pthreads Pthread Support
L4Re supports the standard pthread library functionality. Therefore L4Re
itself does not contain any documentation for pthreads itself. Please refer
to the standard pthread documentation instead.
The L4Re specific parts will be described herein.
<ul>
<li>
Include pthread-l4.h header file:
\code
#include <pthread-l4.h>
\endcode
</li>
<li>Return the local thread capability of a pthread thread:
Use \c pthread_l4_cap(pthread_t t) to get the capability index of
the pthread t.
For example:
\code
pthread_l4_cap(pthread_self());
\endcode
</li>
<li> Setting the L4 priority of an L4 thread works with a special
scheduling policy (other policies do not affect the L4 thread
priority):
\code
pthread_t t;
pthread_attr_t a;
struct sched_param sp;
pthread_attr_init(&a);
sp.sched_priority = l4_priority;
pthread_attr_setschedpolicy(&a, SCHED_L4);
pthread_attr_setschedparam(&a, &sp);
pthread_attr_setinheritsched(&a, PTHREAD_EXPLICIT_SCHED);
if (pthread_create(&t, &a, pthread_func, NULL))
// failure...
pthread_attr_destroy(&a);
\endcode
</li>
<li> You can prevent your pthread from running immediately after the call to
\c pthread_create(..) by adding \c PTHREAD_L4_ATTR_NO_START to the
\c create_flags of the pthread attributes. To finally start the thread
you need to call \c scheduler()->run_thread() passing the capability
of the pthread and scheduling parameters.
\code
pthread_t t;
pthread_attr_t attr;
pthread_attr_init(&attr);
attr.create_flags |= PTHREAD_L4_ATTR_NO_START;
if (pthread_create(&t, &attr, pthread_func, nullptr))
// failure...
pthread_attr_destroy(&attr);
// do stuff
auto ret = L4Re::Env::env()->scheduler()->run_thread(pthread_l4_cap(t),
l4_sched_param(2));
if (l4_error(ret))
// failure...
\endcode
</li>
</ul>
<h4>
Constraints on pthread_t, user-land capability slot, and kernel thread-object
</h4>
<ul>
<li>
`pthread_l4_cap()` is guaranteed to return the valid capability slot
of the pthread (A) until `pthread_join()` or `pthread_detach()` is invoked
on (A)'s `pthread_t`.
</li>
<li>
`pthread_l4_cap()` exposes internal state of the pthread management, take
the necessary precautions as you would for any shared data in concurrent
environments.
If you use `pthread_l4_cap()` guarding against concurrency issues is your
duty.
</li>
<li>
There is no guarantee that a valid capability slot points to a
present capability.
</li>
<li>
<b>Example</b>
It is possible to obtain a valid thread capability slot and for
`l4_task_cap_valid()` to return the capability as not present.
The following example showcases a possible sequence of events.
\code
// Assume: void some_func(void *)
pthread_t pthread = nullptr;
pthread_create(&pthread, nullptr, some_func, nullptr);
// pthread running some_func()
l4_cap_idx_t cap_idx = pthread_l4_cap(pthread);
l4_is_valid_cap(cap_idx); // ---> true
long valid = l4_task_cap_valid(L4RE_THIS_TASK_CAP, cap_idx).label());
// valid == 1 --> capability object is present (refers to a kernel object).
// some_func() exits
cap_idx = pthread_l4_cap(pthread);
l4_is_valid_cap(cap_idx); // ---> true
valid = l4_task_cap_valid(L4RE_THIS_TASK_CAP, cap_idx).label());
// valid == 0 --> capability object is not present (refers to no kernel object).
pthread_join(pthread, nullptr); // invalidates the cap slot and frees
// the pthread's data structures
// using cap_idx here is undefined behavior.
\endcode
</li>
</ul>
*/

View File

@@ -0,0 +1,14 @@
Make Doxygen search field snappier.
diff -Naur old/html/search/search.js new/html/search/search.js
--- old/html/search/search.js 2024-08-05 15:40:32.890343561 +0200
+++ new/html/search/search.js 2024-08-05 15:40:42.557089345 +0200
@@ -63,7 +63,7 @@
this.name = name;
this.resultsPath = resultsPath;
this.keyTimeout = 0;
- this.keyTimeoutLength = 500;
+ this.keyTimeoutLength = 50;
this.closeSelectionTimeout = 300;
this.lastSearchValue = "";
this.lastResultsPage = "";

View File

@@ -0,0 +1,94 @@
// vi:ft=c
/**
\page l4re_servers L4Re Servers
\brief Here you shall find a quick overview over the standard services
running on the L4Re Microkernel.
Sigma0, the Root Pager
======================
Sigma0 is a special server running on L4 because it is responsible
of resolving page faults for the root task, the first useful task on
L4Re. Sigma0 can be seen as part of the kernel, however it runs in
unprivileged mode. To run something useful on the L4Re Microkernel you
usually need to run Sigma0, nevertheless it is possible to replace Sigma0 by
a different implementation.
For more details see \subpage l4re_servers_sigma0
Moe, the Root Task
==================
Moe is our implementation of the L4 root task that is responsible for
bootstrapping the system, and to provide basic resource management services
to the applications on top. Therefore Moe provides L4Re resource management
and multiplexing services:
\li \b Memory in the form of memory allocators (L4Re::Mem_alloc, L4::Factory)
and data spaces (L4Re::Dataspace)
\li \b Cpu in the form of basic scheduler objects (L4::Scheduler)
\li \b Vcon multiplexing for debug output (output only)
\li \b Virtual \b memory \b management for applications, L4Re::Rm
Moe further provides an implementation of L4Re name spaces (L4Re::Namespace),
which are for example used to provide a read only directory of all multi-boot
modules. In the case of a boot loader, like grub that enables a VESA frame
buffer, there is also a single instance of an L4Re graphics session
(L4Re::Goos).
To start the system Moe starts a single ELF program, the init process. The
init process (usually Ned, see the next section) gets access to all resources
managed by Moe and to the Sigma0 root pager interface.
For more details see \subpage l4re_servers_moe "Moe, the Root-Task".
Ned, the Default Init Process
=============================
To keep the root task free from complicated scripting engines and to avoid
circular dependencies in application startup (that could lead to dead locks)
the configuration and startup of the real system is managed by an extra task,
the init process.
Ned is such an init process that allows system configuration via Lua scripts.
For more information see \subpage l4re_servers_ned "Ned".
Io, the Platform and Device Resource Manager
============================================
Because all peripheral management in L4Re is done in user-level
applications, there is the need to have a centralized management of
the resources belonging to the platform and to peripheral devices.
This is the job of Io. Io provides portable abstractions for iterating and
accessing devices and their resources (IRQ's, IO Memory...), as well as
delegating access to those resources to other applications (e.g., device
drivers).
For more details see \subpage io "Io, the Io Server".
Other Servers
=============
The following additional server package are available on top of the core
L4Re environment.
- Rtc, the Real-Time Clock Server
is a simple multiplexer for real-time clock hardware on your platform.
- fb-drv, the Low-Level Graphics Driver
provides low-level access and initialization of various
graphics hardware. It has support for running VESA BIOS calls on Intel x86
platforms, as well as support for various ARM display controllers.
`fb-drv` provides a single instance of the L4Re::Goos interface and can
serve as a back end for the Mag server, in particular, if there is no graphics
support in the boot loader.
*/

View File

@@ -0,0 +1,94 @@
/**
\page l4re_tutorial Tutorial
This tutorial assumes that the reader is familiar with the basic %L4 concepts
that were discussed in the \ref l4re_intro section.
Here you can find the first steps to boot a very simple setup. The setup
consists of the following components:
\li L4Re Microkernel
\li Sigma0 --- Root Pager
\li Moe --- Root Task
\li Ned --- Init Process
\li hello --- The classical 'Hello World' Application
The guide assumes that you already compiled the base components and describes
how to generate an ISO image, with GRUB as a boot loader, that can for
example be booted within QEMU.
First you need a \c modules.list file that contains an entry for the scenario.
\code
modaddr 0x002000000
entry hello
kernel fiasco -serial_esc
roottask moe rom/hello.cfg
module l4re
module ned
module hello.cfg
module hello
\endcode
This file describes all the binaries and scripts to put into the ISO image,
and also describes the GRUB \c menu.lst contents. What you need to do is to
set the \c make variable \c MODULE_SEARCH_PATH to contain the path to your
L4Re Microkernel's build directory and the directory containing your \c hello.cfg
script.
The \c hello.cfg script should look like the following. A ready to use
version can be found in l4/conf/examples.
\code
local L4 = require("L4");
L4.default_loader:start({}, "rom/hello");
\endcode
The first line of this script ensures that the \c L4 package is available
for the script. The second line uses the default loader object defined in that
package and starts the binary \c rom/hello.
\note All modules defined in \c modules.list are available as data spaces
(L4Re::Dataspace) and registered in a name space (L4Re::Namespace). This
name space is in turn available as 'rom' to the init process
(\ref l4re_servers_ned "Ned").
Now you can go to your L4Re build directory and run the following command.
\note The example assumes that you have created the \c modules.list and \c
hello.cfg files in the /tmp directory. Adapt if you created them
somewhere else.
\code
make grub2iso E=hello MODULES_LIST=/tmp/modules.list MODULE_SEARCH_PATH=/tmp:<path_to_fiasco_builddir>
\endcode
Now you should be able to boot the image in QEMU by running:
\code
qemu-system-x86_64 -m 1024 -cdrom images/hello.iso -serial stdio
\endcode
If you press `<ESC>` in the terminal that shows you the serial output you
enter the microkernel's debugger... Have fun.
\section customizations Customizations
A basic set of bootable entries can be found in \c l4/conf/modules.list. This file
is the default for any image creation as shown above. It is recommended that
local modification regarding image creation are done in
\c conf/Makeconf.boot. Initially you may copy \c Makeconf.boot.example to
\c Makeconf.boot. You can overwrite \c MODULES_LIST to set your own
modules-list file. Set \c MODULE_SEARCH_PATH to your setup according to the
examples given in the file.
When configured a \c make call is reduced to:
\code
make grub2iso E=hello
\endcode
All other local configuration can be done in a
\c Makeconf.local file located in the \c l4 directory.
*/

328
src/l4/mk/Kconfig Normal file
View File

@@ -0,0 +1,328 @@
mainmenu "L4Re Configuration"
source "Kconfig.generated.defines"
config ARCH_ENABLE_STACK_PROTECTOR
bool
config ARCH_NO_MMU
bool
choice
prompt "Target Architecture"
# ARCH_CHOICE_DEFAULT
help
Specify for which processor architecture you want to build.
# ARCH_CHOICE
endchoice
config BUILD_ARCH
string
# ARCH_NAME
# currently we have nothing for abi linux, so just do not offer this option
#choice
# prompt "ABI"
# default BUILD_ABI_l4f
#
#config BUILD_ABI_l4f
# bool "L4/Fiasco"
#
#config BUILD_ABI_linux
# bool "Linux"
#
#endchoice
config BUILD_ABI_l4f
def_bool y
config BUILD_ABI
string
default "l4f" if BUILD_ABI_l4f
default "linux" if BUILD_ABI_linux
# PF_INCLUDE
source "mk/arch/Kconfig.common.inc"
choice
prompt "Platform Selection"
# ARCH_DEFAULT_PF
# ARCH_PLATFORMS
endchoice
source "Kconfig.generated.platform_types"
source "Kconfig.generated.pkgs"
config MMU
bool
default y
depends on !ARCH_NO_MMU
config USE_DROPS_STDDIR
def_bool n
config DROPS_STDDIR
string
default "/path/to/l4re"
config DROPS_INSTDIR
string
default "/path/to/l4re"
config BID_COLORED_PHASES
bool
default y
menu "Building"
config YACC
string
default "yacc"
config LEX
string
default "flex"
config BID_OPTIMIZE_SIZE
bool "Optimize for size (-Os)"
help
Use -Os instead of -O2 to build smaller executables.
config BID_DEBUG_INFO
bool "Generate debug information"
default y
help
Generate debug information.
If unsure, say 'Y'.
choice
prompt "Position independent executables"
depends on (BUILD_ARCH_amd64 || BUILD_ARCH_arm || BUILD_ARCH_arm64) && L4_LIBC_UCLIBC
default BID_PIE_VOLUNTARY
config BID_PIE_NONE
bool "no"
help
Do not support position independent executables.
config BID_PIE_VOLUNTARY
bool "selected packages"
help
Build position independent executables where beneficial. All
libraries are built as position independent. Executables are only
linked position independent if the package indicated to do so.
Enabling this option will add some executable size and runtime
overhead.
config BID_PIE_ALL
bool "everything"
depends on EXPERIMENTAL
help
Build all executables as position independent. This is not supported
by all packages on all platforms and might break their build.
Enabling this option will add some executable size and runtime
overhead.
endchoice
config BID_BUILD_TESTS
bool "Also build tests"
default y
help
Enable to build tests.
If unsure, say 'N'.
config BID_BUILD_TESTS_SHARED
bool "Use shared linking for tests" if EXPERT
depends on BID_BUILD_TESTS
default y if !ARCH_NO_MMU
help
Linking tests shared reduces the on-disk footprint of the build tree,
and, potentially, also the amount of data needed to be transferred on
a single test invocation.
Enable this on platforms that support it if in doubt.
config INT_CPP_NAME_SWITCH
bool "Automatically determine internal gcc preprocessor names"
default y
config INT_LD_NAME_SWITCH
bool "Automatically determine internal ld names"
default y
config INT_PP_NAME
string "Internal name of the compiler preprocessor"
default "cpp0"
depends on !INT_CPP_NAME_SWITCH
config INT_LD_NAME
string "Internal name of the compiler linker"
default "ld"
depends on !INT_LD_NAME_SWITCH
config BID_STRIP_BINARIES
bool "Strip binaries on install"
default y
help
If enabled, binaries (libraries and executables) will be stripped on
installation into $(L4DIR)/bin or $(DROPS_STDDIR)/bin. If you want
to load them with all their symbols (eg to show the symbols with the
Fiasco kernel debugger), say 'N' here.
If unsure, say 'Y'.
config BID_LD_EMIT_UNWIND
bool "GCC: Emit unwind tables"
help
If enabled, gcc will be passed the '-funwind-tables' cmdline
option, adding unwind tables for all generated code. Binaries will
be larger, but without unwind tables no backtraces can be created
on most architectures (except on x86) and no exception handling
can be provided by LLVM's libunwind.
If unsure, say 'N'.
config BID_GCC_OMIT_FP
bool "GCC: Omit Frame-pointers"
default y
help
If enabled, gcc will be passed the '-fomit-frame-pointer' cmdline
option, adding an additional register to the register set for the
generated code. Programs will be faster, but backtraces cannot be
done, seriously hindering debugging.
If unsure, say 'Y'.
config BID_GCC_ENABLE_STACK_PROTECTOR
bool "GCC: enable stack protector"
default y if ARCH_ENABLE_STACK_PROTECTOR
help
If enabled, support for the gcc stack protector will be enabled.
The stack protector uses stack canaries to detect stack smashing
attacks (see "man gcc" for details). In L4Re the stack protector is
enabled only for packages that are linked against the full uclibc.
Enabling this feature will add some overhead, but increase security.
If unsure, say 'Y'.
choice
prompt "GCC: Enable stack protector"
depends on BID_GCC_ENABLE_STACK_PROTECTOR
default BID_GCC_STACK_PROTECTOR
config BID_GCC_STACK_PROTECTOR_ALL
bool "on all functions"
help
If enabled, '-fstack-protector-all' flag is used for gcc. This
option adds significant overhead, as the stack canary is checked on
every function return. See "man gcc" for details.
config BID_GCC_STACK_PROTECTOR
bool "exclusively for functions with vulnerable objects"
help
If enabled, '-fstack-protector' flag is passed to gcc. If this
flag is set, gcc will add stack canaries to vulnerable functions, such as
functions that call "alloca", and functions with buffers larger than 8
bytes.
endchoice
config BID_GENERATE_MAPFILE
bool "Generate Map-files for binaries"
help
Enabling this option will generate map-files together with the
binaries. This might be handy for debugging purposes. See ld(1)
for details on mapfiles.
If unsure, say N.
config BID_BUILD_DOC
bool "Build doc directories"
help
Say Y if you also want to build the doc directories.
config RELEASE_MODE
bool "Do a release and non-debug(able) build"
help
Enable to leave out debugging and other code normally not needed.
Do only enable this after you have a working configuration.
Say N.
config MAKECONFS_ADD
string "Additional Makeconf files"
help
List of white space separated suffixes of Makeconf files
which will be included in every source directory as
Makeconf.<suffix>.
config EXPERIMENTAL
bool "Prompt for experimental features"
help
Experimental features are available when enabling this option.
This encompases features that are still in development and might not
work correctly for all packages on all architectures at all times.
Use with caution!
if EXPERIMENTAL
config BID_THUMB
bool "Build thumb code"
depends on BUILD_ARCH_arm
help
Build with -mthumb by default. This will reduce the code size at the
slight expense of execution speed.
config BID_STATIC_HEAP
bool "Static heap reservation"
depends on BID_CAN_STATIC_HEAP
help
Statically reserve the heap in the bss section of executables.
This will save the additional MPU region that would otherwise be
necessary due to the dynmamic allocation of a dataspace.
config BID_STATIC_STACK
bool "Static stack allocation"
depends on BID_CAN_STATIC_STACK
help
Statically allocate stack in bss section of executables.
This will save the additional MPU region that would otherwise be
necessary. Also relieves the loader from dynamically allocating any
stack memory.
endif # EXPERIMENTAL
config BID_CAN_STATIC_HEAP
bool # enabled by l4re-core for configurations that support this
config BID_CAN_STATIC_STACK
bool # enabled by l4re-core for configurations that support this
config BID_PIE
bool
default y
depends on BID_PIE_VOLUNTARY || BID_PIE_ALL
config EXPERT
bool "Show expert options"
help
Expert options are those that you should never have to change unless
you have a very good reason to do so. Their default values are
intended to be used for nearly all use-cases. So only enable this
option if you are certain that you need it and ensure you are aware
of all consequences when changing any of them.
endmenu
# PKG_KCONFIG

790
src/l4/mk/Makeconf Normal file
View File

@@ -0,0 +1,790 @@
# -*- Makefile -*-
# vim:set ft=make:
#
# L4Re Buildsystem
#
# Make configuration file
#
# This file is included by all Makefile-templates. This file defines macros
# for div commands, sets general DROPS-Makefile variables, ensures the
# dependencies from the various Makeconf.locals, defines the messages for
# div actions, and permits the dependency-creation on clean-rules.
#
ifeq ($(origin _L4DIR_MK_MAKECONF),undefined)
_L4DIR_MK_MAKECONF=y
include $(L4DIR)/mk/util.mk
MAKEFLAGS += --no-print-directory -Rr
# the default target is all
all::
mrproper:: cleanall
# make .general.d dependent on the role-file
$(if $(ROLE),$(OBJ_DIR)/.general.d: $(L4DIR)/mk/$(ROLE))
-include $(wildcard $(L4DIR)/mk/arch/Makeconf.*)
# Additional available variants, 'std' is always available
VARIANTS_AVAILABLE := $(patsubst $(L4DIR)/mk/variants/%.inc,%,$(wildcard $(L4DIR)/mk/variants/*.inc))
include $(foreach v,$(VARIANTS_AVAILABLE),$(L4DIR)/mk/variants/$(v).inc)
CHOSEN_VARIANTS := $(subst +, ,$(VARIANT))
# Get variant specific variables for all chosen variants. This will for
# example get <VARNAME>-variant-nofpu if nofpu variant is a chosen variant
define variant_values
$(foreach v, $(CHOSEN_VARIANTS), $($(1)-variant-$(v)))
endef
$(foreach v, $(CHOSEN_VARIANTS), $(eval $(BID_DEFINE-variant-$(v))))
ARCH = $(BUILD_ARCH)
BUILDDIR_SEARCHPATH = $(OBJ_BASE)/bin/$(ARCH)_$(CPU)/plain:$(OBJ_BASE)/bin/$(ARCH)_$(CPU)/$(BUILD_ABI):$(OBJ_BASE)/lib/$(ARCH)_$(CPU)/std/plain:$(OBJ_BASE)/lib/$(ARCH)_$(CPU)/std/$(BUILD_ABI):$(OBJ_BASE)/assets
CROSS_COMPILE ?= $(CROSS_COMPILE_$(ARCH))
OFORMAT = $(OFORMAT_$(ARCH))
BFD_ARCH = $(BFD_ARCH_$(ARCH))
L4_KIP_ADDR ?= $(L4_KIP_ADDR_$(ARCH))
L4_KIP_OFFS_SYS_INVOKE = 0x800
L4_KIP_OFFS_SYS_DEBUGGER = 0x900
L4_STACK_ADDR ?= $(L4_STACK_ADDR_$(ARCH))
L4_STACK_SIZE ?= $(if $(L4_STACK_SIZE_MAIN_THREAD),$(L4_STACK_SIZE_MAIN_THREAD),0x8000)
CC_WHITELIST-gcc := 9 10 11 12 13 14 15
CC_WHITELIST-clang := 15 16 17 18 19
VERBOSE = $(if $(CONFIG_VERBOSE),,@)
DEPEND_VERBOSE = $(if $(CONFIG_DEPEND_VERBOSE),,@)
DROPS_STDDIR = $(patsubst "%",%,$(CONFIG_DROPS_STDDIR))
DROPS_INSTDIR = $(patsubst "%",%,$(CONFIG_DROPS_INSTDIR))
RAM_SIZE_MB = $(CONFIG_RAM_SIZE_MB)
PLATFORM_TYPE ?= $(patsubst "%",%,$(CONFIG_PLATFORM_TYPE))
BITS = $(patsubst "%",%,$(CONFIG_BITS))
CPU = $(patsubst "%",%,$(CONFIG_CPU))
CPU_ABI = $(patsubst "%",%,$(CONFIG_CPU_ABI))
BUILD_ABI = $(patsubst "%",%,$(CONFIG_BUILD_ABI))
BUILD_ARCH = $(patsubst "%",%,$(CONFIG_BUILD_ARCH))
MAKECONFS_ADD = $(call strip_quotes,$(CONFIG_MAKECONFS_ADD))
CARCHFLAGS = $(CARCHFLAGS_$(ARCH)) $(CARCHFLAGS_$(ARCH)_$(CPU))
CCXX_FLAGS = $(CCXX_FLAGS_$(BUILD_ARCH))
error_on_env_vars = $(if $(filter environment,$(origin $1)), \
$(error '$1' specified in environment. \
Please use a Makeconf.local file for \
specifying tool overrides explicitly))
dv = $(call error_on_env_vars,$1)$\
$(if $(filter-out default undefined,$(origin $(1))),$(1)-default,$(1))
$(call dv,AR) = $(CROSS_COMPILE)ar
$(call dv,AS) = $(CROSS_COMPILE)as
AWKP ?= gawk --posix
CCACHE ?= ccache
$(call dv,FC) = $(if $(USE_CCACHE),$(CCACHE) )$(CROSS_COMPILE)gfortran
# Args: 1=$(CLANG); 2=clang/clang++/clang-cpp
# Rules:
# If $(CLANG) contains '-', use $(CLANG) as clang-version
# else if $(CLANG) contains '/', use $(CLANG) as clang-path
# otherwise clang-version/clang-path are both empty.
# The $\ is required to suppress a newline in the command for $(CLANG) without
# '-', see the comparison in BID_call_compiler_default.
clang-bin = $(if $(filter -%,$(1)),$(2)$(1),$\
$(if $(filter %/,$(1)),$(1)$(2),$(2)))
clang-bin-tgt = $(call clang-bin,$(1),$(2)) \
$(addprefix --target=,$(notdir $(CROSS_COMPILE:%-=%)))
$(call dv,CC) = $(if $(USE_CCACHE),$(CCACHE) )$(if $(CLANG),$(call \
clang-bin-tgt,$(CLANG),clang),$(CROSS_COMPILE)gcc)
$(call dv,CXX) = $(if $(USE_CCACHE),$(CCACHE) )$(if $(CLANG),$(call \
clang-bin-tgt,$(CLANG),clang++),$(CROSS_COMPILE)g++)
$(call dv,CPP) = $(if $(CLANG),$(call \
clang-bin-tgt,$(CLANG),clang-cpp),$(CROSS_COMPILE)cpp)
$(call dv,ADAC) = $(CROSS_COMPILE)gnatmake -q
HOST_ADAC = gnatmake -q
CP ?= cp
DOXYGEN ?= doxygen
ECHO ?= echo
ELF_PATCHER = $(OBJ_BASE)/tool/elf-patcher/elf-patcher
FIXDEP = $(OBJ_BASE)/scripts/basic/fixdep
GENOFFSETS = $(L4DIR)/tool/bin/genoffsets.pl
GOSH = $(firstword $(wildcard $(L4DIR)/../tools/gosh/gosh \
$(DROPS_STDDIR)/tool/bin/gosh \
$(shell which gosh 2>/dev/null) ) \
did_not_find_gosh___please_install_gosh )
HOST_CC ?= $(if $(CLANG),$(call clang-bin,$(CLANG),clang),gcc)
HOST_CXX ?= $(if $(CLANG),$(call clang-bin,$(CLANG),clang++),g++)
HOST_LD ?= ld
INSTALL = install
$(call dv,LD) = $(CROSS_COMPILE)ld -m $(LD_EMULATION) --oformat $(OFORMAT)
DTC ?= dtc
LATEX = latex
PDFLATEX = pdflatex
GREP = GREP_OPTIONS= grep
LN = ln
MKDIR = mkdir -p
NM ?= $(CROSS_COMPILE)nm
OBJCOPY ?= $(CROSS_COMPILE)objcopy
OBJDUMP ?= $(CROSS_COMPILE)objdump
RANLIB ?= $(CROSS_COMPILE)ranlib
$(call dv,RM) = rm -f
SCRUB = $(RM) $(wildcard *.old) $(wildcard *~) $(wildcard *.bak) \
$(wildcard \#*\#)
SED = sed
SHELL = bash
SIZE ?= $(CROSS_COMPILE)size
STRIP ?= $(CROSS_COMPILE)strip
SVN = svn
TR = tr
GEN_DOPECODE = $(L4DIR)/tool/gen_dopecode/gen_dopecode
PAGER ?= less
DISASM_CMD ?= $(OBJDUMP) -lCSd $(1) | $(PAGER)
IMAGES_DIR ?= $(OBJ_BASE)/images
# QEMU defaults
QEMU_ARCH_MAP_$(ARCH) ?= qemu-system-$(ARCH)
QEMU_PATH ?= $(QEMU_ARCH_MAP_$(ARCH))
# Arm FVP defaults
FVP_PLAT_MAP_arm_fvp_base ?= FVP_Base_RevC-2xAEMvA
FVP_PLAT_MAP_arm_fvp_base_r ?= FVP_BaseR_AEMv8R
FVP_PATH ?= $(FVP_PLAT_MAP_$(PLATFORM_TYPE))
# Subdirs where libs and binaries are put into
BID_install_subdir_base = $(ARCH)_$(CPU)/$(L4API)
BID_install_subdir_var = $(subst -,/,$(SYSTEM))
ifneq ($(PT),)
PLATFORM_TYPE := $(PT)
endif
# include this one early to be able to set OBJ_BASE
-include $(L4DIR)/Makeconf.local
-include $(L4DIR)/conf/Makeconf.local
# output directory
ifeq ($(O)$(OBJ_BASE),)
$(error need to give builddir with O=.../builddir)
else
ifneq ($(O),)
ifeq ($(filter-out undefined environment,$(origin OBJ_BASE)),)
OBJ_BASE := $(abspath $(O))
export OBJ_BASE
# prevent passing O to sub-makes, because it may be a relative path
# not valid there
override O =
MAKEOVERRIDES := $(filter-out O=%,$(MAKEOVERRIDES))
endif
endif
endif
ifeq ($(origin L4DIR_ABS),undefined)
L4DIR_ABS := $(abspath $(L4DIR))
endif
ifeq ($(origin PKGDIR_ABS),undefined)
PKGDIR_ABS := $(abspath $(PKGDIR))
endif
ifeq ($(origin SRC_DIR),undefined)
SRC_DIR := $(CURDIR)
endif
ifeq ($(origin SRC_BASE_ABS),undefined)
SRC_BASE ?= $(L4DIR)
SRC_BASE_ABS := $(abspath $(SRC_BASE))
export SRC_BASE_ABS
endif
ifeq ($(origin OBJ_DIR),undefined)
OBJ_DIR := $(subst $(SRC_BASE_ABS),$(OBJ_BASE),$(SRC_DIR))
endif
ifeq ($(origin PKGDIR_OBJ),undefined)
PKGDIR_OBJ := $(abspath $(OBJ_DIR)/$(PKGDIR))
endif
PKGDIR_REL := $(patsubst pkg/%,%,$(patsubst $(L4DIR_ABS)/%,%,$(PKGDIR_ABS)))
# if PKGDIR is not in L4DIR, we have an external package, so make up some
# build-dir for it
ifneq ($(patsubst $(L4DIR_ABS)/%,,$(PKGDIR_ABS)),)
ifneq ($(filter-out $(OBJ_BASE)/ext-pkg%,$(PKGDIR_OBJ)),)
PKGDIR_OBJ := $(OBJ_BASE)/ext-pkg$(PKGDIR_OBJ)
OBJ_DIR := $(OBJ_BASE)/ext-pkg$(OBJ_DIR)
endif
endif
# sanity check the object dir
ifneq ($(SRC_BASE_ABS),$(OBJ_BASE))
ifeq ($(SRC_DIR),$(OBJ_DIR))
$(warning Sorry, your object or source path became garbled.)
$(warning OBJ_BASE: $(OBJ_BASE))
$(warning SRC_BASE_ABS: $(SRC_BASE_ABS))
$(warning SRC_DIR: $(SRC_DIR))
$(warning OBJ_DIR: $(OBJ_DIR))
$(warning PKGDIR: $(PKGDIR))
$(warning L4DIR_ABS: $(L4DIR_ABS))
$(warning PKGDIR_ABS: $(PKGDIR_ABS))
$(warning PKGDIR_OBJ: $(PKGDIR_OBJ))
$(error Please investigate.)
endif
endif
OBJ_DIR_EXPORT = $(OBJ_DIR)
export OBJ_DIR_EXPORT
VPATH_SRC_BASE ?= $(SRC_DIR)
# Makeconf.local handling
# dont use -include here, as we have special build conditions in $(L4DIR)/
ifeq ($(origin BID_ROOT_CONF),undefined)
BID_ROOT_CONF := $(abspath $(OBJ_BASE))/.config.all
endif
ifeq ($(wildcard $(BID_ROOT_CONF)),)
ifeq ($(BID_IGN_ROOT_CONF),)
$(error No configuration file found in build directory "$(OBJ_BASE)". Please run "make O=/path/to/objdir config" in "$(L4DIR_ABS)" or specify a valid build directory)
endif
else
include $(BID_ROOT_CONF)
endif
# If we're working on a program that wants the RAM_BASE be considered in its
# linking address, source a possible privately configured one. Without MMU,
# we naturally need RAM_BASE.
ifneq ($(if $(CONFIG_MMU),$(RELOC_PHYS),y),)
INCLUDE_BOOT_CONFIG := required
endif
ifneq ($(INCLUDE_BOOT_CONFIG),)
-include $(L4DIR)/conf/Makeconf.boot
-include $(OBJ_BASE)/conf/Makeconf.boot
PLATFORM_CONF_FILE := $(firstword $(wildcard $(L4DIR)/conf/platforms/$(PLATFORM_TYPE).conf $(L4DIR)/mk/platforms/$(PLATFORM_TYPE).conf))
ifneq ($(PLATFORM_TYPE),$(patsubst "%",%,$(CONFIG_PLATFORM_TYPE)))
include $(PLATFORM_CONF_FILE)
else
ifneq ($(CONFIG_PLATFORM_TYPE_custom),)
PLATFORM_RAM_BASE=$(CONFIG_PLATFORM_RAM_BASE)
PLATFORM_RAM_SIZE_MB=$(CONFIG_PLATFORM_RAM_SIZE_MB)
PLATFORM_UART_NR=$(CONFIG_PLATFORM_UART_NR)
else
ifeq ($(INCLUDE_BOOT_CONFIG),optional)
-include $(PLATFORM_CONF_FILE)
else
include $(PLATFORM_CONF_FILE)
endif
endif
endif
-include $(OBJ_BASE)/Makeconf.ram_base
BID_RAM_BASE_DEP := $(if $(wildcard $(OBJ_BASE)/Makeconf.ram_base),$(OBJ_BASE)/Makeconf.ram_base)
ifeq ($(RAM_BASE),)
RAM_BASE := 0
endif
RAM_SIZE_MB := $(if $(RAM_SIZE_MB),$(RAM_SIZE_MB),$(PLATFORM_RAM_SIZE_MB))
endif
INCLUDE_MAKE_RULES += $(foreach m,$(MAKECONFS_ADD),$(SRC_DIR)/Makeconf.$(m))
INCLUDE_MAKE_RULES_EXPANDED := $(foreach m,$(INCLUDE_MAKE_RULES),$(wildcard $(m)))
ifneq ($(strip $(INCLUDE_MAKE_RULES_EXPANDED)),)
-include $(INCLUDE_MAKE_RULES_EXPANDED)
endif
-include $(OBJ_BASE)/Makeconf.local
-include $(OBJ_BASE)/conf/Makeconf.local
ifneq ($(PKGDIR_ABS),)
-include $(PKGDIR_ABS)/Makeconf.local
endif
# if it is not already set, we use this in the local dir
MAKECONFLOCAL ?= Makeconf.local
-include $(MAKECONFLOCAL)
define _check_toolpath
ifneq ($(CONFIGURED_$1),)
ifneq ($(CONFIGURED_$1),$(realpath $(shell which $(filter-out $(CCACHE),$($1)))))
$$(error Configured $1 different than used one:$$(newline) \
Configured: $(CONFIGURED_$1)$$(newline) \
Used: $(realpath $(shell which $(filter-out $(CCACHE),$($1))))$$(newline) \
==> Please reconfigure by calling "make oldconfig" in the root source directory with the same compiler set)
endif
endif
endef
ifeq ($(BID_IGN_ROOT_CONF),)
$(eval $(call _check_toolpath,CC))
$(eval $(call _check_toolpath,CXX))
endif
DROPS_STDDIR ?= /home/drops
QEMU_OPTIONS ?= -serial stdio $(QEMU_OPTIONS_$(ARCH))
ifneq ($(PL),)
PL_j := -j $(PL)
export PL
endif
include $(L4DIR)/mk/config.inc
# MAKEDEP-call:
# arg1 - compiler binary name
# arg2 - [opt] compiler target. Will be written as target within the
# dependency file
# arg3 - [opt] name of the dependency file. If unset, .<arg2>.d will be used.
# arg4 - [opt] alternative binary name
ifeq ($(origin BID_LIBGENDEP_PATHS), undefined)
ifeq ($(HOST_SYSTEM),linux)
BID_LIBGENDEP_PATHS_fn = \
$(firstword $(wildcard $(abspath $(OBJ_BASE)/tool/gendep$(1) \
$(DROPS_STDDIR)/tool/lib$(1))))
BID_LIBGENDEP_PATHS := \
$(call BID_LIBGENDEP_PATHS_fn,/64):$(call \
BID_LIBGENDEP_PATHS_fn,/32):$(call BID_LIBGENDEP_PATHS_fn)
endif
ifeq ($(HOST_SYSTEM),darwin)
BID_LIBGENDEP_PATHS := \
$(firstword $(wildcard $(abspath $(OBJ_BASE)/tool/gendep \
$(DROPS_STDDIR)/tool/lib)))
endif
endif
ifeq ($(HOST_SYSTEM),linux)
LD_GENDEP_PREFIX = LD_PRELOAD=libgendep.so LD_LIBRARY_PATH=$(if $(LD_LIBRARY_PATH),$(LD_LIBRARY_PATH):)$(BID_LIBGENDEP_PATHS)
endif
ifeq ($(HOST_SYSTEM),darwin)
LD_GENDEP_PREFIX = DYLD_FORCE_FLAT_NAMESPACE=1 DYLD_INSERT_LIBRARIES=$(BID_LIBGENDEP_PATHS)/libgendep.so
endif
MAKEDEP=$(LD_GENDEP_PREFIX) \
GENDEP_TARGET=$(if $(2),$(2),$@) \
GENDEP_BINARY=$(firstword $(1)) $(if $(3),GENDEP_DEPFILE=$(3)) \
$(if $(4),GENDEP_BINARY_ALT1=$(4))
# We recognize the following Fortran file extensions.
FORTRAN_FILE_EXTENSIONS = .f .F .f90 .F90 .f95 .F95
# We recognize the following Ada file extensions.
ADA_FILE_EXTENSIONS = .adb .ads
# We recognize the following file extensions for assembly.
BID_ASM_FILE_EXTENSIONS ?= .S
BID_ASM_CPP_FILE_EXTENSIONS ?= .S
# macros used here and in packages
# check if the current architecture is in the provided list of allowed
# architectures and exit with an error if not.
# 1: list of allowed architectures
define check_for_arch
$(if $(filter $(ARCH),$1),,
$(error ERROR: Architecture '$(ARCH)' is not supported for target $@))
endef
# Get all variants of a variable
# This contains specific versions of this variable for
# - architecture
# - original system
# - target
# - target directory
# As well es their `-y` variants
#
# 1: variable name
define bid_flag_variants
$($(1)-y) $($(1)_$(ARCH)) $($(1)_$(ARCH)-y) \
$($(1)_$(OSYSTEM)) $($(1)_$(OSYSTEM)-y) \
$($(1)_$@) $($(1)_$@-y) $($(1)_$@_$(OSYSTEM)) $($(1)_$@_$(OSYSTEM)-y) \
$($(1)_$(@D)) $($(1)_$<) $($(1)_$(@D)/$(<F)) \
$($(1)_$(<F)) $($(1)_$(<F)_$(OSYSTEM)) $($(1)_$(<F)_$(OSYSTEM)-y) \
$($(1)_$(<D)) $(call variant_values,$(1))
endef
# 1: argument to validate and return if it works
# 2: return if argument does not work with compiler
# 3: compiler name
# 4: compiler type
check_compiler_opt = $(if $(shell $(filter-out $(CCACHE),$(3)) $(CARCHFLAGS) \
$(CCXX_FLAGS) $(check_compiler_flags) $(1) -c -o /dev/null \
-x $(4) /dev/null >/dev/null 2>&1 || echo X),$(2),$(1))
checkcc = $(call check_compiler_opt,$(1),$(2),$(CC),c)
checkcxx = $(call check_compiler_opt,$(1),$(2),$(CXX),c++)
checkdtc = $(shell if $(DTC) $(1) --version /dev/null > /dev/null 2>&1; \
then echo "$(1)"; fi)
checkcc_nowarn = $(if $(call checkcc,-W$(1),),-Wno-$(1))
checkcxx_nowarn = $(if $(call checkcxx,-W$(1),),-Wno-$(1))
checkld = $(shell if $(callld) -v "$1" > /dev/null 2>&1; \
then echo "$(1)"; else echo "$(2)"; fi)
callcc = LC_ALL=C $(filter-out $(CCACHE),$(CC)) $(CARCHFLAGS) $(CCXX_FLAGS)
callcxx = LC_ALL=C $(filter-out $(CCACHE),$(CXX)) $(CARCHFLAGS) $(CCXX_FLAGS)
callfc = LC_ALL=C $(filter-out $(CCACHE),$(FC)) $(CARCHFLAGS) $(CCXX_FLAGS)
callld = LC_ALL=C $(firstword $(LD))
get_cc_version_part = $(shell echo $(1) | $(callcc) -E -x c - | tail -1)
# compiler variables: version, base dir, include dir, gcc lib, ...
# despite having GCC in their name, they are generic and also used with and
# derived for clang
# note: determining these variables is slow, and the values should
# be set in .config.all. However, this is the place were
# they are determined on a 'make config' in $(L4DIR)
BID_COMPILER_TYPE_f = $(if $(findstring clang, $(shell $(callcc) --version)),clang,gcc)
BID_LD_TYPE_f = $(if $(findstring LLD, $(shell $(callld) --version)),lld,gnu)
# We fall back to BID_COMPILER_TYPE_f if BID_COMPILER_TYPE is not cached yet,
# because we need this info in the following lines before caching
__tmp_bid_compiler_type := $(or $(BID_COMPILER_TYPE),$(BID_COMPILER_TYPE_f))
ifeq ($(__tmp_bid_compiler_type),gcc)
BID_COMPILER_IS_GCC = 1
endif
ifeq ($(__tmp_bid_compiler_type),clang)
BID_COMPILER_IS_CLANG = 1
check_compiler_flags := -Werror=unknown-warning-option -Werror=unused-command-line-argument
endif
GCCMAJORVERSION_ID_gcc = __GNUC__
GCCMINORVERSION_ID_gcc = __GNUC_MINOR__
GCCPATCHLEVEL_ID_gcc = __GNUC_PATCHLEVEL__
GCCMAJORVERSION_ID_clang = __clang_major__
GCCMINORVERSION_ID_clang = __clang_minor__
GCCPATCHLEVEL_ID_clang = __clang_patchlevel__
GCCMAJORVERSION_ID_f = $(GCCMAJORVERSION_ID_$(BID_COMPILER_TYPE_f))
GCCMINORVERSION_ID_f = $(GCCMINORVERSION_ID_$(BID_COMPILER_TYPE_f))
GCCPATCHLEVEL_ID_f = $(GCCPATCHLEVEL_ID_$(BID_COMPILER_TYPE_f))
GCCMAJORVERSION_f = $(call get_cc_version_part, $(GCCMAJORVERSION_ID_f))
GCCMINORVERSION_f = $(call get_cc_version_part, $(GCCMINORVERSION_ID_f))
GCCPATCHLEVEL_f = $(call get_cc_version_part, $(GCCPATCHLEVEL_ID_f))
# the version is just the major version except for GCC 1-4 where it is
# major.minor
GCCVERSION_f_gcc = $(GCCMAJORVERSION_f)$(if $(filter $(GCCMAJORVERSION_f),1 2 3 4),.$(GCCMINORVERSION_f))
GCCVERSION_f_clang = $(GCCMAJORVERSION_f)
GCCVERSION_f = $(GCCVERSION_f_$(BID_COMPILER_TYPE_f))
GNATVERSION_f = $(shell LC_ALL=C $(ADAC) --version 2>/dev/null | sed -ne 's/GNATMAKE \([^ ]*\).*/\1/p')
HOST_GNATVERSION_f = $(shell LC_ALL=C $(HOST_ADAC) --version 2>/dev/null | sed -ne 's/GNATMAKE \([^ ]*\).*/\1/p')
GNATMAJORVERSION = $(word 1,$(subst ., ,$(GNATVERSION)))
HOST_GNATMAJORVERSION = $(word 1,$(subst ., ,$(HOST_GNATVERSION)))
GNATMINORVERSION = $(word 2,$(subst ., ,$(GNATVERSION)))
GNATPATCHVERSION = $(word 3,$(subst ., ,$(GNATVERSION)))
GCCDIR_f_clang = $(shell $(callcc) -print-resource-dir)
GCCDIR_f_gcc = $(shell $(callcc) -print-search-dirs | sed -ne 's+^install: \(.*[^/][^/]*\)/+\1+p' )
GCCDIR_f = $(GCCDIR_f_$(BID_COMPILER_TYPE_f))
LDVERSION_f = $(shell $(callld) -v | sed -e \
$(if $(filter LLD,$(shell $(callld) -v)),\
'/.* \([0-9]\+\)\.\([0-9]\+\)\.\([0-9]\+\).*/{s//\1\2\3/;p;q}' -n,\
's/.* \([0-9]\)\.\([^. ]*\).*/\1\2/'))
LDNOWARNRWX_f = $(call checkld,--no-warn-rwx-segments)
GCCSYSLIBDIRS_f = $(shell $(callcc) -print-search-dirs | sed '/^libraries:/{s/^libraries: =\?/-L/;s/:/ -L/g;q;};d')
GCCLIB_file_f = $(call check_path_absolute,GCCLIB_file_$(1),$(shell $(callcc) -print-file-name=$(1)))
GCCLIB_HOST_f = $(if $(CONFIG_COMPILER_RT_USE_TOOLCHAIN_LIBGCC),$(call check_path_absolute,GCCLIB_HOST,$(shell $(callcc) -print-libgcc-file-name)))
GCCLIB_EH_HOST_f = $(if $(CONFIG_COMPILER_RT_USE_TOOLCHAIN_LIBGCC),$(call check_path_absolute,GCCLIB_EH_HOST,$(shell $(callcc) -print-file-name=libgcc_eh.a)))
GCCNOSTACKPROTOPT_f= $(call checkcc,-fno-stack-protector)
GCCSTACKPROTOPT_f = $(call checkcc,-fstack-protector)
GCCSTACKPROTALLOPT_f = $(call checkcc,-fstack-protector-all)
GCCWNONOEXCEPTTYPE_f = $(call checkcxx_nowarn,noexcept-type)
GCCWNOPSABI_f = $(call checkcxx_nowarn,psabi)
GCCWNOUNUSEDPRIVATEFIELD_f = $(call checkcxx_nowarn,unused-private-field)
GCCWNOUNTERMINATEDSTRINGINITIALIZATION_f = $(call checkcc_nowarn,$\
unterminated-string-initialization)
GCCWNOC99DESIGNATOR_f = $(call checkcxx_nowarn,c99-designator)
GCCARMV5TEFPOPT_arm_f = $(call checkcc,-march=armv5te+fp,-march=armv5te)
GCCARMV6FPOPT_arm_f = $(call checkcc,-march=armv6+fp,-march=armv6)
GCCARMV6T2FPOPT_arm_f = $(call checkcc,-march=armv6t2+fp,-march=armv6t2)
GCCARMV6ZKFPOPT_arm_f = $(call checkcc,-march=armv6zk+fp,-march=armv6zk)
GCCARMV7AFPOPT_arm_f = $(call checkcc,-march=armv7-a+fp,-march=armv7-a)
GCCARMV7RFPOPT_arm_f = $(call checkcc,-march=armv7-r+fp,-march=armv7-r)
GCCARMV7VEFPOPT_arm_f = $(call checkcc,-march=armv7ve+fp,-march=armv7ve)
GCCARM64OUTLINEATOMICSOPT_arm64_f = $(call checkcc,-mno-outline-atomics)
GCCFORTRANAVAIL_f = $(shell echo | $(callfc) -dD -E - 2>&1 | grep -q __GNUC__ && echo y)
GCCLIBCAVAIL_f = $(shell echo -e '$(BID_POUND)include <unistd.h>\nint main(void){return 0;}' | $(callcc) -x c -o /dev/null - > /dev/null 2>&1 && echo y)
CLANGVISNEWDELETEHIDDEN_f = $(call checkcxx,-fvisibility-global-new-delete=force-hidden,$\
$(call checkcxx,-fvisibility-global-new-delete-hidden))
GCC_HAS_ATOMICS_f = $(shell if echo '$(BID_POUND)include <bits/c++config.h>' | \
$(callcxx) -dD -E -x c++ - 2>&1 | \
grep -q _GLIBCXX_ATOMIC_BUILTINS; then \
echo y; fi)
GCCINCFIXEDPATH_f = $(patsubst %/limits.h,%,$(strip $(firstword $(wildcard \
$(addsuffix /limits.h, \
$(call GCCDIR_f)/include-fixed$(if $(filter .,$(shell $(callcc) -print-multi-directory)),,/$(shell $(callcc) -print-multi-directory)) \
$(call GCCDIR_f)/include-fixed)))))
CONDITIONAL_WARNINGS_MEDIUM_f = $(call checkcc,-Wmissing-prototypes)
CONDITIONAL_WARNINGS_FULL_f = $(call checkcc,-Wfloat-conversion) \
$(call checkcc,-Wfloat-equal) \
$(call checkcc,-Wlogical-op)
DIAGNOSTICS_SARIF_f = $(call checkcc,-fdiagnostics-format=sarif -Wno-sarif-format-unstable)
# $(call checkcc,-fdiagnostics-format=sarif-stderr)
DIAGNOSTICS_JSON_f = $(call checkcc,-fdiagnostics-format=json)
DIAGNOSTICS_COLOR_f = $(call checkcc,-fdiagnostics-color=always)
GCCPREFIXOPT_f = $(call checkcc,-fmacro-prefix-map=$(L4DIR_ABS)/= \
-fmacro-prefix-map=$(OBJ_BASE)/=)
BID_NOSTDINC_clang ?= -nostdinc
BID_NOSTDINC_gcc ?= -nostdinc
BID_NOSTDINC ?= $(BID_NOSTDINC_$(BID_COMPILER_TYPE))
# Options that must be filtered from gcc since they are linker flags
BID_GCC_OPTS=-static -shared -nostdlib -Wl$(BID_COMMA)% -L% -l% -PC% -nocrt1 -nocrt -r
# Tool to filter LD flags for the corresponding tool invocation type
# Convert arguments to a format compatible with gcc invocation
ldflags_to_gcc=$(foreach o,$(1),$(if $(filter $(BID_GCC_OPTS),$o),$o,$(addprefix -Wl$(BID_COMMA),$o)))
ifneq ($(strip $(GCCDIR)),)
GCCINCDIR = $(GCCDIR)/include $(GCCINCFIXEDPATH)
I_GCCINCDIR = $(addprefix -isystem ,$(GCCINCDIR))
endif
PKGNAME_DIRNAME := $(notdir $(abspath $(if $(PKGDIR),$(PKGDIR),.)))
ifneq ($(PKGDIR),)
ifeq ($(origin PKGNAME),undefined)
PKGNAME := $(PKGNAME_DIRNAME)
endif
endif
ifeq ($(V),1)
VERBOSE =
endif
ifeq ($(V),0)
VERBOSE = @
endif
ifeq ($(D),1)
DEBUG_MODE = y
endif
ifeq ($(CONFIG_RELEASE_MODE),y)
DEFINES += -DL4BID_RELEASE_MODE -DNDEBUG
endif
ifneq ($(filter linux host,$(MODE)),)
HOST_LINK := 1
HOST_LINK_HOST := 1
endif
ifneq ($(filter l4linux targetsys,$(MODE)),)
HOST_LINK := 1
HOST_LINK_TARGET := 1
endif
#
# SUBDIR handling, not within the OBJ-*/ dirs
#
ifeq ($(SYSTEM),)
ifneq ($(SUBDIRS),)
.PHONY: $(SUBDIRS)
$(SUBDIRS):
$(VERBOSE)$(MAKE) -C $@ all
# we know that SUBDIRS isn't empty, hence we can avoid the dir-test
scrub clean cleanall::
$(VERBOSE)set -e; $(foreach i,$(SUBDIRS), \
$(MAKE) -C $(i) $@;)
install:: $(SUBDIRS)
$(VERBOSE)set -e; $(foreach i,$(SUBDIRS), \
$(MAKE) -C $(i) $@;)
DIAG_DISPLAY_CMD := cat
diag::
@printf $(EMPHSTART)"Diagnostics:"$(EMPHSTOP)
@DIAGS=( $$(find $(OBJ_DIR) -name '*.diag') ); \
if [[ "$${#DIAGS[@]}" -eq 0 ]] ; then \
echo "<None>"; \
else \
$(DIAG_DISPLAY_CMD) "$${DIAGS[@]}"; \
fi
endif
all:: $(OBJ_DIR)/Makefile
$(OBJ_DIR)/Makefile: $(L4DIR)/mk/Makeconf
$(call build_obj_redir_Makefile,$@)
else
# we are within an OBJ-*/ dir, create dummy target
$(SUBDIRS):
endif
#
# Dependency section
#
#
# the general dependencies: All generated files depend on ".general.d".
# ".general.d" itself depends on the mk-Makeconf, the optional
# Makeconf.local, the .config.all, the packet-Makeconf.local and the
# Makeconf.local. This ensures a rebuilt if any of the configuration-
# or make-files changes.
#
# We have this nasty if-readable-magic to allow the files to disappear
# or to appear. Depending on if the according makeconf exists now, the
# if-readable magic .general.d is used on existance or non-existence.
BID_DEPEND_GENERAL_D_COND = \
if [ -r $(1) ] ; then echo -e '$@: $(strip $(1))\n$(strip $(1)):\n' >>$@ ; \
else echo '$$(if $$(wildcard $(strip $(1))), $@: FORCE)' >>$@; fi
ifeq ($(SYSTEM),)
GENERAL_D_LOC := $(OBJ_DIR)/.general.d
else
GENERAL_D_LOC := .general.d
endif
$(FIXDEP): $(L4DIR)/tool/kconfig/scripts/basic/fixdep.c
ifeq ($(ROOT_MAKEFILE),1)
@$(MAKE) genfixdep
else
@echo \'fixdep\' outdated or unavailable, please call \'make oldconfig\' in the root of your build directory.
@exit 1
endif
$(dir $(GENERAL_D_LOC)):
$(VERBOSE)$(MKDIR) $@
$(GENERAL_D_LOC): $(L4DIR)/mk/Makeconf $(FIXDEP) $(EXTRA_GENERAL_D_DEP)
$(GENERAL_D_LOC): | $(dir $(GENERAL_D_LOC))
@$(BUILD_MESSAGE)
$(file >$@.in,$(filter-out %.cmd,$(DEPS)))
$(DEPEND_VERBOSE)xargs -a $@.in $(RM)
$(DEPEND_VERBOSE)$(RM) $@.in
$(DEPEND_VERBOSE)echo '$@: $(SRC_DIR)/Makefile ' > $@
$(DEPEND_VERBOSE)$(call BID_DEPEND_GENERAL_D_COND,\
$(OBJ_BASE)/.config.all)
$(DEPEND_VERBOSE)$(call BID_DEPEND_GENERAL_D_COND,\
$(OBJ_BASE)/Makeconf.local)
$(DEPEND_VERBOSE)$(call BID_DEPEND_GENERAL_D_COND,\
$(OBJ_BASE)/conf/Makeconf.local)
$(DEPEND_VERBOSE)$(call BID_DEPEND_GENERAL_D_COND,\
$(L4DIR)/Makeconf.local)
$(DEPEND_VERBOSE)$(call BID_DEPEND_GENERAL_D_COND,\
$(L4DIR)/conf/Makeconf.local)
$(DEPEND_VERBOSE)$(foreach m,$(wildcard $(INCLUDE_MAKE_RULES)),\
$(call BID_DEPEND_GENERAL_D_COND,$(m)); )
$(if $(PKGDIR_ABS),$(DEPEND_VERBOSE)$(call BID_DEPEND_GENERAL_D_COND,\
$(PKGDIR_ABS)/Makeconf.local))
$(DEPEND_VERBOSE)$(call BID_DEPEND_GENERAL_D_COND,\
$(MAKECONFLOCAL))
$(DEPEND_VERBOSE)$(call BID_DEPEND_GENERAL_D_COND,\
$(L4DIR)/mk/arch/Makeconf.$(BUILD_ARCH))
DEPS += $(GENERAL_D_LOC)
#
# Messages
#
# coloring on color-capable terminals
# enabled by setting CONFIG_BID_COLORED_PHASES to y
ifeq ($(CONFIG_BID_COLORED_PHASES),y)
ifneq ($(BID_COLORS_TESTED),y)
BID_COLORS_TESTED := y
BID_COLORS_SUPPORTED := $(shell tput colors 2>/dev/null 1>&2; [ $$? -eq 0 ] && echo -n 'y' || echo -n 'n')
export BID_COLORS_TESTED
export BID_COLORS_SUPPORTED
endif
ifeq ($(BID_COLORS_SUPPORTED), y)
EMPHSTART = '\033[34;1m'
EMPHSTOP = '\033[0m'
else
EMPHSTART =
EMPHSTOP =
endif
endif
BID_MESSAGE_TAG ?= $(PKGDIR_REL)$(if $(filter-out std,$(VARIANT)), - $(VARIANT))
AR_MESSAGE ?= echo -e " [$(BID_MESSAGE_TAG)] ==> Archiving into $@"
BUILD_MESSAGE ?= echo -e " [$(BID_MESSAGE_TAG)] ... Building $(if $(filter $(GENERAL_D_LOC),$@),Dependencies,$@)"
BUILT_MESSAGE ?= echo -e $(EMPHSTART)' [$(BID_MESSAGE_TAG)] ==> $@ built'$(EMPHSTOP)
COMP_MESSAGE ?= echo -e " [$(BID_MESSAGE_TAG)] ... Compiling $@$(1)"
COMP_P_MESSAGE ?= echo -e " [$(BID_MESSAGE_TAG)] ... Compiling PIC $@"
COMP_PR_MESSAGE ?= echo -e " [$(BID_MESSAGE_TAG)] ... Compiling PROFILE $@"
GEN_MESSAGE ?= echo -e " [$(BID_MESSAGE_TAG)] ... Generating $(if $(1),$(1),$@)"
LINK_MESSAGE ?= echo -e " [$(BID_MESSAGE_TAG)] ==> Linking $@"
LINK_SHARED_MESSAGE ?= echo -e " [$(BID_MESSAGE_TAG)] ==> Linking to shared $@"
LINK_PARTIAL_MESSAGE ?= echo -e " [$(BID_MESSAGE_TAG)] ==> Partial linking to $@"
DEP_MESSAGE ?= echo -e " [$(BID_MESSAGE_TAG)] ... Building dependencies for $<"
CLEAN_MESSAGE ?= echo -e " [$(BID_MESSAGE_TAG)] ... Removing created files"
CLEANALL_MESSAGE ?= echo -e " [$(BID_MESSAGE_TAG)] ... Removing all created files"
INSTALL_LINK_MESSAGE ?= echo -e " [$(BID_MESSAGE_TAG)] ==> Updating symlinks"
INSTALL_DOC_MESSAGE ?= echo -e " [$(BID_MESSAGE_TAG)] ==> Installing $(if $(1),$(1),$(<)) documentation"
INSTALL_DOC_LOCAL_MESSAGE ?= echo -e " [$(BID_MESSAGE_TAG)] ==> Installing $(if $(1),$(1),$(<)) documentation locally"
INSTALL_MESSAGE ?= echo -e " [$(BID_MESSAGE_TAG)] ==> Installing $(if $(1),$(1),$^)"
INSTALL_LOCAL_MESSAGE ?= echo -e " [$(BID_MESSAGE_TAG)] ==> Installing $(if $(1),$(1),$(<)) to local build-tree"
# allows an include $(DEPSVAR) at the end of the makefile
# but prevents rebuilding them on a scrub, clean, cleanall and help
ifneq ($(filter scrub clean cleanall mrproper help,$(MAKECMDGOALS)),)
DEPSVAR =
else
DEPSVAR = $(DEPS)
endif
#
# Some rules
#
# addfileheader-rule: allows "make addfileheader main.c server.c"-like
# commands and automatically inserts the path within the package
# options may be passed with $(ADDFILEHEADER_OPTIONS)
ADDFILEHEADER_PREFIX = $(patsubst $(abspath $(PKGDIR)/)%,\
$(PKGNAME)/%,$(abspath ./))
ADDFILEHEADER_FILES = $(filter-out addfileheader,$(MAKECMDGOALS))
addfileheader:
addfileheader $(ADDFILEHEADER_OPTIONS) -p $(ADDFILEHEADER_PREFIX) $(ADDFILEHEADER_FILES)
.PHONY: FORCE
# 1: name
# 2: output file
# 3: inc path (one only)
# 4: libs
# 5: requires_libs
# 6: PC_CFLAGS
# 7: extras
generate_pcfile = \
[ -d $(dir $(2)) ] || mkdir -p $(dir $(2)) \
;echo -n > $(2) \
$(if $(3),;echo "incdir=/empty_incdir" >> $(2)) \
;echo "Name: $(1)" >> $(2) \
;echo "Version: 0" >> $(2) \
;echo "Description: L4 library" >> $(2) \
$(if $(3),;echo -n "Cflags: $(addprefix -I\$${incdir}/,$(3)) ">> $(2))\
$(if $(6),$(if $(3),,;echo -n "Cflags:" >> $(2))) \
$(if $(6),;echo " $(6)" >> $(2),;echo "" >> $(2)) \
$(if $(4),;echo "Libs: $(4)" >> $(2)) \
$(if $(5),;echo "Requires: $(5)" >> $(2)) \
$(if $(7),;echo -e '$(subst $(newline),\n,$(7))' >> $(2)) \
$(if $(BID_GEN_CONTROL),;echo "Provides: $(1)" >> $(PKGDIR)/Control) \
$(if $(BID_GEN_CONTROL),;echo "Requires: $(5)" >> $(PKGDIR)/Control) ;
define build_obj_redir_Makefile
$(VERBOSE)install -d $(dir $(1))
$(VERBOSE)echo '# automatically created -- modifications will be lost' > $(1)
$(VERBOSE)echo 'SRC := $(if $(2),$(2),$(SRC_DIR))' >> $(1)
$(VERBOSE)echo 'OBJ := $(OBJ_BASE)' >> $(1)
$(VERBOSE)echo '.PHONY: $$(MAKECMDGOALS) do-all-make-goals' >> $(1)
$(VERBOSE)echo 'do-all-make-goals:' >> $(1)
$(VERBOSE)echo ' @$$(MAKE) -C $$(SRC) O=$$(OBJ) $$(MAKECMDGOALS)'>> $(1)
$(VERBOSE)echo '$$(MAKECMDGOALS): do-all-make-goals' >> $(1)
endef
endif # _L4DIR_MK_MAKECONF undefined

2
src/l4/mk/WhatIsThis Normal file
View File

@@ -0,0 +1,2 @@
# DROPS Building Makros
filelist="*.mk *.inc config.*"

View File

@@ -0,0 +1 @@
This directory contains global package aliases

View File

@@ -0,0 +1,68 @@
# ARCH: BUILD_ARCH_arm arm
# ARCHDESCR: ARM architecture
# ARCHSELECT: ARCH_ENABLE_STACK_PROTECTOR
# ARCHDEFAULTPF: PLATFORM_TYPE_arm_virt
choice
prompt "CPU variant"
default CPU_ARM_ARMV7A
config CPU_ARM_ARMV4
bool "ARMv4 type CPU"
depends on BUILD_ARCH_arm
config CPU_ARM_ARMV4T
bool "ARMv4T type CPU"
depends on BUILD_ARCH_arm
config CPU_ARM_ARMV5
bool "ARMv5 type CPU"
depends on BUILD_ARCH_arm
config CPU_ARM_ARMV5T
bool "ARMv5T type CPU"
depends on BUILD_ARCH_arm
config CPU_ARM_ARMV5TE
bool "ARMv5TE type CPU"
depends on BUILD_ARCH_arm
config CPU_ARM_ARMV6
bool "ARMv6 type CPU"
depends on BUILD_ARCH_arm
config CPU_ARM_ARMV6T2
bool "ARMv6t2 type CPU"
depends on BUILD_ARCH_arm
config CPU_ARM_ARMV6ZK
bool "ARMv6zk type CPU"
depends on BUILD_ARCH_arm
config CPU_ARM_ARMV7A
bool "ARMv7A type CPU"
depends on BUILD_ARCH_arm
config CPU_ARM_ARMV8R_AARCH32
bool "ARMv8R type CPU"
depends on BUILD_ARCH_arm
select ARCH_NO_MMU
endchoice
config CPU
string
default "armv4" if CPU_ARM_ARMV4
default "armv4t" if CPU_ARM_ARMV4T
default "armv5" if CPU_ARM_ARMV5
default "armv5t" if CPU_ARM_ARMV5T
default "armv5te" if CPU_ARM_ARMV5TE
default "armv6" if CPU_ARM_ARMV6
default "armv6t2" if CPU_ARM_ARMV6T2
default "armv6zk" if CPU_ARM_ARMV6ZK
default "armv7a" if CPU_ARM_ARMV7A
default "armv8r" if CPU_ARM_ARMV8R_AARCH32
config BITS
int
default 32

View File

@@ -0,0 +1,28 @@
# ARCH: BUILD_ARCH_arm64 arm64
# ARCHDESCR: ARM64 architecture (AArch64)
# ARCHSELECT: ARCH_ENABLE_STACK_PROTECTOR
# ARCHDEFAULTPF: PLATFORM_TYPE_arm_virt
choice
prompt "CPU variant"
default CPU_ARM_ARMV8A
config CPU_ARM_ARMV8A
bool "ARMv8-A type CPU"
depends on BUILD_ARCH_arm64
config CPU_ARM_ARMV8R_AARCH64
bool "ARMv8-R type CPU"
depends on BUILD_ARCH_arm64
select ARCH_NO_MMU
endchoice
config CPU
string
default "armv8a" if CPU_ARM_ARMV8A
default "armv8r" if CPU_ARM_ARMV8R_AARCH64
config BITS
int
default 64

View File

@@ -0,0 +1,19 @@
# vi:se ft=kconfig:
# Common symbols for arm and arm64
config CPU_ARMV6PLUS
bool
default y if CPU_ARM_ARMV6 || CPU_ARM_ARMV6T2 || CPU_ARMV6KPLUS
config CPU_ARMV6KPLUS
bool
default y if CPU_ARM_ARMV6ZK || CPU_ARMV7PLUS
config CPU_ARMV7PLUS
bool
default y if CPU_ARM_ARMV7A || CPU_ARM_ARMV7R || CPU_ARMV8PLUS
config CPU_ARMV8PLUS
bool
default y if CPU_ARM_ARMV8R_AARCH32 || CPU_ARM_ARMV8R_AARCH64

View File

@@ -0,0 +1,16 @@
# ARCH: BUILD_ARCH_x86 x86
# ARCHDESCR: X86-32 architecture
# ARCHSELECT: ARCH_ENABLE_STACK_PROTECTOR
# ARCH: BUILD_ARCH_amd64 amd64
# ARCHDESCR: AMD64 architecture
# ARCHSELECT: ARCH_ENABLE_STACK_PROTECTOR
config CPU
string "CPU variant identifier"
default "gen"
config BITS
int
default 32 if BUILD_ARCH_x86
default 64 if BUILD_ARCH_amd64

View File

@@ -0,0 +1,66 @@
# ARCH: BUILD_ARCH_mips mips
# ARCHDESCR: MIPS architecture
# ARCHSELECT: ARCH_ENABLE_STACK_PROTECTOR
choice
prompt "CPU variant"
default CPU_MIPS_32R2
config CPU_MIPS_32R2
bool "MIPS32 Release 2"
config CPU_MIPS_32R6
bool "MIPS32 Release 6"
config CPU_MIPS_64R2
bool "MIPS64 release 2"
config CPU_MIPS_64R6
bool "MIPS64 release 6"
endchoice
choice
prompt "Endianess"
default MIPS_LITTLE_ENDIAN
config MIPS_LITTLE_ENDIAN
bool "Little Endian"
config MIPS_BIG_ENDIAN
bool "Big Endian"
endchoice
config CPU
string
default "32r2" if CPU_MIPS_32R2
default "32r6" if CPU_MIPS_32R6
default "64r2" if CPU_MIPS_64R2
default "64r6" if CPU_MIPS_64R6
config CPU_ABI
string
default "32" if CPU_MIPS_32R2
default "32" if CPU_MIPS_32R6
default "64" if CPU_MIPS_64R2
default "64" if CPU_MIPS_64R6
config BITS
int
default 32 if CPU_MIPS_32R2
default 32 if CPU_MIPS_32R6
default 64 if CPU_MIPS_64R2
default 64 if CPU_MIPS_64R6
choice
prompt "Page Size"
default PAGE_SIZE_16KB
config PAGE_SIZE_16KB
bool "16KiB Page size"
config PAGE_SIZE_4KB
bool "4KiB Page size"
endchoice

View File

@@ -0,0 +1,6 @@
# ARCH: BUILD_ARCH_ppc32 ppc32
# ARCHDESCR: PowerPC 32 architecture (EXPERIMENTAL!)
config BITS
int
default 32

View File

@@ -0,0 +1,64 @@
# ARCH: BUILD_ARCH_riscv riscv
# ARCHDESCR: RISC-V architecture
# ARCHSELECT: ARCH_ENABLE_STACK_PROTECTOR
# ARCHDEFAULTPF: PLATFORM_TYPE_riscv_virt
choice
prompt "CPU variant"
default CPU_RISCV_64IMA
config CPU_RISCV_32IMA
bool "RV32IMA"
config CPU_RISCV_64IMA
bool "RV64IMA"
endchoice
choice
prompt "FPU"
default FPU_RISCV_DOUBLE
config FPU_RISCV_NONE
bool "Off"
config FPU_RISCV_SINGLE
bool "Single precision"
config FPU_RISCV_DOUBLE
bool "Double precision"
endchoice
config RISCV_ISA_C
bool "Emit compressed instructions"
default y
config CPU
string
default "rv32ima" if CPU_RISCV_32IMA && FPU_RISCV_NONE && !RISCV_ISA_C
default "rv32imaf" if CPU_RISCV_32IMA && FPU_RISCV_SINGLE && !RISCV_ISA_C
default "rv32imafd" if CPU_RISCV_32IMA && FPU_RISCV_DOUBLE && !RISCV_ISA_C
default "rv64ima" if CPU_RISCV_64IMA && FPU_RISCV_NONE && !RISCV_ISA_C
default "rv64imaf" if CPU_RISCV_64IMA && FPU_RISCV_SINGLE && !RISCV_ISA_C
default "rv64imafd" if CPU_RISCV_64IMA && FPU_RISCV_DOUBLE && !RISCV_ISA_C
default "rv32imac" if CPU_RISCV_32IMA && FPU_RISCV_NONE && RISCV_ISA_C
default "rv32imafc" if CPU_RISCV_32IMA && FPU_RISCV_SINGLE && RISCV_ISA_C
default "rv32imafdc" if CPU_RISCV_32IMA && FPU_RISCV_DOUBLE && RISCV_ISA_C
default "rv64imac" if CPU_RISCV_64IMA && FPU_RISCV_NONE && RISCV_ISA_C
default "rv64imafc" if CPU_RISCV_64IMA && FPU_RISCV_SINGLE && RISCV_ISA_C
default "rv64imafdc" if CPU_RISCV_64IMA && FPU_RISCV_DOUBLE && RISCV_ISA_C
config CPU_ABI
string
default "ilp32" if CPU_RISCV_32IMA && FPU_RISCV_NONE
default "ilp32f" if CPU_RISCV_32IMA && FPU_RISCV_SINGLE
default "ilp32d" if CPU_RISCV_32IMA && FPU_RISCV_DOUBLE
default "lp64" if CPU_RISCV_64IMA && FPU_RISCV_NONE
default "lp64f" if CPU_RISCV_64IMA && FPU_RISCV_SINGLE
default "lp64d" if CPU_RISCV_64IMA && FPU_RISCV_DOUBLE
config BITS
int
default 32 if CPU_RISCV_32IMA
default 64 if CPU_RISCV_64IMA

View File

@@ -0,0 +1,68 @@
# ARCH: BUILD_ARCH_sparc sparc
# ARCHDESCR: Sparc architecture (EXPERIMENTAL)
choice
prompt "CPU"
config CPU_SPARC_V7
bool "Generic Sparc V7"
depends on BUILD_ARCH_sparc
config CPU_SPARC_LEON
bool "LEON"
depends on BUILD_ARCH_sparc
config CPU_SPARC_LEON3
bool "LEON3"
depends on BUILD_ARCH_sparc
config CPU_SPARC_V8
bool "Generic Sparc V8"
depends on BUILD_ARCH_sparc
config CPU_SPARC_V9
bool "Generic Sparc V9"
depends on BUILD_ARCH_sparc
config CPU_SPARC_ULTRASPARC
bool "Ultrasparc"
depends on BUILD_ARCH_sparc
config CPU_SPARC_ULTRASPARC3
bool "Ultrasparc3"
depends on BUILD_ARCH_sparc
config CPU_SPARC_NIAGARA
bool "Niagara"
depends on BUILD_ARCH_sparc
config CPU_SPARC_NIAGARA2
bool "Niagara2"
depends on BUILD_ARCH_sparc
config CPU_SPARC_NIAGARA3
bool "Niagara3"
depends on BUILD_ARCH_sparc
config CPU_SPARC_NIAGARA4
bool "Niagara4"
depends on BUILD_ARCH_sparc
endchoice
config CPU
string
default "leon" if CPU_SPARC_LEON
default "leon3" if CPU_SPARC_LEON3
default "v7" if CPU_SPARC_V7
default "v8" if CPU_SPARC_V8
default "v9" if CPU_SPARC_V9
default "ultrasparc" if CPU_SPARC_ULTRASPARC
default "ultrasparc3" if CPU_SPARC_ULTRASPARC3
default "niagara" if CPU_SPARC_NIAGARA
default "niagara2" if CPU_SPARC_NIAGARA2
default "niagara3" if CPU_SPARC_NIAGARA3
default "niagara4" if CPU_SPARC_NIAGARA4
config BITS
int
default 32

View File

@@ -0,0 +1,30 @@
# vim:se ft=make:
CROSS_COMPILE_amd64 = x86_64-linux-gnu-
CARCHFLAGS_amd64 = -mno-red-zone
ASFLAGS_amd64 = -m64 -Wa,--noexecstack
LDFLAGS_amd64 += -z max-page-size=0x1000 -z common-page-size=0x1000 \
-z noexecstack
LD_EMULATION_CHOICE_amd64 = elf_x86_64
OFORMAT_amd64 = elf64-x86-64
BFD_ARCH_amd64 = i386
L4_KIP_ADDR_amd64 ?= 0x6ffff000
L4_STACK_ADDR_amd64 ?= 0x70000000
CARCHFLAGS_amd64_K8 = -march=k8
CARCHFLAGS_amd64_K10 = -march=k10
CARCHFLAGS_amd64_opteron = -march=opteron
CARCHFLAGS_amd64 += -m64
SYSTEMS_ABI += amd64-l4f
SYSTEMS_PLAIN += amd64-plain
GCCNOFPU_amd64_f = $(call checkcc,-mno-mmx) $(call checkcc,-mno-3dnow) \
$(call checkcc,-mno-sse) $(call checkcc,-mno-sse2) \
$(call checkcc,-mno-sse3) $(call checkcc,-mno-sse4) \
$(call checkcc,-mno-sse4a) $(call checkcc,-mno-avx) \
$(call checkcc,-mno-avx2)
QEMU_ARCH_MAP_amd64 = qemu-system-x86_64
QEMU_OPTIONS_amd64 = -m 512 -M q35

View File

@@ -0,0 +1,35 @@
# vim:se ft=make:
CROSS_COMPILE_arm = arm-linux-gnueabihf-
ASFLAGS_arm = -Wa,--noexecstack
LD_EMULATION_CHOICE_arm = armelf armelf_linux_eabi
LDFLAGS_arm += -z max-page-size=0x1000 -z common-page-size=0x1000 \
-z noexecstack
OFORMAT_arm = elf32-littlearm
BFD_ARCH_arm = arm
L4_KIP_ADDR_arm ?= 0xaffff000
L4_STACK_ADDR_arm ?= 0xb0000000
CARCHFLAGS_arm_armv4 = -march=armv4
CARCHFLAGS_arm_armv4t = -march=armv4t
CARCHFLAGS_arm_armv5 = -march=armv5
CARCHFLAGS_arm_armv5t = -march=armv5t
CARCHFLAGS_arm_armv5te = $(GCCARMV5TEFPOPT_arm)
CARCHFLAGS_arm_armv6 = $(GCCARMV6FPOPT_arm)
CARCHFLAGS_arm_armv6t2 = $(GCCARMV6T2FPOPT_arm)
CARCHFLAGS_arm_armv6zk = $(GCCARMV6ZKFPOPT_arm)
CARCHFLAGS_arm_armv7a = $(GCCARMV7AFPOPT_arm)
CARCHFLAGS_arm_armv7r = $(GCCARMV7RFPOPT_arm)
CARCHFLAGS_arm_armv8r = -march=armv8-r -mfpu=fp-armv8
CARCHFLAGS_arm += $(if $(CONFIG_BID_THUMB),-mthumb,-marm)
SYSTEMS_ABI += arm-l4f
SYSTEMS_PLAIN += arm-plain
GCCNOFPU_arm_f = $(call checkcc,-mfpu=none) $(call checkcc,-mgeneral-regs-only)
# GCC 4.8.0-4.8.2 showed to be buggy on ARM at least
CC_BLACKLIST-arm-gcc := 4.8.0 4.8.1 4.8.2
QEMU_ARCH_MAP_arm = qemu-system-arm

View File

@@ -0,0 +1,21 @@
# vim:se ft=make:
CROSS_COMPILE_arm64 = aarch64-linux-gnu-
ASFLAGS_arm64 = -Wa,--noexecstack
LD_EMULATION_CHOICE_arm64 = aarch64linux aarch64elf
LDFLAGS_arm64 += -z max-page-size=0x1000 -z common-page-size=0x1000 \
-z noexecstack
OFORMAT_arm64 = elf64-littleaarch64
BFD_ARCH_arm64 = aarch64
L4_KIP_ADDR_arm64 ?= 0xb0000000
L4_STACK_ADDR_arm64 ?= 0xb0000000
CARCHFLAGS_arm64_armv8a = -march=armv8-a $(GCCARM64OUTLINEATOMICSOPT_arm64)
CARCHFLAGS_arm64_armv8r = -march=armv8-r $(GCCARM64OUTLINEATOMICSOPT_arm64)
SYSTEMS_ABI += arm64-l4f
SYSTEMS_PLAIN += arm64-plain
GCCNOFPU_arm64_f = -mgeneral-regs-only
QEMU_ARCH_MAP_arm64 = qemu-system-aarch64

View File

@@ -0,0 +1,21 @@
# vim:se ft=make:
CROSS_COMPILE_mips = mips-linux-
ASFLAGS_mips = -Wa,--noexecstack
ELF_BINARY_TYPE_mips_bl = $(if $(CONFIG_MIPS_LITTLE_ENDIAN),l,b)
OFORMAT_mips_bl = $(if $(CONFIG_MIPS_LITTLE_ENDIAN),little,big)
LD_EMULATION_CHOICE_mips = elf$(CPU_ABI)$(ELF_BINARY_TYPE_mips_bl)tsmip
OFORMAT_mips = elf$(CPU_ABI)-trad$(OFORMAT_mips_bl)mips
BFD_ARCH_mips = mips:isa$(CPU)
L4_KIP_ADDR_mips ?= 0x7fff0000
L4_STACK_ADDR_mips ?= 0x70000000
CARCHFLAGS_mips += -march=mips$(CPU) -mabi=$(CPU_ABI)
CARCHFLAGS_mips += $(if $(CONFIG_MIPS_LITTLE_ENDIAN),-EL,-EB)
LDFLAGS_mips += $(if $(CONFIG_MIPS_LITTLE_ENDIAN),-EL,-EB) \
-z noexecstack
SYSTEMS_ABI += mips-l4f
SYSTEMS_PLAIN += mips-plain
QEMU_ARCH_MAP_mips_64 = qemu-system-mips64el
QEMU_ARCH_MAP_mips_32 = qemu-system-mipsel
QEMU_ARCH_MAP_mips = $(QEMU_ARCH_MAP_mips_$(CPU_ABI))

View File

@@ -0,0 +1,15 @@
# vim:se ft=make:
CROSS_COMPILE_ppc32 = powerpc-linux-
LD_EMULATION_CHOICE_ppc32 = elf32ppc
OFORMAT_ppc32 = elf32-powerpc
BFD_ARCH_ppc32 = powerpc
L4_KIP_ADDR_ppc32 ?= 0xaffff000
L4_STACK_ADDR_ppc32 ?= 0xb0000000
CARCHFLAGS_ppc32 += -m32
SYSTEMS_ABI += ppc32-l4f
SYSTEMS_PLAIN += ppc32-plain
QEMU_ARCH_MAP_ppc32 = qemu-system-ppc

View File

@@ -0,0 +1,29 @@
# vim:se ft=make:
CROSS_COMPILE_riscv = riscv64-linux-gnu-
ASFLAGS_riscv = -Wa,--noexecstack
ELF_BINARY_TYPE_riscv = elf$(BITS)
LD_EMULATION_CHOICE_riscv = $(ELF_BINARY_TYPE_riscv)lriscv
OFORMAT_riscv = $(ELF_BINARY_TYPE_riscv)-littleriscv
BFD_ARCH_riscv = littleriscv
L4_KIP_ADDR_riscv ?= 0x7fff0000
L4_STACK_ADDR_riscv ?= 0x70000000
# Since version 2.38, binutils by default targets the ISA specification version
# 20191213, where the CSR instructions and the FENCE.I instruction have been
# moved from the I extension into separate extensions: Zicsr and Zifencei
RISCV_ZICSR_ZIFENCEI_riscv_f = $(if $(call checkcc,-march=$(CPU)_zicsr_zifencei \
-mabi=$(CPU_ABI) \
-mcmodel=medany),_zicsr_zifencei)
CARCHFLAGS_riscv += -march=$(CPU)$(RISCV_ZICSR_ZIFENCEI_riscv) \
-mabi=$(CPU_ABI) -mcmodel=medany
LDFLAGS_riscv += -z noexecstack
SYSTEMS_ABI += riscv-l4f
SYSTEMS_PLAIN += riscv-plain
# As of now (gcc-12) there is no option to prevent the compiler from generating
# FPU instructions. So we just have to assume that the compiler does not do it,
# until it introduces a flag able to prevent it.
GCCNOFPU_riscv_f =
QEMU_ARCH_MAP_riscv = qemu-system-riscv$(BITS)

View File

@@ -0,0 +1,27 @@
# vim:se ft=make:
CROSS_COMPILE_sparc = $(if $(GCCIS_sparc_leon),sparc-elf-,sparc-linux-)
LD_EMULATION_CHOICE_sparc = $(if $(GCCIS_sparc_leon),sparcleon,elf32_sparc)
OFORMAT_sparc = elf32-sparc
BFD_ARCH_sparc = sparc
L4_KIP_ADDR_sparc ?= 0xaffff000
L4_STACK_ADDR_sparc ?= 0xb0000000
CARCHFLAGS_sparc_v7 = -mcpu=v7
# the -Wa.. is probably a gcc buglet fix only, check again later
CARCHFLAGS_sparc_leon = -mcpu=leon -Wa,-Av8
CARCHFLAGS_sparc_leon3 = -mcpu=leon3
CARCHFLAGS_sparc_v8 = -mcpu=v8
CARCHFLAGS_sparc_v9 = -mcpu=v9
CARCHFLAGS_sparc_ultrasparc = -mcpu=ultrasparc
CARCHFLAGS_sparc_ultrasparc3 = -mcpu=ultrasparc3
CARCHFLAGS_sparc_niagara = -mcpu=niagara
CARCHFLAGS_sparc_niagara2 = -mcpu=niagara2
CARCHFLAGS_sparc_niagara3 = -mcpu=niagara3
CARCHFLAGS_sparc_niagara4 = -mcpu=niagara4
CARCHFLAGS_sparc += -m32
SYSTEMS_ABI += sparc-l4f
SYSTEMS_PLAIN += sparc-plain

View File

@@ -0,0 +1,42 @@
# vim:se ft=make:
CROSS_COMPILE_x86 = x86_64-linux-gnu-
LD_EMULATION_CHOICE_x86 = elf_i386
ASFLAGS_x86 = -Wa,--noexecstack
LDFLAGS_x86 += -z noexecstack
OFORMAT_x86 = elf32-i386
BFD_ARCH_x86 = i386
L4_KIP_ADDR_x86 ?= 0xaffff000
L4_STACK_ADDR_x86 ?= 0xb0000000
CARCHFLAGS_x86_586 = -march=i586
CARCHFLAGS_x86_pentium = -march=i586
CARCHFLAGS_x86_pentiummmx = -march=pentium-mmx
CARCHFLAGS_x86_pentiumpro = -march=pentiumpro
CARCHFLAGS_x86_686 = -march=i686
CARCHFLAGS_x86_pentium2 = -march=pentium2
CARCHFLAGS_x86_pentium3 = -march=pentium3
CARCHFLAGS_x86_pentiumm = -march=pentium-m
CARCHFLAGS_x86_pentium4 = -march=pentium4
CARCHFLAGS_x86_prescott = -march=prescott
CARCHFLAGS_x86_nocona = -march=nocona
CARCHFLAGS_x86_core2 = -march=core2
CARCHFLAGS_x86_K6 = -march=k6
CARCHFLAGS_x86_K7 = -march=athlon
CARCHFLAGS_x86_athlon4 = -march=athlon-4
CARCHFLAGS_x86_K8 = -march=k8
CARCHFLAGS_x86_opteron = -march=opteron
CARCHFLAGS_x86 += -m32
SYSTEMS_ABI += x86-l4f
SYSTEMS_PLAIN += x86-plain
GCCNOFPU_x86_f = $(call checkcc,-mno-mmx) $(call checkcc,-mno-3dnow) \
$(call checkcc,-mno-sse) $(call checkcc,-mno-sse2) \
$(call checkcc,-mno-sse3) $(call checkcc,-mno-sse4) \
$(call checkcc,-mno-sse4a) $(call checkcc,-mno-avx) \
$(call checkcc,-mno-avx2)
QEMU_ARCH_MAP_x86 = $(strip $(shell if qemu-system-i386 -version > /dev/null; then echo qemu-system-i386; else echo qemu; fi))

86
src/l4/mk/assets.mk Normal file
View File

@@ -0,0 +1,86 @@
# -*- Makefile -*-
#
# L4Re Buildsystem
#
ifeq ($(origin _L4DIR_MK_ASSETS_MK),undefined)
_L4DIR_MK_ASSETS_MK=y
ROLE = assets.mk
include $(L4DIR)/mk/Makeconf
$(GENERAL_D_LOC): $(L4DIR)/mk/assets.mk
# Args: dirname, targets
define register_asset_targets
$(foreach t,$(2), \
$(eval INSTALLDIR_$(t) ?= $(INSTALLDIR)/$(1)) \
$(eval INSTALLDIR_LOCAL_$(t) ?= $(INSTALLDIR_LOCAL)/$(1)))
endef
define src_asset_link
$1: $(SRC_DIR)/$1
@$(INSTALL_MESSAGE)
$(VERBOSE)$(MKDIR) $$(@D)
$(VERBOSE)ln -fs $$< $$@
endef
define install_assets
$(foreach t,$2,$(eval $(call src_asset_link,$t)))
$(call register_asset_targets,$1,$2)
$(eval INSTALL_TARGET += $2)
endef
INSTALLDIR_ASSETS ?= $(DROPS_STDDIR)/assets
INSTALLDIR_ASSETS_LOCAL ?= $(OBJ_BASE)/assets
INSTALLFILE_ASSETS ?= $(INSTALL) -m 644 $(1) $(2)
INSTALLFILE_ASSETS_LOCAL ?= $(LN) -sf $(abspath $(1)) $(2)
INSTALLFILE = $(INSTALLFILE_ASSETS)
INSTALLDIR = $(INSTALLDIR_ASSETS)
INSTALLFILE_LOCAL = $(INSTALLFILE_ASSETS_LOCAL)
INSTALLDIR_LOCAL = $(INSTALLDIR_ASSETS_LOCAL)
MODE ?= assets
REQUIRE_HOST_TOOLS ?= $(if $(SRC_DTS),dtc)
include $(L4DIR)/mk/binary.inc
ifneq ($(SYSTEM),) # if we are a system, really build
# Functionality for device-tree file handling
TARGET_DTB = $(patsubst %.dts,%.dtb,$(SRC_DTS))
TARGET_DTBO = $(patsubst %.dtso,%.dtbo,$(SRC_DTS))
TARGET += $(TARGET_DTB) $(TARGET_DTBO)
INSTALL_TARGET += $(TARGET)
DEPS += $(foreach file,$(TARGET_DTB) $(TARGET_DTBO),$(call BID_dot_fname,$(file)).d)
$(call register_asset_targets,dtb,$(TARGET_DTB))
$(call register_asset_targets,dtbo,$(TARGET_DTBO))
$(call install_assets,modlist/$(PKGNAME),$(SRC_ASSETS_MODLIST))
$(call install_assets,ned/$(PKGNAME),$(SRC_ASSETS_NED))
$(call install_assets,io/,$(SRC_ASSETS_IO))
$(call install_assets,misc/$(PKGNAME),$(SRC_ASSETS_MISC))
include $(L4DIR)/mk/install.inc
endif # SYSTEM
.PHONY: all clean cleanall config help install oldconfig txtconfig
-include $(DEPSVAR)
help::
@echo " all - generate assets locally"
ifneq ($(SYSTEM),)
@echo " to $(INSTALLDIR_LOCAL)"
endif
@echo " install - generate and install assets globally"
ifneq ($(SYSTEM),)
@echo " to $(INSTALLDIR)"
endif
@echo " scrub - delete backup and temporary files"
@echo " clean - delete generated object files"
@echo " cleanall - delete all generated, backup and temporary files"
@echo " help - this help"
endif # _L4DIR_MK_ASSETS_MK undefined

167
src/l4/mk/bid-bender.spec Normal file
View File

@@ -0,0 +1,167 @@
incdir = %:set-var(incdir %(l4obj)/include/contrib)
pc_file_dir = %:set-var(pc_file_dir %(l4obj)/pc)
# options that take an extra argument
link_arg_opts =
%:arg-option(L m z o O h e -entry fini init -defsym Map)
%:arg-option(b -format A -architecture y -trace-symbol MF)
%:arg-option(-hash-style -version-script)
%:arg-option(T Tbss Tdata Ttext Ttext-segment Trodata-segment Tldata-segment)
%:arg-option(dT -image-base)
# options that are part of the output file list %o
link_output_args =
%:output-option(l* -whole-archive -no-whole-archive
-start-group -end-group u)
l4libdir =
l4libdir_x = %:set-var(l4libdir
%(l4system:%(l4api:%(l4obj)/lib/%(l4system)/%(l4api)))
%(l4system:%(l4obj)/lib/%(l4system)) %(l4obj)/lib)
# compile a list of dirs from -L options
libdir = %:set-var(libdir %{L*:%*} %(l4libdir))
# get dependency file name from -MF or from -o options
deps_file = %:strip(%{MF*:%*;:%{o*:.%*.d;:.pcs-deps}})
# generate dependency files for used spec/pc files
generate_deps =
# main dependency
%:echo-file(>%(deps_file) %{o*:%*}: %:all-specs())
# empty deps for all spec/pc files for graceful removal
%:foreach(%%:echo-file(>>%(deps_file) %%*:) %:all-specs())
# check whether the linker variable is set
check_linker = %(linker:;:%:error(linker variable not defined))
######### ld compatibility (pass through) mode for linking ##################
# options to pass to the linker (binutils GNU ld and LLVM ld)
link_pass_opts = %:set-var(link_pass_opts
%{M} %{-print-map} %{-trace-symbol*} %{y} %{-verbose}
%{-cref} %{-trace} %{r} %{O*}
%{m} %{-error-*} %{-warn-*&-no-warn-*}
%{-sort-*} %{-unique*}
%{-define-common&-no-define-common} %{B*}
%{-check-*&-no-check-*}
%{-no-undefined} %{rpath*} %{-verbose*}
%{-discard-*}
%{x} %{X} %{S} %{s} %{t} %{z} %{Z} %{n} %{N} %{init*} %{fini*}
%{soname*} %{h} %{E} %{-export-dynamic&-no-export-dynamic}
%{e} %{-entry*} %{-defsym*} %{Map*} %{b} %{-format*} %{A} %{-architecture*}
%{-gc-sections} %{gc-sections} %{-no-gc-sections} %{-hash-style*} %{-eh-frame-hdr}
# we always set -nostlib below so drop it but use it to avoid an error
%{nostdlib:} %{no-pie:} %{pie} %{-no-dynamic-linker} %{-version-script*})
%{-wrap*}
# linker arguments part I
link_args_ld_part1 =
%(link_arg_opts)%(link_output_args)
%:read-pc-file(%(pc_file_dir) %{PC*:%*})
%{nocrt|r:;:%:read-pc-file(%(pc_file_dir) ldscripts)}
%{o} -nostdlib %{static:-static;:--eh-frame-hdr} %{shared}
%{static-pie:-static -pie --no-dynamic-linker -z text}
# linker arguments part II -- specific to GNU ld
link_args_ld_part2_gnu_ld =
%(link_pass_opts) %:foreach(%%{: -L%%*} %(l4libdir)) %{T*&L*}
%{!r:%{!dT:-dT %:search(main_%{static:stat;static-pie:pie;shared:rel;:dyn}.ld
%(libdir));dT}}
# linker arguments part II -- specific to LLVM ld
# - use `-T <script>` rather than `-dT <script>`
# - use `--image-base=...` rather than `-Ttext-segment=...`
# - allow `--undefined-version` for compatibility with GNU ld
# - use --icf=none to disable identical code folding (lld-specific)
link_args_ld_part2_llvm_lld =
%(link_pass_opts) %:foreach(%%{: -L%%*} %(l4libdir)) %{L*}
%{-undefined-version}
%{-image-base*}
--icf=none
%{!r:%{!T:-T %:search(main_%{static:stat;static-pie:pie;shared:rel;:dyn}.ld
%(libdir));T}}
# linker arguments part III
link_args_ld_part3 =
%{r|shared|static|static-pie|-dynamic-linker*:;:
--dynamic-linker=%(Link_DynLinker)
%(Link_DynLinker:;:
%:error(Link_DynLinker not specified, cannot link with shared libs.))}
%{-dynamic-linker*}
%(Link_Start) %o %{OBJ*:%*} %{pie:%(Libs_pic);:%(Libs)}
%{static|static-pie:--start-group} %{pie:%(Link_Libs_pic);:%(Link_Libs)}
%{static|static-pie:--end-group} %(Link_End)
%{EL&EB}
%{MD:%(generate_deps)} %:error-unused-options()
# executed when called with '-t ld' (L4 linker with ld)
ld = %(check_linker) %:exec(%(linker) %(link_args_ld_part1)
%(link_args_ld_part2_gnu_ld) %(link_args_ld_part3))
# executed when called with '-t lld' (L4 linker with ld)
lld = %(check_linker) %:exec(%(linker) %(link_args_ld_part1)
%(link_args_ld_part2_llvm_lld) %(link_args_ld_part3))
######### gcc command line compatibility mode for linker ###################
# maps GCC command line options directly to gnu-ld options
# specify command line compatible to linking with GCC
gcc_arg_opts =
%:arg-option(aux-info param x idirafter include imacro iprefix
iwithprefix iwithprefixbefore isystem imultilib
isysroot Xpreprocessor Xassembler T
Xlinker u z G o U D I MF)
link_output_args_gcc = %:output-option(l*)
# pass all -Wl, and -Xlinker flags as output to the linker, preserving the order
# with all -l and non-option args
link_pass_opts_gcc = %:set-var(link_pass_opts_gcc %{Wl,*&Xlinker*})
link_args_gcc =
%(gcc_arg_opts)%(link_output_args_gcc)
%{pie:}%{no-pie:}%{nostdlib:}%{static:}%{static-pie:}%{shared:}%{nostdinc:}
%{std*:} %{m*:}
%:read-pc-file(%(pc_file_dir) %{PC*:%*})
%{r}
%{r|nocrt|nostartfiles|nostdlib:;:%:read-pc-file(%(pc_file_dir) ldscripts)}
%{o} -nostdlib %{static:-static;:-Wl,--eh-frame-hdr} %{shared}
%{static-pie:-static -pie --no-dynamic-linker -z text}
%(link_pass_opts_gcc) %{W*:} %{f*:} %{u*} %{O*} %{g*} %{T*&L*}
%{!r:%{!dT:-Wl,-dT,%:search(main_%{static:stat;static-pie:pie;shared:rel;:dyn}.ld
%(libdir))}}
%{r|shared|static|static-pie|-dynamic-linker*:;:
-Wl,--dynamic-linker=%(Link_DynLinker)
%(Link_DynLinker:;:
%:error(Link_DynLinker not specified, cannot link with shared libs.))}
%{r|nostartfiles|nostdlib:;:%(Link_Start)} %o %(Libs)
%{r|nodefaultlibs|nostdlib:;:%{static|static-pie:-Wl,--start-group}
%(Link_Libs)
%{static|static-pie:-Wl,--end-group}}
%{r|nostartfiles|nostdlib:;:%(Link_End)}
%{EL&EB}
%{MD:%(generate_deps)} %:error-unused-options()
# executed when called with '-t gcc-ld' (L4 linker with gcc)
gcc-ld = %(check_linker) %:exec(%(linker) %(link_args_gcc))
################## GCC pass through for linking host / l4linux mode ###########
# implementation for modes 'host' and 'l4linux' that use GCC/G++ as linker
# (we use gcc as linker in that case)
link_host_mode_args =
%(gcc_arg_opts)
%:read-pc-file(%(pc_file_dir) %{PC*:%*})
%{o} %{z} %{pie&no-pie} %{v} %{g*} %{-coverage} %{undef}
%{static} %o
%{I*&D*&U*} %{L*&l*&Wl,*&Xlinker*} %<Wl,*
%{!static:-Wl,-Bstatic} -Wl,--start-group %(Libs) %(Link_Libs) -Wl,--end-group
%{!static:-Wl,-Bdynamic}
%{EL&EB} %{m*} %{W*} %{f*}
%{MD:%(generate_deps)} %:error-unused-options()
# executed when called with '-t host-ld', host linker.
host-ld = %(check_linker) %:exec(%(linker) %(link_host_mode_args))

984
src/l4/mk/binary.inc Normal file
View File

@@ -0,0 +1,984 @@
# -*- Makefile -*-
# vim:set ft=make:
#
# L4Re Buildsystem
#
# Makefile-Include for compiling templates (prog.mk, lib.mk)
# Makefile-Include for binary and lib directories
# Definitions for building the Makefile.inc, building dependencies,
# compiler configuration.
#
# If SYSTEM is defined and we do not clean, we generate Makefile.inc. This file
# holds the dependencies of the targets. Is also contains the definitions of
# variables holding the objects of the related targets. In a multiple
# architecture makefile, Makefile.inc will be built in arch-specific subdirs,
# like the other components built.
#
# Most compiler- and linker-flag variables are defined in such a way that
# using them in the rule will expand all the target- and
# architecture-specific definitions.
#
# The relink-rule is defined in this file.
#
# The dependencies for compiling files are defined here, the dep-files are
# generated with names .(source-file).d for .c, .cc and .S-files.
#
# Clean-rules are defined here.
#
include $(L4DIR)/mk/util.mk
$(GENERAL_D_LOC): $(L4DIR)/mk/binary.inc $(L4DIR)/mk/modes.inc $(L4DIR)/mk/rules.inc
# our default Makefile-name in the OBJ-Subdirs
BID_OBJ_Makefile ?= Makefile
include $(OBJ_BASE)/.Package.deps
# Building variants:
ifeq ($(ROLE),prog.mk)
VARIANTS ?= std
else
ifeq ($(filter-out lib.mk prog.mk test.mk assets.mk, $(ROLE)),)
VARIANTS_lib.mk = std
# If there is a variants variable for the src dir, we use it. Otherwise, we
# fall back to the pkgdir one. If there is neither, use std.
SRC_VARIANTS += $(VARIANTS_$(SRC_DIR:$(L4DIR_ABS)/%=%))
PKGDIR_VARIANTS = $(VARIANTS_$(PKGDIR_ABS:$(L4DIR_ABS)/%=%))
VARIANTS = $(or $(SRC_VARIANTS), $(PKGDIR_VARIANTS), std)
VARIANTS += $(VARIANTS_$(ROLE))
VARIANTS := $(sort $(VARIANTS))
endif
endif
$(if $(VARIANTS),,$(error No variants defined))
ifeq ($(SYSTEM),) # if we have no system yet, build the subdirs
#################################################################
#
# we have NO system defined in $(SYSTEM), we are in the src/ dir
#
#################################################################
# our default systems
SYSTEMS ?= $(SYSTEMS_ABI)
DEPENDS_PKGS ?= $(if $(PKG_OPTIONAL),$(REQUIRES_LIBS))
BID_MISSING_PCS := \
$(strip $(if $(DEPENDS_PKGS), \
$(strip $(foreach i,$(DEPENDS_PKGS), \
$(if $(strip $(wildcard $(OBJ_BASE)/pc/$(i).pc)),,$(i))))))
ifneq ($(strip $(SRC_F)$(foreach t,$(TARGET),$(SRC_F_$(t)))),)
ifeq ($(filter x86 amd64,$(BUILD_ARCH)),)
$(info $(shell echo -e "\033[32mFortran is only available on x86 and amd64 currently, skipping directory '$(SRC_DIR)'.\033[0m"))
SYSTEMS =
else
ifeq ($(GCCFORTRANAVAIL),)
$(info $(shell echo -e "\033[32mFortran compiler (gcc-4.6 or later) missing, skipping directory '$(SRC_DIR)'.\033[0m"))
SYSTEMS =
endif
endif
endif
ifneq ($(strip $(SRC_ADA)$(foreach t,$(TARGET),$(SRC_ADA_$(t)))),)
ifeq ($(GNATVERSION),)
$(info $(shell echo -e "\033[32mAda compiler (gnatmake) missing, skipping directory '$(SRC_DIR)'.033[0m"))
SYSTEMS =
endif
endif
ifneq ($(BID_MISSING_PCS),)
# clear SYSTEMS to prevent building anything
SYSTEMS =
text := $(shell echo -e "\033[32mPackage dependencies missing: \033[1m$(BID_MISSING_PCS)\033[22m; skipping directory '$(SRC_DIR)'.\033[0m")
$(if $(BID_FAIL_ON_MISSING),$(error $(text)), $(info $(text)))
endif
ifneq ($(filter l4linux targetsys,$(MODE)),)
ifneq ($(GCCLIBCAVAIL),y)
$(info Skipping target in $(SRC_DIR) as the target compiler cannot compile them.)
SYSTEMS :=
endif
endif
# intersection with BUILD_SYSTEMS
# filter the systems from the local SYSTEMS variable ($2), that match
# the build-architecture.
# args: $(1) - build architecture (one from BUILD_SYSTEMS)
# $(2) - SYSTEMS
# 1. check, if both systems are the same (optionally reduced by the CPU)
# 2. check, if at least the arch matches (and optionally the cpu)
FILTER_SYSTEM = $(shell echo $(2)|$(AWKP) '\
BEGIN{m=s="$(1)";sub("_[^-]*","",m)}\
{for(i=1;i<=NF;i++){\
if(m==$$i||s==$$i){print s}else\
if(index(m,$$i)==1||index(s,$$i)==1)\
{t=s;sub("-.*","",t);print t}}}')
# print that system of the SYSTEMS variable that actually matched with
# $(BUILD_SYSTEMS) to the given system
# args: $(1) - build architecture (SYSTEM)
# $(2) - SYSTEMS
# + do nearly the same as in FILTER_SYSTEM, but additionally check if
# the resulting system matches $(1). If so, print the according pattern from
# SYSTEMS and exit
BID_ORIG_SYSTEM = $(shell echo $(2)|$(AWKP) '\
BEGIN{s="$(1)";sub("-[^-]*","",s);m=s;sub("_[^-]*","",m)}\
{for(i=1;i<=NF;i++){\
if(m==$$i||s==$$i){print $$i;exit};\
if(index(m,$$i)==1||index(s,$$i)==1)\
{t=s;sub("-.*","",t);\
if(m==$$i&&t=="$(1)"){print $$i;exit}}}}')
TARGET_SYSTEMS := $(sort $(foreach sys,$(BUILD_SYSTEMS),\
$(call FILTER_SYSTEM,$(sys),$(SYSTEMS))))
# Add Variant infix -- helper
TARGET_SYSTEMS_ADD_VARIANT = $(firstword $(1))-$(2)-$(word 2,$(1))
# Add Variant infix to TARGET_SYSTEMS
TARGET_SYSTEMS := $(strip \
$(foreach ts,$(TARGET_SYSTEMS), \
$(foreach v,$(sort $(VARIANTS)), \
$(call TARGET_SYSTEMS_ADD_VARIANT,$(subst -,$(BID_SPACE),$(ts)),$(v)) \
) \
) \
)
DIR_FROM_SUB = $(firstword $(addprefix ../,$(patsubst /%,,$(1))) $(1))
SYSTEM_TO_ARCH = $(shell echo $(1)|$(SED) -e 's/[_-].*//')
SYSTEM_TO_CPU = $(shell echo $(1)|$(SED) -ne 's/[^-_]*_\([^-]*\).*/\1/p')
SYSTEM_TO_L4API = $(word 3,$(subst -,$(BID_SPACE),$(1)))
SYSTEM_TO_VARIANT = $(word 2,$(subst -,$(BID_SPACE),$(1)))
$(foreach sys,$(TARGET_SYSTEMS),$(OBJ_DIR)/OBJ-$(sys)/$(BID_OBJ_Makefile)):$(OBJ_DIR)/OBJ-%/$(BID_OBJ_Makefile):$(OBJ_DIR)/.general.d $(L4DIR_ABS)/mk/binary.inc
@install -d $(dir $@)
@echo 'L4DIR=$(L4DIR_ABS)'>$@
@echo 'OBJ_BASE=$(OBJ_BASE)'>>$@
@echo 'OBJ_DIR=$(OBJ_DIR)'>>$@
@echo 'SRC_DIR=$(SRC_DIR)'>>$@
@echo 'PKGDIR=$(PKGDIR_ABS)'>>$@
@echo 'PKGDIR_ABS=$(PKGDIR_ABS)'>>$@
@echo 'PKGDIR_OBJ=$(PKGDIR_OBJ)'>>$@
@echo 'MAKECONFLOCAL=$(SRC_DIR)/Makeconf.local'>>$@
@echo 'OSYSTEM=$(call BID_ORIG_SYSTEM,$*,$(SYSTEMS))'>>$@
@echo 'SYSTEM=$*'>>$@
@echo 'ARCH=$(call SYSTEM_TO_ARCH,$*)'>>$@
@echo 'CPU=$(call SYSTEM_TO_CPU,$*)'>>$@
@echo 'L4API=$(call SYSTEM_TO_L4API,$*)'>>$@
@echo 'VARIANT=$(call SYSTEM_TO_VARIANT,$*)'>>$@
@for ext in .c .cc .cpp $(FORTRAN_FILE_EXTENSIONS) $(BID_ASM_FILE_EXTENSIONS) $(ADA_FILE_EXTENSIONS) .y .l .ld .dpe .dts .dtso; \
do echo "vpath %$$ext $(VPATH_SRC_BASE)">>$@ ; done
@echo '.general.d: $(SRC_DIR)/$(if $(wildcard Make.rules),Make.rules,Makefile)'>>$@
@echo 'include $$(OBJ_BASE)/include/config/auto.conf'>>$@
@echo 'include $(SRC_DIR)/$(if $(wildcard Make.rules),Make.rules,Makefile)'>>$@
@echo 'include $$(L4DIR)/mk/$(ROLE)'>>$@
install relink scrub:: $(foreach arch,$(TARGET_SYSTEMS),\
$(OBJ_DIR)/OBJ-$(arch)/$(BID_OBJ_Makefile))
$(if $^,\
$(VERBOSE)set -e; \
for d in $(^D); do \
cd $$d; $(MAKE) -f $(BID_OBJ_Makefile) $@; \
done )
.PHONY: pre-obj
pre-obj::
all:: $(foreach arch,$(TARGET_SYSTEMS), $(OBJ_DIR)/OBJ-$(arch))
.PHONY: $(foreach arch,$(TARGET_SYSTEMS), $(OBJ_DIR)/OBJ-$(arch))
$(foreach arch,$(TARGET_SYSTEMS), $(OBJ_DIR)/OBJ-$(arch)):%:%/$(BID_OBJ_Makefile) pre-obj
$(VERBOSE)$(MAKE) $(PL_j) -C $@ -f $(BID_OBJ_Makefile)
foreach_objdir = $(if $(wildcard $(OBJ_DIR)/OBJ-*), $(VERBOSE)set -e ; \
for d in $(wildcard $(OBJ_DIR)/OBJ-*) ; do \
$(MAKE) -C $$d -f $(BID_OBJ_Makefile) $(1); \
done, @true)
%.i %.s.i:: export DO_SHOW_RESULT_FILE=y
%.i %.s.i::
$(call foreach_objdir,$@)
clean disasm::
$(call foreach_objdir,$@)
cleanall::
$(VERBOSE)$(RM) -r $(wildcard $(OBJ_DIR))
.PHONY: $(TARGET_SYSTEMS)
else
###############################################################
#
# we have a system defined in $(SYSTEM), we are in an OBJ- dir
#
###############################################################
# In Ada we need to generate the ada library information file, which also
# potentially needs to be installed. If installation is wished provide the
# target path as ADA_ALI_INSTALL_PATH and ali files will be symlinked there.
ifneq ($(strip $(SRC_ADA)$(foreach t,$(TARGET),$(SRC_ADA_$(t)))),)
ADAINSTALL=$(if $(ADA_ALI_INSTALL_PATH),\
$(MKDIR) -p $(ADA_ALI_INSTALL_PATH); \
$(LN) -fs $(abspath $*.ali) $(ADA_ALI_INSTALL_PATH))
define adarule=
%.o %.ali &: %$(1)
@$$(call COMP_MESSAGE, from $$(<F))
$(VERBOSE)$$(MKDIR) $$(@D)
$(VERBOSE)$$(ADAC) $$(ADACFLAGS) -c $$< -o $$*.o
$(VERBOSE)$$(ADAINSTALL)
endef
$(foreach ext,$(ADA_FILE_EXTENSIONS),$(eval $(call adarule,$(ext))))
endif
all:: $(TARGET)
disasm: $(TARGET)
$(call DISASM_CMD,$(if $(DABIN),$(DABIN),$<))
ifneq ($(CONFIG_USE_DROPS_STDDIR),)
L4INCDIR ?= $(addprefix $(OBJ_BASE)/include/$(ARCH)/,$(L4API)) \
$(addprefix $(OBJ_BASE)/include/,$(L4API)) \
$(OBJ_BASE)/include/$(ARCH) \
$(OBJ_BASE)/include \
$(addprefix $(DROPS_STDDIR)/include/$(ARCH)/,$(L4API)) \
$(addprefix $(DROPS_STDDIR)/include/,$(L4API)) \
$(DROPS_STDDIR)/include/$(ARCH) \
$(DROPS_STDDIR)/include
L4LIBDIR ?= $(addprefix $(OBJ_BASE)/lib/$(ARCH)_$(CPU)/$(VARIANT)/,$(L4API)) \
$(OBJ_BASE)/lib/$(ARCH)_$(CPU)/$(VARIANT)/plain \
$(OBJ_BASE)/lib/$(VARIANT) \
$(addprefix $(DROPS_STDDIR)/lib/$(ARCH)_$(CPU)/$(VARIANT)/,$(L4API)) \
$(DROPS_STDDIR)/lib/$(ARCH)_$(CPU)/$(VARIANT)/plain \
$(DROPS_STDDIR)/lib/$(VARIANT)
else
L4INCDIR ?= $(addprefix $(OBJ_BASE)/include/$(ARCH)/,$(L4API)) \
$(wildcard $(addprefix $(OBJ_BASE)/include/,$(L4API))) \
$(OBJ_BASE)/include/$(ARCH) \
$(OBJ_BASE)/include
L4LIBDIR ?= $(addprefix $(OBJ_BASE)/lib/$(ARCH)_$(CPU)/$(VARIANT)/,$(L4API)) \
$(OBJ_BASE)/lib/$(ARCH)_$(CPU)/$(VARIANT)/plain \
$(OBJ_BASE)/lib/$(VARIANT)
endif
#
# Variables Section
#
# There is a hierarchy on defining variables depending on the targets they
# refer to: Most standard-Make Variables are supported. This includes
# LDFLAGS - options for ld, defined in prog.mk and lib.mk
# CPPFLAGS - options for the c preprocessor, included in CFLAGS
# CFLAGS - options for the c compiler
# CXXFLAGS - options for the c++ compiler
# FFLAGS - options for the fortran compiler
# ASFLAGS - options for the assembler
#
# Additionally, the following variables are supported:
# SRC_C, SRC_CC, SRC_F, SRC_S - .c, .cc, .f90, .S source files
# LIBS - additional libs to link (with -l), including paths (-L)
# TARGET - targets to be built
#
# These variables will be used for all operations with the corresponding
# file types. More specific description is possible by using variables with
# added specifications. These specifications include a referred element and
# the architecture, both optional but in this order, separated by
# underscores. The referred element for CPPFLAGS, CFLAGS, CXXFLAGS and
# ASFLAGS is the source file. For the other variables, it is one of the
# target files. The TARGET variable can only be postfixed by an
# architecture.
# The specific variables will be used for the target and the referred element
# given in the name, additionally to the more general ones.
#
# Example for a valid specifications:
# SRC_C_libxverbose.a = verbose.c - ar's verbose.o into libxverbose.a, but
# not in other libs in the TARGET var.
include $(L4DIR)/mk/modes.inc
# select the variable specified in $(1) from the current architecture and
# mode. Fall back to "all" architecture if no specific version exists.
BID_mode_var= $(if $($(1)_$(ARCH)_$(MODE)),$($(1)_$(ARCH)_$(MODE)),$($(1)_all_$(MODE)))
BID_SUPPORTED ?= $(call BID_mode_var,BID_SUPPORTED)
ifneq ($(BID_SUPPORTED),y)
$(error Mode "$(MODE)" is not supported for CPU architecture "$(ARCH)")
endif
LIBCINCDIR ?= $(call BID_mode_var,LIBCINCDIR)
LIBCLIBDIR ?= $(call BID_mode_var,LIBCLIBDIR)
LDSCRIPT ?= $(call BID_mode_var,LDSCRIPT)
LDFLAGS += $(call BID_mode_var,LDFLAGS)
REQUIRES_LIBS += $(call BID_mode_var,REQUIRES_LIBS)
REQUIRES_CFLAGS += $(call BID_mode_var,REQUIRES_CFLAGS)
CARCHFLAGS += $(call variant_values,CARCHFLAGS)
LDFLAGS += $(call bid_flag_variants,LDFLAGS)
REQUIRES_LIBS += $(call bid_flag_variants,REQUIRES_LIBS)
# ---------------------------------
BID_MISSING_LIBS :=
# call pkg-config, returns __PKGCONFIG_FAILED__ if the call failed
# 1: OBJ_BASE
# 2: parameters to pkg-config
# 3: list of packages
# use L4_BID_PKG_CONFIG because of export-defs, the function is copied
L4_BID_PKG_CONFIG = $(L4DIR)/tool/bin/l4-bender
BID_PKG_CONFIG = \
$(shell PKG_CONFIG_LIBDIR=$(1)/pc \
PKG_CONFIG_PATH= $(L4_BID_PKG_CONFIG) \
--define-variable=incdir=$(1)/include/contrib \
$(if $(VERBOSE),--silence-errors) \
$(2) $(3) || echo __PKGCONFIG_FAILED__)
BID_PKG_CONFIG_MISSING = \
$(if $(strip $(3)), \
$(shell PKG_CONFIG_LIBDIR=$(1)/pc \
PKG_CONFIG_PATH= LC_ALL=C $(L4_BID_PKG_CONFIG) \
--errors-to-stdout --print-errors $(2) $(3) \
| LC_ALL=C grep ", not found"))
BID_PKG_CONFIG_FAILED = $(findstring __PKGCONFIG_FAILED__,$(1))
BID_BENDER_DEFINES = \
-Dl4obj=$(1) \
-Dl4dir=$(2) \
-Dgcclibdir="$(3:-L%=%)" \
-Dl4system=$(4) \
$(if $(5),-Dl4api=$(5))
bid_bender_default_vars = $(call BID_BENDER_DEFINES,$(OBJ_BASE),$(L4DIR),$(GCCSYSLIBDIRS),$(ARCH)_$(CPU),$(L4API))
# linker for L4 libs and applications
BID_LINK = $(L4DIR)/tool/bin/l4-bender $(if $(VERBOSE),,--trace-exec) \
-t $(if $(filter lld,$(BID_LD_TYPE)),lld,ld) \
$(bid_bender_default_vars) -Dlinker="$(LD)" \
--spec=$(L4DIR)/mk/bid-bender.spec --
# linker for host mode and l4linux mode
BID_LINK_MODE_host = $(L4DIR)/tool/bin/l4-bender $(if $(VERBOSE),,--trace-exec) \
-t host-ld $(bid_bender_default_vars) -Dlinker="$(1)" \
--spec=$(L4DIR)/mk/bid-bender.spec --
BID_link_deps_file = $(call BID_dot_fname,$1).pcs.d
BID_LINK_DEPS = $(call BID_dot_fname,$1).d $(call BID_link_deps_file,$1)
ifeq ($(BID_MISSING_PCS),)
ifneq ($(SYSTEM),)
ifneq ($(strip $(REQUIRES_LIBS)),)
MY_DEPS := $(sort $(DEPS_$(PKGDIR_ABS:$(L4DIR_ABS)/%=%)))
exclude_req_check := $(wildcard $(addprefix $(PKGDIR_ABS)/,broken obsolete))
MISSING_DEPS := $(if $(exclude_req_check),,$(filter-out $(MY_DEPS),$(REQUIRES_LIBS)))
ifneq ($(and $(MISSING_DEPS),$(BID_GLOBAL_MAKE)),)
SRC_MAKEFILE := $(firstword $(filter $(SRC_DIR)%,$(MAKEFILE_LIST)))
#RL_DEBUG_INFO := : PD[$(PKGDIR_ABS)] L4D[$(L4DIR_ABS)] D:[$(MY_DEPS)] RL:[$(REQUIRES_LIBS)] M:[$(MISSING_DEPS)]
TEXT := $(shell echo -e "\n\033[31m$(SRC_MAKEFILE): '$(MISSING_DEPS)' in REQUIRES_LIBS in Makefile but not in Control file requires$(RL_DEBUG_INFO)\033[0m")
$(if $(filter-out l4defs.gen.dir,$(notdir $(PKGDIR_ABS))),$(error $(TEXT)))
endif
REQUIRES_LIBS_LIST := $(strip $(call BID_PKG_CONFIG,$(OBJ_BASE),--libs,$(REQUIRES_LIBS)))
# error handling
ifneq ($(call BID_PKG_CONFIG_FAILED,$(REQUIRES_LIBS_LIST)),)
BID_MISSING_PCS := $(strip $(foreach i,$(REQUIRES_LIBS), \
$(if $(filter __PKGCONFIG_FAILED__,$(call BID_PKG_CONFIG,$(OBJ_BASE),--libs --print-errors,$(i))),$(i))))
text := $(shell echo -e "\033[31mLibrary dependencies missing: \033[1m$(BID_MISSING_PCS)\033[22m in directory '$(SRC_DIR)'; aborting.\033[0m")
text2 := $(strip $(foreach i,$(REQUIRES_LIBS), $(call BID_PKG_CONFIG_MISSING,$(OBJ_BASE),--libs,$(i))))
$(if $(text2),$(info $(shell echo -e "\033[31m$(text2)\033[0m")))
$(if $(BID_MISSING_PCS),$(info $(text)),$(error $(text)))
endif
endif
BID_PKG_CONFIG_CFLAGS := $(call BID_PKG_CONFIG,$(OBJ_BASE),--cflags, $(REQUIRES_CFLAGS) $(REQUIRES_LIBS))
# error handling
ifneq ($(call BID_PKG_CONFIG_FAILED,$(BID_PKG_CONFIG_CFLAGS)),)
BID_MISSING_PCS := $(strip $(foreach i,$(REQUIRES_CFLAGS) $(REQUIRES_LIBS), \
$(if $(filter __PKGCONFIG_FAILED__,$(call BID_PKG_CONFIG,$(OBJ_BASE),--cflags --print-errors,$(i))),$(i))))
text := $(shell echo -e "\033[31mCflags dependencies missing: \033[1m$(BID_MISSING_PCS)\033[22m in directory '$(SRC_DIR)'; aborting.\033[0m")
text2 := $(strip $(foreach i,$(REQUIRES_LIBS), $(call BID_PKG_CONFIG_MISSING,$(OBJ_BASE),--cflags,$(i))))
$(if $(text2),$(info $(shell echo -e "\033[31m$(text2)\033[0m")))
$(error $(text))
endif
endif # SYSTEM
endif
ifneq ($(REQUIRE_HOST_TOOLS),)
CHECK_HOST_TOOLS = \
$(shell unset mis; \
for i in $(1); do \
if ! command -v $$i >/dev/null 2>&1; then \
[ -n "$$mis" ] && mis="$$mis "; \
mis="$$mis$$i"; \
fi \
done; echo $$mis)
ifneq ($(call CHECK_HOST_TOOLS,$(REQUIRE_HOST_TOOLS)),)
$(info $(shell echo -e "\033[32mHost tool(s) missing: \033[1m$(REQUIRE_HOST_TOOLS)\033[22m needed in directory '$(SRC_DIR)'. Skipping.\033[0m"))
SYSTEMS :=
INSTALL_TARGET :=
endif
endif
# -----------------------
# TEMP-only
$(if $(filter x86 arm arm64 amd64 mips sparc ppc32,$(SYSTEMS)), $(error Please appends "-plain" to each architecture in SYSTEMS ))
LDFLAGS += $(if $(CONFIG_BID_LD_EMIT_UNWIND),--eh-frame-hdr,)
OPTS_DEBUG-$(CONFIG_BID_DEBUG_INFO) = -g
OPTS_DEBUG ?= $(OPTS_DEBUG-y)
OPTS ?= $(OPTS_DEBUG) $(if $(CONFIG_BID_OPTIMIZE_SIZE),-Os,-O2) \
-fno-strict-aliasing
WARNINGS_MINIMAL ?= -Wall $(call bid_flag_variants,WARNINGS)
WARNINGS_MEDIUM ?= -Wall -Wstrict-prototypes $(CONDITIONAL_WARNINGS_MEDIUM) \
-Wmissing-declarations $(call bid_flag_variants,WARNINGS)
WARNINGS_FULL ?= -Wextra -Wbad-function-cast -Wdouble-promotion \
$(CONDITIONAL_WARNINGS_FULL) $(WARNINGS_MEDIUM)
WARNINGS ?= $(WARNINGS_FULL)
ifeq ($(MODE),host)
# never cross compile in host mode
override CROSS_COMPILE =
override CC = $(HOST_CC)
override CXX = $(HOST_CXX)
override ADAC = $(HOST_ADAC)
else
# no architecture specific flags in host mode
LDFLAGS += $(LDFLAGS_$(ARCH))
endif
# additional libraries go after the requires-libs-list
LIBS += $(strip $(LIBS_$(OSYSTEM)) $(LIBS_$@) $(LIBS_$@_$(OSYSTEM)))
# no link address if build a lib or we're compiling a host program and using
# the host linker scripts
ifeq ($(ROLE),lib.mk)
NO_DEFAULT_RELOC := y
endif
ifneq ($(HOST_LINK),)
NO_DEFAULT_RELOC := y
endif
# stack protector support
# check if uclibc signaled support for stack protector
ifneq ($(filter bid_allow_stack_protector, $(BID_PKG_CONFIG_CFLAGS)),)
BID_PKG_CONFIG_CFLAGS := $(filter-out bid_allow_stack_protector, $(BID_PKG_CONFIG_CFLAGS))
ifdef CONFIG_BID_GCC_ENABLE_STACK_PROTECTOR # stack protector option was selected in make config
GCCSTACKPROTECTOROPT := $(if $(CONFIG_BID_GCC_STACK_PROTECTOR_ALL), $(GCCSTACKPROTALLOPT), \
$(GCCSTACKPROTOPT))
ifneq ('$(CONFIG_BID_GCC_STACK_PROTECTOR_ALL)$(CONFIG_BID_GCC_STACK_PROTECTOR)','y')
$(error invalid combination of CONFIG_BID_GCC_STACK_PROTECTOR... options)
endif
endif # CONFIG_BID_GCC_ENABLE_STACK_PROTECTOR
else
# explicity disable the stack protector (some compilers enable stack protector by default)
GCCSTACKPROTECTOROPT = $(GCCNOSTACKPROTOPT)
endif # stack protector
# We need relocation to RAM_BASE if:
# - requested explicitly (RELOC_PHYS)
# - otherwise, only if _none_ of the following things applies:
# - we compile for an MMU system
# - all binaries are PIE
# - the current binary can be PIE and this is enabled
default_reloc_phys = $(if $(CONFIG_MMU)$(CONFIG_BID_PIE_ALL)$(and $(CONFIG_BID_PIE_VOLUNTARY),$(BID_CAN_PIE)),$(RELOC_PHYS),y)
default_reloc_base = $(if $(NO_DEFAULT_RELOC),,$(firstword $(DEFAULT_RELOC_$(1)) \
$(DEFAULT_RELOC_$(ARCH)) \
$(DEFAULT_RELOC)))
# The default relocation is directly used by the bootstrap Make.rules.
default_reloc = $(if $(call default_reloc_base,$(1)),\
$(if $(default_reloc_phys), \
$(shell printf "0x%x" $$(($(RAM_BASE) + $(call default_reloc_base,$(1))))), \
$(call default_reloc_base,$(1))))
# Default relocation should not be applied for PIE binaries!
apply_default_reloc = $(if $(CONFIG_BID_PIE_ALL)$(and $(CONFIG_BID_PIE_VOLUNTARY),$(BID_CAN_PIE)),,$(call default_reloc,$(1)))
default_heap_size = $(if $(if $(NO_DEFAULT_RELOC),,$(CONFIG_BID_STATIC_HEAP)),\
$(firstword $(DEFAULT_HEAP_SIZE_$(1)) \
$(DEFAULT_HEAP_SIZE_$(ARCH)) \
$(DEFAULT_HEAP_SIZE) \
0x10000))
default_stack_size = $(if $(if $(NO_DEFAULT_RELOC),,$(CONFIG_BID_STATIC_STACK)),\
$(firstword $(DEFAULT_STACK_SIZE_$(1)) \
$(DEFAULT_STACK_SIZE_$(ARCH)) \
$(DEFAULT_STACK_SIZE) \
0x1000))
CCXX_FLAGS += $(if $(CONFIG_FULL_PATH_NAMES_IN_BINARIES),,$(GCCPREFIXOPT))
# can be overwritten to get the old mode
CFLAGS_C99 ?= -std=gnu99
ifneq ($(MODE),host)
CFLAGS_L4_GENERIC += $(CARCHFLAGS) $(CCXX_FLAGS) $(GCCSTACKPROTECTOROPT)
CFLAGS_L4_GENERIC += -ffunction-sections -fdata-sections
CFLAGS_L4_NOPIC += $(call BID_mode_var,NOPICFLAGS)
CFLAGS_L4_PIC += $(PICFLAGS)
endif
BID_DEFINES_SOURCE_STANDARD ?= -D_POSIX_C_SOURCE=200809L -D_XOPEN_SOURCE=700
CFLAGS += $(if $(CONFIG_BID_GCC_OMIT_FP),-fomit-frame-pointer,-fno-omit-frame-pointer)
CFLAGS += $(if $(CONFIG_BID_LD_EMIT_UNWIND),-funwind-tables,-fno-unwind-tables)
CFLAGS += $(OPTS) $(WARNINGS)
CFLAGS += -fno-common
CFLAGS += $(CFLAGS_C99)
CFLAGS += $(CFLAGS_L4_GENERIC)
CFLAGS += $(call bid_flag_variants,CFLAGS)
DEFINES += -DSYSTEM_$(subst -,_,$(subst +,_,$(SYSTEM))) -DARCH_$(ARCH) -DCPUTYPE_$(CPU) -DL4API_$(L4API)
DEFINES += $(BID_DEFINES_SOURCE_STANDARD) -D_FILE_OFFSET_BITS=64
DEFINES-l4api-plain := -DL4_MINIMAL_LIBC
DEFINES += $(DEFINES-l4api-$(L4API))
ifdef DEBUG
ifneq (,$(filter 0 n N, $(DEBUG)))
DEFINES += -DNDEBUG
endif
endif
DEFINES += $(call bid_flag_variants,DEFINES)
ifneq ($(MODE),host)
CPPFLAGS_L4_GENERIC += $(CARCHFLAGS)
endif
CPPFLAGS-DEBUG_MODE = \
$(if $(filter l4f,$(L4API)), \
$(addprefix -include ,$(OBJ_BASE)/include/l4/sys/kdebug.h \
$(OBJ_BASE)/include/l4/sys/ktrace.h \
$(OBJ_BASE)/include/l4/util/kprintf.h \
$(OBJ_BASE)/include/l4/sys/debugger.h))
CPPFLAGS+= $(DEFINES)
CPPFLAGS+= $(CPPFLAGS_L4_GENERIC)
CPPFLAGS+= $(addprefix -I, $(PRIVATE_INCDIR) $(call bid_flag_variants,PRIVATE_INCDIR))
CPPFLAGS+= $(if $(CONTRIB_INCDIR),$(addprefix -I$(OBJ_BASE)/include/contrib/,$(CONTRIB_INCDIR)))
CPPFLAGS+= $(BID_PKG_CONFIG_CFLAGS)
ifneq ($(MODE),host)
CPPFLAGS+= $(addprefix -I, $(L4INCDIR))
endif
CPPFLAGS+= $(if $(DEBUG_MODE),$(CPPFLAGS-DEBUG_MODE))
CPPFLAGS+= $(LIBCINCDIR)
CPPFLAGS+= $(call bid_flag_variants,CPPFLAGS)
ifneq ($(MODE),host)
CPPFLAGS += -include l4/bid_config.h
CXXFLAGS_L4_GENERIC += $(CARCHFLAGS) $(CCXX_FLAGS)
CXXFLAGS_L4_GENERIC += $(if $(GCC_HAS_ATOMICS),-DL4_GCC_HAS_ATOMICS)
CXXFLAGS_L4_GENERIC += $(GCCSTACKPROTECTOROPT)
CXXFLAGS_L4_GENERIC += -fuse-cxa-atexit -ffunction-sections -fdata-sections
CXXFLAGS_L4_NOPIC += $(call BID_mode_var,NOPICFLAGS)
CXXFLAGS_L4_PIC += $(PICFLAGS)
endif
CXXFLAGS_EARLY += $(if $(filter 1-15,$(BID_COMPILER_IS_CLANG)-$(GCCVERSION)),-std=gnu++17)
CXXFLAGS_EARLY += $(if $(filter 1-9 1-10,$(BID_COMPILER_IS_GCC)-$(GCCVERSION)),-std=gnu++17)
CXXFLAGS+= $(if $(CONFIG_BID_GCC_OMIT_FP),-fomit-frame-pointer,-fno-omit-frame-pointer)
CXXFLAGS+= $(if $(CONFIG_BID_LD_EMIT_UNWIND),-funwind-tables,-fno-unwind-tables)
CXXFLAGS+= $(OPTS) $(filter-out $(foreach w,$\
-Wbad-function-cast $\
-Wstrict-prototypes $\
-Wmissing-prototypes $\
-Wunterminated-string-initialization,$\
$(w) $(patsubst -W%,-Wno-%,$(w))),$\
$(WARNINGS))
CXXFLAGS+= $(GCCWNONOEXCEPTTYPE) $(GCCWNOPSABI) $(GCCWNOUNUSEDPRIVATEFIELD) \
$(GCCWNOC99DESIGNATOR)
CXXFLAGS+= -fno-common
CXXFLAGS+= $(CXXFLAGS_L4_GENERIC)
CXXFLAGS+= $(call bid_flag_variants,CXXFLAGS)
ifeq ($(BID_COLLECT_DIAGNOSTICS),sarif)
ifneq ($(strip $(DIAGNOSTICS_SARIF)),)
CXXFLAGS += $(DIAGNOSTICS_SARIF)
CFLAGS += $(DIAGNOSTICS_SARIF)
else
$(error SARIF diagnostics not supported by compiler)
endif
endif
ifeq ($(BID_COLLECT_DIAGNOSTICS),json)
ifneq ($(strip $(DIAGNOSTICS_JSON)),)
CXXFLAGS += $(DIAGNOSTICS_JSON)
CFLAGS += $(DIAGNOSTICS_JSON)
CXX_COLLECT_REDIR = |& sed '/^\[\]/d' | tee $$@.diag && ( [[ -s $$@.diag ]] || rm $$@.diag )
else
$(error JSON diagnostics not supported by compiler)
endif
endif
ifneq ($(BID_COLLECT_DIAGNOSTICS),)
CXXFLAGS += $(DIAGNOSTICS_COLOR)
CFLAGS += $(DIAGNOSTICS_COLOR)
CXX_COLLECT_REDIR ?= |& tee $@.diag && ( [[ -s $@.diag ]] || rm $@.diag )
C_COLLECT_REDIR = $(CXX_COLLECT_REDIR)
endif
FFLAGS += $(OPTS)
FFLAGS += $(filter-out $(GCCPREFIXOPT),$(CFLAGS_L4_GENERIC))
FFLAGS += $(call bid_flag_variants,FFLAGS)
ifneq ($(MODE),host)
ADACFLAGS += -nostdinc -I$(OBJ_BASE)/include/contrib/ada/adainclude/
ADACFLAGS += --RTS=$(OBJ_BASE)/include/contrib/ada
endif
NO_CPP_ADAC = y
NOPICFLAGS += $(if $(CONFIG_BID_PIE),-fPIE)
PICFLAGS += -fPIC -U__PIC__ -D__PIC__=1
# select NOPIEFLAGS and NOPICFLAGS, use the most specific mode variable
# first and the try the more generic _all_ and global version
NOPICFLAGS_all_$(MODE) ?= $(NOPICFLAGS)
NOPICFLAGS_$(ARCH)_$(MODE) ?= $(NOPICFLAGS_all_$(MODE))
NOPIEFLAGS_all_$(MODE) ?= $(NOPIEFLAGS)
NOPIEFLAGS_$(ARCH)_$(MODE) ?= $(NOPIEFLAGS_all_$(MODE))
ifneq ($(MODE),host)
ASFLAGS_L4_GENERIC += $(CARCHFLAGS) $(CCXX_FLAGS)
endif
ASFLAGS += $(OPTS) $(ASFLAGS_L4_GENERIC)
ASFLAGS += $(call bid_flag_variants,ASFLAGS)
ALLOBJS = $(OBJS) $(foreach target,$(TARGET) $(TARGET_$(OSYSTEM)),\
$(OBJS_$(target)) $(OBJS_$(target)_$(OSYSTEM)))
ALLDPI = $(sort $(foreach obj,$(ALLOBJS),$(patsubst %.dpe,%.dpi,\
$(DPE_$(obj:.o=.c)))))
# convert list of c++ files names to .o files
# arg: 1 - list of files
# 2 - infix between the basename and the .o
convert_cc_to_o_file = $(patsubst %.cc,%$(2).o, $(filter %.cc,$(1))) \
$(patsubst %.cpp,%$(2).o,$(filter %.cpp,$(1)))
#
# Get the combined contents of generic and target-specific variables.
#
# Returns:
# $(<var>) $(<var>_$(OSYSTEM)) $(<var>_<target>) $(<var>_<target>_$(OSYSTEM))
#
# arg: 1 - name of the variable (<var>), e.g. SRC_C
# 2 - target name
#
get_target_var = $(strip \
$($(1)) $($(1)-y) \
$($(1)_$(ARCH)) $($(1)_$(ARCH)-y) \
$(if $(OSYSTEM), \
$($(1)_$(OSYSTEM)) $($(1)_$(OSYSTEM)-y)) \
$($(1)_$(2)) $($(1)_$(2)-y) \
$(if $(OSYSTEM), \
$($(1)_$(2)_$(OSYSTEM)) $($(1)_$(2)_$(OSYSTEM)-y)))
# convert list of Fortran file names to .o files
# arg: 1 - list of files
# 2 - infix between the basename and the .o
convert_f_to_o_file = $(foreach e,$(FORTRAN_FILE_EXTENSIONS),$(patsubst %$e,%$(2).o,$(filter %$e,$(1))))
# convert list of Ada file names to .o files
# arg: 1 - list of files
# 2 - infix between the basename and the .o
convert_ada_to_o_file = $(foreach e,$(ADA_FILE_EXTENSIONS),$(patsubst %$e,%$(2).o,$(filter %$e,$(1))))
convert_asm_to_o_file = $(foreach e,$(BID_ASM_FILE_EXTENSIONS),$(patsubst %$e,%$(2).o,$(filter %$e,$(1))))
#
# generic source to object file name converters
# args: 1 - (list of) source file(s)
# 2 - object file infix 1 (after the source base-name)
#
gen_SRC_CC_obj = $(call convert_cc_to_o_file,$(1),$(2))
gen_SRC_C_obj = $(1:.c=$(2).o)
gen_SRC_S_obj = $(call convert_asm_to_o_file,$(1),$(2))
gen_SRC_F_obj = $(call convert_f_to_o_file,$(1),$(2))
gen_SRC_ADA_obj = $(call convert_ada_to_o_file,$(1),$(2))
gen_SRC_DATA_obj = $(addsuffix .bin.o,$1)
#
# Check source file constraints and generate and add the object file
# name to OBJS_<target>.
#
# Generates:
# BID_OBJ_SRC_<object-name> := <source-name>
# BID_SRC_OBJ_<source-name> += <object-name>
# OBJS_<target> += <object-name>
#
# Checks:
# * source files must be relative paths
# * there must be only one source file generating an object file
#
# arg: 1 - target name
# 2 - object file name
# 3 - source file name
#
define make_per_obj_vars
# $$(info make_per_obj_vars: '$(1)' '$(2)' '$(3)')
$$(if $$(filter /%,$(3)), $$(error Source file must be relative: $(3)))
$$(if $$(and $$(BID_OBJ_SRC_$(2)), $$(filter-out $$(BID_OBJ_SRC_$(2)), $(3))), \
$$(error $(2) has ambigous source files: $(3) $$(BID_OBJ_SRC_$(2))))
BID_OBJ_SRC_$(2) := $(3)
BID_SRC_OBJ_$(3) += $(2)
OBJS_$(1) += $(2)
endef
#
# Make variables for all source files in $($(2))
#
# args: 1 - source var name (e.g., SRC_C)
# 2 - target
# 3 - object name infix 1
#
define make_per_source_type_vars
$(foreach src,$(call get_target_var,$(1),$(2)),\
$(eval $(call make_per_obj_vars,$(2),$(strip $(call gen_$(1)_obj,$(src),$(3))),$(src))))
endef
#
# All supported SRC_<x> variables
#
BID_SRC_VARS ?= S C CC F ADA DATA
#
# Generate per target/source/object variables for all sources
# found in SRC_[$(BID_SRC_VARS)].
#
# args: 1 - target
# 2 - object file infix 1
#
define make_per_target_vars
$(foreach svar,$(BID_SRC_VARS),$(call make_per_source_type_vars,SRC_$(svar),$(1),$(2)))
endef
#
# Generate all target / object / source specific variables and
# dependencies for a given target.
#
# args: 1 - target name
# 2 - object-file infix 1 (added after the source files base-name)
#
define make_per_target_vars_and_deps
$$(call make_per_target_vars,$(1),$(2))
OBJS_$(1) := $$(call get_target_var,OBJS,$(1))
$$(OBJS_$(1)): .general.d
$(1): OBJS = $$(OBJS_$(1))
$(1): $$(OBJS_$(1))
endef
# handle per-target DEFAULT_RELOC.
#
# Create a dependency to $(BID_RAM_BASE_DEP) and LDFLAGS for the given target.
# NOTE: the handling depends on the global MODE setting in the Makefile.
ifneq ($(MODE),shared)
ifneq ($(filter l4linux host,$(MODE)),)
define make_per_target_reloc
$$(error DEFAULT_RELOC / DEFAULT_RELOC_$(1) must not be set if MODE is l4linux or host)
endef
define make_per_target_heap_size
$$(error DEFAULT_HEAP_SIZE / DEFAULT_HEAP_SIZE_$(1) must not be set if MODE is l4linux or host)
endef
define make_per_target_stack_size
$$(error DEFAULT_STACK_SIZE / DEFAULT_STACK_SIZE_$(1) must not be set if MODE is l4linux or host)
endef
else
define make_per_target_reloc
$(1): $$(BID_RAM_BASE_DEP)
LDFLAGS_$(1) += $$(if $$(filter lld,$$(BID_LD_TYPE)),\
--image-base=$$(firstword $$(call default_reloc,$(1))),\
-Ttext-segment=$$(firstword $$(call default_reloc,$(1))))
endef
define make_per_target_heap_size
LDFLAGS_$(1) += --defsym=__heap_size=$$(firstword $$(call default_heap_size,$(1)))
endef
define make_per_target_stack_size
LDFLAGS_$(1) += --defsym=__stack_size=$$(firstword $$(call default_stack_size,$(1)))
endef
endif
else
define make_per_target_reloc
endef
define make_per_target_heap_size
endef
define make_per_target_stack_size
endef
endif
#
# Generate $(1): %.dpi -> %.dpe dependencies for one source file
# arg: 1 - name of the C or C++ source file
#
# This function generates a dependency if DPE_$(1) is not empty
#
define gen_src_to_dpe_deps
$(if $(DPE_$(1)),$(eval $(SRC_DIR)/$(1): $(patsubst %.dpe,%.dpi,$(DPE_$(1)))))
endef
define gen_target_vars_and_deps
$(eval $(call make_per_target_vars_and_deps,$(1),$(2))) \
$(foreach src,$(call get_target_var,SRC_C,$(1)) \
$(call get_target_var,SRC_CC,$(1)), \
$(call gen_src_to_dpe_deps,$(src))) \
$(if $(call apply_default_reloc,$(1)),$(eval $(call make_per_target_reloc,$(1)))) \
$(if $(call default_heap_size,$(1)),$(eval $(call make_per_target_heap_size,$(1))))
$(if $(call default_stack_size,$(1)),$(eval $(call make_per_target_stack_size,$(1))))
endef
# Generate dependency rules and target-specific variables for all
# targets, using the functions above.
define GENERATE_PER_TARGET_RULES
$(foreach target,$(1),$(call gen_target_vars_and_deps,$(target),$(2)))
endef
#
# Rules Section
#
# the default target "all" ensures building of the targets. When multiple
# architectures are used, the targets are build in subdirs.
# the relink-rule: make the TARGETs phony. Specification of build-targets
# in MAKECMDGOALS is not allowed. Possibility: TARGET=
#
ifneq ($(filter relink,$(MAKECMDGOALS)),)
.PHONY: $(TARGET)
relink: all
endif
DEPFLAGS = -MD -MP -MF $(@D)/.$(@F).d
DEPFLAGS_F = -cpp
include $(L4DIR)/mk/rules.inc
# generate rules to compile %.cc files to %.o, %.s.o etc
$(eval $(call BID_GENERATE_CXX_MAKE_RULES,cc))
# generate rules to compile %.cpp files to %.o, %.s.o etc
$(eval $(call BID_GENERATE_CXX_MAKE_RULES,cpp))
# generate rules to compile %.c files to %.o, %.s.o etc
$(eval $(call BID_GENERATE_C_MAKE_RULES,c))
# generate rules to compile %.f90 files to %.o, %.s.o etc
$(foreach e,$(FORTRAN_FILE_EXTENSIONS),$(eval $(call BID_GENERATE_F_MAKE_RULES,$(subst .,,$e))))
# generate rules to compile %.adb/%.ads files to %.o, %.s.o etc
$(foreach e,$(ADA_FILE_EXTENSIONS),$(eval $(call BID_GENERATE_ADA_MAKE_RULES,$(subst .,,$e))))
# generate rules to compile %.S files to %.o, %.s.o etc
$(foreach e,$(BID_ASM_FILE_EXTENSIONS),$(eval $(call BID_GENERATE_ASM_MAKE_RULES,$(subst .,,$e))))
# Reset implicit rules, mind the TAB.
define reset_implicit_rule =
%o: %$(1)
endef
$(foreach e,.c .cc .cpp $(BID_ASM_FILE_EXTENSIONS) $(FORTRAN_FILE_EXTENSIONS) $(ADA_FILE_EXTENSIONS),$(eval $(call reset_implicit_rule,$e)))
$(eval $(call BID_GENERATE_I_MAKE_RULE,%.i,%.c,$(CC),$(CFLAGS) $(call BID_mode_var,NOPICFLAGS)))
$(eval $(call BID_GENERATE_I_MAKE_RULE,%.s.i,%.c,$(CC),$(CFLAGS) $(PICFLAGS)))
$(eval $(call BID_GENERATE_I_MAKE_RULE,%.i,%.cc,$(CXX),$(CXXFLAGS) $(call BID_mode_var,NOPICFLAGS)))
$(eval $(call BID_GENERATE_I_MAKE_RULE,%.s.i,%.cc,$(CXX),$(CXXFLAGS) $(PICFLAGS)))
$(eval $(call BID_GENERATE_I_MAKE_RULE,%.i,%.cpp,$(CXX),$(CXXFLAGS) $(call BID_mode_var,NOPICFLAGS)))
$(eval $(call BID_GENERATE_I_MAKE_RULE,%.s.i,%.cpp,$(CXX),$(CXXFLAGS) $(PICFLAGS)))
$(eval $(call BID_GENERATE_I_MAKE_RULE,%.i,%.S,$(CC),$(ASFLAGS)))
$(eval $(call BID_GENERATE_S_MAKE_RULE,%.c,$(CC),$(CFLAGS)))
$(eval $(call BID_GENERATE_S_MAKE_RULE,%.cc,$(CC),$(CXXFLAGS)))
$(eval $(call BID_GENERATE_S_MAKE_RULE,%.cpp,$(CC),$(CXXFLAGS)))
%.c: %.y
@$(GEN_MESSAGE)
$(VERBOSE)$(CONFIG_YACC) $(YFLAGS) $(abspath $<)
$(VERBOSE)mv -f y.tab.c $@
$(VERBOSE)if [ -f y.tab.h ]; then mv -f y.tab.h $(@:.c=.h); fi
%.c: %.l
@$(COMP_MESSAGE)
$(VERBOSE)$(CONFIG_LEX) -o$@ $(abspath $<)
%.dpi: %.dpe
@$(GEN_MESSAGE)
$(VERBOSE)$(call MAKEDEP,perl) $(GEN_DOPECODE) $< >$@
define device_tree_rule
%.$(2): %.$(1) $(GENERAL_D_LOC)
@$$(BUILD_MESSAGE)
$(VERBOSE)$(call lessfork_mkdir,$$(@D))
$(VERBOSE)$(CPP) $(CPPFLAGS) -undef $$(addprefix -I, $(PRIVATE_INCDIR)) -x assembler-with-cpp -Wp,-MD,$$(@D)/.$$(@F).d,-MT$$@,-MP -nostdinc -o $$@.pre $$<
$(VERBOSE)$(DTC) $(DTC_FLAGS) $$(addprefix -i , $(PRIVATE_INCDIR)) -i $$(dir $$<) -d $$(call BID_dot_fname,$$@).d-x -O dtb -b 0 -o $$@ $$@.pre
$(VERBOSE)$(SED) -e "s|$$@.pre|$$<|" $$(call BID_dot_fname,$$@).d-x | \
perl -ne 'print "$$$$_\n"; if (/^.*:\s*(.*)$$$$/) { print "$$$$_:\n" foreach (split(/ /,$$$$1)); }' >> $$(@D)/.$$(@F).d
$(VERBOSE)$(RM) $$(call BID_dot_fname,$$@).d-x $$@.pre
endef
$(eval $(call device_tree_rule,dts,dtb))
$(eval $(call device_tree_rule,dtso,dtbo))
define bin_to_asm_recipe
echo -e ".section .rodata, \"a\"\n" \
".global _binary_$(3)_start\n" \
".global _binary_$(3)_end\n" \
".p2align 3\n" \
"_binary_$(3)_start:\n" \
".incbin \"$(1)\"\n" \
"_binary_$(3)_end:\n" >$(2)
endef
SRC_DATA_VPATH ?= $(SRC_DIR)
$(foreach s,$(SRC_DATA),$(eval vpath $(s) $(SRC_DATA_VPATH)))
$(addsuffix .bin.S,$(SRC_DATA)): %.bin.S: % $(GENERAL_D_LOC)
@$(GEN_MESSAGE)
$(VERBOSE)$(MKDIR) $(@D)
$(VERBOSE)$(call bin_to_asm_recipe,$<,$@,$(subst -,_,$(subst /,_,$(subst .,_,$(strip $(*F))))))
DEPS += $(foreach file,$(ALLOBJS), $(call BID_dot_fname,$(file)).d)
DEPS += $(foreach file,$(ALLOBJS) $(INSTALL_TARGET), $(call BID_dot_fname,$(file)).cmd)
DEPS += $(foreach file,$(ALLDPI), $(call BID_dot_fname,$(file)).d)
# Common clean Rules
clean cleanall::
$(file >$@.in,\
$(strip $(filter-out $(KEEP_ON_CLEAN),\
$(wildcard *.dpi) $(wildcard *.o) $(wildcard *.i) \
$(wildcard *.S) $(wildcard *.ali) \
$(wildcard $(filter-out -%, $(ALLOBJS) $(DEL_ON_CLEAN))))))
$(VERBOSE)xargs -a $@.in $(RM)
$(VERBOSE)$(RM) $@.in
# clean: delete all temporary editor files, objects, binaries
# and most generated files
cleanall::
$(VERBOSE)$(RM) $(TARGET) \
$(addsuffix .*.d,$(sort $(dir $(ALLOBJS)))) \
$(addsuffix .*.cmd,$(sort $(dir $(ALLOBJS)))) \
$(wildcard $(BID_OBJ_Makefile).inc)
.PHONY: scrub clean cleanall disasm
endif # $(SYSTEM) is defined
# General rules
# scrub: delete temporary editor files and stuff like this
# can be extended by locals
scrub cleanall::
$(VERBOSE)$(SCRUB)

203
src/l4/mk/config.inc Normal file
View File

@@ -0,0 +1,203 @@
# -*- Makefile -*-
# vim:set ft=make:
#
# L4Re Buildsystem
#
# Makefile-Include for compiling templates (prog.mk, lib.mk)
#
# Makefile-Include for binary, lib, subdir and other directories.
# Definitions and rules for the DROPS configuration tool.
# Supported targets:
#
# config:: - run the menu-driven configuration tool
# menuconfig xconfig:: - run the configuration tool
# oldconfig:: - (re)create the configuration header
# based on a prior configuration
# or default values
# genfixdep - build fixdep tool
#
# Required Parameters:
#
# PKGDIR
#
#
# Optional Parameters:
#
# DROPSCONF - if nonempty, the configuration tool is run for
# target config::. If empty, the configuration tool
# is not run.
# DROPSCONF_TITLE - the main title in the configuration tool.
# DROPSCONF_DEFCONFIG - default config file
# DROPSCONF_CONFIG_IN - configuration defintion file
# DROPSCONF_CONFIG - config file
# DROPSCONF_CONFIG_H - generated config header file
# DROPSCONF_MACRO - macro to indicate inclusion of config header file
# DROPSCONF_HELPFILE - options help file
# DROPSCONF_TOOL - the menudriven configuration tool
# DROPSCONF_TOOL_TXT - the configuration tool
# DROPSCONF_TOOL_OLD - helper for recreating the config header file
MAKECONFIGGOALS := config menuconfig textconfig oldconfig olddefconfig xconfig \
gconfig nconfig randconfig allyesconfig allnoconfig \
savedefconfig txtconfig
.PHONY: $(MAKECONFIGGOALS)
KCONFIG_OBJ_DIR = $(OBJ_BASE)/scripts/kconfig
kconfig_call = $(MAKE) -C $(L4DIR)/tool/kconfig O=$(OBJ_BASE) \
Kconfig=$(KCONFIG_FILE) \
KCONFIG_AUTOHEADER=include/generated/autoconf.h \
KCONFIG_CONFIG=.kconfig \
KCONFIG_AUTOCONFIG=include/config/auto.conf \
KCONFIG_TRISTATE=.kconfig.tristate \
l4re_srcdir=$(L4DIR_ABS)
DROPSCONF ?=
#DROPSCONF_TITLE ?= DROPS Configuration Tool
#DROPSCONF_DEFCONFIG ?= defconfig
#DROPSCONF_CONFIG_IN ?= config.in
#DROPSCONF_CONFIG ?= $(OBJ_DIR)/.config
#DROPSCONF_CONFIG_H ?= $(OBJ_DIR)/config.h
#DROPSCONF_CONFIG_MK ?= $(OBJ_DIR)/Makeconf.bid.local
DROPSCONF_DONTINC_MK ?=
#DROPSCONF_MACRO ?= CONFIG_H_INCLUDED
#DROPSCONF_HELPFILE ?= config.help
#DROPSCONF_LXDIALOG ?= $(OBJ_BASE)/tool/config/lxdialog/lxdialog
#DROPSCONF_TOOL ?= $(firstword $(wildcard \
# $(L4DIR)/tool/config/Menuconfig \
# $(DROPS_STDDIR)/tool/bin/Menuconfig) \
# did_not_find_BID_Menuconfig)
#DROPSCONF_TOOL_TXT ?= $(firstword $(wildcard \
# $(L4DIR)/tool/config/Configure \
# $(DROPS_STDDIR)/tool/bin/Configure) \
# did_not_find_BID_Configure)
#DROPSCONF_TOOL_OLD ?= $(firstword $(wildcard \
# $(L4DIR)/tool/config/Configure \
# $(DROPS_STDDIR)/tool/bin/Configure) \
# did_not_find_BID_Configure) -d
#DROPSCONF_VARDEFS = $(foreach v,TITLE DEFCONFIG CONFIG_IN CONFIG CONFIG_H \
# MACRO HELPFILE UNDEF LXDIALOG,DROPSCONF_$v='$(DROPSCONF_$v)')
ifneq ($(DROPSCONF),)
.o: $(DROPSCONF_CONFIG_H)
DIRS_FOR_CONFIG = $(KCONFIG_OBJ_DIR) $(OBJ_BASE)/config $(OBJ_BASE)/include/l4
$(DIRS_FOR_CONFIG):
$(VERBOSE)$(MKDIR) $@
DROPSCONF_CONFIG_DEPS = $(KCONFIG_FILE) $(KCONFIG_FILE).defines
menuconfig config: $(DROPSCONF_CONFIG_DEPS) | $(DIRS_FOR_CONFIG)
$(VERBOSE)+$(kconfig_call) menuconfig
$(VERBOSE)+$(kconfig_call) syncconfig
$(VERBOSE)test ! -r $(DROPSCONF_CONFIG) -o \
! $(DROPSCONF_CONFIG) -nt $(DROPSCONF_CONFIG_MK) || \
$(MAKE) $(DROPSCONF_CONFIG_MK)
textconfig: $(DROPSCONF_CONFIG_DEPS) | $(DIRS_FOR_CONFIG)
$(VERBOSE)+$(kconfig_call) config
$(VERBOSE)+$(kconfig_call) syncconfig
@$(MAKE) $(DROPSCONF_CONFIG_MK)
oldconfig olddefconfig xconfig gconfig nconfig randconfig allyesconfig allnoconfig savedefconfig: $(DROPSCONF_CONFIG_DEPS) | $(DIRS_FOR_CONFIG)
$(VERBOSE)+$(kconfig_call) $@
$(VERBOSE)+$(kconfig_call) syncconfig
@$(MAKE) $(DROPSCONF_CONFIG_MK)
syncconfig: $(DROPSCONF_CONFIG_DEPS) | $(DIRS_FOR_CONFIG)
$(VERBOSE)+$(kconfig_call) syncconfig
$(DROPSCONF_CONFIG): $(DROPSCONF_CONFIG_DEPS) | $(DIRS_FOR_CONFIG)
$(VERBOSE)+$(kconfig_call) syncconfig
.PHONY: genfixdep
# script_basic: only fixdep for now
# config-build=1: Force doing config things and not Linux build system things
genfixdep:
$(VERBOSE)+$(kconfig_call) config-build=1 scripts_basic
#$(DROPSCONF_CONFIG_H): $(DROPSCONF_CONFIG)
#$(DROPSCONF_CONFIG_H) $(DROPSCONF_CONFIG): $(DROPSCONF_CONFIG_IN)
# @$(GEN_MESSAGE)
# $(VERBOSE)install -d $(dir $(DROPSCONF_CONFIG))
# $(VERBOSE)install -d $(dir $(DROPSCONF_CONFIG_H))
# $(VERBOSE)if tty >/dev/null; then \
# $(DROPSCONF_VARDEFS) $(DROPSCONF_TOOL_OLD); \
# else \
# true | $(DROPSCONF_VARDEFS) $(DROPSCONF_TOOL_OLD) \
# $(if $(VERBOSE),>/dev/null,) || \
# ( echo -e "\nError: Unattended mode -- Some defaults for config options are missing." ; \
# false ) \
# fi
_HAS_MAKECONFIGGOAL=$(filter $(MAKECONFIGGOALS),$(MAKECMDGOALS))
$(DROPSCONF_CONFIG_MK): $(if $(_HAS_MAKECONFIGGOAL),,$(DROPSCONF_CONFIG))
$(VERBOSE)sed -e "s/\(^[^= ]*=\)'\([^']*\)'/\1\2/" \
<$(DROPSCONF_CONFIG) >$@
$(VERBOSE)$(MAKE) DROPSCONF_CONFIG_MK_POST_HOOK
DROPSCONF_CONFIG_MK_POST_HOOK::
#config:: $(DROPSCONF_LXDIALOG)
# $(VERBOSE)install -d $(dir $(DROPSCONF_CONFIG_H))
# $(VERBOSE)$(DROPSCONF_VARDEFS) $(DROPSCONF_TOOL)
# $(VERBOSE)test ! -r $(DROPSCONF_CONFIG) -o \
# ! $(DROPSCONF_CONFIG) -nt $(DROPSCONF_CONFIG_MK) || \
# $(MAKE) $(DROPSCONF_CONFIG_MK)
#txtconfig::
# $(VERBOSE)install -d $(dir $(DROPSCONF_CONFIG_H))
# $(VERBOSE)$(DROPSCONF_VARDEFS) $(DROPSCONF_TOOL_TXT)
# @$(MAKE) $(DROPSCONF_CONFIG_MK)
#
#oldconfig::
# $(VERBOSE)install -d $(dir $(DROPSCONF_CONFIG_H))
# $(VERBOSE)$(DROPSCONF_VARDEFS) $(DROPSCONF_TOOL_OLD)
# @$(MAKE) $(DROPSCONF_CONFIG_MK)
#
#$(DROPSCONF_LXDIALOG):
# $(VERBOSE)install -d $(@D)
# $(VERBOSE)PWD=$(abspath $(L4DIR)/tool/config) $(MAKE) -C $(L4DIR)/tool/config
#
clean::
ifeq ($(SUBDIRS_TO_BUILD),)
cleanall::
$(VERBOSE)$(RM) -r $(KCONFIG_OBJ_DIR)
mrproper::
$(VERBOSE)$(RM) $(DROPSCONF_CONFIG) $(DROPSCONF_CONFIG_H) \
$(DROPSCONF_CONFIG_MK) .menuconfig.log \
$(DROPSCONF_CONFIG).old
endif
help::
@echo
@echo "Configuration targets:"
@echo " config - run the menu-driven configuration tool"
@echo " gconfig - run a graphical configuration tool"
@echo " xconfig - run a graphical configuration tool"
@echo " oldconfig - (re)create the configuration header based on a prior"
@echo " configuration or default values"
# special switch not to include DROPSCONF_CONFIG_MK
ifeq ($(DROPSCONF_DONTINC_MK),)
# do not prebuild the config file on "make config"
ifeq ($(filter $(MAKECONFIGGOALS) help scrub clean cleanall mrproper \
$(DROPSCONF_CONFIG_MK),$(MAKECMDGOALS)),)
$(info INCLUDING $(DROPSCONF_CONFIG_MK) config.inc)
-include $(DROPSCONF_CONFIG_MK)
endif
endif
# end of DROPSCONF defined
else
config txtconfig oldconfig olddefconfig syncconfig::
endif

View File

@@ -0,0 +1,2 @@
CONFIG_BUILD_ARCH_amd64=y
# CONFIG_BID_GCC_OMIT_FP is not set

View File

@@ -0,0 +1,4 @@
CONFIG_BUILD_ARCH_arm=y
CONFIG_CPU_ARM_ARMV5TE=y
CONFIG_PLATFORM_TYPE_rv=y
# CONFIG_BID_GCC_OMIT_FP is not set

View File

@@ -0,0 +1,3 @@
CONFIG_BUILD_ARCH_arm=y
CONFIG_PLATFORM_TYPE_rv=y
# CONFIG_BID_GCC_OMIT_FP is not set

View File

@@ -0,0 +1,3 @@
CONFIG_BUILD_ARCH_arm64=y
CONFIG_PLATFORM_TYPE_rv_vexpress_a15=y
# CONFIG_BID_GCC_OMIT_FP is not set

View File

@@ -0,0 +1,2 @@
CONFIG_BUILD_ARCH_arm64=y
CONFIG_PLATFORM_TYPE_arm_virt=y

View File

@@ -0,0 +1 @@
CONFIG_BUILD_ARCH_mips=y

View File

@@ -0,0 +1,2 @@
CONFIG_BUILD_ARCH_ppc32=y
# CONFIG_BID_GCC_OMIT_FP is not set

View File

@@ -0,0 +1,3 @@
CONFIG_BUILD_ARCH_riscv=y
CONFIG_CPU_RISCV_32IMA=y
# CONFIG_BID_GCC_OMIT_FP is not set

View File

@@ -0,0 +1,2 @@
CONFIG_BUILD_ARCH_riscv=y
# CONFIG_BID_GCC_OMIT_FP is not set

View File

@@ -0,0 +1 @@
# CONFIG_BID_GCC_OMIT_FP is not set

333
src/l4/mk/doc.mk Normal file
View File

@@ -0,0 +1,333 @@
# -*- Makefile -*-
#
# L4Re Buildsystem
#
# Makefile-Template for doc directories
#
# install.inc is used, see there for further documentation
ifeq ($(origin _L4DIR_MK_DOC_MK),undefined)
_L4DIR_MK_DOC_MK=y
ROLE = doc.mk
include $(L4DIR)/mk/Makeconf
$(GENERAL_D_LOC): $(L4DIR)/mk/doc.mk
ifeq ($(IN_OBJ_DIR),)
##################################################################
#
# Empty IN_OBJ_DIR means we are in the source directory and have
# to first generate a Makefile in the build-dir.
#
##################################################################
all install clean cleanall help:: $(OBJ_DIR)/Makefile.build
$(VERBOSE)$(MAKE) -C $(OBJ_DIR) O=$(OBJ_BASE) -f Makefile.build $@
$(OBJ_DIR)/Makefile.build: $(SRC_DIR)/Makefile
$(VERBOSE)install -d $(dir $@)
$(VERBOSE)echo 'IN_OBJ_DIR=1' > $@
$(VERBOSE)echo 'L4DIR=$(L4DIR_ABS)' >> $@
$(VERBOSE)echo 'SRC_DIR=$(SRC_DIR)' >> $@
$(VERBOSE)echo 'OBJ_BASE=$(OBJ_BASE)' >> $@
$(VERBOSE)echo 'PKGDIR_ABS=$(PKGDIR_ABS)' >> $@
$(VERBOSE)echo 'vpath %.fig $(SRC_DIR)' >> $@
$(VERBOSE)echo 'vpath %.tex $(SRC_DIR)' >> $@
$(VERBOSE)echo 'include $(SRC_DIR)/Makefile' >> $@
else
###################################################################
#
# We are in the build directory and can process the documentation
#
###################################################################
# default is to install all targets
INSTALL_TARGET_MASK ?= %
ifneq ($(TARGET),)
# if no SRC_DOX is given, but TARGET, extract it from TARGET
ifeq ($(origin SRC_DOX),undefined)
SRC_DOX := $(filter $(addsuffix .cfg, $(TARGET)),$(wildcard *.cfg))
ifneq ($(SRC_DOX),)
$(error SRC_DOX is undefined, but TARGET is defined. This is invalid since 04/23/2003)
endif
endif
# the same for SRC_TEX
ifeq ($(origin SRC_TEX),undefined)
SRC_TEX := $(filter $(TARGET:.ps=.tex),$(wildcard *.tex)) \
$(filter $(TARGET:.pdf=.tex),$(wildcard *.tex))
$(filter $(TARGET:.dvi=.tex),$(wildcard *.tex))
ifneq ($(SRC_TEX),)
$(error SRC_TEX is undefined, but TARGET is defined. This is invalid since 04/23/2003)
endif
endif
endif
TARGET_DOX = $(SRC_DOX:.cfg=) $(SRC_DOX_REF:.cfg=) \
$(SRC_DOX_GUIDE:.cfg=) $(SRC_DOX_INT:.cfg=)
INSTALL_TARGET_DOX ?= $(filter $(INSTALL_TARGET_MASK), $(TARGET_DOX))
TARGET_TEX ?= $(SRC_TEX:.tex=.ps) $(SRC_TEX:.tex=.pdf)
DEPS += $(foreach x,$(SRC_TEX:.tex=.dvi),$(dir $x).$(notdir $x).d)
# if no TARGET is given, generate it from all types of targets
TARGET ?= $(TARGET_DOX) $(TARGET_TEX)
DEPS += $(foreach file,$(TARGET),$(dir $(file)).$(notdir $(file)).d)
all:: $(TARGET)
$(TARGET): $(OBJ_DIR)/.general.d
####################################################################
#
# Doxygen specific
#
####################################################################
DOXY_FLAGS += $(DOXY_FLAGS_$@)
OUTPUTDIR = $(shell perl -n -e '/^\s*OUTPUT_DIRECTORY\s*=\s*(\S+)/ && print "$$1\n"' $(1))
# we refer to %/html sometimes. However, make fails on a rule of the form
# "% %/html:%.cfg", thus the workaround (others than static-pattern-rules
# won't work)
$(addprefix $(OBJ_DIR)/,$(addsuffix /html,$(TARGET_DOX))):$(OBJ_DIR)/%/html:$(TARGET_DOX)
# all our packages
ifeq ($(ALL_SUBDIRS),)
ALL_SUBDIRS := $(shell find -L $(L4DIR)/pkg -maxdepth 4 -type d ! -name .svn -exec test -f {}/Control \; -printf %P' ' -prune)
endif
# We can give an internal rule for doxygen, as the directory specified
# in the config-file should be the name of the config file with the
# .cfg removed.
# $(VERBOSE)$(ECHO) ENABLED_SECTIONS=WORKING_SUBPAGES >> $@.flags
FORCE: ;
$(OBJ_DIR)/% $(OBJ_DIR)/%/html:$(SRC_DIR)/%.cfg $(SRC_DIR)/search.js.reduce_keyTimeoutLength.patch FORCE
#generate the flags-file
$(VERBOSE)$(MKDIR) $@
$(VERBOSE)$(ECHO) '@INCLUDE_PATH=/' > $@.flags
$(VERBOSE)$(ECHO) '@INCLUDE=$(SRC_DIR)/$(notdir $<)' >> $@.flags
$(VERBOSE)$(ECHO) 'INCLUDE_PATH += $(OBJ_BASE)/include' >> $@.flags
$(VERBOSE)$(ECHO) $(DOXY_FLAGS) >> $@.flags
$(VERBOSE)$(ECHO) OUTPUT_DIRECTORY=$(OBJ_DIR)/$(call OUTPUTDIR,$<) >> $@.flags
$(VERBOSE)if [ "$(DOC_VARIANT)" = "fast" ]; then $(ECHO) HAVE_DOT=NO; $(ECHO) GENERATE_LATEX=NO; fi >> $@.flags
$(VERBOSE)if [ "$(DOC_VARIANT)" = "full" ]; then $(ECHO) HAVE_DOT=YES; $(ECHO) GENERATE_LATEX=YES; fi >> $@.flags
$(VERBOSE)if [ "$(DOC_VARIANT)" = "release" ]; then \
$(ECHO) HAVE_DOT=YES; \
$(ECHO) GENERATE_LATEX=YES; \
$(ECHO) SHOW_FILES=YES; \
$(ECHO) INTERNAL_DOCS=NO; \
$(ECHO) GENERATE_TODOLIST=NO; \
$(ECHO) GENERATE_TESTLIST=NO; \
$(ECHO) GENERATE_BUGLIST=NO; \
$(ECHO) HIDE_UNDOC_CLASSES=YES; \
$(ECHO) HIDE_UNDOC_MEMBERS=YES; \
fi >> $@.flags
$(VERBOSE)cd $(L4DIR)/pkg && \
for f in $(ALL_SUBDIRS); \
do [ ! -e $(L4DIR)/pkg/$$f/doc/files.cfg ] || sed -e "s,%PKGDIR%,$(L4DIR)/pkg/$$f,g" $(L4DIR)/pkg/$$f/doc/files.cfg || true; echo; done >> $@.flags
$(VERBOSE)cd $(OBJ_BASE)/include && L4DIR=$(L4DIR) $(DOXYGEN) $@.flags
$(VERBOSE)patch --forward --unified \
$(OBJ_DIR)/$(call OUTPUTDIR,$<)/html/search/search.js \
$(SRC_DIR)/search.js.reduce_keyTimeoutLength.patch \
|| true
$(VERBOSE)for file in $(ADD_FILES_TO_HTML); do cp $$file $@/html; done
$(VERBOSE)( [ -r $@/latex/Makefile ] && \
echo | $(MAKE) -C $@/latex ) || true
$(VERBOSE)if [ -d $@ ] ; then touch $@ ; fi
# Installation rules follow
#
# define LOCAL_INSTALLDIR prior to including install.inc, where the install-
# rules are defined. Same for INSTALLDIR.
INSTALLDIR_HTML ?= $(DROPS_STDDIR)/doc/html
INSTALLFILE_HTML ?= $(CP) -pR $(1) $(2)
INSTALLDIR_HTML_LOCAL ?= $(OBJ_BASE)/doc/html
INSTALLFILE_HTML_LOCAL ?= $(if $(call is_dir,$(2)), \
find '$(dir $(1))' -name '$(notdir $(1))' | xargs $(LN) -t $(2) -sf, \
find '$(dir $(1))' -name '$(notdir $(1))' | xargs -I '{}' $(LN) -sf '{}' $(2))
INSTALLDIR = $(INSTALLDIR_HTML)
INSTALLFILE = $(INSTALLFILE_HTML)
INSTALLDIR_LOCAL = $(INSTALLDIR_HTML_LOCAL)
INSTALLFILE_LOCAL = $(INSTALLFILE_HTML_LOCAL)
all:: $(TARGET) \
$(addprefix $(INSTALLDIR_LOCAL)/, $(addsuffix .title, $(INSTALL_TARGET_DOX)))
$(OBJ_DIR)/$(SRC_DOX_REF:.cfg=.title): BID_DOC_DOXTYPE=ref
$(OBJ_DIR)/$(SRC_DOX_GUIDE:.cfg=.title): BID_DOC_DOXTYPE=guide
$(OBJ_DIR)/$(SRC_DOX_INT:.cfg=.title): BID_DOC_DOXTYPE=int
# first line: type
# second line: title that will appear at the generated index page
$(OBJ_DIR)/%.title:$(SRC_DIR)/%.cfg $(OBJ_DIR)/.general.d
$(VERBOSE)$(ECHO) $(BID_DOC_DOXTYPE)>$@
$(VERBOSE)MAKEFLAGS= $(MAKE) -s -f $(L4DIR)/mk/makehelpers.inc -f $< \
BID_print VAR=PROJECT_NAME >>$@
# Install the title file locally
# The installed title file depends on the installed doku for message reasons
$(foreach f,$(INSTALL_TARGET_DOX),$(INSTALLDIR_LOCAL)/$(f).title):$(INSTALLDIR_LOCAL)/%.title:$(OBJ_DIR)/%.title $(INSTALLDIR_LOCAL)/%
$(VERBOSE)$(call INSTALLFILE_LOCAL,$<,$@)
# Install the docu locally, the title file will depend on
$(foreach f,$(INSTALL_TARGET_DOX),$(INSTALLDIR_LOCAL)/$(f)):$(INSTALLDIR_LOCAL)/%:$(OBJ_DIR)/% $(OBJ_DIR)/%/html
@$(INSTALL_DOC_LOCAL_MESSAGE)
$(VERBOSE)$(INSTALL) -d $@
$(VERBOSE)$(call INSTALLFILE_LOCAL,$</html/*,$@)
# Install the title file globally
# The installed title file depends on the installed doku for message reasons
$(foreach f,$(INSTALL_TARGET_DOX),$(INSTALLDIR)/$(f).title):$(INSTALLDIR)/%.title:$(OBJ_DIR)/%.title $(INSTALLDIR)/%
$(VERBOSE)$(call INSTALLFILE,$<,$@)
# Install the docu globally, the title file will depend on
$(foreach f,$(INSTALL_TARGET_DOX),$(INSTALLDIR)/$(f)):$(INSTALLDIR)/%:$(OBJ_DIR)/% $(OBJ_DIR)/%/html
@$(INSTALL_DOC_MESSAGE)
$(if $(INSTALLFILE),$(VERBOSE)$(INSTALL) -d $@)
$(VERBOSE)$(call INSTALLFILE,$</html/*,$@)
install:: $(addprefix $(INSTALLDIR)/,$(addsuffix .title,$(INSTALL_TARGET_DOX)))
.PHONY: $(addprefix $(INSTALLDIR)/,$(INSTALL_TARGET_DOX) \
$(addsuffix .title,$(INSTALL_TARGET_DOX)))
#################################################################
#
# Latex specific
#
#################################################################
FIG2EPS_PROG ?= fig2dev -L eps
FIG2PDF_PROG ?= fig2dev -L pdf
FIG2PNG_PROG ?= fig2dev -L png
$(SRC_TEX:.tex=.dvi) $(TARGET): $(SRC_FIG:.fig=.pdf) $(SRC_FIG:.fig=.png) $(SRC_FIG:.fig=.eps)
%.eps: %.fig $(OBJ_DIR)/.general.d
@$(GEN_MESSAGE)
$(VERBOSE)$(FIG2EPS_PROG) $< $@
%.pdf: %.fig $(OBJ_DIR)/.general.d
@$(GEN_MESSAGE)
$(VERBOSE)$(FIG2PDF_PROG) $< $@
%.png: %.fig $(OBJ_DIR)/.general.d
@$(GEN_MESSAGE)
$(VERBOSE)$(FIG2PNG_PROG) $< $@
%.ps: %.dvi $(OBJ_DIR)/.general.d
@$(GEN_MESSAGE)
$(VERBOSE)$(call MAKEDEP,dvips) dvips -o $@ $<
$(VERBOSE)$(VIEWERREFRESH_PS)
%.pdf: %.tex $(OBJ_DIR)/.general.d
@$(GEN_MESSAGE)
$(VERBOSE)$(PDFLATEX) $< || \
(($(GREP) 'TeX capacity exceeded' $*.log && \
echo -e "\n\033[31mIncrease pool_size to 200000 in" \
"/etc/texmf/texmf.cnf!\033[m\n" && false) || false)
$(VERBOSE)$(GREP) '\citation' $*.aux && \
bibtex $* || true
$(VERBOSE)(export size=1; touch $@; \
until [ $$size -eq `ls -o $@ | awk '{print $$4}'` ]; do\
export size=`ls -o $@ | awk '{print $$4}'` ;\
$(PDFLATEX) $< ;\
done)
# one more time, just to be sure ...
$(VERBOSE)$(PDFLATEX) $<
%.dvi: %.tex $(OBJ_DIR)/.general.d
@$(GEN_MESSAGE)
$(VERBOSE)$(call MAKEDEP,$(LATEX)) $(LATEX) $<
$(VERBOSE)if grep -q '\indexentry' $*.idx; then makeindex $*; fi
$(VERBOSE)if grep -q '\citation' $*.aux; then bibtex $*; fi
# Do we really need to call latex unconditionally again? Isn't it
# sufficient to check the logfile for the "rerun" text?
$(VERBOSE)$(LATEX) $<
$(VERBOSE)latex_count=5 ; \
while egrep -s 'Rerun (LaTeX|to get cross-references right)' $*.log &&\
[ $$latex_count -gt 0 ] ; do \
$(LATEX) $< \
let latex_count=$$latex_count-1 ;\
done
$(VERBOSE)$(VIEWERREFRESH_DVI)
SHOWTEX ?= $(firstword $(SRC_TEX))
SHOWDVI ?= $(SHOWTEX:.tex=.dvi)
SHOWPS ?= $(SHOWTEX:.tex=.ps)
SHOWPDF ?= $(SHOWTEX:.tex=.pdf)
VIEWER_DVI ?= xdvi
VIEWER_PS ?= gv
VIEWER_PDF ?= xpdf
VIEWERREFRESH_DVI ?= killall -USR1 xdvi xdvi.bin xdvi.real || true
VIEWERREFRESH_PS ?= killall -HUP $(VIEWER_PS) || true
dvi: $(SHOWDVI)
show showdvi: dvi
$(VERBOSE)$(VIEWER_DVI) $(SHOWDVI) &
ps: $(SHOWPS)
showps: ps
$(VERBOSE)$(VIEWER_PS) $(SHOWPS) &
pdf: $(SHOWPDF)
showpdf: pdf
$(VERBOSE)$(VIEWER_PDF) $(SHOWPDF) &
clean::
$(VERBOSE)$(RM) $(addprefix $(OBJ_DIR)/, \
$(addsuffix .title,$(TARGET_DOX)))
$(VERBOSE)$(RM) $(addprefix $(OBJ_DIR)/, \
$(addsuffix .flags,$(TARGET_DOX)))
$(VERBOSE)$(RM) $(wildcard $(addprefix $(OBJ_DIR)/, $(foreach ext, \
aux bbl blg dvi idx ilg ind log lod ltf toc out, \
$(SRC_TEX:.tex=.$(ext))) texput.log ))
cleanall:: clean
$(VERBOSE)$(RM) -r $(wildcard $(addprefix $(OBJ_DIR)/, \
$(TARGET)) $(wildcard .*.d))
$(VERBOSE)$(RM) $(wildcard $(addprefix $(OBJ_DIR)/, \
$(SRC_TEX:.tex=.ps) $(SRC_TEX:.tex=.pdf)))
$(VERBOSE)$(RM) $(wildcard $(addprefix $(OBJ_DIR)/, \
$(SRC_FIG:.fig=.eps) $(SRC_FIG:.fig=.pdf) $(SRC_FIG:.fig=.png)))
$(VERBOSE)$(RM) $(wildcard $(addprefix $(OBJ_DIR)/, \
Makefile Makefile.build))
.PHONY: all clean cleanall config help install oldconfig txtconfig
.PHONY: ps pdf dvi showps showpdf showdvi show
help::
@echo "Specify a target:"
@echo "all - generate documentation and install locally"
ifneq (,$(INSTALL_TARGET_DOX))
@echo "install - generate documentation and install globally"
endif
@echo "dvi - compile the primary TeX file into dvi"
@echo "showdvi - invoke the dvi viewer on the primary TeX file"
@echo "ps - compile the primary TeX file into ps"
@echo "showps - invoke the ps viewer on the primary TeX file"
@echo "pdf - compile the primary TeX file into pdf"
@echo "showpdf - invoke the pdf viewer on the primary TeX file"
@echo "clean - delete generated intermediate files"
@echo "cleanall - delete all generated files"
@echo "help - this help"
@echo
ifneq (,$(SRC_TEX))
@echo "Primary TeX file: $(SHOWTEX)"
@echo "Other documentation to be built: $(filter-out $(SHOWPDF) $(SHOWPS) $(SHOWDVI),$(TARGET))"
else
ifneq (,$(TARGET_DOX))
@echo "Primary Doxygen file: $(addsuffix .cfg, $(TARGET_DOX))"
endif
@echo "Documentation to be built: $(TARGET)"
endif
-include $(DEPSVAR)
endif # IN_OBJ_DIR
endif # _L4DIR_MK_DOC_MK undefined

192
src/l4/mk/export_defs.inc Normal file
View File

@@ -0,0 +1,192 @@
# Makefile snippet to generate l4defs.inc file
# vim:set ft=make:
#
# L4Re Buildsystem
#
PKGDIR = .
SYSTEMS = $(BUILD_ARCH)-$(BUILD_ABI)
OBJ_DIR = $(SRC_DIR)/build
# the target file
L4DEF_FILE_MK ?= l4defs.mk.inc
L4DEF_FILE_SH ?= l4defs.sh.inc
L4DEF_FILE_PL ?= l4defs.pl.inc
do_output_all = echo '$(1) = $($(1))' >> $(L4DEF_FILE_MK); echo '$(1)="$($(1))"' >> $(L4DEF_FILE_SH); echo ' "$(1)" => "$($(1))",' >> $(L4DEF_FILE_PL);
do_output_mk = echo '$(1) = $($(1))' >> $(L4DEF_FILE_MK);
ifeq ($(CALLED_FOR),static)
MODE = static
ifneq ($(SYSTEM),)
L4_SYSTEM = $(ARCH)_$(CPU)
L4_CC = $(CC)
L4_CXX = $(CXX)
L4_LD = $(LD)
L4_LDFLAGS_LD_STATIC = $(filter-out -l%,$(LDFLAGS))
L4_LDFLAGS_GCC_STATIC = $(filter-out -l%,$(call ldflags_to_gcc,$(LDFLAGS)))
L4_LDFLAGS_DYNAMIC_LINKER_LD = $(LDFLAGS_DYNAMIC_LINKER)
L4_LDFLAGS_DYNAMIC_LINKER_GCC= $(LDFLAGS_DYNAMIC_LINKER_GCC)
L4_LIBDIRS = $(addprefix -L,$(L4LIBDIR))
L4_CPPFLAGS = $(CPPFLAGS)
L4_CFLAGS = $(CFLAGS)
L4_CXXFLAGS = $(CXXFLAGS)
L4_GCCSYSLIBDIRS = $(GCCSYSLIBDIRS)
L4_LDS_stat_bin = $(LDS_stat_bin)
L4_BID_STACK_ADDR = $(L4_STACK_ADDR)
L4_BID_STACK_SIZE = $(L4_STACK_SIZE)
L4_BID_KIP_ADDR = $(L4_KIP_ADDR)
L4_BID_KIP_OFFS_SYS_INVOKE = $(L4_KIP_OFFS_SYS_INVOKE)
L4_BID_KIP_OFFS_SYS_DEBUGGER = $(L4_KIP_OFFS_SYS_DEBUGGER)
L4_BID_PKG_CONFIG_CALL = $(value BID_PKG_CONFIG)
L4_BID_PKG_CONFIG_FAILED = $(value BID_PKG_CONFIG_FAILED)
L4_VARIANT = $(VARIANT)
L4_BID_BENDER_LINK = $(value BID_BENDER_LINK)
L4_BID_BENDER_DEFINES = $(value BID_BENDER_DEFINES)
all::
@echo -e $(EMPHSTART)"Creating $(L4DEF_FILE_MK)"$(EMPHSTOP)
@echo "# Definitions for 'make' from L4 BID" > $(L4DEF_FILE_MK)
@echo "# vim:se ft=make:" >> $(L4DEF_FILE_MK)
@echo "# --- Automatically created, do not modify ---" >> $(L4DEF_FILE_MK)
@:
@echo -e $(EMPHSTART)"Creating $(L4DEF_FILE_SH)"$(EMPHSTOP)
@echo "# Definitions for 'sh' from L4 BID" > $(L4DEF_FILE_SH)
@echo "# vim:se ft=sh:" >> $(L4DEF_FILE_SH)
@echo "# --- Automatically created, do not modify ---" >> $(L4DEF_FILE_SH)
@echo "" >> $(L4DEF_FILE_SH)
@echo "l4_bid_call_pkgconfig()" >> $(L4DEF_FILE_SH)
@echo "{" >> $(L4DEF_FILE_SH)
@echo " obj_base=\$$1; shift; " >> $(L4DEF_FILE_SH)
@echo " PKG_CONFIG_LIBDIR=\$$obj_base/pc PKG_CONFIG_PATH= \\" >> $(L4DEF_FILE_SH)
@echo " \$$L4_BID_PKG_CONFIG \\" >> $(L4DEF_FILE_SH)
@echo " --define-variable=incdir=\$$obj_base/include/contrib \\" >> $(L4DEF_FILE_SH)
@echo " \"\$$@\"" >> $(L4DEF_FILE_SH)
@echo "}" >> $(L4DEF_FILE_SH)
@echo "" >> $(L4DEF_FILE_SH)
@:
@echo -e $(EMPHSTART)"Creating $(L4DEF_FILE_PL)"$(EMPHSTOP)
@echo "# Definitions for 'perl' from L4 BID" > $(L4DEF_FILE_PL)
@echo "# vim:se ft=pl:" >> $(L4DEF_FILE_PL)
@echo "# --- Automatically created, do not modify ---" >> $(L4DEF_FILE_PL)
@echo "{" >> $(L4DEF_FILE_PL)
@$(call do_output_all,L4_SYSTEM)
@$(call do_output_all,L4_CC)
@$(call do_output_all,L4_CXX)
@$(call do_output_all,L4_LD)
@$(call do_output_all,L4_LDFLAGS_LD_STATIC)
@$(call do_output_all,L4_LDFLAGS_GCC_STATIC)
@$(call do_output_all,L4_LDFLAGS_DYNAMIC_LINKER_LD)
@$(call do_output_all,L4_LDFLAGS_DYNAMIC_LINKER_GCC)
@$(call do_output_all,L4_LIBDIRS_R)
@$(call do_output_all,L4_LIBDIRS)
@$(call do_output_all,L4_GCCSYSLIBDIRS)
@$(call do_output_all,L4_CPPFLAGS)
@$(call do_output_all,L4_CFLAGS)
@$(call do_output_all,L4_CXXFLAGS)
@$(call do_output_all,L4_LDS_stat_bin)
@$(call do_output_all,L4_BID_STACK_ADDR)
@$(call do_output_all,L4_BID_KIP_ADDR)
@$(call do_output_all,L4_BID_KIP_OFFS_SYS_INVOKE)
@$(call do_output_all,L4_BID_KIP_OFFS_SYS_DEBUGGER)
@$(call do_output_all,L4_BID_PKG_CONFIG)
@$(call do_output_all,L4_VARIANT)
@$(call do_output_mk,L4_BID_PKG_CONFIG_CALL)
@$(call do_output_mk,L4_BID_PKG_CONFIG_FAILED)
@$(call do_output_mk,L4_BID_BENDER_LINK)
@$(call do_output_mk,L4_BID_BENDER_DEFINES)
@$(foreach v,LIBCINCDIR REQUIRES_LIBS LDSCRIPT LDFLAGS, \
$(call do_output_all,$(v)_all_static) $(call do_output_all,$(v)_all_shared))
else
all::
endif
include $(L4DIR)/mk/prog.mk
endif # called for static
# ----------------------------------------------------
ifeq ($(CALLED_FOR),minimal)
MODE = sigma0
ifneq ($(SYSTEM),)
REQUIRES_LIBS = libc_minimal
L4_CPPFLAGS_MINIMAL = $(CPPFLAGS)
L4_CFLAGS_MINIMAL = $(CFLAGS)
L4_CXXFLAGS_MINIMAL = $(CXXFLAGS)
all::
@$(call do_output_all,L4_CPPFLAGS_MINIMAL)
@$(call do_output_all,L4_CFLAGS_MINIMAL)
@$(call do_output_all,L4_CXXFLAGS_MINIMAL)
else
all::
endif
include $(L4DIR)/mk/prog.mk
endif # called for minimal
# ----------------------------------------------------
ifeq ($(CALLED_FOR),shared)
MODE = shared
ifneq ($(SYSTEM),)
L4_LDFLAGS_LD_SHARED = $(filter-out -l%,$(LDFLAGS))
L4_LDFLAGS_GCC_SHARED = $(filter-out -l%,$(call ldflags_to_gcc,$(LDFLAGS)))
L4_LDS_so = $(LDS_so)
L4_LDS_dyn_bin = $(LDS_dyn_bin)
all::
@$(call do_output_all,L4_LDFLAGS_LD_SHARED)
@$(call do_output_all,L4_LDFLAGS_GCC_SHARED)
@$(call do_output_all,L4_LDS_so)
@$(call do_output_all,L4_LDS_dyn_bin)
else
all::
endif
include $(L4DIR)/mk/prog.mk
endif # called for shared
# ----------------------------------------------------
ifeq ($(CALLED_FOR),sharedlib)
ifneq ($(SYSTEM),)
NOTARGETSTOINSTALL = y
endif
all::
include $(L4DIR)/mk/lib.mk
endif # called for sharedlib
# Used to add any trailing lines required.
ifeq ($(CALLED_FOR),finalize)
ifneq ($(SYSTEM),)
all::
@echo "}" >> $(L4DEF_FILE_PL)
else
all::
endif
include $(L4DIR)/mk/prog.mk
endif # called for finalize

Some files were not shown because too many files have changed in this diff Show More