mirror of
https://github.com/xcat2/xcat-dep.git
synced 2025-08-18 17:20:20 +00:00
Check in ipxe source files from gitclone ipxe.org on October 29th
This commit is contained in:
345
ipxe/COPYING
345
ipxe/COPYING
@@ -1,339 +1,12 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
In general iPXE files are licensed under the GPL. For historical
|
||||
reasons, individual files may contain their own licence declarations.
|
||||
Most builds of iPXE do not contain all iPXE code (in particular, most
|
||||
builds will include only one driver), and so the overall licence can
|
||||
vary depending on what target you are building.
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
|
||||
675 Mass Ave, Cambridge, MA 02139, USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
The resultant applicable licence(s) for any particular build can be
|
||||
determined by using "make bin/xxxxxxx.yyy.licence"; for example:
|
||||
|
||||
Preamble
|
||||
make bin/rtl8139.rom.licence
|
||||
|
||||
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 Library 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
|
||||
|
||||
Appendix: 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) 19yy <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., 675 Mass Ave, Cambridge, MA 02139, 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) 19yy 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 Library General
|
||||
Public License instead of this License.
|
||||
to determine the resultant licence(s) for the build bin/rtl8139.rom
|
||||
|
@@ -1,12 +0,0 @@
|
||||
In general iPXE files are licensed under the GPL. For historical
|
||||
reasons, individual files may contain their own licence declarations.
|
||||
Most builds of iPXE do not contain all iPXE code (in particular, most
|
||||
builds will include only one driver), and so the overall licence can
|
||||
vary depending on what target you are building.
|
||||
|
||||
The resultant applicable licence(s) for any particular build can be
|
||||
determined by using "make bin/xxxxxxx.yyy.licence"; for example:
|
||||
|
||||
make bin/rtl8139.rom.licence
|
||||
|
||||
to determine the resultant licence(s) for the build bin/rtl8139.rom
|
1
ipxe/contrib/errdb/.gitignore
vendored
1
ipxe/contrib/errdb/.gitignore
vendored
@@ -1 +0,0 @@
|
||||
errors.db
|
@@ -73,6 +73,7 @@ my $xrefs = {};
|
||||
while ( <> ) {
|
||||
chomp;
|
||||
( my $errno, my $filename, my $line, my $description ) = split ( /\t/ );
|
||||
$errno = substr ( $errno, 0, 6 ) unless $errno =~ /^7f/;
|
||||
$errors->{$errno} = $description;
|
||||
$xrefs->{$errno} ||= {};
|
||||
$xrefs->{$errno}->{$filename} ||= {};
|
||||
|
@@ -1,4 +1,4 @@
|
||||
<?
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Copyright (C) 2009 Marty Connor <mdc@etherboot.org>.
|
||||
@@ -27,25 +27,25 @@ Resources:
|
||||
<ul>
|
||||
<li>
|
||||
Source code for iPXE images is available at
|
||||
<a href="http://etherboot.org/wiki/download" target="_blank">
|
||||
http://etherboot.org/wiki/download</a>
|
||||
<a href="http://www.ipxe.org/download" target="_blank">
|
||||
http://www.ipxe.org/download</a>
|
||||
<br><br>
|
||||
</li>
|
||||
<li>
|
||||
For general information about using iPXE, please visit the
|
||||
<a href="http://www.etherboot.org/" target="_blank">
|
||||
Etherboot Project Home Page</a>
|
||||
<a href="http://www.ipxe.org/" target="_blank">
|
||||
iPXE Project Home Page</a>
|
||||
<br><br>
|
||||
</li>
|
||||
<li>
|
||||
For Email-based support for iPXE please join
|
||||
<a href="http://etherboot.org/wiki/mailinglists" target="_blank">
|
||||
Etherboot Project mailing lists.</a>
|
||||
<a href="http://www.ipxe.org/contact" target="_blank">
|
||||
iPXE Project mailing lists.</a>
|
||||
<br><br>
|
||||
</li>
|
||||
<li>
|
||||
For real-time online iPXE support via IRC please visit the
|
||||
<a href="irc://irc.freenode.net/%23etherboot"> #etherboot channel
|
||||
<a href="irc://irc.freenode.net/%23ipxe"> #ipxe channel
|
||||
of irc.freenode.net</a>.
|
||||
<br><br>
|
||||
</li>
|
||||
@@ -53,7 +53,7 @@ Resources:
|
||||
<hr>
|
||||
<font size="-1">
|
||||
<br>
|
||||
Please email <a href="mailto:<? echo "${webmaster_email}" ?>"><? echo "${webmaster_email}"?></a>
|
||||
Please email <a href="mailto:<?php echo "${webmaster_email}" ?>"><?php echo "${webmaster_email}"?></a>
|
||||
with questions or comments about this website.
|
||||
</font>
|
||||
<br><br>
|
||||
|
@@ -179,7 +179,12 @@ if ( $embedded_script != "" ) {
|
||||
|
||||
// Make the requested image. $status is set to 0 on success
|
||||
$make_target = "bin/${nic}.${fmt_extension}";
|
||||
$make_cmd = "make -C '$build_dir' '$make_target' $emb_script_cmd $2>&1";
|
||||
$gitversion = exec('git describe --always --abbrev=1 --match "" 2>/dev/null');
|
||||
if ($gitversion) {
|
||||
$gitversion = "GITVERSION=$gitversion";
|
||||
}
|
||||
|
||||
$make_cmd = "make -C '$build_dir' '$make_target' $gitversion $emb_script_cmd 2>&1";
|
||||
|
||||
exec ( $make_cmd, $maketxt, $status );
|
||||
|
||||
@@ -239,7 +244,7 @@ if ( $status == 0 ) {
|
||||
// Delete build directory as soon as it is not needed
|
||||
rm_build_dir ();
|
||||
|
||||
$output_filename = "ipxe-${version}-${nic}.${fmt_extension}";
|
||||
$output_filename = preg_replace('/[^a-z0-9\+\.\-]/i', '', "ipxe-${version}-${nic}.${fmt_extension}");
|
||||
|
||||
// Try to force IE to handle downloading right.
|
||||
Header ( "Cache-control: private");
|
||||
|
@@ -34,30 +34,30 @@ include_once $top_inc;
|
||||
?>
|
||||
|
||||
<form action="build.php" method=POST>
|
||||
<input type="hidden" name="version" value = "<? echo $version ?>">
|
||||
<input type="hidden" name="version" value = "<?php echo $version ?>">
|
||||
<input type="hidden" name="use_flags" value="1">
|
||||
<h3>
|
||||
Make changes below and press <? echo $build ?> to create an image, <br>
|
||||
Or press <? echo $restart ?> to return to the main page.
|
||||
Make changes below and press <?php echo $build ?> to create an image, <br>
|
||||
Or press <?php echo $restart ?> to return to the main page.
|
||||
</h3>
|
||||
<hr>
|
||||
<ul>
|
||||
<? require ( "directions.php" ); ?>
|
||||
<?php require ( "directions.php" ); ?>
|
||||
</ul>
|
||||
<hr>
|
||||
<? echo_flags( $flags ); ?>
|
||||
<?php echo_flags( $flags ); ?>
|
||||
<hr>
|
||||
<h3>Embedded Script:</h3>
|
||||
<? echo textarea ( "embedded_script", "", "10", "50" ); ?>
|
||||
<?php echo textarea ( "embedded_script", "", "10", "50" ); ?>
|
||||
<br><br>
|
||||
<hr>
|
||||
<center><table width="35%"><tr>
|
||||
<td align="left"> <? echo $build; ?> </td>
|
||||
<td align="right"> <? echo $restart ?></td>
|
||||
<td align="left"> <?php echo $build; ?> </td>
|
||||
<td align="right"> <?php echo $restart ?></td>
|
||||
</tr></table></center>
|
||||
</form>
|
||||
|
||||
<? include_once $bottom_inc; ?>
|
||||
<?php include_once $bottom_inc; ?>
|
||||
<?
|
||||
// For emacs:
|
||||
//
|
||||
|
@@ -1,4 +1,4 @@
|
||||
<?
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Copyright (C) 2009 Marty Connor <mdc@etherboot.org>.
|
||||
@@ -21,12 +21,12 @@
|
||||
|
||||
?>
|
||||
<li>
|
||||
Choose an output format: <? echo keys_menubox ( "ofmt", $ofmts,
|
||||
Choose an output format: <?php echo keys_menubox ( "ofmt", $ofmts,
|
||||
isset ( $_POST['ofmt'] ) ? $_POST['ofmt'] : "") ?>
|
||||
<br><br>
|
||||
</li>
|
||||
<li>
|
||||
Choose a NIC type: <? echo keys_menubox ( "nic", $nics,
|
||||
Choose a NIC type: <?php echo keys_menubox ( "nic", $nics,
|
||||
isset ( $_POST['nic'] ) ? $_POST['nic'] : "" ) ?>
|
||||
<br><br>
|
||||
</li>
|
||||
@@ -37,14 +37,14 @@
|
||||
<em>PCI VENDOR CODE</em> and <em>PCI DEVICE CODE</em> <br>
|
||||
that match the NIC device for which you are making this image.<br><br>
|
||||
Information on how to determine NIC PCI IDs may be found
|
||||
<a href="http://etherboot.org/wiki/romburning"
|
||||
<a href="http://www.ipxe.org/howto/romburning"
|
||||
target="_blank">here</a>.
|
||||
<br><br>
|
||||
PCI VENDOR CODE: <? echo textbox ( "pci_vendor_code",
|
||||
PCI VENDOR CODE: <?php echo textbox ( "pci_vendor_code",
|
||||
isset ( $_POST['pci_vendor_code'] ) ? $_POST['pci_vendor_code']
|
||||
: "", 6 ); ?>
|
||||
|
||||
PCI DEVICE CODE: <? echo textbox ( "pci_device_code",
|
||||
PCI DEVICE CODE: <?php echo textbox ( "pci_device_code",
|
||||
isset ( $_POST['pci_device_code'] ) ? $_POST['pci_device_code']
|
||||
: "", 6 ); ?>
|
||||
<h4>Please note for ROM images:</h4>
|
||||
|
@@ -98,6 +98,27 @@ $flag_table = array (
|
||||
"cfgsec" => "general"
|
||||
),
|
||||
|
||||
"KEYBOARD_MAP"
|
||||
=> array (
|
||||
"flag" => "KEYBOARD_MAP",
|
||||
"type" => "choice",
|
||||
"options" => array("al","az","bg","by","cf","cz","de","dk","es","et","fi","fr",
|
||||
"gr","hu","il","it","lt","mk","mt","nl","no","pl","pt","ro","ru","sg","sr",
|
||||
"th","ua","uk","us","wo"),
|
||||
"value" => "us",
|
||||
"cfgsec" => "console"
|
||||
),
|
||||
|
||||
"LOG_LEVEL"
|
||||
=> array (
|
||||
"flag" => "LOG_LEVEL",
|
||||
"type" => "choice",
|
||||
"options" => array("LOG_NONE","LOG_EMERG","LOG_ALERT","LOG_CRIT","LOG_ERR",
|
||||
"LOG_WARNING","LOG_NOTICE","LOG_INFO","LOG_DEBUG","LOG_ALL"),
|
||||
"value" => "LOG_NONE",
|
||||
"cfgsec" => "console"
|
||||
),
|
||||
|
||||
// End Console Options
|
||||
|
||||
// Begin Network Protocol Options:
|
||||
@@ -487,6 +508,17 @@ $flag_table = array (
|
||||
|
||||
// End Wireless options
|
||||
|
||||
// Obscure options required to compile
|
||||
"NETDEV_DISCARD_RATE"
|
||||
=> array (
|
||||
"flag" => "NETDEV_DISCARD_RATE",
|
||||
"type" => "integer",
|
||||
"value" => "0",
|
||||
"cfgsec" => "general",
|
||||
"hide_from_user" => true
|
||||
)
|
||||
|
||||
// End Obscure options
|
||||
);
|
||||
|
||||
// For emacs:
|
||||
|
@@ -27,10 +27,10 @@ include_once $top_inc;
|
||||
|
||||
?>
|
||||
<form action="build.php" method=POST>
|
||||
<input type="hidden" name="version" value = "<? echo $version ?>">
|
||||
<input type="hidden" name="version" value = "<?php echo $version ?>">
|
||||
<h3>To create an image:</h3>
|
||||
<ol>
|
||||
<? require ( "directions.php" ); ?>
|
||||
<?php require ( "directions.php" ); ?>
|
||||
<li>
|
||||
Generate and download an image:
|
||||
<input type="submit" name="A" value="Get Image">
|
||||
@@ -44,4 +44,4 @@ include_once $top_inc;
|
||||
</ol>
|
||||
</form>
|
||||
|
||||
<? include_once $bottom_inc ?>
|
||||
<?php include_once $bottom_inc ?>
|
||||
|
@@ -1,6 +1,6 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||
|
||||
<?
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Copyright (C) 2009 Marty Connor <mdc@etherboot.org>.
|
||||
@@ -25,17 +25,17 @@
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<link rev="made" href="mailto:<? echo "${webmaster_email}" ?>">
|
||||
<link rev="made" href="mailto:<?php echo "${webmaster_email}" ?>">
|
||||
<meta name="keywords" content="rom, etherboot, ipxe, open source, rom-o-matic.net">
|
||||
<title><? echo $header_title ?></title>
|
||||
<meta name="description" content="<? echo $description ?>">
|
||||
<title><?php echo $header_title ?></title>
|
||||
<meta name="description" content="<?php echo $description ?>">
|
||||
</head>
|
||||
<h1>
|
||||
<? echo "$html_title" ?>
|
||||
<?php echo "$html_title" ?>
|
||||
</h1>
|
||||
<hr>
|
||||
<h2>
|
||||
<? echo "$html_tagline" ?>
|
||||
<?php echo "$html_tagline" ?>
|
||||
</h2>
|
||||
</form>
|
||||
<hr>
|
||||
|
@@ -1,4 +1,4 @@
|
||||
<? // -*- Mode: PHP; -*-
|
||||
<?php // -*- Mode: PHP; -*-
|
||||
|
||||
/**
|
||||
* Copyright (C) 2009 Marty Connor <mdc@etherboot.org>.
|
||||
@@ -131,7 +131,8 @@ function parse_nic_file ()
|
||||
if ( strpos ( $first_eight_chars, "family" ) === 0 ) {
|
||||
|
||||
// get pathname of NIC driver
|
||||
list ( $dummy, $nic ) = split( "[ \t]+", $line );
|
||||
#list ( $dummy, $nic ) = split( "[ \t]+", $line );
|
||||
list ( $dummy, $nic ) = explode("\t", $line);
|
||||
settype ( $nic, "string" );
|
||||
|
||||
// extract filename name of driver from pathname
|
||||
|
6
ipxe/contrib/vm/.gitignore
vendored
6
ipxe/contrib/vm/.gitignore
vendored
@@ -1,6 +0,0 @@
|
||||
bochsout.txt
|
||||
parport.out
|
||||
ne2k-tx.log
|
||||
ne2k-txdump.txt
|
||||
bochs
|
||||
qemu
|
File diff suppressed because it is too large
Load Diff
4
ipxe/src/.gitignore
vendored
4
ipxe/src/.gitignore
vendored
@@ -1,4 +0,0 @@
|
||||
.toolcheck
|
||||
.echocheck
|
||||
TAGS*
|
||||
bin*
|
@@ -7,7 +7,9 @@ CLEANUP :=
|
||||
CFLAGS :=
|
||||
ASFLAGS :=
|
||||
LDFLAGS :=
|
||||
HOST_CFLAGS :=
|
||||
MAKEDEPS := Makefile
|
||||
CROSS_COMPILE ?= $(CROSS)
|
||||
|
||||
###############################################################################
|
||||
#
|
||||
@@ -32,6 +34,8 @@ RANLIB := $(CROSS_COMPILE)ranlib
|
||||
OBJCOPY := $(CROSS_COMPILE)objcopy
|
||||
NM := $(CROSS_COMPILE)nm
|
||||
OBJDUMP := $(CROSS_COMPILE)objdump
|
||||
OPENSSL := openssl
|
||||
CSPLIT := csplit
|
||||
PARSEROM := ./util/parserom.pl
|
||||
FIXROM := ./util/fixrom.pl
|
||||
SYMCHECK := ./util/symcheck.pl
|
||||
@@ -43,12 +47,13 @@ ZBIN := ./util/zbin
|
||||
ELF2EFI32 := ./util/elf2efi32
|
||||
ELF2EFI64 := ./util/elf2efi64
|
||||
EFIROM := ./util/efirom
|
||||
EFIFATBIN := ./util/efifatbin
|
||||
ICCFIX := ./util/iccfix
|
||||
EINFO := ./util/einfo
|
||||
GENKEYMAP := ./util/genkeymap.pl
|
||||
DOXYGEN := doxygen
|
||||
BINUTILS_DIR := /usr
|
||||
BFD_DIR := $(BINUTILS_DIR)
|
||||
ZLIB_DIR := /usr
|
||||
LCAB := lcab
|
||||
QEMUIMG := qemu-img
|
||||
|
||||
###############################################################################
|
||||
#
|
||||
@@ -57,35 +62,61 @@ ZLIB_DIR := /usr
|
||||
SRCDIRS :=
|
||||
SRCDIRS += libgcc
|
||||
SRCDIRS += core
|
||||
SRCDIRS += net net/tcp net/udp net/infiniband net/80211
|
||||
SRCDIRS += net net/tcp net/udp net/infiniband
|
||||
SRCDIRS += image
|
||||
SRCDIRS += drivers/bus
|
||||
SRCDIRS += drivers/net
|
||||
SRCDIRS += drivers/net/e1000
|
||||
SRCDIRS += drivers/net/e1000e
|
||||
SRCDIRS += drivers/net/igb
|
||||
SRCDIRS += drivers/net/igbvf
|
||||
SRCDIRS += drivers/net/phantom
|
||||
SRCDIRS += drivers/net/rtl818x
|
||||
SRCDIRS += drivers/net/ath5k
|
||||
SRCDIRS += drivers/net/vxge
|
||||
SRCDIRS += drivers/net/efi
|
||||
SRCDIRS += drivers/net/tg3
|
||||
SRCDIRS += drivers/net/bnxt
|
||||
SRCDIRS += drivers/net/sfc
|
||||
SRCDIRS += drivers/block
|
||||
SRCDIRS += drivers/nvs
|
||||
SRCDIRS += drivers/bitbash
|
||||
SRCDIRS += drivers/infiniband
|
||||
SRCDIRS += drivers/linux
|
||||
SRCDIRS += interface/pxe interface/efi interface/smbios interface/linux
|
||||
SRCDIRS += drivers/infiniband/mlx_utils_flexboot/src
|
||||
SRCDIRS += drivers/infiniband/mlx_utils/src/public
|
||||
SRCDIRS += drivers/infiniband/mlx_utils/mlx_lib/mlx_reg_access
|
||||
SRCDIRS += drivers/infiniband/mlx_utils/mlx_lib/mlx_nvconfig
|
||||
SRCDIRS += drivers/infiniband/mlx_utils/mlx_lib/mlx_vmac
|
||||
SRCDIRS += drivers/infiniband/mlx_utils/mlx_lib/mlx_blink_leds
|
||||
SRCDIRS += drivers/infiniband/mlx_utils/mlx_lib/mlx_link_speed
|
||||
SRCDIRS += drivers/infiniband/mlx_utils/mlx_lib/mlx_mtu
|
||||
SRCDIRS += drivers/infiniband/mlx_nodnic/src
|
||||
SRCDIRS += drivers/usb
|
||||
SRCDIRS += interface/pxe interface/efi interface/smbios
|
||||
SRCDIRS += interface/bofm
|
||||
SRCDIRS += interface/xen
|
||||
SRCDIRS += interface/hyperv
|
||||
SRCDIRS += tests
|
||||
SRCDIRS += crypto crypto/axtls crypto/matrixssl
|
||||
SRCDIRS += crypto crypto/mishmash
|
||||
SRCDIRS += hci hci/commands hci/tui
|
||||
SRCDIRS += hci/mucurses hci/mucurses/widgets
|
||||
SRCDIRS += hci/keymap
|
||||
SRCDIRS += usr
|
||||
SRCDIRS += config
|
||||
|
||||
# These directories contain code that is not eligible for UEFI Secure
|
||||
# Boot signing.
|
||||
#
|
||||
SRCDIRS_INSEC += net/oncrpc
|
||||
SRCDIRS_INSEC += net/80211
|
||||
SRCDIRS_INSEC += drivers/net/rtl818x
|
||||
SRCDIRS_INSEC += drivers/net/ath
|
||||
SRCDIRS_INSEC += drivers/net/ath/ath5k
|
||||
SRCDIRS_INSEC += drivers/net/ath/ath9k
|
||||
|
||||
# NON_AUTO_SRCS lists files that are excluded from the normal
|
||||
# automatic build system.
|
||||
#
|
||||
NON_AUTO_SRCS :=
|
||||
NON_AUTO_SRCS += core/version.c
|
||||
NON_AUTO_SRCS += drivers/net/prism2.c
|
||||
|
||||
# INCDIRS lists the include path
|
||||
@@ -98,8 +129,12 @@ INCDIRS += include .
|
||||
# Default build target: build the most common targets and print out a
|
||||
# helpfully suggestive message
|
||||
#
|
||||
ALL := bin/blib.a bin/ipxe.dsk bin/ipxe.iso bin/ipxe.usb \
|
||||
bin/undionly.kpxe bin/rtl8139.rom
|
||||
ALL := bin/blib.a bin/ipxe.dsk bin/ipxe.lkrn bin/ipxe.iso \
|
||||
bin/ipxe.usb bin/ipxe.pxe bin/undionly.kpxe bin/rtl8139.rom \
|
||||
bin/8086100e.mrom bin/80861209.rom bin/10500940.rom \
|
||||
bin/10222000.rom bin/10ec8139.rom bin/1af41000.rom \
|
||||
bin/8086100f.mrom bin/808610d3.mrom bin/15ad07b0.rom
|
||||
|
||||
all : $(ALL)
|
||||
@$(ECHO) '==========================================================='
|
||||
@$(ECHO)
|
||||
@@ -131,11 +166,33 @@ all : $(ALL)
|
||||
#
|
||||
everything :
|
||||
$(Q)$(MAKE) --no-print-directory $(ALL) \
|
||||
bin/3c509.rom bin/intel.rom bin/intel.mrom \
|
||||
bin-x86_64-pcbios/8086100e.mrom bin-x86_64-pcbios/intel.rom \
|
||||
bin-x86_64-pcbios/ipxe.usb bin-x86_64-pcbios/ipxe.pxe \
|
||||
bin-x86_64-pcbios/undionly.kpxe \
|
||||
bin-i386-efi/ipxe.efi bin-i386-efi/ipxe.efidrv \
|
||||
bin-i386-efi/ipxe.efirom \
|
||||
bin-x86_64-efi/ipxe.efi bin-x86_64-efi/ipxe.efidrv \
|
||||
bin-x86_64-efi/ipxe.efirom \
|
||||
bin-i386-linux/tap.linux bin-x86_64-linux/tap.linux
|
||||
bin-i386-linux/tap.linux bin-x86_64-linux/tap.linux \
|
||||
bin-i386-linux/tests.linux bin-x86_64-linux/tests.linux
|
||||
|
||||
###############################################################################
|
||||
#
|
||||
# VMware build target: all ROMs used with VMware
|
||||
#
|
||||
vmware : bin/8086100f.mrom bin/808610d3.mrom bin/10222000.rom bin/15ad07b0.rom
|
||||
@$(ECHO) '==========================================================='
|
||||
@$(ECHO)
|
||||
@$(ECHO) 'Available ROMs:'
|
||||
@$(ECHO) ' bin/8086100f.mrom -- intel/e1000'
|
||||
@$(ECHO) ' bin/808610d3.mrom -- intel/e1000e'
|
||||
@$(ECHO) ' bin/10222000.rom -- vlance/pcnet32'
|
||||
@$(ECHO) ' bin/15ad07b0.rom -- vmxnet3'
|
||||
@$(ECHO)
|
||||
@$(ECHO) 'For more information, see http://ipxe.org/howto/vmware'
|
||||
@$(ECHO)
|
||||
@$(ECHO) '==========================================================='
|
||||
|
||||
###############################################################################
|
||||
#
|
||||
@@ -151,19 +208,44 @@ install :
|
||||
#
|
||||
# Version number calculations
|
||||
#
|
||||
ifneq ($(wildcard ../.git),)
|
||||
VERSIONS := $(shell git describe --tags --always --long --abbrev=1 --match "v*")
|
||||
VERSION_TUPLE := $(subst ., ,$(subst -, ,$(patsubst v%,%,$(VERSIONS))))
|
||||
VERSION_MAJOR := $(word 1,$(VERSION_TUPLE))
|
||||
VERSION_MINOR := $(word 2,$(VERSION_TUPLE))
|
||||
VERSION_PATCH := $(word 3,$(VERSION_TUPLE))
|
||||
ifeq ($(word 4,$(VERSION_TUPLE)),0)
|
||||
EXTRAVERSION :=
|
||||
else
|
||||
EXTRAVERSION := +
|
||||
endif
|
||||
GITVERSION = $(word 5,$(VERSION_TUPLE))
|
||||
else
|
||||
VERSION_MAJOR = 1
|
||||
VERSION_MINOR = 0
|
||||
VERSION_PATCH = 0
|
||||
EXTRAVERSION = +
|
||||
endif
|
||||
MM_VERSION = $(VERSION_MAJOR).$(VERSION_MINOR)
|
||||
VERSION = $(MM_VERSION).$(VERSION_PATCH)$(EXTRAVERSION)
|
||||
CFLAGS += -DVERSION_MAJOR=$(VERSION_MAJOR) \
|
||||
-DVERSION_MINOR=$(VERSION_MINOR) \
|
||||
-DVERSION_PATCH=$(VERSION_PATCH) \
|
||||
-DVERSION=\"$(VERSION)\"
|
||||
IDENT = '$(@F) $(VERSION) (GPL) ipxe.org'
|
||||
ifneq ($(GITVERSION),)
|
||||
VERSION += ($(GITVERSION))
|
||||
endif
|
||||
version :
|
||||
@$(ECHO) $(VERSION)
|
||||
@$(ECHO) "$(VERSION)"
|
||||
|
||||
###############################################################################
|
||||
#
|
||||
# Predefined build shortcuts (for e.g. bin/ipxe.iso)
|
||||
|
||||
# All drivers (excluding USB)
|
||||
#
|
||||
DRIVERS_ipxe = $(DRIVERS_net) $(DRIVERS_infiniband) \
|
||||
$(DRIVERS_xen) $(DRIVERS_hyperv)
|
||||
|
||||
# Raspberry Pi
|
||||
#
|
||||
DRIVERS_rpi = smsc95xx lan78xx
|
||||
|
||||
###############################################################################
|
||||
#
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -54,6 +54,8 @@ CFLAGS += -m32
|
||||
ASFLAGS += --32
|
||||
ifeq ($(HOST_OS),FreeBSD)
|
||||
LDFLAGS += -m elf_i386_fbsd
|
||||
else ifeq ($(HOST_OS),OpenBSD)
|
||||
LDFLAGS += -m elf_i386_obsd
|
||||
else
|
||||
LDFLAGS += -m elf_i386
|
||||
endif
|
||||
@@ -67,32 +69,26 @@ CFLAGS += -fshort-wchar
|
||||
#
|
||||
CFLAGS += -Ui386
|
||||
|
||||
# Locations of utilities
|
||||
# Some widespread patched versions of gcc include -fPIE -Wl,-pie by
|
||||
# default. Note that gcc will exit *successfully* if it fails to
|
||||
# recognise an option that starts with "no", so we have to test for
|
||||
# output on stderr instead of checking the exit status.
|
||||
#
|
||||
ISOLINUX_BIN_LIST := \
|
||||
$(ISOLINUX_BIN) \
|
||||
/usr/lib/syslinux/isolinux.bin \
|
||||
/usr/share/syslinux/isolinux.bin \
|
||||
/usr/local/share/syslinux/isolinux.bin
|
||||
ISOLINUX_BIN = $(firstword $(wildcard $(ISOLINUX_BIN_LIST)))
|
||||
# Current versions of gcc require -no-pie; older versions require
|
||||
# -nopie. We therefore test for both.
|
||||
#
|
||||
ifeq ($(CCTYPE),gcc)
|
||||
PIE_TEST = [ -z "`$(CC) -fno-PIE -no-pie -x c -c /dev/null -o /dev/null 2>&1`" ]
|
||||
PIE_FLAGS := $(shell $(PIE_TEST) && $(ECHO) '-fno-PIE -no-pie')
|
||||
PIE_TEST2 = [ -z "`$(CC) -fno-PIE -nopie -x c -c /dev/null -o /dev/null 2>&1`" ]
|
||||
PIE_FLAGS2 := $(shell $(PIE_TEST2) && $(ECHO) '-fno-PIE -nopie')
|
||||
WORKAROUND_CFLAGS += $(PIE_FLAGS) $(PIE_FLAGS2)
|
||||
endif
|
||||
|
||||
# i386-specific directories containing source files
|
||||
#
|
||||
SRCDIRS += arch/i386/core arch/i386/transitions arch/i386/prefix
|
||||
SRCDIRS += arch/i386/firmware/pcbios
|
||||
SRCDIRS += arch/i386/image
|
||||
SRCDIRS += arch/i386/interface/pcbios
|
||||
SRCDIRS += arch/i386/interface/pxe
|
||||
SRCDIRS += arch/i386/interface/pxeparent
|
||||
SRCDIRS += arch/i386/interface/syslinux
|
||||
SRCDIRS += arch/i386/hci/commands
|
||||
|
||||
# The various xxx_loader.c files are #included into core/loader.c and
|
||||
# should not be compiled directly.
|
||||
#
|
||||
NON_AUTO_SRCS += arch/i386/core/aout_loader.c
|
||||
NON_AUTO_SRCS += arch/i386/core/freebsd_loader.c
|
||||
NON_AUTO_SRCS += arch/i386/core/wince_loader.c
|
||||
SRCDIRS += arch/i386/core
|
||||
SRCDIRS += arch/i386/tests
|
||||
|
||||
# Include common x86 Makefile
|
||||
#
|
||||
|
@@ -4,6 +4,14 @@
|
||||
#
|
||||
ELF2EFI = $(ELF2EFI32)
|
||||
|
||||
# Use EFI ABI
|
||||
#
|
||||
CFLAGS += -malign-double
|
||||
|
||||
# Specify EFI boot file
|
||||
#
|
||||
EFI_BOOT_FILE = bootia32.efi
|
||||
|
||||
# Include generic EFI Makefile
|
||||
#
|
||||
MAKEDEPS += arch/x86/Makefile.efi
|
||||
|
@@ -1,84 +1,6 @@
|
||||
# -*- makefile -*- : Force emacs to use Makefile mode
|
||||
|
||||
# The i386 linker script
|
||||
# Include generic BIOS Makefile
|
||||
#
|
||||
LDSCRIPT = arch/i386/scripts/i386.lds
|
||||
|
||||
# Stop ld from complaining about our customised linker script
|
||||
#
|
||||
LDFLAGS += -N --no-check-sections
|
||||
|
||||
# pcbios specific drivers
|
||||
SRCDIRS += arch/i386/drivers
|
||||
SRCDIRS += arch/i386/drivers/net
|
||||
|
||||
# Media types.
|
||||
#
|
||||
MEDIA += rom
|
||||
MEDIA += mrom
|
||||
MEDIA += pxe
|
||||
MEDIA += kpxe
|
||||
MEDIA += kkpxe
|
||||
MEDIA += lkrn
|
||||
MEDIA += dsk
|
||||
MEDIA += nbi
|
||||
MEDIA += hd
|
||||
MEDIA += raw
|
||||
|
||||
# Padding rules
|
||||
#
|
||||
PAD_rom = $(PERL) $(PADIMG) --blksize=512 --byte=0xff $@
|
||||
PAD_mrom = $(PAD_rom)
|
||||
PAD_dsk = $(PERL) $(PADIMG) --blksize=512 $@
|
||||
PAD_hd = $(PERL) $(PADIMG) --blksize=32768 $@
|
||||
|
||||
# Finalisation rules
|
||||
#
|
||||
FINALISE_rom = $(PERL) $(FIXROM) $@
|
||||
FINALISE_mrom = $(FINALISE_rom)
|
||||
|
||||
# rule to make a non-emulation ISO boot image
|
||||
NON_AUTO_MEDIA += iso
|
||||
%iso: %lkrn util/geniso
|
||||
$(QM)$(ECHO) " [GENISO] $@"
|
||||
$(Q)ISOLINUX_BIN=$(ISOLINUX_BIN) bash util/geniso $@ $<
|
||||
|
||||
# rule to make a floppy emulation ISO boot image
|
||||
NON_AUTO_MEDIA += liso
|
||||
%liso: %lkrn util/genliso
|
||||
$(QM)$(ECHO) " [GENLISO] $@"
|
||||
$(Q)bash util/genliso $@ $<
|
||||
|
||||
# rule to make a syslinux floppy image (mountable, bootable)
|
||||
NON_AUTO_MEDIA += sdsk
|
||||
%sdsk: %lkrn util/gensdsk
|
||||
$(QM)$(ECHO) " [GENSDSK] $@"
|
||||
$(Q)bash util/gensdsk $@ $<
|
||||
|
||||
# rule to write disk images to /dev/fd0
|
||||
NON_AUTO_MEDIA += fd0
|
||||
%fd0 : %dsk
|
||||
$(QM)$(ECHO) " [DD] $@"
|
||||
$(Q)dd if=$< bs=512 conv=sync of=/dev/fd0
|
||||
$(Q)sync
|
||||
|
||||
# Special target for building Master Boot Record binary
|
||||
$(BIN)/mbr.bin : $(BIN)/mbr.o
|
||||
$(QM)$(ECHO) " [OBJCOPY] $@"
|
||||
$(Q)$(OBJCOPY) -O binary $< $@
|
||||
|
||||
# rule to make a USB disk image
|
||||
$(BIN)/usbdisk.bin : $(BIN)/usbdisk.o
|
||||
$(QM)$(ECHO) " [OBJCOPY] $@"
|
||||
$(Q)$(OBJCOPY) -O binary $< $@
|
||||
|
||||
NON_AUTO_MEDIA += usb
|
||||
%usb: $(BIN)/usbdisk.bin %hd
|
||||
$(QM)$(ECHO) " [FINISH] $@"
|
||||
$(Q)cat $^ > $@
|
||||
|
||||
# Padded floppy image (e.g. for iLO)
|
||||
NON_AUTO_MEDIA += pdsk
|
||||
%pdsk : %dsk
|
||||
$(Q)cp $< $@
|
||||
$(Q)$(PADIMG) --blksize=1474560 $@
|
||||
MAKEDEPS += arch/x86/Makefile.pcbios
|
||||
include arch/x86/Makefile.pcbios
|
||||
|
@@ -1,144 +0,0 @@
|
||||
/* a.out */
|
||||
struct exec {
|
||||
unsigned long a_midmag; /* flags<<26 | mid<<16 | magic */
|
||||
unsigned long a_text; /* text segment size */
|
||||
unsigned long a_data; /* initialized data size */
|
||||
unsigned long a_bss; /* uninitialized data size */
|
||||
unsigned long a_syms; /* symbol table size */
|
||||
unsigned long a_entry; /* entry point */
|
||||
unsigned long a_trsize; /* text relocation size */
|
||||
unsigned long a_drsize; /* data relocation size */
|
||||
};
|
||||
|
||||
struct aout_state {
|
||||
struct exec head;
|
||||
unsigned long curaddr;
|
||||
int segment; /* current segment number, -1 for none */
|
||||
unsigned long loc; /* start offset of current block */
|
||||
unsigned long skip; /* padding to be skipped to current segment */
|
||||
unsigned long toread; /* remaining data to be read in the segment */
|
||||
};
|
||||
|
||||
static struct aout_state astate;
|
||||
|
||||
static sector_t aout_download(unsigned char *data, unsigned int len, int eof);
|
||||
static inline os_download_t aout_probe(unsigned char *data, unsigned int len)
|
||||
{
|
||||
unsigned long start, mid, end, istart, iend;
|
||||
if (len < sizeof(astate.head)) {
|
||||
return 0;
|
||||
}
|
||||
memcpy(&astate.head, data, sizeof(astate.head));
|
||||
if ((astate.head.a_midmag & 0xffff) != 0x010BL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
printf("(a.out");
|
||||
aout_freebsd_probe();
|
||||
printf(")... ");
|
||||
/* Check the aout image */
|
||||
start = astate.head.a_entry;
|
||||
mid = (((start + astate.head.a_text) + 4095) & ~4095) + astate.head.a_data;
|
||||
end = ((mid + 4095) & ~4095) + astate.head.a_bss;
|
||||
istart = 4096;
|
||||
iend = istart + (mid - start);
|
||||
if (!prep_segment(start, mid, end, istart, iend))
|
||||
return dead_download;
|
||||
astate.segment = -1;
|
||||
astate.loc = 0;
|
||||
astate.skip = 0;
|
||||
astate.toread = 0;
|
||||
return aout_download;
|
||||
}
|
||||
|
||||
static sector_t aout_download(unsigned char *data, unsigned int len, int eof)
|
||||
{
|
||||
unsigned int offset; /* working offset in the current data block */
|
||||
|
||||
offset = 0;
|
||||
|
||||
#ifdef AOUT_LYNX_KDI
|
||||
astate.segment++;
|
||||
if (astate.segment == 0) {
|
||||
astate.curaddr = 0x100000;
|
||||
astate.head.a_entry = astate.curaddr + 0x20;
|
||||
}
|
||||
memcpy(phys_to_virt(astate.curaddr), data, len);
|
||||
astate.curaddr += len;
|
||||
return 0;
|
||||
#endif
|
||||
|
||||
do {
|
||||
if (astate.segment != -1) {
|
||||
if (astate.skip) {
|
||||
if (astate.skip >= len - offset) {
|
||||
astate.skip -= len - offset;
|
||||
break;
|
||||
}
|
||||
offset += astate.skip;
|
||||
astate.skip = 0;
|
||||
}
|
||||
|
||||
if (astate.toread) {
|
||||
if (astate.toread >= len - offset) {
|
||||
memcpy(phys_to_virt(astate.curaddr), data+offset,
|
||||
len - offset);
|
||||
astate.curaddr += len - offset;
|
||||
astate.toread -= len - offset;
|
||||
break;
|
||||
}
|
||||
memcpy(phys_to_virt(astate.curaddr), data+offset, astate.toread);
|
||||
offset += astate.toread;
|
||||
astate.toread = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Data left, but current segment finished - look for the next
|
||||
* segment. This is quite simple for a.out files. */
|
||||
astate.segment++;
|
||||
switch (astate.segment) {
|
||||
case 0:
|
||||
/* read text */
|
||||
astate.curaddr = astate.head.a_entry;
|
||||
astate.skip = 4096;
|
||||
astate.toread = astate.head.a_text;
|
||||
break;
|
||||
case 1:
|
||||
/* read data */
|
||||
/* skip and curaddr may be wrong, but I couldn't find
|
||||
* examples where this failed. There is no reasonable
|
||||
* documentation for a.out available. */
|
||||
astate.skip = ((astate.curaddr + 4095) & ~4095) - astate.curaddr;
|
||||
astate.curaddr = (astate.curaddr + 4095) & ~4095;
|
||||
astate.toread = astate.head.a_data;
|
||||
break;
|
||||
case 2:
|
||||
/* initialize bss and start kernel */
|
||||
astate.curaddr = (astate.curaddr + 4095) & ~4095;
|
||||
astate.skip = 0;
|
||||
astate.toread = 0;
|
||||
memset(phys_to_virt(astate.curaddr), '\0', astate.head.a_bss);
|
||||
goto aout_startkernel;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} while (offset < len);
|
||||
|
||||
astate.loc += len;
|
||||
|
||||
if (eof) {
|
||||
unsigned long entry;
|
||||
|
||||
aout_startkernel:
|
||||
entry = astate.head.a_entry;
|
||||
done(1);
|
||||
|
||||
aout_freebsd_boot();
|
||||
#ifdef AOUT_LYNX_KDI
|
||||
xstart32(entry);
|
||||
#endif
|
||||
printf("unexpected a.out variant\n");
|
||||
longjmp(restart_etherboot, -2);
|
||||
}
|
||||
return 0;
|
||||
}
|
@@ -1,32 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2007 Michael Brown <mbrown@fensystems.co.uk>.
|
||||
*
|
||||
* 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 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER );
|
||||
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
* Packet buffer in base memory. Used by various components which
|
||||
* need to pass packets to and from external real-mode code.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <basemem_packet.h>
|
||||
|
||||
#undef basemem_packet
|
||||
char __bss16_array ( basemem_packet, [BASEMEM_PACKET_LEN] );
|
@@ -1,73 +0,0 @@
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <cpu.h>
|
||||
|
||||
/** @file
|
||||
*
|
||||
* CPU identification
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Test to see if CPU flag is changeable
|
||||
*
|
||||
* @v flag Flag to test
|
||||
* @ret can_change Flag is changeable
|
||||
*/
|
||||
static inline int flag_is_changeable ( unsigned int flag ) {
|
||||
uint32_t f1, f2;
|
||||
|
||||
__asm__ ( "pushfl\n\t"
|
||||
"pushfl\n\t"
|
||||
"popl %0\n\t"
|
||||
"movl %0,%1\n\t"
|
||||
"xorl %2,%0\n\t"
|
||||
"pushl %0\n\t"
|
||||
"popfl\n\t"
|
||||
"pushfl\n\t"
|
||||
"popl %0\n\t"
|
||||
"popfl\n\t"
|
||||
: "=&r" ( f1 ), "=&r" ( f2 )
|
||||
: "ir" ( flag ) );
|
||||
|
||||
return ( ( ( f1 ^ f2 ) & flag ) != 0 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get CPU information
|
||||
*
|
||||
* @v cpu CPU information structure to fill in
|
||||
*/
|
||||
void get_cpuinfo ( struct cpuinfo_x86 *cpu ) {
|
||||
unsigned int cpuid_level;
|
||||
unsigned int cpuid_extlevel;
|
||||
unsigned int discard_1, discard_2, discard_3;
|
||||
|
||||
memset ( cpu, 0, sizeof ( *cpu ) );
|
||||
|
||||
/* Check for CPUID instruction */
|
||||
if ( ! flag_is_changeable ( X86_EFLAGS_ID ) ) {
|
||||
DBG ( "CPUID not supported\n" );
|
||||
return;
|
||||
}
|
||||
|
||||
/* Get features, if present */
|
||||
cpuid ( 0x00000000, &cpuid_level, &discard_1,
|
||||
&discard_2, &discard_3 );
|
||||
if ( cpuid_level >= 0x00000001 ) {
|
||||
cpuid ( 0x00000001, &discard_1, &discard_2,
|
||||
&discard_3, &cpu->features );
|
||||
} else {
|
||||
DBG ( "CPUID cannot return capabilities\n" );
|
||||
}
|
||||
|
||||
/* Get 64-bit features, if present */
|
||||
cpuid ( 0x80000000, &cpuid_extlevel, &discard_1,
|
||||
&discard_2, &discard_3 );
|
||||
if ( ( cpuid_extlevel & 0xffff0000 ) == 0x80000000 ) {
|
||||
if ( cpuid_extlevel >= 0x80000001 ) {
|
||||
cpuid ( 0x80000001, &discard_1, &discard_2,
|
||||
&discard_3, &cpu->amd_features );
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,23 +0,0 @@
|
||||
#include <stdio.h>
|
||||
#include <realmode.h>
|
||||
|
||||
void __asmcall _dump_regs ( struct i386_all_regs *ix86 ) {
|
||||
|
||||
__asm__ __volatile__ (
|
||||
TEXT16_CODE ( ".globl dump_regs\n\t"
|
||||
"\ndump_regs:\n\t"
|
||||
"pushl $_dump_regs\n\t"
|
||||
"pushw %%cs\n\t"
|
||||
"call prot_call\n\t"
|
||||
"addr32 leal 4(%%esp), %%esp\n\t"
|
||||
"ret\n\t" ) : : );
|
||||
|
||||
printf ( "EAX=%08x EBX=%08x ECX=%08x EDX=%08x\n"
|
||||
"ESI=%08x EDI=%08x EBP=%08x ESP=%08x\n"
|
||||
"CS=%04x SS=%04x DS=%04x ES=%04x FS=%04x GS=%04x\n",
|
||||
ix86->regs.eax, ix86->regs.ebx, ix86->regs.ecx,
|
||||
ix86->regs.edx, ix86->regs.esi, ix86->regs.edi,
|
||||
ix86->regs.ebp, ix86->regs.esp,
|
||||
ix86->segs.cs, ix86->segs.ss, ix86->segs.ds,
|
||||
ix86->segs.es, ix86->segs.fs, ix86->segs.gs );
|
||||
}
|
@@ -1,377 +0,0 @@
|
||||
/* bootinfo */
|
||||
#define BOOTINFO_VERSION 1
|
||||
#define NODEV (-1) /* non-existent device */
|
||||
#define PAGE_SHIFT 12 /* LOG2(PAGE_SIZE) */
|
||||
#define PAGE_SIZE (1<<PAGE_SHIFT) /* bytes/page */
|
||||
#define PAGE_MASK (PAGE_SIZE-1)
|
||||
#define N_BIOS_GEOM 8
|
||||
|
||||
struct bootinfo {
|
||||
unsigned int bi_version;
|
||||
const unsigned char *bi_kernelname;
|
||||
struct nfs_diskless *bi_nfs_diskless;
|
||||
/* End of fields that are always present. */
|
||||
#define bi_endcommon bi_n_bios_used
|
||||
unsigned int bi_n_bios_used;
|
||||
unsigned long bi_bios_geom[N_BIOS_GEOM];
|
||||
unsigned int bi_size;
|
||||
unsigned char bi_memsizes_valid;
|
||||
unsigned char bi_pad[3];
|
||||
unsigned long bi_basemem;
|
||||
unsigned long bi_extmem;
|
||||
unsigned long bi_symtab;
|
||||
unsigned long bi_esymtab;
|
||||
/* Note that these are in the FreeBSD headers but were not here... */
|
||||
unsigned long bi_kernend; /* end of kernel space */
|
||||
unsigned long bi_envp; /* environment */
|
||||
unsigned long bi_modulep; /* preloaded modules */
|
||||
};
|
||||
|
||||
static struct bootinfo bsdinfo;
|
||||
|
||||
#ifdef ELF_IMAGE
|
||||
static Elf32_Shdr *shdr; /* To support the FreeBSD kludge! */
|
||||
static Address symtab_load;
|
||||
static Address symstr_load;
|
||||
static int symtabindex;
|
||||
static int symstrindex;
|
||||
#endif
|
||||
|
||||
static enum {
|
||||
Unknown, Tagged, Aout, Elf, Aout_FreeBSD, Elf_FreeBSD,
|
||||
} image_type = Unknown;
|
||||
|
||||
static unsigned int off;
|
||||
|
||||
|
||||
#ifdef ELF_IMAGE
|
||||
static void elf_freebsd_probe(void)
|
||||
{
|
||||
image_type = Elf;
|
||||
if ( (estate.e.elf32.e_entry & 0xf0000000) &&
|
||||
(estate.e.elf32.e_type == ET_EXEC))
|
||||
{
|
||||
image_type = Elf_FreeBSD;
|
||||
printf("/FreeBSD");
|
||||
off = -(estate.e.elf32.e_entry & 0xff000000);
|
||||
estate.e.elf32.e_entry += off;
|
||||
}
|
||||
/* Make sure we have a null to start with... */
|
||||
shdr = 0;
|
||||
|
||||
/* Clear the symbol index values... */
|
||||
symtabindex = -1;
|
||||
symstrindex = -1;
|
||||
|
||||
/* ...and the load addresses of the symbols */
|
||||
symtab_load = 0;
|
||||
symstr_load = 0;
|
||||
}
|
||||
|
||||
static void elf_freebsd_fixup_segment(void)
|
||||
{
|
||||
if (image_type == Elf_FreeBSD) {
|
||||
estate.p.phdr32[estate.segment].p_paddr += off;
|
||||
}
|
||||
}
|
||||
|
||||
static void elf_freebsd_find_segment_end(void)
|
||||
{
|
||||
/* Count the bytes read even for the last block
|
||||
* as we will need to know where the last block
|
||||
* ends in order to load the symbols correctly.
|
||||
* (plus it could be useful elsewhere...)
|
||||
* Note that we need to count the actual size,
|
||||
* not just the end of the disk image size.
|
||||
*/
|
||||
estate.curaddr +=
|
||||
(estate.p.phdr32[estate.segment].p_memsz -
|
||||
estate.p.phdr32[estate.segment].p_filesz);
|
||||
}
|
||||
|
||||
static int elf_freebsd_debug_loader(unsigned int offset)
|
||||
{
|
||||
/* No more segments to be loaded - time to start the
|
||||
* nasty state machine to support the loading of
|
||||
* FreeBSD debug symbols due to the fact that FreeBSD
|
||||
* uses/exports the kernel's debug symbols in order
|
||||
* to make much of the system work! Amazing (arg!)
|
||||
*
|
||||
* We depend on the fact that for the FreeBSD kernel,
|
||||
* there is only one section of debug symbols and that
|
||||
* the section is after all of the loaded sections in
|
||||
* the file. This assumes a lot but is somewhat required
|
||||
* to make this code not be too annoying. (Where do you
|
||||
* load symbols when the code has not loaded yet?)
|
||||
* Since this function is actually just a callback from
|
||||
* the network data transfer code, we need to be able to
|
||||
* work with the data as it comes in. There is no chance
|
||||
* for doing a seek other than forwards.
|
||||
*
|
||||
* The process we use is to first load the section
|
||||
* headers. Once they are loaded (shdr != 0) we then
|
||||
* look for where the symbol table and symbol table
|
||||
* strings are and setup some state that we found
|
||||
* them and fall into processing the first one (which
|
||||
* is the symbol table) and after that has been loaded,
|
||||
* we try the symbol strings. Note that the order is
|
||||
* actually required as the memory image depends on
|
||||
* the symbol strings being loaded starting at the
|
||||
* end of the symbol table. The kernel assumes this
|
||||
* layout of the image.
|
||||
*
|
||||
* At any point, if we get to the end of the load file
|
||||
* or the section requested is earlier in the file than
|
||||
* the current file pointer, we just end up falling
|
||||
* out of this and booting the kernel without this
|
||||
* information.
|
||||
*/
|
||||
|
||||
/* Make sure that the next address is long aligned... */
|
||||
/* Assumes size of long is a power of 2... */
|
||||
estate.curaddr = (estate.curaddr + sizeof(long) - 1) & ~(sizeof(long) - 1);
|
||||
|
||||
/* If we have not yet gotten the shdr loaded, try that */
|
||||
if (shdr == 0)
|
||||
{
|
||||
estate.toread = estate.e.elf32.e_shnum * estate.e.elf32.e_shentsize;
|
||||
estate.skip = estate.e.elf32.e_shoff - (estate.loc + offset);
|
||||
if (estate.toread)
|
||||
{
|
||||
#if ELF_DEBUG
|
||||
printf("shdr *, size %lX, curaddr %lX\n",
|
||||
estate.toread, estate.curaddr);
|
||||
#endif
|
||||
|
||||
/* Start reading at the curaddr and make that the shdr */
|
||||
shdr = (Elf32_Shdr *)phys_to_virt(estate.curaddr);
|
||||
|
||||
/* Start to read... */
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* We have the shdr loaded, check if we have found
|
||||
* the indexs where the symbols are supposed to be */
|
||||
if ((symtabindex == -1) && (symstrindex == -1))
|
||||
{
|
||||
int i;
|
||||
/* Make sure that the address is page aligned... */
|
||||
/* Symbols need to start in their own page(s)... */
|
||||
estate.curaddr = (estate.curaddr + 4095) & ~4095;
|
||||
|
||||
/* Need to make new indexes... */
|
||||
for (i=0; i < estate.e.elf32.e_shnum; i++)
|
||||
{
|
||||
if (shdr[i].sh_type == SHT_SYMTAB)
|
||||
{
|
||||
int j;
|
||||
for (j=0; j < estate.e.elf32.e_phnum; j++)
|
||||
{
|
||||
/* Check only for loaded sections */
|
||||
if ((estate.p.phdr32[j].p_type | 0x80) == (PT_LOAD | 0x80))
|
||||
{
|
||||
/* Only the extra symbols */
|
||||
if ((shdr[i].sh_offset >= estate.p.phdr32[j].p_offset) &&
|
||||
((shdr[i].sh_offset + shdr[i].sh_size) <=
|
||||
(estate.p.phdr32[j].p_offset + estate.p.phdr32[j].p_filesz)))
|
||||
{
|
||||
shdr[i].sh_offset=0;
|
||||
shdr[i].sh_size=0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ((shdr[i].sh_offset != 0) && (shdr[i].sh_size != 0))
|
||||
{
|
||||
symtabindex = i;
|
||||
symstrindex = shdr[i].sh_link;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Check if we have a symbol table index and have not loaded it */
|
||||
if ((symtab_load == 0) && (symtabindex >= 0))
|
||||
{
|
||||
/* No symbol table yet? Load it first... */
|
||||
|
||||
/* This happens to work out in a strange way.
|
||||
* If we are past the point in the file already,
|
||||
* we will skip a *large* number of bytes which
|
||||
* ends up bringing us to the end of the file and
|
||||
* an old (default) boot. Less code and lets
|
||||
* the state machine work in a cleaner way but this
|
||||
* is a nasty side-effect trick... */
|
||||
estate.skip = shdr[symtabindex].sh_offset - (estate.loc + offset);
|
||||
|
||||
/* And we need to read this many bytes... */
|
||||
estate.toread = shdr[symtabindex].sh_size;
|
||||
|
||||
if (estate.toread)
|
||||
{
|
||||
#if ELF_DEBUG
|
||||
printf("db sym, size %lX, curaddr %lX\n",
|
||||
estate.toread, estate.curaddr);
|
||||
#endif
|
||||
/* Save where we are loading this... */
|
||||
symtab_load = estate.curaddr;
|
||||
|
||||
*((long *)phys_to_virt(estate.curaddr)) = estate.toread;
|
||||
estate.curaddr += sizeof(long);
|
||||
|
||||
/* Start to read... */
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
else if ((symstr_load == 0) && (symstrindex >= 0))
|
||||
{
|
||||
/* We have already loaded the symbol table, so
|
||||
* now on to the symbol strings... */
|
||||
|
||||
|
||||
/* Same nasty trick as above... */
|
||||
estate.skip = shdr[symstrindex].sh_offset - (estate.loc + offset);
|
||||
|
||||
/* And we need to read this many bytes... */
|
||||
estate.toread = shdr[symstrindex].sh_size;
|
||||
|
||||
if (estate.toread)
|
||||
{
|
||||
#if ELF_DEBUG
|
||||
printf("db str, size %lX, curaddr %lX\n",
|
||||
estate.toread, estate.curaddr);
|
||||
#endif
|
||||
/* Save where we are loading this... */
|
||||
symstr_load = estate.curaddr;
|
||||
|
||||
*((long *)phys_to_virt(estate.curaddr)) = estate.toread;
|
||||
estate.curaddr += sizeof(long);
|
||||
|
||||
/* Start to read... */
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* all done */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void elf_freebsd_boot(unsigned long entry)
|
||||
{
|
||||
if (image_type != Elf_FreeBSD)
|
||||
return;
|
||||
|
||||
memset(&bsdinfo, 0, sizeof(bsdinfo));
|
||||
bsdinfo.bi_basemem = meminfo.basememsize;
|
||||
bsdinfo.bi_extmem = meminfo.memsize;
|
||||
bsdinfo.bi_memsizes_valid = 1;
|
||||
bsdinfo.bi_version = BOOTINFO_VERSION;
|
||||
bsdinfo.bi_kernelname = virt_to_phys(KERNEL_BUF);
|
||||
bsdinfo.bi_nfs_diskless = NULL;
|
||||
bsdinfo.bi_size = sizeof(bsdinfo);
|
||||
#define RB_BOOTINFO 0x80000000 /* have `struct bootinfo *' arg */
|
||||
if(freebsd_kernel_env[0] != '\0'){
|
||||
freebsd_howto |= RB_BOOTINFO;
|
||||
bsdinfo.bi_envp = (unsigned long)freebsd_kernel_env;
|
||||
}
|
||||
|
||||
/* Check if we have symbols loaded, and if so,
|
||||
* made the meta_data needed to pass those to
|
||||
* the kernel. */
|
||||
if ((symtab_load !=0) && (symstr_load != 0))
|
||||
{
|
||||
unsigned long *t;
|
||||
|
||||
bsdinfo.bi_symtab = symtab_load;
|
||||
|
||||
/* End of symbols (long aligned...) */
|
||||
/* Assumes size of long is a power of 2... */
|
||||
bsdinfo.bi_esymtab = (symstr_load +
|
||||
sizeof(long) +
|
||||
*((long *)phys_to_virt(symstr_load)) +
|
||||
sizeof(long) - 1) & ~(sizeof(long) - 1);
|
||||
|
||||
/* Where we will build the meta data... */
|
||||
t = phys_to_virt(bsdinfo.bi_esymtab);
|
||||
|
||||
#if ELF_DEBUG
|
||||
printf("Metadata at %lX\n",t);
|
||||
#endif
|
||||
|
||||
/* Set up the pointer to the memory... */
|
||||
bsdinfo.bi_modulep = virt_to_phys(t);
|
||||
|
||||
/* The metadata structure is an array of 32-bit
|
||||
* words where we store some information about the
|
||||
* system. This is critical, as FreeBSD now looks
|
||||
* only for the metadata for the extended symbol
|
||||
* information rather than in the bootinfo.
|
||||
*/
|
||||
/* First, do the kernel name and the kernel type */
|
||||
/* Note that this assumed x86 byte order... */
|
||||
|
||||
/* 'kernel\0\0' */
|
||||
*t++=MODINFO_NAME; *t++= 7; *t++=0x6E72656B; *t++=0x00006C65;
|
||||
|
||||
/* 'elf kernel\0\0' */
|
||||
*t++=MODINFO_TYPE; *t++=11; *t++=0x20666C65; *t++=0x6E72656B; *t++ = 0x00006C65;
|
||||
|
||||
/* Now the symbol start/end - note that they are
|
||||
* here in local/physical address - the Kernel
|
||||
* boot process will relocate the addresses. */
|
||||
*t++=MODINFOMD_SSYM | MODINFO_METADATA; *t++=sizeof(*t); *t++=bsdinfo.bi_symtab;
|
||||
*t++=MODINFOMD_ESYM | MODINFO_METADATA; *t++=sizeof(*t); *t++=bsdinfo.bi_esymtab;
|
||||
|
||||
*t++=MODINFO_END; *t++=0; /* end of metadata */
|
||||
|
||||
/* Since we have symbols we need to make
|
||||
* sure that the kernel knows its own end
|
||||
* of memory... It is not _end but after
|
||||
* the symbols and the metadata... */
|
||||
bsdinfo.bi_kernend = virt_to_phys(t);
|
||||
|
||||
/* Signal locore.s that we have a valid bootinfo
|
||||
* structure that was completely filled in. */
|
||||
freebsd_howto |= 0x80000000;
|
||||
}
|
||||
|
||||
xstart32(entry, freebsd_howto, NODEV, 0, 0, 0,
|
||||
virt_to_phys(&bsdinfo), 0, 0, 0);
|
||||
longjmp(restart_etherboot, -2);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef AOUT_IMAGE
|
||||
static void aout_freebsd_probe(void)
|
||||
{
|
||||
image_type = Aout;
|
||||
if (((astate.head.a_midmag >> 16) & 0xffff) == 0) {
|
||||
/* Some other a.out variants have a different
|
||||
* value, and use other alignments (e.g. 1K),
|
||||
* not the 4K used by FreeBSD. */
|
||||
image_type = Aout_FreeBSD;
|
||||
printf("/FreeBSD");
|
||||
off = -(astate.head.a_entry & 0xff000000);
|
||||
astate.head.a_entry += off;
|
||||
}
|
||||
}
|
||||
|
||||
static void aout_freebsd_boot(void)
|
||||
{
|
||||
if (image_type == Aout_FreeBSD) {
|
||||
memset(&bsdinfo, 0, sizeof(bsdinfo));
|
||||
bsdinfo.bi_basemem = meminfo.basememsize;
|
||||
bsdinfo.bi_extmem = meminfo.memsize;
|
||||
bsdinfo.bi_memsizes_valid = 1;
|
||||
bsdinfo.bi_version = BOOTINFO_VERSION;
|
||||
bsdinfo.bi_kernelname = virt_to_phys(KERNEL_BUF);
|
||||
bsdinfo.bi_nfs_diskless = NULL;
|
||||
bsdinfo.bi_size = sizeof(bsdinfo);
|
||||
xstart32(astate.head.a_entry, freebsd_howto, NODEV, 0, 0, 0,
|
||||
virt_to_phys(&bsdinfo), 0, 0, 0);
|
||||
longjmp(restart_etherboot, -2);
|
||||
}
|
||||
}
|
||||
#endif
|
@@ -1,101 +1,10 @@
|
||||
/*
|
||||
* Interrupt Descriptor Table (IDT) setup and interrupt handlers for GDB stub.
|
||||
* Interrupt handlers for GDB stub
|
||||
*/
|
||||
|
||||
#include <librm.h>
|
||||
|
||||
#define SIZEOF_I386_REGS 32
|
||||
#define SIZEOF_I386_FLAGS 4
|
||||
|
||||
/****************************************************************************
|
||||
* Interrupt Descriptor Table
|
||||
****************************************************************************
|
||||
*/
|
||||
.section ".data16", "aw", @progbits
|
||||
.globl idtr
|
||||
idtr:
|
||||
idt_limit:
|
||||
.word idt_length - 1
|
||||
idt_base:
|
||||
.long 0
|
||||
|
||||
/* IDT entries have the following format:
|
||||
* offset_lo, segment selector, flags, offset_hi
|
||||
*
|
||||
* Since it is not possible to specify relocations in arbitrary
|
||||
* expressions like (int_overflow & 0xffff), we initialise the
|
||||
* IDT with entries in an incorrect format.
|
||||
*
|
||||
* The entries are shuffled into the correct format in init_librm().
|
||||
*/
|
||||
#define IDT_ENTRY_EMPTY(name) .word 0, 0, 0, 0
|
||||
#define IDT_ENTRY_PRESENT(name) \
|
||||
.long int_##name; \
|
||||
.word 0x8e00, VIRTUAL_CS
|
||||
|
||||
.align 16
|
||||
idt:
|
||||
IDT_ENTRY_PRESENT(divide_error)
|
||||
IDT_ENTRY_PRESENT(debug_trap)
|
||||
IDT_ENTRY_EMPTY(non_maskable_interrupt)
|
||||
IDT_ENTRY_PRESENT(breakpoint)
|
||||
IDT_ENTRY_PRESENT(overflow)
|
||||
IDT_ENTRY_PRESENT(bound_range_exceeded)
|
||||
IDT_ENTRY_PRESENT(invalid_opcode)
|
||||
IDT_ENTRY_EMPTY(device_not_available)
|
||||
IDT_ENTRY_PRESENT(double_fault)
|
||||
IDT_ENTRY_EMPTY(coprocessor_segment_overrun)
|
||||
IDT_ENTRY_PRESENT(invalid_tss)
|
||||
IDT_ENTRY_PRESENT(segment_not_present)
|
||||
IDT_ENTRY_PRESENT(stack_segment_fault)
|
||||
IDT_ENTRY_PRESENT(general_protection)
|
||||
IDT_ENTRY_PRESENT(page_fault)
|
||||
idt_end:
|
||||
.equ idt_length, idt_end - idt
|
||||
|
||||
/* The IDT entries are fixed up (once) in init_librm() */
|
||||
idt_fixed:
|
||||
.byte 0
|
||||
|
||||
/****************************************************************************
|
||||
* idt_init (real-mode near call, 16-bit real-mode near return address)
|
||||
*
|
||||
* Initialise the IDT, called from init_librm.
|
||||
*
|
||||
* Parameters:
|
||||
* %eax : IDT base address
|
||||
*
|
||||
* Destroys %ax, %bx, and %di.
|
||||
****************************************************************************
|
||||
*/
|
||||
.section ".text16", "ax", @progbits
|
||||
.code16
|
||||
.globl idt_init
|
||||
idt_init:
|
||||
movl %eax, idt_base
|
||||
addl $idt, idt_base
|
||||
|
||||
/* IDT entries are only fixed up once */
|
||||
movb idt_fixed, %al
|
||||
orb %al, %al
|
||||
jnz 2f
|
||||
movb $1, idt_fixed
|
||||
|
||||
/* Shuffle IDT entries into the correct format */
|
||||
movb $(idt_length / 8), %al
|
||||
movw $idt, %bx
|
||||
or %al, %al
|
||||
jz 2f
|
||||
1:
|
||||
movw 2(%bx), %di
|
||||
xchg %di, 6(%bx)
|
||||
movw %di, 2(%bx)
|
||||
addw $8, %bx
|
||||
dec %al
|
||||
jnz 1b
|
||||
2:
|
||||
ret
|
||||
|
||||
/****************************************************************************
|
||||
* Interrupt handlers
|
||||
****************************************************************************
|
||||
@@ -106,40 +15,28 @@ idt_init:
|
||||
/* POSIX signal numbers for reporting traps to GDB */
|
||||
#define SIGILL 4
|
||||
#define SIGTRAP 5
|
||||
#define SIGBUS 7
|
||||
#define SIGFPE 8
|
||||
#define SIGSEGV 11
|
||||
#define SIGSTKFLT 16
|
||||
|
||||
int_divide_error:
|
||||
.globl gdbmach_sigfpe
|
||||
gdbmach_sigfpe:
|
||||
pushl $SIGFPE
|
||||
jmp do_interrupt
|
||||
jmp gdbmach_interrupt
|
||||
|
||||
int_debug_trap:
|
||||
int_breakpoint:
|
||||
.globl gdbmach_sigtrap
|
||||
gdbmach_sigtrap:
|
||||
pushl $SIGTRAP
|
||||
jmp do_interrupt
|
||||
jmp gdbmach_interrupt
|
||||
|
||||
int_overflow:
|
||||
int_bound_range_exceeded:
|
||||
.globl gdbmach_sigstkflt
|
||||
gdbmach_sigstkflt:
|
||||
pushl $SIGSTKFLT
|
||||
jmp do_interrupt
|
||||
jmp gdbmach_interrupt
|
||||
|
||||
int_invalid_opcode:
|
||||
.globl gdbmach_sigill
|
||||
gdbmach_sigill:
|
||||
pushl $SIGILL
|
||||
jmp do_interrupt
|
||||
|
||||
int_double_fault:
|
||||
movl $SIGBUS, (%esp)
|
||||
jmp do_interrupt
|
||||
|
||||
int_invalid_tss:
|
||||
int_segment_not_present:
|
||||
int_stack_segment_fault:
|
||||
int_general_protection:
|
||||
int_page_fault:
|
||||
movl $SIGSEGV, (%esp)
|
||||
jmp do_interrupt
|
||||
jmp gdbmach_interrupt
|
||||
|
||||
/* When invoked, the stack contains: eflags, cs, eip, signo. */
|
||||
#define IH_OFFSET_GDB_REGS ( 0 )
|
||||
@@ -161,7 +58,7 @@ int_page_fault:
|
||||
#define IH_OFFSET_FLUX_OLD_EFLAGS ( IH_OFFSET_OLD_EFLAGS - 40 )
|
||||
#define IH_OFFSET_FLUX_OLD_EIP ( IH_OFFSET_OLD_EIP - 36 )
|
||||
#define IH_OFFSET_FLUX_END ( IH_OFFSET_END - 20 )
|
||||
do_interrupt:
|
||||
gdbmach_interrupt:
|
||||
/* Store CPU state in GDB register snapshot */
|
||||
pushw $0
|
||||
pushw %gs
|
||||
@@ -187,25 +84,41 @@ do_interrupt:
|
||||
pushl %ecx
|
||||
pushl %eax
|
||||
|
||||
/* Switch to virtual addressing */
|
||||
call _intr_to_virt
|
||||
|
||||
/* Call GDB stub exception handler */
|
||||
pushl %esp
|
||||
pushl (IH_OFFSET_SIGNO + 4)(%esp)
|
||||
call gdbmach_handler
|
||||
addl $8, %esp
|
||||
|
||||
/* Copy register snapshot to new stack and switch to new stack */
|
||||
movl %esp, %esi
|
||||
movl (IH_OFFSET_GDB_SEG_REGS + 4)(%esp), %eax
|
||||
movl %eax, %es
|
||||
movl (IH_OFFSET_GDB_REGS + 16)(%esp), %edi
|
||||
subl $IH_OFFSET_END, %edi
|
||||
movl $(IH_OFFSET_END / 4), %ecx
|
||||
pushl %edi
|
||||
ss rep movsl
|
||||
popl %edi
|
||||
movl %eax, %ss
|
||||
movl %edi, %esp
|
||||
|
||||
/* Restore CPU state from GDB register snapshot */
|
||||
popl %eax
|
||||
popl %ecx
|
||||
popl %edx
|
||||
popl %ebx
|
||||
addl $4, %esp /* Changing ESP currently not supported */
|
||||
popl %ebp /* Skip %esp: already loaded */
|
||||
popl %ebp
|
||||
popl %esi
|
||||
popl %edi
|
||||
popl IH_OFFSET_FLUX_OLD_EIP(%esp)
|
||||
popl IH_OFFSET_FLUX_OLD_EFLAGS(%esp)
|
||||
popl IH_OFFSET_FLUX_OLD_CS(%esp)
|
||||
popl %ss
|
||||
popl %ds /* Skip %ss: already loaded */
|
||||
popl %ds
|
||||
popl %es
|
||||
popl %fs
|
||||
|
@@ -1,149 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Stefan Hajnoczi <stefanha@gmail.com>.
|
||||
*
|
||||
* 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 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include <ipxe/uaccess.h>
|
||||
#include <ipxe/gdbstub.h>
|
||||
#include <gdbmach.h>
|
||||
|
||||
/** @file
|
||||
*
|
||||
* GDB architecture-specific bits for i386
|
||||
*
|
||||
*/
|
||||
|
||||
enum {
|
||||
DR7_CLEAR = 0x00000400, /* disable hardware breakpoints */
|
||||
DR6_CLEAR = 0xffff0ff0, /* clear breakpoint status */
|
||||
};
|
||||
|
||||
/** Hardware breakpoint, fields stored in x86 bit pattern form */
|
||||
struct hwbp {
|
||||
int type; /* type (1=write watchpoint, 3=access watchpoint) */
|
||||
unsigned long addr; /* linear address */
|
||||
size_t len; /* length (0=1-byte, 1=2-byte, 3=4-byte) */
|
||||
int enabled;
|
||||
};
|
||||
|
||||
static struct hwbp hwbps [ 4 ];
|
||||
static gdbreg_t dr7 = DR7_CLEAR;
|
||||
|
||||
static struct hwbp *gdbmach_find_hwbp ( int type, unsigned long addr, size_t len ) {
|
||||
struct hwbp *available = NULL;
|
||||
unsigned int i;
|
||||
for ( i = 0; i < sizeof hwbps / sizeof hwbps [ 0 ]; i++ ) {
|
||||
if ( hwbps [ i ].type == type && hwbps [ i ].addr == addr && hwbps [ i ].len == len ) {
|
||||
return &hwbps [ i ];
|
||||
}
|
||||
if ( !hwbps [ i ].enabled ) {
|
||||
available = &hwbps [ i ];
|
||||
}
|
||||
}
|
||||
return available;
|
||||
}
|
||||
|
||||
static void gdbmach_commit_hwbp ( struct hwbp *bp ) {
|
||||
unsigned int regnum = bp - hwbps;
|
||||
|
||||
/* Set breakpoint address */
|
||||
assert ( regnum < ( sizeof hwbps / sizeof hwbps [ 0 ] ) );
|
||||
switch ( regnum ) {
|
||||
case 0:
|
||||
__asm__ __volatile__ ( "movl %0, %%dr0\n" : : "r" ( bp->addr ) );
|
||||
break;
|
||||
case 1:
|
||||
__asm__ __volatile__ ( "movl %0, %%dr1\n" : : "r" ( bp->addr ) );
|
||||
break;
|
||||
case 2:
|
||||
__asm__ __volatile__ ( "movl %0, %%dr2\n" : : "r" ( bp->addr ) );
|
||||
break;
|
||||
case 3:
|
||||
__asm__ __volatile__ ( "movl %0, %%dr3\n" : : "r" ( bp->addr ) );
|
||||
break;
|
||||
}
|
||||
|
||||
/* Set type */
|
||||
dr7 &= ~( 0x3 << ( 16 + 4 * regnum ) );
|
||||
dr7 |= bp->type << ( 16 + 4 * regnum );
|
||||
|
||||
/* Set length */
|
||||
dr7 &= ~( 0x3 << ( 18 + 4 * regnum ) );
|
||||
dr7 |= bp->len << ( 18 + 4 * regnum );
|
||||
|
||||
/* Set/clear local enable bit */
|
||||
dr7 &= ~( 0x3 << 2 * regnum );
|
||||
dr7 |= bp->enabled << 2 * regnum;
|
||||
}
|
||||
|
||||
int gdbmach_set_breakpoint ( int type, unsigned long addr, size_t len, int enable ) {
|
||||
struct hwbp *bp;
|
||||
|
||||
/* Check and convert breakpoint type to x86 type */
|
||||
switch ( type ) {
|
||||
case GDBMACH_WATCH:
|
||||
type = 0x1;
|
||||
break;
|
||||
case GDBMACH_AWATCH:
|
||||
type = 0x3;
|
||||
break;
|
||||
default:
|
||||
return 0; /* unsupported breakpoint type */
|
||||
}
|
||||
|
||||
/* Only lengths 1, 2, and 4 are supported */
|
||||
if ( len != 2 && len != 4 ) {
|
||||
len = 1;
|
||||
}
|
||||
len--; /* convert to x86 breakpoint length bit pattern */
|
||||
|
||||
/* Calculate linear address by adding segment base */
|
||||
addr += virt_offset;
|
||||
|
||||
/* Set up the breakpoint */
|
||||
bp = gdbmach_find_hwbp ( type, addr, len );
|
||||
if ( !bp ) {
|
||||
return 0; /* ran out of hardware breakpoints */
|
||||
}
|
||||
bp->type = type;
|
||||
bp->addr = addr;
|
||||
bp->len = len;
|
||||
bp->enabled = enable;
|
||||
gdbmach_commit_hwbp ( bp );
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void gdbmach_disable_hwbps ( void ) {
|
||||
/* Store and clear hardware breakpoints */
|
||||
__asm__ __volatile__ ( "movl %0, %%dr7\n" : : "r" ( DR7_CLEAR ) );
|
||||
}
|
||||
|
||||
static void gdbmach_enable_hwbps ( void ) {
|
||||
/* Clear breakpoint status register */
|
||||
__asm__ __volatile__ ( "movl %0, %%dr6\n" : : "r" ( DR6_CLEAR ) );
|
||||
|
||||
/* Restore hardware breakpoints */
|
||||
__asm__ __volatile__ ( "movl %0, %%dr7\n" : : "r" ( dr7 ) );
|
||||
}
|
||||
|
||||
__asmcall void gdbmach_handler ( int signo, gdbreg_t *regs ) {
|
||||
gdbmach_disable_hwbps();
|
||||
gdbstub_handler ( signo, regs );
|
||||
gdbmach_enable_hwbps();
|
||||
}
|
@@ -1,38 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2009 H. Peter Anvin <hpa@zytor.com>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER )
|
||||
|
||||
.text
|
||||
.arch i386
|
||||
.code16
|
||||
|
||||
/****************************************************************************
|
||||
* Set/clear CF on the stack as appropriate, assumes stack is as it should
|
||||
* be immediately before IRET
|
||||
****************************************************************************
|
||||
*/
|
||||
.section ".text16", "ax", @progbits
|
||||
.globl patch_cf
|
||||
patch_cf:
|
||||
pushw %bp
|
||||
movw %sp, %bp
|
||||
setc 8(%bp) /* Set/reset CF; clears PF, AF, ZF, SF */
|
||||
popw %bp
|
||||
ret
|
||||
.size patch_cf, . - patch_cf
|
@@ -1,66 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2007 Michael Brown <mbrown@fensystems.co.uk>.
|
||||
*
|
||||
* 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 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER );
|
||||
|
||||
#include <ipxe/io.h>
|
||||
#include <pic8259.h>
|
||||
|
||||
/** @file
|
||||
*
|
||||
* Minimal support for the 8259 Programmable Interrupt Controller
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Send non-specific EOI(s)
|
||||
*
|
||||
* @v irq IRQ number
|
||||
*
|
||||
* This seems to be inherently unsafe.
|
||||
*/
|
||||
static inline void send_nonspecific_eoi ( unsigned int irq ) {
|
||||
DBG ( "Sending non-specific EOI for IRQ %d\n", irq );
|
||||
if ( irq >= IRQ_PIC_CUTOFF ) {
|
||||
outb ( ICR_EOI_NON_SPECIFIC, PIC2_ICR );
|
||||
}
|
||||
outb ( ICR_EOI_NON_SPECIFIC, PIC1_ICR );
|
||||
}
|
||||
|
||||
/**
|
||||
* Send specific EOI(s)
|
||||
*
|
||||
* @v irq IRQ number
|
||||
*/
|
||||
static inline void send_specific_eoi ( unsigned int irq ) {
|
||||
DBG ( "Sending specific EOI for IRQ %d\n", irq );
|
||||
if ( irq >= IRQ_PIC_CUTOFF ) {
|
||||
outb ( ( ICR_EOI_SPECIFIC | ICR_VALUE ( CHAINED_IRQ ) ),
|
||||
ICR_REG ( CHAINED_IRQ ) );
|
||||
}
|
||||
outb ( ( ICR_EOI_SPECIFIC | ICR_VALUE ( irq ) ), ICR_REG ( irq ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Send End-Of-Interrupt to the PIC
|
||||
*
|
||||
* @v irq IRQ number
|
||||
*/
|
||||
void send_eoi ( unsigned int irq ) {
|
||||
send_specific_eoi ( irq );
|
||||
}
|
@@ -1,89 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Michael Brown <mbrown@fensystems.co.uk>.
|
||||
*
|
||||
* 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 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER );
|
||||
|
||||
/** @file
|
||||
*
|
||||
* RDTSC timer
|
||||
*
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <ipxe/timer.h>
|
||||
#include <ipxe/timer2.h>
|
||||
|
||||
/**
|
||||
* Number of TSC ticks per microsecond
|
||||
*
|
||||
* This is calibrated on the first use of the timer.
|
||||
*/
|
||||
static unsigned long rdtsc_ticks_per_usec;
|
||||
|
||||
/**
|
||||
* Delay for a fixed number of microseconds
|
||||
*
|
||||
* @v usecs Number of microseconds for which to delay
|
||||
*/
|
||||
static void rdtsc_udelay ( unsigned long usecs ) {
|
||||
unsigned long start;
|
||||
unsigned long elapsed;
|
||||
|
||||
/* Sanity guard, since we may divide by this */
|
||||
if ( ! usecs )
|
||||
usecs = 1;
|
||||
|
||||
start = currticks();
|
||||
if ( rdtsc_ticks_per_usec ) {
|
||||
/* Already calibrated; busy-wait until done */
|
||||
do {
|
||||
elapsed = ( currticks() - start );
|
||||
} while ( elapsed < ( usecs * rdtsc_ticks_per_usec ) );
|
||||
} else {
|
||||
/* Not yet calibrated; use timer2 and calibrate
|
||||
* based on result.
|
||||
*/
|
||||
timer2_udelay ( usecs );
|
||||
elapsed = ( currticks() - start );
|
||||
rdtsc_ticks_per_usec = ( elapsed / usecs );
|
||||
DBG ( "RDTSC timer calibrated: %ld ticks in %ld usecs "
|
||||
"(%ld MHz)\n", elapsed, usecs,
|
||||
( rdtsc_ticks_per_usec << TSC_SHIFT ) );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get number of ticks per second
|
||||
*
|
||||
* @ret ticks_per_sec Number of ticks per second
|
||||
*/
|
||||
static unsigned long rdtsc_ticks_per_sec ( void ) {
|
||||
|
||||
/* Calibrate timer, if not already done */
|
||||
if ( ! rdtsc_ticks_per_usec )
|
||||
udelay ( 1 );
|
||||
|
||||
/* Sanity check */
|
||||
assert ( rdtsc_ticks_per_usec != 0 );
|
||||
|
||||
return ( rdtsc_ticks_per_usec * 1000 * 1000 );
|
||||
}
|
||||
|
||||
PROVIDE_TIMER ( rdtsc, udelay, rdtsc_udelay );
|
||||
PROVIDE_TIMER_INLINE ( rdtsc, currticks );
|
||||
PROVIDE_TIMER ( rdtsc, ticks_per_sec, rdtsc_ticks_per_sec );
|
@@ -1,129 +0,0 @@
|
||||
#include <ipxe/io.h>
|
||||
#include <registers.h>
|
||||
|
||||
/*
|
||||
* Originally by Eric Biederman
|
||||
*
|
||||
* Heavily modified by Michael Brown
|
||||
*
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER );
|
||||
|
||||
/*
|
||||
* The linker passes in the symbol _max_align, which is the alignment
|
||||
* that we must preserve, in bytes.
|
||||
*
|
||||
*/
|
||||
extern char _max_align[];
|
||||
#define max_align ( ( unsigned int ) _max_align )
|
||||
|
||||
/* Linker symbols */
|
||||
extern char _textdata[];
|
||||
extern char _etextdata[];
|
||||
|
||||
/* within 1MB of 4GB is too close.
|
||||
* MAX_ADDR is the maximum address we can easily do DMA to.
|
||||
*
|
||||
* Not sure where this constraint comes from, but kept it from Eric's
|
||||
* old code - mcb30
|
||||
*/
|
||||
#define MAX_ADDR (0xfff00000UL)
|
||||
|
||||
/**
|
||||
* Relocate iPXE
|
||||
*
|
||||
* @v ix86 x86 register dump from prefix
|
||||
* @ret ix86 x86 registers to return to prefix
|
||||
*
|
||||
* This finds a suitable location for iPXE near the top of 32-bit
|
||||
* address space, and returns the physical address of the new location
|
||||
* to the prefix in %edi.
|
||||
*/
|
||||
__asmcall void relocate ( struct i386_all_regs *ix86 ) {
|
||||
struct memory_map memmap;
|
||||
unsigned long start, end, size, padded_size;
|
||||
unsigned long new_start, new_end;
|
||||
unsigned i;
|
||||
|
||||
/* Get memory map and current location */
|
||||
get_memmap ( &memmap );
|
||||
start = virt_to_phys ( _textdata );
|
||||
end = virt_to_phys ( _etextdata );
|
||||
size = ( end - start );
|
||||
padded_size = ( size + max_align - 1 );
|
||||
|
||||
DBG ( "Relocate: currently at [%lx,%lx)\n"
|
||||
"...need %lx bytes for %d-byte alignment\n",
|
||||
start, end, padded_size, max_align );
|
||||
|
||||
/* Walk through the memory map and find the highest address
|
||||
* below 4GB that iPXE will fit into.
|
||||
*/
|
||||
new_end = end;
|
||||
for ( i = 0 ; i < memmap.count ; i++ ) {
|
||||
struct memory_region *region = &memmap.regions[i];
|
||||
unsigned long r_start, r_end;
|
||||
|
||||
DBG ( "Considering [%llx,%llx)\n", region->start, region->end);
|
||||
|
||||
/* Truncate block to MAX_ADDR. This will be less than
|
||||
* 4GB, which means that we can get away with using
|
||||
* just 32-bit arithmetic after this stage.
|
||||
*/
|
||||
if ( region->start > MAX_ADDR ) {
|
||||
DBG ( "...starts after MAX_ADDR=%lx\n", MAX_ADDR );
|
||||
continue;
|
||||
}
|
||||
r_start = region->start;
|
||||
if ( region->end > MAX_ADDR ) {
|
||||
DBG ( "...end truncated to MAX_ADDR=%lx\n", MAX_ADDR );
|
||||
r_end = MAX_ADDR;
|
||||
} else {
|
||||
r_end = region->end;
|
||||
}
|
||||
DBG ( "...usable portion is [%lx,%lx)\n", r_start, r_end );
|
||||
|
||||
/* If we have rounded down r_end below r_ start, skip
|
||||
* this block.
|
||||
*/
|
||||
if ( r_end < r_start ) {
|
||||
DBG ( "...truncated to negative size\n" );
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Check that there is enough space to fit in iPXE */
|
||||
if ( ( r_end - r_start ) < size ) {
|
||||
DBG ( "...too small (need %lx bytes)\n", size );
|
||||
continue;
|
||||
}
|
||||
|
||||
/* If the start address of the iPXE we would
|
||||
* place in this block is higher than the end address
|
||||
* of the current highest block, use this block.
|
||||
*
|
||||
* Note that this avoids overlaps with the current
|
||||
* iPXE, as well as choosing the highest of all viable
|
||||
* blocks.
|
||||
*/
|
||||
if ( ( r_end - size ) > new_end ) {
|
||||
new_end = r_end;
|
||||
DBG ( "...new best block found.\n" );
|
||||
}
|
||||
}
|
||||
|
||||
/* Calculate new location of iPXE, and align it to the
|
||||
* required alignemnt.
|
||||
*/
|
||||
new_start = new_end - padded_size;
|
||||
new_start += ( start - new_start ) & ( max_align - 1 );
|
||||
new_end = new_start + size;
|
||||
|
||||
DBG ( "Relocating from [%lx,%lx) to [%lx,%lx)\n",
|
||||
start, end, new_start, new_end );
|
||||
|
||||
/* Let prefix know what to copy */
|
||||
ix86->regs.esi = start;
|
||||
ix86->regs.edi = new_start;
|
||||
ix86->regs.ecx = size;
|
||||
}
|
@@ -1,42 +1,64 @@
|
||||
/* setjmp and longjmp. Use of these functions is deprecated. */
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER )
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
|
||||
|
||||
.text
|
||||
.arch i386
|
||||
.code32
|
||||
|
||||
/**************************************************************************
|
||||
SETJMP - Save stack context for non-local goto
|
||||
**************************************************************************/
|
||||
|
||||
/* Must match jmp_buf structure layout */
|
||||
.struct 0
|
||||
env_retaddr: .long 0
|
||||
env_stack: .long 0
|
||||
env_ebx: .long 0
|
||||
env_esi: .long 0
|
||||
env_edi: .long 0
|
||||
env_ebp: .long 0
|
||||
.previous
|
||||
|
||||
/*
|
||||
* Save stack context for non-local goto
|
||||
*/
|
||||
.globl setjmp
|
||||
setjmp:
|
||||
movl 4(%esp),%ecx /* jmpbuf */
|
||||
movl 0(%esp),%edx /* return address */
|
||||
movl %edx,0(%ecx)
|
||||
movl %ebx,4(%ecx)
|
||||
movl %esp,8(%ecx)
|
||||
movl %ebp,12(%ecx)
|
||||
movl %esi,16(%ecx)
|
||||
movl %edi,20(%ecx)
|
||||
movl $0,%eax
|
||||
/* Get jmp_buf pointer in %edx */
|
||||
movl 4(%esp),%edx
|
||||
/* Save return address */
|
||||
movl 0(%esp),%eax
|
||||
movl %eax, env_retaddr(%edx)
|
||||
/* Save stack pointer */
|
||||
movl %esp, env_stack(%edx)
|
||||
/* Save other registers */
|
||||
movl %ebx, env_ebx(%edx)
|
||||
movl %esi, env_esi(%edx)
|
||||
movl %edi, env_edi(%edx)
|
||||
movl %ebp, env_ebp(%edx)
|
||||
/* Return 0 when returning as setjmp() */
|
||||
xorl %eax, %eax
|
||||
ret
|
||||
.size setjmp, . - setjmp
|
||||
|
||||
/**************************************************************************
|
||||
LONGJMP - Non-local jump to a saved stack context
|
||||
**************************************************************************/
|
||||
/*
|
||||
* Non-local jump to a saved stack context
|
||||
*/
|
||||
.globl longjmp
|
||||
longjmp:
|
||||
movl 4(%esp),%edx /* jumpbuf */
|
||||
movl 8(%esp),%eax /* result */
|
||||
movl 0(%edx),%ecx
|
||||
movl 4(%edx),%ebx
|
||||
movl 8(%edx),%esp
|
||||
movl 12(%edx),%ebp
|
||||
movl 16(%edx),%esi
|
||||
movl 20(%edx),%edi
|
||||
cmpl $0,%eax
|
||||
jne 1f
|
||||
movl $1,%eax
|
||||
1: movl %ecx,0(%esp)
|
||||
/* Get jmp_buf pointer in %edx */
|
||||
movl 4(%esp),%edx
|
||||
/* Get result in %eax */
|
||||
movl 8(%esp),%eax
|
||||
/* Force result to non-zero */
|
||||
testl %eax, %eax
|
||||
jnz 1f
|
||||
incl %eax
|
||||
1: /* Restore stack pointer */
|
||||
movl env_stack(%edx), %esp
|
||||
/* Restore other registers */
|
||||
movl env_ebx(%edx), %ebx
|
||||
movl env_esi(%edx), %esi
|
||||
movl env_edi(%edx), %edi
|
||||
movl env_ebp(%edx), %ebp
|
||||
/* Replace return address on the new stack */
|
||||
popl %ecx /* discard */
|
||||
pushl env_retaddr(%edx)
|
||||
/* Return to setjmp() caller */
|
||||
ret
|
||||
.size longjmp, . - longjmp
|
||||
|
@@ -1,15 +0,0 @@
|
||||
FILE_LICENCE ( GPL2_OR_LATER )
|
||||
|
||||
.arch i386
|
||||
|
||||
/****************************************************************************
|
||||
* Internal stack
|
||||
****************************************************************************
|
||||
*/
|
||||
.section ".stack", "aw", @nobits
|
||||
.align 8
|
||||
.globl _stack
|
||||
_stack:
|
||||
.space 4096
|
||||
.globl _estack
|
||||
_estack:
|
@@ -1,15 +0,0 @@
|
||||
FILE_LICENCE ( GPL2_OR_LATER )
|
||||
|
||||
.arch i386
|
||||
|
||||
/****************************************************************************
|
||||
* Internal stack
|
||||
****************************************************************************
|
||||
*/
|
||||
.section ".stack16", "aw", @nobits
|
||||
.align 8
|
||||
.globl _stack16
|
||||
_stack16:
|
||||
.space 4096
|
||||
.globl _estack16
|
||||
_estack16:
|
@@ -1,87 +0,0 @@
|
||||
/*
|
||||
* arch/i386/core/i386_timer.c
|
||||
*
|
||||
* Use the "System Timer 2" to implement the udelay callback in
|
||||
* the BIOS timer driver. Also used to calibrate the clock rate
|
||||
* in the RTDSC timer driver.
|
||||
*
|
||||
* 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, or (at
|
||||
* your option) any later version.
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER );
|
||||
|
||||
#include <stddef.h>
|
||||
#include <ipxe/timer2.h>
|
||||
#include <ipxe/io.h>
|
||||
|
||||
/* Timers tick over at this rate */
|
||||
#define TIMER2_TICKS_PER_SEC 1193180U
|
||||
|
||||
/* Parallel Peripheral Controller Port B */
|
||||
#define PPC_PORTB 0x61
|
||||
|
||||
/* Meaning of the port bits */
|
||||
#define PPCB_T2OUT 0x20 /* Bit 5 */
|
||||
#define PPCB_SPKR 0x02 /* Bit 1 */
|
||||
#define PPCB_T2GATE 0x01 /* Bit 0 */
|
||||
|
||||
/* Ports for the 8254 timer chip */
|
||||
#define TIMER2_PORT 0x42
|
||||
#define TIMER_MODE_PORT 0x43
|
||||
|
||||
/* Meaning of the mode bits */
|
||||
#define TIMER0_SEL 0x00
|
||||
#define TIMER1_SEL 0x40
|
||||
#define TIMER2_SEL 0x80
|
||||
#define READBACK_SEL 0xC0
|
||||
|
||||
#define LATCH_COUNT 0x00
|
||||
#define LOBYTE_ACCESS 0x10
|
||||
#define HIBYTE_ACCESS 0x20
|
||||
#define WORD_ACCESS 0x30
|
||||
|
||||
#define MODE0 0x00
|
||||
#define MODE1 0x02
|
||||
#define MODE2 0x04
|
||||
#define MODE3 0x06
|
||||
#define MODE4 0x08
|
||||
#define MODE5 0x0A
|
||||
|
||||
#define BINARY_COUNT 0x00
|
||||
#define BCD_COUNT 0x01
|
||||
|
||||
static void load_timer2 ( unsigned int ticks ) {
|
||||
/*
|
||||
* Now let's take care of PPC channel 2
|
||||
*
|
||||
* Set the Gate high, program PPC channel 2 for mode 0,
|
||||
* (interrupt on terminal count mode), binary count,
|
||||
* load 5 * LATCH count, (LSB and MSB) to begin countdown.
|
||||
*
|
||||
* Note some implementations have a bug where the high bits byte
|
||||
* of channel 2 is ignored.
|
||||
*/
|
||||
/* Set up the timer gate, turn off the speaker */
|
||||
/* Set the Gate high, disable speaker */
|
||||
outb((inb(PPC_PORTB) & ~PPCB_SPKR) | PPCB_T2GATE, PPC_PORTB);
|
||||
/* binary, mode 0, LSB/MSB, Ch 2 */
|
||||
outb(TIMER2_SEL|WORD_ACCESS|MODE0|BINARY_COUNT, TIMER_MODE_PORT);
|
||||
/* LSB of ticks */
|
||||
outb(ticks & 0xFF, TIMER2_PORT);
|
||||
/* MSB of ticks */
|
||||
outb(ticks >> 8, TIMER2_PORT);
|
||||
}
|
||||
|
||||
static int timer2_running ( void ) {
|
||||
return ((inb(PPC_PORTB) & PPCB_T2OUT) == 0);
|
||||
}
|
||||
|
||||
void timer2_udelay ( unsigned long usecs ) {
|
||||
load_timer2 ( ( usecs * TIMER2_TICKS_PER_SEC ) / ( 1000 * 1000 ) );
|
||||
while (timer2_running()) {
|
||||
/* Do nothing */
|
||||
}
|
||||
}
|
@@ -1,104 +0,0 @@
|
||||
/*
|
||||
*
|
||||
* modified from linuxbios code
|
||||
* by Cai Qiang <rimy2000@hotmail.com>
|
||||
*
|
||||
*/
|
||||
|
||||
#include "stddef.h"
|
||||
#include "string.h"
|
||||
#include <ipxe/io.h>
|
||||
#include "console.h"
|
||||
#include <ipxe/init.h>
|
||||
#include "vga.h"
|
||||
|
||||
struct console_driver vga_console __console_driver;
|
||||
|
||||
static char *vidmem; /* The video buffer */
|
||||
static int video_line, video_col;
|
||||
|
||||
#define VIDBUFFER 0xB8000
|
||||
|
||||
static void memsetw(void *s, int c, unsigned int n)
|
||||
{
|
||||
unsigned int i;
|
||||
u16 *ss = (u16 *) s;
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
ss[i] = ( u16 ) c;
|
||||
}
|
||||
}
|
||||
|
||||
static void video_init(void)
|
||||
{
|
||||
static int inited=0;
|
||||
|
||||
vidmem = (char *)phys_to_virt(VIDBUFFER);
|
||||
|
||||
if (!inited) {
|
||||
video_line = 0;
|
||||
video_col = 0;
|
||||
|
||||
memsetw(vidmem, VGA_ATTR_CLR_WHT, 2*1024); //
|
||||
|
||||
inited=1;
|
||||
}
|
||||
}
|
||||
|
||||
static void video_scroll(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
memcpy(vidmem, vidmem + COLS * 2, (LINES - 1) * COLS * 2);
|
||||
for (i = (LINES - 1) * COLS * 2; i < LINES * COLS * 2; i += 2)
|
||||
vidmem[i] = ' ';
|
||||
}
|
||||
|
||||
static void vga_putc(int byte)
|
||||
{
|
||||
if (byte == '\n') {
|
||||
video_line++;
|
||||
video_col = 0;
|
||||
|
||||
} else if (byte == '\r') {
|
||||
video_col = 0;
|
||||
|
||||
} else if (byte == '\b') {
|
||||
video_col--;
|
||||
|
||||
} else if (byte == '\t') {
|
||||
video_col += 4;
|
||||
|
||||
} else if (byte == '\a') {
|
||||
//beep
|
||||
//beep(500);
|
||||
|
||||
} else {
|
||||
vidmem[((video_col + (video_line *COLS)) * 2)] = byte;
|
||||
vidmem[((video_col + (video_line *COLS)) * 2) +1] = VGA_ATTR_CLR_WHT;
|
||||
video_col++;
|
||||
}
|
||||
if (video_col < 0) {
|
||||
video_col = 0;
|
||||
}
|
||||
if (video_col >= COLS) {
|
||||
video_line++;
|
||||
video_col = 0;
|
||||
}
|
||||
if (video_line >= LINES) {
|
||||
video_scroll();
|
||||
video_line--;
|
||||
}
|
||||
// move the cursor
|
||||
write_crtc((video_col + (video_line *COLS)) >> 8, CRTC_CURSOR_HI);
|
||||
write_crtc((video_col + (video_line *COLS)) & 0x0ff, CRTC_CURSOR_LO);
|
||||
}
|
||||
|
||||
struct console_driver vga_console __console_driver = {
|
||||
.putchar = vga_putc,
|
||||
.disabled = 1,
|
||||
};
|
||||
|
||||
struct init_fn video_init_fn __init_fn ( INIT_EARLY ) = {
|
||||
.initialise = video_init,
|
||||
};
|
@@ -1,103 +0,0 @@
|
||||
/*
|
||||
* Functions to support the virtual addressing method of relocation
|
||||
* that Etherboot uses.
|
||||
*
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER )
|
||||
|
||||
#include "librm.h"
|
||||
|
||||
.arch i386
|
||||
.text
|
||||
.code32
|
||||
|
||||
/****************************************************************************
|
||||
* _virt_to_phys (virtual addressing)
|
||||
*
|
||||
* Switch from virtual to flat physical addresses. %esp is adjusted
|
||||
* to a physical value. Segment registers are set to flat physical
|
||||
* selectors. All other registers are preserved. Flags are
|
||||
* preserved.
|
||||
*
|
||||
* Parameters: none
|
||||
* Returns: none
|
||||
****************************************************************************
|
||||
*/
|
||||
.globl _virt_to_phys
|
||||
_virt_to_phys:
|
||||
/* Preserve registers and flags */
|
||||
pushfl
|
||||
pushl %eax
|
||||
pushl %ebp
|
||||
|
||||
/* Change return address to a physical address */
|
||||
movl virt_offset, %ebp
|
||||
addl %ebp, 12(%esp)
|
||||
|
||||
/* Switch to physical code segment */
|
||||
pushl $PHYSICAL_CS
|
||||
leal 1f(%ebp), %eax
|
||||
pushl %eax
|
||||
lret
|
||||
1:
|
||||
/* Reload other segment registers and adjust %esp */
|
||||
movl $PHYSICAL_DS, %eax
|
||||
movl %eax, %ds
|
||||
movl %eax, %es
|
||||
movl %eax, %fs
|
||||
movl %eax, %gs
|
||||
movl %eax, %ss
|
||||
addl %ebp, %esp
|
||||
|
||||
/* Restore registers and flags, and return */
|
||||
popl %ebp
|
||||
popl %eax
|
||||
popfl
|
||||
ret
|
||||
|
||||
/****************************************************************************
|
||||
* _phys_to_virt (flat physical addressing)
|
||||
*
|
||||
* Switch from flat physical to virtual addresses. %esp is adjusted
|
||||
* to a virtual value. Segment registers are set to virtual
|
||||
* selectors. All other registers are preserved. Flags are
|
||||
* preserved.
|
||||
*
|
||||
* Note that this depends on the GDT already being correctly set up
|
||||
* (e.g. by a call to run_here()).
|
||||
*
|
||||
* Parameters: none
|
||||
* Returns: none
|
||||
****************************************************************************
|
||||
*/
|
||||
.globl _phys_to_virt
|
||||
_phys_to_virt:
|
||||
/* Preserve registers and flags */
|
||||
pushfl
|
||||
pushl %eax
|
||||
pushl %ebp
|
||||
|
||||
/* Switch to virtual code segment */
|
||||
ljmp $VIRTUAL_CS, $1f
|
||||
1:
|
||||
/* Reload data segment registers */
|
||||
movl $VIRTUAL_DS, %eax
|
||||
movl %eax, %ds
|
||||
movl %eax, %es
|
||||
movl %eax, %fs
|
||||
movl %eax, %gs
|
||||
|
||||
/* Reload stack segment and adjust %esp */
|
||||
movl virt_offset, %ebp
|
||||
movl %eax, %ss
|
||||
subl %ebp, %esp
|
||||
|
||||
/* Change the return address to a virtual address */
|
||||
subl %ebp, 12(%esp)
|
||||
|
||||
/* Restore registers and flags, and return */
|
||||
popl %ebp
|
||||
popl %eax
|
||||
popfl
|
||||
ret
|
@@ -1,273 +0,0 @@
|
||||
#define LOAD_DEBUG 0
|
||||
|
||||
static int get_x_header(unsigned char *data, unsigned long now);
|
||||
static void jump_2ep();
|
||||
static unsigned char ce_signature[] = {'B', '0', '0', '0', 'F', 'F', '\n',};
|
||||
static char ** ep;
|
||||
|
||||
#define BOOT_ARG_PTR_LOCATION 0x001FFFFC
|
||||
|
||||
typedef struct _BOOT_ARGS{
|
||||
unsigned char ucVideoMode;
|
||||
unsigned char ucComPort;
|
||||
unsigned char ucBaudDivisor;
|
||||
unsigned char ucPCIConfigType;
|
||||
|
||||
unsigned long dwSig;
|
||||
#define BOOTARG_SIG 0x544F4F42
|
||||
unsigned long dwLen;
|
||||
|
||||
unsigned char ucLoaderFlags;
|
||||
unsigned char ucEshellFlags;
|
||||
unsigned char ucEdbgAdapterType;
|
||||
unsigned char ucEdbgIRQ;
|
||||
|
||||
unsigned long dwEdbgBaseAddr;
|
||||
unsigned long dwEdbgDebugZone;
|
||||
unsigned long dwDHCPLeaseTime;
|
||||
unsigned long dwEdbgFlags;
|
||||
|
||||
unsigned long dwEBootFlag;
|
||||
unsigned long dwEBootAddr;
|
||||
unsigned long dwLaunchAddr;
|
||||
|
||||
unsigned long pvFlatFrameBuffer;
|
||||
unsigned short vesaMode;
|
||||
unsigned short cxDisplayScreen;
|
||||
unsigned short cyDisplayScreen;
|
||||
unsigned short cxPhysicalScreen;
|
||||
unsigned short cyPhysicalScreen;
|
||||
unsigned short cbScanLineLength;
|
||||
unsigned short bppScreen;
|
||||
|
||||
unsigned char RedMaskSize;
|
||||
unsigned char REdMaskPosition;
|
||||
unsigned char GreenMaskSize;
|
||||
unsigned char GreenMaskPosition;
|
||||
unsigned char BlueMaskSize;
|
||||
unsigned char BlueMaskPosition;
|
||||
} BOOT_ARGS;
|
||||
|
||||
BOOT_ARGS BootArgs;
|
||||
|
||||
static struct segment_info{
|
||||
unsigned long addr; // Section Address
|
||||
unsigned long size; // Section Size
|
||||
unsigned long checksum; // Section CheckSum
|
||||
} X;
|
||||
|
||||
#define PSIZE (1500) //Max Packet Size
|
||||
#define DSIZE (PSIZE+12)
|
||||
static unsigned long dbuffer_available =0;
|
||||
static unsigned long not_loadin =0;
|
||||
static unsigned long d_now =0;
|
||||
|
||||
unsigned long entry;
|
||||
static unsigned long ce_curaddr;
|
||||
|
||||
|
||||
static sector_t ce_loader(unsigned char *data, unsigned int len, int eof);
|
||||
static os_download_t wince_probe(unsigned char *data, unsigned int len)
|
||||
{
|
||||
if (strncmp(ce_signature, data, sizeof(ce_signature)) != 0) {
|
||||
return 0;
|
||||
}
|
||||
printf("(WINCE)");
|
||||
return ce_loader;
|
||||
}
|
||||
|
||||
static sector_t ce_loader(unsigned char *data, unsigned int len, int eof)
|
||||
{
|
||||
static unsigned char dbuffer[DSIZE];
|
||||
int this_write = 0;
|
||||
static int firsttime = 1;
|
||||
|
||||
/*
|
||||
* new packet in, we have to
|
||||
* [1] copy data to dbuffer,
|
||||
*
|
||||
* update...
|
||||
* [2] dbuffer_available
|
||||
*/
|
||||
memcpy( (dbuffer+dbuffer_available), data, len); //[1]
|
||||
dbuffer_available += len; // [2]
|
||||
len = 0;
|
||||
|
||||
d_now = 0;
|
||||
|
||||
#if 0
|
||||
printf("dbuffer_available =%ld \n", dbuffer_available);
|
||||
#endif
|
||||
|
||||
if (firsttime)
|
||||
{
|
||||
d_now = sizeof(ce_signature);
|
||||
printf("String Physical Address = %lx \n",
|
||||
*(unsigned long *)(dbuffer+d_now));
|
||||
|
||||
d_now += sizeof(unsigned long);
|
||||
printf("Image Size = %ld [%lx]\n",
|
||||
*(unsigned long *)(dbuffer+d_now),
|
||||
*(unsigned long *)(dbuffer+d_now));
|
||||
|
||||
d_now += sizeof(unsigned long);
|
||||
dbuffer_available -= d_now;
|
||||
|
||||
d_now = (unsigned long)get_x_header(dbuffer, d_now);
|
||||
firsttime = 0;
|
||||
}
|
||||
|
||||
if (not_loadin == 0)
|
||||
{
|
||||
d_now = get_x_header(dbuffer, d_now);
|
||||
}
|
||||
|
||||
while ( not_loadin > 0 )
|
||||
{
|
||||
/* dbuffer do not have enough data to loading, copy all */
|
||||
#if LOAD_DEBUG
|
||||
printf("[0] not_loadin = [%ld], dbuffer_available = [%ld] \n",
|
||||
not_loadin, dbuffer_available);
|
||||
printf("[0] d_now = [%ld] \n", d_now);
|
||||
#endif
|
||||
|
||||
if( dbuffer_available <= not_loadin)
|
||||
{
|
||||
this_write = dbuffer_available ;
|
||||
memcpy(phys_to_virt(ce_curaddr), (dbuffer+d_now), this_write );
|
||||
ce_curaddr += this_write;
|
||||
not_loadin -= this_write;
|
||||
|
||||
/* reset index and available in the dbuffer */
|
||||
dbuffer_available = 0;
|
||||
d_now = 0;
|
||||
#if LOAD_DEBUG
|
||||
printf("[1] not_loadin = [%ld], dbuffer_available = [%ld] \n",
|
||||
not_loadin, dbuffer_available);
|
||||
printf("[1] d_now = [%ld], this_write = [%d] \n",
|
||||
d_now, this_write);
|
||||
#endif
|
||||
|
||||
// get the next packet...
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* dbuffer have more data then loading ... , copy partital.... */
|
||||
else
|
||||
{
|
||||
this_write = not_loadin;
|
||||
memcpy(phys_to_virt(ce_curaddr), (dbuffer+d_now), this_write);
|
||||
ce_curaddr += this_write;
|
||||
not_loadin = 0;
|
||||
|
||||
/* reset index and available in the dbuffer */
|
||||
dbuffer_available -= this_write;
|
||||
d_now += this_write;
|
||||
#if LOAD_DEBUG
|
||||
printf("[2] not_loadin = [%ld], dbuffer_available = [%ld] \n",
|
||||
not_loadin, dbuffer_available);
|
||||
printf("[2] d_now = [%ld], this_write = [%d] \n\n",
|
||||
d_now, this_write);
|
||||
#endif
|
||||
|
||||
/* dbuffer not empty, proceed processing... */
|
||||
|
||||
// don't have enough data to get_x_header..
|
||||
if ( dbuffer_available < (sizeof(unsigned long) * 3) )
|
||||
{
|
||||
// printf("we don't have enough data remaining to call get_x. \n");
|
||||
memcpy( (dbuffer+0), (dbuffer+d_now), dbuffer_available);
|
||||
return (0);
|
||||
}
|
||||
else
|
||||
{
|
||||
#if LOAD_DEBUG
|
||||
printf("with remaining data to call get_x \n");
|
||||
printf("dbuffer available = %ld , d_now = %ld\n",
|
||||
dbuffer_available, d_now);
|
||||
#endif
|
||||
d_now = get_x_header(dbuffer, d_now);
|
||||
}
|
||||
}
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int get_x_header(unsigned char *dbuffer, unsigned long now)
|
||||
{
|
||||
X.addr = *(unsigned long *)(dbuffer + now);
|
||||
X.size = *(unsigned long *)(dbuffer + now + sizeof(unsigned long));
|
||||
X.checksum = *(unsigned long *)(dbuffer + now + sizeof(unsigned long)*2);
|
||||
|
||||
if (X.addr == 0)
|
||||
{
|
||||
entry = X.size;
|
||||
done(1);
|
||||
printf("Entry Point Address = [%lx] \n", entry);
|
||||
jump_2ep();
|
||||
}
|
||||
|
||||
if (!prep_segment(X.addr, X.addr + X.size, X.addr + X.size, 0, 0)) {
|
||||
longjmp(restart_etherboot, -2);
|
||||
}
|
||||
|
||||
ce_curaddr = X.addr;
|
||||
now += sizeof(unsigned long)*3;
|
||||
|
||||
/* re-calculate dbuffer available... */
|
||||
dbuffer_available -= sizeof(unsigned long)*3;
|
||||
|
||||
/* reset index of this section */
|
||||
not_loadin = X.size;
|
||||
|
||||
#if 1
|
||||
printf("\n");
|
||||
printf("\t Section Address = [%lx] \n", X.addr);
|
||||
printf("\t Size = %d [%lx]\n", X.size, X.size);
|
||||
printf("\t Checksum = %ld [%lx]\n", X.checksum, X.checksum);
|
||||
#endif
|
||||
#if LOAD_DEBUG
|
||||
printf("____________________________________________\n");
|
||||
printf("\t dbuffer_now = %ld \n", now);
|
||||
printf("\t dbuffer available = %ld \n", dbuffer_available);
|
||||
printf("\t not_loadin = %ld \n", not_loadin);
|
||||
#endif
|
||||
|
||||
return now;
|
||||
}
|
||||
|
||||
static void jump_2ep()
|
||||
{
|
||||
BootArgs.ucVideoMode = 1;
|
||||
BootArgs.ucComPort = 1;
|
||||
BootArgs.ucBaudDivisor = 1;
|
||||
BootArgs.ucPCIConfigType = 1; // do not fill with 0
|
||||
|
||||
BootArgs.dwSig = BOOTARG_SIG;
|
||||
BootArgs.dwLen = sizeof(BootArgs);
|
||||
|
||||
if(BootArgs.ucVideoMode == 0)
|
||||
{
|
||||
BootArgs.cxDisplayScreen = 640;
|
||||
BootArgs.cyDisplayScreen = 480;
|
||||
BootArgs.cxPhysicalScreen = 640;
|
||||
BootArgs.cyPhysicalScreen = 480;
|
||||
BootArgs.bppScreen = 16;
|
||||
BootArgs.cbScanLineLength = 1024;
|
||||
BootArgs.pvFlatFrameBuffer = 0x800a0000; // ollie say 0x98000000
|
||||
}
|
||||
else if(BootArgs.ucVideoMode != 0xFF)
|
||||
{
|
||||
BootArgs.cxDisplayScreen = 0;
|
||||
BootArgs.cyDisplayScreen = 0;
|
||||
BootArgs.cxPhysicalScreen = 0;
|
||||
BootArgs.cyPhysicalScreen = 0;
|
||||
BootArgs.bppScreen = 0;
|
||||
BootArgs.cbScanLineLength = 0;
|
||||
BootArgs.pvFlatFrameBuffer = 0;
|
||||
}
|
||||
|
||||
ep = phys_to_virt(BOOT_ARG_PTR_LOCATION);
|
||||
*ep= virt_to_phys(&BootArgs);
|
||||
xstart32(entry);
|
||||
}
|
@@ -1,96 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Michael Brown <mbrown@fensystems.co.uk>.
|
||||
*
|
||||
* 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 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER );
|
||||
|
||||
#include <ipxe/io.h>
|
||||
#include <ipxe/x86_io.h>
|
||||
|
||||
/** @file
|
||||
*
|
||||
* iPXE I/O API for x86
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Read 64-bit qword from memory-mapped device
|
||||
*
|
||||
* @v io_addr I/O address
|
||||
* @ret data Value read
|
||||
*
|
||||
* This routine uses MMX instructions.
|
||||
*/
|
||||
static uint64_t x86_readq ( volatile uint64_t *io_addr ) {
|
||||
uint64_t data;
|
||||
__asm__ __volatile__ ( "pushl %%edx\n\t"
|
||||
"pushl %%eax\n\t"
|
||||
"movq (%1), %%mm0\n\t"
|
||||
"movq %%mm0, (%%esp)\n\t"
|
||||
"popl %%eax\n\t"
|
||||
"popl %%edx\n\t"
|
||||
"emms\n\t"
|
||||
: "=A" ( data ) : "r" ( io_addr ) );
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write 64-bit qword to memory-mapped device
|
||||
*
|
||||
* @v data Value to write
|
||||
* @v io_addr I/O address
|
||||
*
|
||||
* This routine uses MMX instructions.
|
||||
*/
|
||||
static void x86_writeq ( uint64_t data, volatile uint64_t *io_addr ) {
|
||||
__asm__ __volatile__ ( "pushl %%edx\n\t"
|
||||
"pushl %%eax\n\t"
|
||||
"movq (%%esp), %%mm0\n\t"
|
||||
"movq %%mm0, (%1)\n\t"
|
||||
"popl %%eax\n\t"
|
||||
"popl %%edx\n\t"
|
||||
"emms\n\t"
|
||||
: : "A" ( data ), "r" ( io_addr ) );
|
||||
}
|
||||
|
||||
PROVIDE_IOAPI_INLINE ( x86, phys_to_bus );
|
||||
PROVIDE_IOAPI_INLINE ( x86, bus_to_phys );
|
||||
PROVIDE_IOAPI_INLINE ( x86, ioremap );
|
||||
PROVIDE_IOAPI_INLINE ( x86, iounmap );
|
||||
PROVIDE_IOAPI_INLINE ( x86, io_to_bus );
|
||||
PROVIDE_IOAPI_INLINE ( x86, readb );
|
||||
PROVIDE_IOAPI_INLINE ( x86, readw );
|
||||
PROVIDE_IOAPI_INLINE ( x86, readl );
|
||||
PROVIDE_IOAPI ( x86, readq, x86_readq );
|
||||
PROVIDE_IOAPI_INLINE ( x86, writeb );
|
||||
PROVIDE_IOAPI_INLINE ( x86, writew );
|
||||
PROVIDE_IOAPI_INLINE ( x86, writel );
|
||||
PROVIDE_IOAPI ( x86, writeq, x86_writeq );
|
||||
PROVIDE_IOAPI_INLINE ( x86, inb );
|
||||
PROVIDE_IOAPI_INLINE ( x86, inw );
|
||||
PROVIDE_IOAPI_INLINE ( x86, inl );
|
||||
PROVIDE_IOAPI_INLINE ( x86, outb );
|
||||
PROVIDE_IOAPI_INLINE ( x86, outw );
|
||||
PROVIDE_IOAPI_INLINE ( x86, outl );
|
||||
PROVIDE_IOAPI_INLINE ( x86, insb );
|
||||
PROVIDE_IOAPI_INLINE ( x86, insw );
|
||||
PROVIDE_IOAPI_INLINE ( x86, insl );
|
||||
PROVIDE_IOAPI_INLINE ( x86, outsb );
|
||||
PROVIDE_IOAPI_INLINE ( x86, outsw );
|
||||
PROVIDE_IOAPI_INLINE ( x86, outsl );
|
||||
PROVIDE_IOAPI_INLINE ( x86, iodelay );
|
||||
PROVIDE_IOAPI_INLINE ( x86, mb );
|
@@ -1,148 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2007 Michael Brown <mbrown@fensystems.co.uk>.
|
||||
*
|
||||
* 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 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER );
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <ipxe/pci.h>
|
||||
#include <undi.h>
|
||||
#include <undirom.h>
|
||||
#include <undiload.h>
|
||||
#include <undinet.h>
|
||||
#include <undipreload.h>
|
||||
|
||||
/** @file
|
||||
*
|
||||
* UNDI PCI driver
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Find UNDI ROM for PCI device
|
||||
*
|
||||
* @v pci PCI device
|
||||
* @ret undirom UNDI ROM, or NULL
|
||||
*
|
||||
* Try to find a driver for this device. Try an exact match on the
|
||||
* ROM address first, then fall back to a vendor/device ID match only
|
||||
*/
|
||||
static struct undi_rom * undipci_find_rom ( struct pci_device *pci ) {
|
||||
struct undi_rom *undirom;
|
||||
unsigned long rombase;
|
||||
|
||||
rombase = pci_bar_start ( pci, PCI_ROM_ADDRESS );
|
||||
undirom = undirom_find_pci ( pci->vendor, pci->device, rombase );
|
||||
if ( ! undirom )
|
||||
undirom = undirom_find_pci ( pci->vendor, pci->device, 0 );
|
||||
return undirom;
|
||||
}
|
||||
|
||||
/**
|
||||
* Probe PCI device
|
||||
*
|
||||
* @v pci PCI device
|
||||
* @v id PCI ID
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int undipci_probe ( struct pci_device *pci,
|
||||
const struct pci_device_id *id __unused ) {
|
||||
struct undi_device *undi;
|
||||
struct undi_rom *undirom;
|
||||
unsigned int busdevfn = PCI_BUSDEVFN ( pci->bus, pci->devfn );
|
||||
int rc;
|
||||
|
||||
/* Ignore non-network devices */
|
||||
if ( PCI_BASE_CLASS ( pci->class ) != PCI_BASE_CLASS_NETWORK )
|
||||
return -ENOTTY;
|
||||
|
||||
/* Allocate UNDI device structure */
|
||||
undi = zalloc ( sizeof ( *undi ) );
|
||||
if ( ! undi )
|
||||
return -ENOMEM;
|
||||
pci_set_drvdata ( pci, undi );
|
||||
|
||||
/* Find/create our pixie */
|
||||
if ( preloaded_undi.pci_busdevfn == busdevfn ) {
|
||||
/* Claim preloaded UNDI device */
|
||||
DBGC ( undi, "UNDI %p using preloaded UNDI device\n", undi );
|
||||
memcpy ( undi, &preloaded_undi, sizeof ( *undi ) );
|
||||
memset ( &preloaded_undi, 0, sizeof ( preloaded_undi ) );
|
||||
} else {
|
||||
/* Find UNDI ROM for PCI device */
|
||||
if ( ! ( undirom = undipci_find_rom ( pci ) ) ) {
|
||||
rc = -ENODEV;
|
||||
goto err_find_rom;
|
||||
}
|
||||
|
||||
/* Call UNDI ROM loader to create pixie */
|
||||
if ( ( rc = undi_load_pci ( undi, undirom, busdevfn ) ) != 0 )
|
||||
goto err_load_pci;
|
||||
}
|
||||
|
||||
/* Add to device hierarchy */
|
||||
snprintf ( undi->dev.name, sizeof ( undi->dev.name ),
|
||||
"UNDI-%s", pci->dev.name );
|
||||
memcpy ( &undi->dev.desc, &pci->dev.desc, sizeof ( undi->dev.desc ) );
|
||||
undi->dev.parent = &pci->dev;
|
||||
INIT_LIST_HEAD ( &undi->dev.children );
|
||||
list_add ( &undi->dev.siblings, &pci->dev.children );
|
||||
|
||||
/* Create network device */
|
||||
if ( ( rc = undinet_probe ( undi ) ) != 0 )
|
||||
goto err_undinet_probe;
|
||||
|
||||
return 0;
|
||||
|
||||
err_undinet_probe:
|
||||
undi_unload ( undi );
|
||||
list_del ( &undi->dev.siblings );
|
||||
err_find_rom:
|
||||
err_load_pci:
|
||||
free ( undi );
|
||||
pci_set_drvdata ( pci, NULL );
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove PCI device
|
||||
*
|
||||
* @v pci PCI device
|
||||
*/
|
||||
static void undipci_remove ( struct pci_device *pci ) {
|
||||
struct undi_device *undi = pci_get_drvdata ( pci );
|
||||
|
||||
undinet_remove ( undi );
|
||||
undi_unload ( undi );
|
||||
list_del ( &undi->dev.siblings );
|
||||
free ( undi );
|
||||
pci_set_drvdata ( pci, NULL );
|
||||
}
|
||||
|
||||
static struct pci_device_id undipci_nics[] = {
|
||||
PCI_ROM ( 0xffff, 0xffff, "undipci", "UNDI (PCI)", 0 ),
|
||||
};
|
||||
|
||||
struct pci_driver undipci_driver __pci_driver = {
|
||||
.ids = undipci_nics,
|
||||
.id_count = ( sizeof ( undipci_nics ) / sizeof ( undipci_nics[0] ) ),
|
||||
.probe = undipci_probe,
|
||||
.remove = undipci_remove,
|
||||
};
|
@@ -1,87 +0,0 @@
|
||||
FILE_LICENCE ( GPL2_OR_LATER )
|
||||
|
||||
#define PXENV_UNDI_ISR 0x0014
|
||||
#define PXENV_UNDI_ISR_IN_START 1
|
||||
#define PXENV_UNDI_ISR_OUT_OURS 0
|
||||
#define PXENV_UNDI_ISR_OUT_NOT_OURS 1
|
||||
|
||||
#define IRQ_PIC_CUTOFF 8
|
||||
#define ICR_EOI_NON_SPECIFIC 0x20
|
||||
#define PIC1_ICR 0x20
|
||||
#define PIC2_ICR 0xa0
|
||||
|
||||
.text
|
||||
.arch i386
|
||||
.code16
|
||||
|
||||
.section ".text16", "ax", @progbits
|
||||
.globl undiisr
|
||||
undiisr:
|
||||
|
||||
/* Preserve registers */
|
||||
pushw %ds
|
||||
pushw %es
|
||||
pushw %fs
|
||||
pushw %gs
|
||||
pushfl
|
||||
pushal
|
||||
|
||||
/* Set up our segment registers */
|
||||
movw %cs:rm_ds, %ax
|
||||
movw %ax, %ds
|
||||
|
||||
/* Check that we have an UNDI entry point */
|
||||
cmpw $0, pxeparent_entry_point
|
||||
je chain
|
||||
|
||||
/* Issue UNDI API call */
|
||||
movw %ax, %es
|
||||
movw $undinet_params, %di
|
||||
movw $PXENV_UNDI_ISR, %bx
|
||||
movw $PXENV_UNDI_ISR_IN_START, funcflag
|
||||
pushw %es
|
||||
pushw %di
|
||||
pushw %bx
|
||||
lcall *pxeparent_entry_point
|
||||
cli /* Just in case */
|
||||
addw $6, %sp
|
||||
cmpw $PXENV_UNDI_ISR_OUT_OURS, funcflag
|
||||
jne eoi
|
||||
|
||||
trig: /* Record interrupt occurence */
|
||||
incb undiisr_trigger_count
|
||||
|
||||
eoi: /* Send EOI */
|
||||
movb $ICR_EOI_NON_SPECIFIC, %al
|
||||
cmpb $IRQ_PIC_CUTOFF, undiisr_irq
|
||||
jb 1f
|
||||
outb %al, $PIC2_ICR
|
||||
1: outb %al, $PIC1_ICR
|
||||
jmp exit
|
||||
|
||||
chain: /* Chain to next handler */
|
||||
pushfw
|
||||
lcall *undiisr_next_handler
|
||||
|
||||
exit: /* Restore registers and return */
|
||||
cli
|
||||
popal
|
||||
movzwl %sp, %esp
|
||||
addr32 movl -20(%esp), %esp /* %esp isn't restored by popal */
|
||||
popfl
|
||||
popw %gs
|
||||
popw %fs
|
||||
popw %es
|
||||
popw %ds
|
||||
iret
|
||||
|
||||
.section ".data16", "aw", @progbits
|
||||
undinet_params:
|
||||
status: .word 0
|
||||
funcflag: .word 0
|
||||
bufferlength: .word 0
|
||||
framelength: .word 0
|
||||
frameheaderlength: .word 0
|
||||
frame: .word 0, 0
|
||||
prottype: .byte 0
|
||||
pkttype: .byte 0
|
@@ -1,173 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2007 Michael Brown <mbrown@fensystems.co.uk>.
|
||||
*
|
||||
* 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 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER );
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <pxe.h>
|
||||
#include <realmode.h>
|
||||
#include <bios.h>
|
||||
#include <pnpbios.h>
|
||||
#include <basemem.h>
|
||||
#include <ipxe/pci.h>
|
||||
#include <undi.h>
|
||||
#include <undirom.h>
|
||||
#include <undiload.h>
|
||||
|
||||
/** @file
|
||||
*
|
||||
* UNDI load/unload
|
||||
*
|
||||
*/
|
||||
|
||||
/** Parameter block for calling UNDI loader */
|
||||
static struct s_UNDI_LOADER __bss16 ( undi_loader );
|
||||
#define undi_loader __use_data16 ( undi_loader )
|
||||
|
||||
/** UNDI loader entry point */
|
||||
static SEGOFF16_t __bss16 ( undi_loader_entry );
|
||||
#define undi_loader_entry __use_data16 ( undi_loader_entry )
|
||||
|
||||
/**
|
||||
* Call UNDI loader to create a pixie
|
||||
*
|
||||
* @v undi UNDI device
|
||||
* @v undirom UNDI ROM
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
int undi_load ( struct undi_device *undi, struct undi_rom *undirom ) {
|
||||
struct s_PXE ppxe;
|
||||
unsigned int fbms_seg;
|
||||
uint16_t exit;
|
||||
int rc;
|
||||
|
||||
/* Only one UNDI instance may be loaded at any given time */
|
||||
if ( undi_loader_entry.segment ) {
|
||||
DBG ( "UNDI %p cannot load multiple instances\n", undi );
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
/* Set up START_UNDI parameters */
|
||||
memset ( &undi_loader, 0, sizeof ( undi_loader ) );
|
||||
undi_loader.AX = undi->pci_busdevfn;
|
||||
undi_loader.BX = undi->isapnp_csn;
|
||||
undi_loader.DX = undi->isapnp_read_port;
|
||||
undi_loader.ES = BIOS_SEG;
|
||||
undi_loader.DI = find_pnp_bios();
|
||||
|
||||
/* Allocate base memory for PXE stack */
|
||||
undi->restore_fbms = get_fbms();
|
||||
fbms_seg = ( undi->restore_fbms << 6 );
|
||||
fbms_seg -= ( ( undirom->code_size + 0x0f ) >> 4 );
|
||||
undi_loader.UNDI_CS = fbms_seg;
|
||||
fbms_seg -= ( ( undirom->data_size + 0x0f ) >> 4 );
|
||||
undi_loader.UNDI_DS = fbms_seg;
|
||||
|
||||
/* Debug info */
|
||||
DBGC ( undi, "UNDI %p loading UNDI ROM %p to CS %04x DS %04x for ",
|
||||
undi, undirom, undi_loader.UNDI_CS, undi_loader.UNDI_DS );
|
||||
if ( undi->pci_busdevfn != UNDI_NO_PCI_BUSDEVFN ) {
|
||||
unsigned int bus = ( undi->pci_busdevfn >> 8 );
|
||||
unsigned int devfn = ( undi->pci_busdevfn & 0xff );
|
||||
DBGC ( undi, "PCI %02x:%02x.%x\n",
|
||||
bus, PCI_SLOT ( devfn ), PCI_FUNC ( devfn ) );
|
||||
}
|
||||
if ( undi->isapnp_csn != UNDI_NO_ISAPNP_CSN ) {
|
||||
DBGC ( undi, "ISAPnP(%04x) CSN %04x\n",
|
||||
undi->isapnp_read_port, undi->isapnp_csn );
|
||||
}
|
||||
|
||||
/* Call loader */
|
||||
undi_loader_entry = undirom->loader_entry;
|
||||
__asm__ __volatile__ ( REAL_CODE ( "pushw %%ds\n\t"
|
||||
"pushw %%ax\n\t"
|
||||
"lcall *undi_loader_entry\n\t"
|
||||
"addw $4, %%sp\n\t" )
|
||||
: "=a" ( exit )
|
||||
: "a" ( __from_data16 ( &undi_loader ) )
|
||||
: "ebx", "ecx", "edx", "esi", "edi", "ebp" );
|
||||
|
||||
if ( exit != PXENV_EXIT_SUCCESS ) {
|
||||
/* Clear entry point */
|
||||
memset ( &undi_loader_entry, 0, sizeof ( undi_loader_entry ) );
|
||||
|
||||
rc = -undi_loader.Status;
|
||||
if ( rc == 0 ) /* Paranoia */
|
||||
rc = -EIO;
|
||||
DBGC ( undi, "UNDI %p loader failed: %s\n",
|
||||
undi, strerror ( rc ) );
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Populate PXE device structure */
|
||||
undi->pxenv = undi_loader.PXENVptr;
|
||||
undi->ppxe = undi_loader.PXEptr;
|
||||
copy_from_real ( &ppxe, undi->ppxe.segment, undi->ppxe.offset,
|
||||
sizeof ( ppxe ) );
|
||||
undi->entry = ppxe.EntryPointSP;
|
||||
DBGC ( undi, "UNDI %p loaded PXENV+ %04x:%04x !PXE %04x:%04x "
|
||||
"entry %04x:%04x\n", undi, undi->pxenv.segment,
|
||||
undi->pxenv.offset, undi->ppxe.segment, undi->ppxe.offset,
|
||||
undi->entry.segment, undi->entry.offset );
|
||||
|
||||
/* Update free base memory counter */
|
||||
undi->fbms = ( fbms_seg >> 6 );
|
||||
set_fbms ( undi->fbms );
|
||||
DBGC ( undi, "UNDI %p using [%d,%d) kB of base memory\n",
|
||||
undi, undi->fbms, undi->restore_fbms );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unload a pixie
|
||||
*
|
||||
* @v undi UNDI device
|
||||
* @ret rc Return status code
|
||||
*
|
||||
* Erases the PXENV+ and !PXE signatures, and frees the used base
|
||||
* memory (if possible).
|
||||
*/
|
||||
int undi_unload ( struct undi_device *undi ) {
|
||||
static uint32_t dead = 0xdeaddead;
|
||||
|
||||
DBGC ( undi, "UNDI %p unloading\n", undi );
|
||||
|
||||
/* Clear entry point */
|
||||
memset ( &undi_loader_entry, 0, sizeof ( undi_loader_entry ) );
|
||||
|
||||
/* Erase signatures */
|
||||
if ( undi->pxenv.segment )
|
||||
put_real ( dead, undi->pxenv.segment, undi->pxenv.offset );
|
||||
if ( undi->ppxe.segment )
|
||||
put_real ( dead, undi->ppxe.segment, undi->ppxe.offset );
|
||||
|
||||
/* Free base memory, if possible */
|
||||
if ( undi->fbms == get_fbms() ) {
|
||||
DBGC ( undi, "UNDI %p freeing [%d,%d) kB of base memory\n",
|
||||
undi, undi->fbms, undi->restore_fbms );
|
||||
set_fbms ( undi->restore_fbms );
|
||||
return 0;
|
||||
} else {
|
||||
DBGC ( undi, "UNDI %p leaking [%d,%d) kB of base memory\n",
|
||||
undi, undi->fbms, undi->restore_fbms );
|
||||
return -EBUSY;
|
||||
}
|
||||
}
|
@@ -1,631 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2007 Michael Brown <mbrown@fensystems.co.uk>.
|
||||
*
|
||||
* 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 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER );
|
||||
|
||||
#include <string.h>
|
||||
#include <pxe.h>
|
||||
#include <realmode.h>
|
||||
#include <pic8259.h>
|
||||
#include <biosint.h>
|
||||
#include <pnpbios.h>
|
||||
#include <basemem_packet.h>
|
||||
#include <ipxe/io.h>
|
||||
#include <ipxe/iobuf.h>
|
||||
#include <ipxe/netdevice.h>
|
||||
#include <ipxe/if_ether.h>
|
||||
#include <ipxe/ethernet.h>
|
||||
#include <undi.h>
|
||||
#include <undinet.h>
|
||||
#include <pxeparent.h>
|
||||
|
||||
|
||||
/** @file
|
||||
*
|
||||
* UNDI network device driver
|
||||
*
|
||||
*/
|
||||
|
||||
/** An UNDI NIC */
|
||||
struct undi_nic {
|
||||
/** Assigned IRQ number */
|
||||
unsigned int irq;
|
||||
/** Currently processing ISR */
|
||||
int isr_processing;
|
||||
/** Bug workarounds */
|
||||
int hacks;
|
||||
};
|
||||
|
||||
/**
|
||||
* @defgroup undi_hacks UNDI workarounds
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** Work around Etherboot 5.4 bugs */
|
||||
#define UNDI_HACK_EB54 0x0001
|
||||
|
||||
/** @} */
|
||||
|
||||
static void undinet_close ( struct net_device *netdev );
|
||||
|
||||
/** Address of UNDI entry point */
|
||||
static SEGOFF16_t undinet_entry;
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* UNDI interrupt service routine
|
||||
*
|
||||
*****************************************************************************
|
||||
*/
|
||||
|
||||
/**
|
||||
* UNDI interrupt service routine
|
||||
*
|
||||
* The UNDI ISR increments a counter (@c trigger_count) and exits.
|
||||
*/
|
||||
extern void undiisr ( void );
|
||||
|
||||
/** IRQ number */
|
||||
uint8_t __data16 ( undiisr_irq );
|
||||
#define undiisr_irq __use_data16 ( undiisr_irq )
|
||||
|
||||
/** IRQ chain vector */
|
||||
struct segoff __data16 ( undiisr_next_handler );
|
||||
#define undiisr_next_handler __use_data16 ( undiisr_next_handler )
|
||||
|
||||
/** IRQ trigger count */
|
||||
volatile uint8_t __data16 ( undiisr_trigger_count ) = 0;
|
||||
#define undiisr_trigger_count __use_data16 ( undiisr_trigger_count )
|
||||
|
||||
/** Last observed trigger count */
|
||||
static unsigned int last_trigger_count = 0;
|
||||
|
||||
/**
|
||||
* Hook UNDI interrupt service routine
|
||||
*
|
||||
* @v irq IRQ number
|
||||
*/
|
||||
static void undinet_hook_isr ( unsigned int irq ) {
|
||||
|
||||
assert ( irq <= IRQ_MAX );
|
||||
assert ( undiisr_irq == 0 );
|
||||
|
||||
undiisr_irq = irq;
|
||||
hook_bios_interrupt ( IRQ_INT ( irq ),
|
||||
( ( unsigned int ) undiisr ),
|
||||
&undiisr_next_handler );
|
||||
}
|
||||
|
||||
/**
|
||||
* Unhook UNDI interrupt service routine
|
||||
*
|
||||
* @v irq IRQ number
|
||||
*/
|
||||
static void undinet_unhook_isr ( unsigned int irq ) {
|
||||
|
||||
assert ( irq <= IRQ_MAX );
|
||||
|
||||
unhook_bios_interrupt ( IRQ_INT ( irq ),
|
||||
( ( unsigned int ) undiisr ),
|
||||
&undiisr_next_handler );
|
||||
undiisr_irq = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test to see if UNDI ISR has been triggered
|
||||
*
|
||||
* @ret triggered ISR has been triggered since last check
|
||||
*/
|
||||
static int undinet_isr_triggered ( void ) {
|
||||
unsigned int this_trigger_count;
|
||||
|
||||
/* Read trigger_count. Do this only once; it is volatile */
|
||||
this_trigger_count = undiisr_trigger_count;
|
||||
|
||||
if ( this_trigger_count == last_trigger_count ) {
|
||||
/* Not triggered */
|
||||
return 0;
|
||||
} else {
|
||||
/* Triggered */
|
||||
last_trigger_count = this_trigger_count;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* UNDI network device interface
|
||||
*
|
||||
*****************************************************************************
|
||||
*/
|
||||
|
||||
/** UNDI transmit buffer descriptor */
|
||||
static struct s_PXENV_UNDI_TBD __data16 ( undinet_tbd );
|
||||
#define undinet_tbd __use_data16 ( undinet_tbd )
|
||||
|
||||
/**
|
||||
* Transmit packet
|
||||
*
|
||||
* @v netdev Network device
|
||||
* @v iobuf I/O buffer
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int undinet_transmit ( struct net_device *netdev,
|
||||
struct io_buffer *iobuf ) {
|
||||
struct s_PXENV_UNDI_TRANSMIT undi_transmit;
|
||||
size_t len = iob_len ( iobuf );
|
||||
int rc;
|
||||
|
||||
/* Technically, we ought to make sure that the previous
|
||||
* transmission has completed before we re-use the buffer.
|
||||
* However, many PXE stacks (including at least some Intel PXE
|
||||
* stacks and Etherboot 5.4) fail to generate TX completions.
|
||||
* In practice this won't be a problem, since our TX datapath
|
||||
* has a very low packet volume and we can get away with
|
||||
* assuming that a TX will be complete by the time we want to
|
||||
* transmit the next packet.
|
||||
*/
|
||||
|
||||
/* Copy packet to UNDI I/O buffer */
|
||||
if ( len > sizeof ( basemem_packet ) )
|
||||
len = sizeof ( basemem_packet );
|
||||
memcpy ( &basemem_packet, iobuf->data, len );
|
||||
|
||||
/* Create PXENV_UNDI_TRANSMIT data structure */
|
||||
memset ( &undi_transmit, 0, sizeof ( undi_transmit ) );
|
||||
undi_transmit.DestAddr.segment = rm_ds;
|
||||
undi_transmit.DestAddr.offset = __from_data16 ( &undinet_tbd );
|
||||
undi_transmit.TBD.segment = rm_ds;
|
||||
undi_transmit.TBD.offset = __from_data16 ( &undinet_tbd );
|
||||
|
||||
/* Create PXENV_UNDI_TBD data structure */
|
||||
undinet_tbd.ImmedLength = len;
|
||||
undinet_tbd.Xmit.segment = rm_ds;
|
||||
undinet_tbd.Xmit.offset = __from_data16 ( basemem_packet );
|
||||
|
||||
/* Issue PXE API call */
|
||||
if ( ( rc = pxeparent_call ( undinet_entry, PXENV_UNDI_TRANSMIT,
|
||||
&undi_transmit,
|
||||
sizeof ( undi_transmit ) ) ) != 0 )
|
||||
goto done;
|
||||
|
||||
/* Free I/O buffer */
|
||||
netdev_tx_complete ( netdev, iobuf );
|
||||
|
||||
done:
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Poll for received packets
|
||||
*
|
||||
* @v netdev Network device
|
||||
*
|
||||
* Fun, fun, fun. UNDI drivers don't use polling; they use
|
||||
* interrupts. We therefore cheat and pretend that an interrupt has
|
||||
* occurred every time undinet_poll() is called. This isn't too much
|
||||
* of a hack; PCI devices share IRQs and so the first thing that a
|
||||
* proper ISR should do is call PXENV_UNDI_ISR to determine whether or
|
||||
* not the UNDI NIC generated the interrupt; there is no harm done by
|
||||
* spurious calls to PXENV_UNDI_ISR. Similarly, we wouldn't be
|
||||
* handling them any more rapidly than the usual rate of
|
||||
* undinet_poll() being called even if we did implement a full ISR.
|
||||
* So it should work. Ha!
|
||||
*
|
||||
* Addendum (21/10/03). Some cards don't play nicely with this trick,
|
||||
* so instead of doing it the easy way we have to go to all the hassle
|
||||
* of installing a genuine interrupt service routine and dealing with
|
||||
* the wonderful 8259 Programmable Interrupt Controller. Joy.
|
||||
*
|
||||
* Addendum (10/07/07). When doing things such as iSCSI boot, in
|
||||
* which we have to co-operate with a running OS, we can't get away
|
||||
* with the "ISR-just-increments-a-counter-and-returns" trick at all,
|
||||
* because it involves tying up the PIC for far too long, and other
|
||||
* interrupt-dependent components (e.g. local disks) start breaking.
|
||||
* We therefore implement a "proper" ISR which calls PXENV_UNDI_ISR
|
||||
* from within interrupt context in order to deassert the device
|
||||
* interrupt, and sends EOI if applicable.
|
||||
*/
|
||||
static void undinet_poll ( struct net_device *netdev ) {
|
||||
struct undi_nic *undinic = netdev->priv;
|
||||
struct s_PXENV_UNDI_ISR undi_isr;
|
||||
struct io_buffer *iobuf = NULL;
|
||||
size_t len;
|
||||
size_t frag_len;
|
||||
size_t max_frag_len;
|
||||
int rc;
|
||||
|
||||
if ( ! undinic->isr_processing ) {
|
||||
/* Do nothing unless ISR has been triggered */
|
||||
if ( ! undinet_isr_triggered() ) {
|
||||
/* Allow interrupt to occur */
|
||||
__asm__ __volatile__ ( REAL_CODE ( "sti\n\t"
|
||||
"nop\n\t"
|
||||
"nop\n\t"
|
||||
"cli\n\t" ) : : );
|
||||
return;
|
||||
}
|
||||
|
||||
/* Start ISR processing */
|
||||
undinic->isr_processing = 1;
|
||||
undi_isr.FuncFlag = PXENV_UNDI_ISR_IN_PROCESS;
|
||||
} else {
|
||||
/* Continue ISR processing */
|
||||
undi_isr.FuncFlag = PXENV_UNDI_ISR_IN_GET_NEXT;
|
||||
}
|
||||
|
||||
/* Run through the ISR loop */
|
||||
while ( 1 ) {
|
||||
if ( ( rc = pxeparent_call ( undinet_entry, PXENV_UNDI_ISR,
|
||||
&undi_isr,
|
||||
sizeof ( undi_isr ) ) ) != 0 )
|
||||
break;
|
||||
switch ( undi_isr.FuncFlag ) {
|
||||
case PXENV_UNDI_ISR_OUT_TRANSMIT:
|
||||
/* We don't care about transmit completions */
|
||||
break;
|
||||
case PXENV_UNDI_ISR_OUT_RECEIVE:
|
||||
/* Packet fragment received */
|
||||
len = undi_isr.FrameLength;
|
||||
frag_len = undi_isr.BufferLength;
|
||||
if ( ( len == 0 ) || ( len < frag_len ) ) {
|
||||
/* Don't laugh. VMWare does it. */
|
||||
DBGC ( undinic, "UNDINIC %p reported insane "
|
||||
"fragment (%zd of %zd bytes)\n",
|
||||
undinic, frag_len, len );
|
||||
netdev_rx_err ( netdev, NULL, -EINVAL );
|
||||
break;
|
||||
}
|
||||
if ( ! iobuf )
|
||||
iobuf = alloc_iob ( len );
|
||||
if ( ! iobuf ) {
|
||||
DBGC ( undinic, "UNDINIC %p could not "
|
||||
"allocate %zd bytes for RX buffer\n",
|
||||
undinic, len );
|
||||
/* Fragment will be dropped */
|
||||
netdev_rx_err ( netdev, NULL, -ENOMEM );
|
||||
goto done;
|
||||
}
|
||||
max_frag_len = iob_tailroom ( iobuf );
|
||||
if ( frag_len > max_frag_len ) {
|
||||
DBGC ( undinic, "UNDINIC %p fragment too big "
|
||||
"(%zd+%zd does not fit into %zd)\n",
|
||||
undinic, iob_len ( iobuf ), frag_len,
|
||||
( iob_len ( iobuf ) + max_frag_len ) );
|
||||
frag_len = max_frag_len;
|
||||
}
|
||||
copy_from_real ( iob_put ( iobuf, frag_len ),
|
||||
undi_isr.Frame.segment,
|
||||
undi_isr.Frame.offset, frag_len );
|
||||
if ( iob_len ( iobuf ) == len ) {
|
||||
/* Whole packet received; deliver it */
|
||||
netdev_rx ( netdev, iob_disown ( iobuf ) );
|
||||
/* Etherboot 5.4 fails to return all packets
|
||||
* under mild load; pretend it retriggered.
|
||||
*/
|
||||
if ( undinic->hacks & UNDI_HACK_EB54 )
|
||||
--last_trigger_count;
|
||||
}
|
||||
break;
|
||||
case PXENV_UNDI_ISR_OUT_DONE:
|
||||
/* Processing complete */
|
||||
undinic->isr_processing = 0;
|
||||
goto done;
|
||||
default:
|
||||
/* Should never happen. VMWare does it routinely. */
|
||||
DBGC ( undinic, "UNDINIC %p ISR returned invalid "
|
||||
"FuncFlag %04x\n", undinic, undi_isr.FuncFlag );
|
||||
undinic->isr_processing = 0;
|
||||
goto done;
|
||||
}
|
||||
undi_isr.FuncFlag = PXENV_UNDI_ISR_IN_GET_NEXT;
|
||||
}
|
||||
|
||||
done:
|
||||
if ( iobuf ) {
|
||||
DBGC ( undinic, "UNDINIC %p returned incomplete packet "
|
||||
"(%zd of %zd)\n", undinic, iob_len ( iobuf ),
|
||||
( iob_len ( iobuf ) + iob_tailroom ( iobuf ) ) );
|
||||
netdev_rx_err ( netdev, iobuf, -EINVAL );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Open NIC
|
||||
*
|
||||
* @v netdev Net device
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int undinet_open ( struct net_device *netdev ) {
|
||||
struct undi_nic *undinic = netdev->priv;
|
||||
struct s_PXENV_UNDI_SET_STATION_ADDRESS undi_set_address;
|
||||
struct s_PXENV_UNDI_OPEN undi_open;
|
||||
int rc;
|
||||
|
||||
/* Hook interrupt service routine and enable interrupt */
|
||||
undinet_hook_isr ( undinic->irq );
|
||||
enable_irq ( undinic->irq );
|
||||
send_eoi ( undinic->irq );
|
||||
|
||||
/* Set station address. Required for some PXE stacks; will
|
||||
* spuriously fail on others. Ignore failures. We only ever
|
||||
* use it to set the MAC address to the card's permanent value
|
||||
* anyway.
|
||||
*/
|
||||
memcpy ( undi_set_address.StationAddress, netdev->ll_addr,
|
||||
sizeof ( undi_set_address.StationAddress ) );
|
||||
pxeparent_call ( undinet_entry, PXENV_UNDI_SET_STATION_ADDRESS,
|
||||
&undi_set_address, sizeof ( undi_set_address ) );
|
||||
|
||||
/* Open NIC. We ask for promiscuous operation, since it's the
|
||||
* only way to ask for all multicast addresses. On any
|
||||
* switched network, it shouldn't really make a difference to
|
||||
* performance.
|
||||
*/
|
||||
memset ( &undi_open, 0, sizeof ( undi_open ) );
|
||||
undi_open.PktFilter = ( FLTR_DIRECTED | FLTR_BRDCST | FLTR_PRMSCS );
|
||||
if ( ( rc = pxeparent_call ( undinet_entry, PXENV_UNDI_OPEN,
|
||||
&undi_open, sizeof ( undi_open ) ) ) != 0 )
|
||||
goto err;
|
||||
|
||||
DBGC ( undinic, "UNDINIC %p opened\n", undinic );
|
||||
return 0;
|
||||
|
||||
err:
|
||||
undinet_close ( netdev );
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Close NIC
|
||||
*
|
||||
* @v netdev Net device
|
||||
*/
|
||||
static void undinet_close ( struct net_device *netdev ) {
|
||||
struct undi_nic *undinic = netdev->priv;
|
||||
struct s_PXENV_UNDI_ISR undi_isr;
|
||||
struct s_PXENV_UNDI_CLOSE undi_close;
|
||||
int rc;
|
||||
|
||||
/* Ensure ISR has exited cleanly */
|
||||
while ( undinic->isr_processing ) {
|
||||
undi_isr.FuncFlag = PXENV_UNDI_ISR_IN_GET_NEXT;
|
||||
if ( ( rc = pxeparent_call ( undinet_entry, PXENV_UNDI_ISR,
|
||||
&undi_isr,
|
||||
sizeof ( undi_isr ) ) ) != 0 )
|
||||
break;
|
||||
switch ( undi_isr.FuncFlag ) {
|
||||
case PXENV_UNDI_ISR_OUT_TRANSMIT:
|
||||
case PXENV_UNDI_ISR_OUT_RECEIVE:
|
||||
/* Continue draining */
|
||||
break;
|
||||
default:
|
||||
/* Stop processing */
|
||||
undinic->isr_processing = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Close NIC */
|
||||
pxeparent_call ( undinet_entry, PXENV_UNDI_CLOSE,
|
||||
&undi_close, sizeof ( undi_close ) );
|
||||
|
||||
/* Disable interrupt and unhook ISR */
|
||||
disable_irq ( undinic->irq );
|
||||
undinet_unhook_isr ( undinic->irq );
|
||||
|
||||
DBGC ( undinic, "UNDINIC %p closed\n", undinic );
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable/disable interrupts
|
||||
*
|
||||
* @v netdev Net device
|
||||
* @v enable Interrupts should be enabled
|
||||
*/
|
||||
static void undinet_irq ( struct net_device *netdev, int enable ) {
|
||||
struct undi_nic *undinic = netdev->priv;
|
||||
|
||||
/* Cannot support interrupts yet */
|
||||
DBGC ( undinic, "UNDINIC %p cannot %s interrupts\n",
|
||||
undinic, ( enable ? "enable" : "disable" ) );
|
||||
}
|
||||
|
||||
/** UNDI network device operations */
|
||||
static struct net_device_operations undinet_operations = {
|
||||
.open = undinet_open,
|
||||
.close = undinet_close,
|
||||
.transmit = undinet_transmit,
|
||||
.poll = undinet_poll,
|
||||
.irq = undinet_irq,
|
||||
};
|
||||
|
||||
/**
|
||||
* Probe UNDI device
|
||||
*
|
||||
* @v undi UNDI device
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
int undinet_probe ( struct undi_device *undi ) {
|
||||
struct net_device *netdev;
|
||||
struct undi_nic *undinic;
|
||||
struct s_PXENV_START_UNDI start_undi;
|
||||
struct s_PXENV_UNDI_STARTUP undi_startup;
|
||||
struct s_PXENV_UNDI_INITIALIZE undi_initialize;
|
||||
struct s_PXENV_UNDI_GET_INFORMATION undi_info;
|
||||
struct s_PXENV_UNDI_GET_IFACE_INFO undi_iface;
|
||||
struct s_PXENV_UNDI_SHUTDOWN undi_shutdown;
|
||||
struct s_PXENV_UNDI_CLEANUP undi_cleanup;
|
||||
struct s_PXENV_STOP_UNDI stop_undi;
|
||||
int rc;
|
||||
|
||||
/* Allocate net device */
|
||||
netdev = alloc_etherdev ( sizeof ( *undinic ) );
|
||||
if ( ! netdev )
|
||||
return -ENOMEM;
|
||||
netdev_init ( netdev, &undinet_operations );
|
||||
undinic = netdev->priv;
|
||||
undi_set_drvdata ( undi, netdev );
|
||||
netdev->dev = &undi->dev;
|
||||
memset ( undinic, 0, sizeof ( *undinic ) );
|
||||
undinet_entry = undi->entry;
|
||||
DBGC ( undinic, "UNDINIC %p using UNDI %p\n", undinic, undi );
|
||||
|
||||
/* Hook in UNDI stack */
|
||||
if ( ! ( undi->flags & UNDI_FL_STARTED ) ) {
|
||||
memset ( &start_undi, 0, sizeof ( start_undi ) );
|
||||
start_undi.AX = undi->pci_busdevfn;
|
||||
start_undi.BX = undi->isapnp_csn;
|
||||
start_undi.DX = undi->isapnp_read_port;
|
||||
start_undi.ES = BIOS_SEG;
|
||||
start_undi.DI = find_pnp_bios();
|
||||
if ( ( rc = pxeparent_call ( undinet_entry, PXENV_START_UNDI,
|
||||
&start_undi,
|
||||
sizeof ( start_undi ) ) ) != 0 )
|
||||
goto err_start_undi;
|
||||
}
|
||||
undi->flags |= UNDI_FL_STARTED;
|
||||
|
||||
/* Bring up UNDI stack */
|
||||
if ( ! ( undi->flags & UNDI_FL_INITIALIZED ) ) {
|
||||
memset ( &undi_startup, 0, sizeof ( undi_startup ) );
|
||||
if ( ( rc = pxeparent_call ( undinet_entry, PXENV_UNDI_STARTUP,
|
||||
&undi_startup,
|
||||
sizeof ( undi_startup ) ) ) != 0 )
|
||||
goto err_undi_startup;
|
||||
memset ( &undi_initialize, 0, sizeof ( undi_initialize ) );
|
||||
if ( ( rc = pxeparent_call ( undinet_entry,
|
||||
PXENV_UNDI_INITIALIZE,
|
||||
&undi_initialize,
|
||||
sizeof ( undi_initialize ))) != 0 )
|
||||
goto err_undi_initialize;
|
||||
}
|
||||
undi->flags |= UNDI_FL_INITIALIZED;
|
||||
|
||||
/* Get device information */
|
||||
memset ( &undi_info, 0, sizeof ( undi_info ) );
|
||||
if ( ( rc = pxeparent_call ( undinet_entry, PXENV_UNDI_GET_INFORMATION,
|
||||
&undi_info, sizeof ( undi_info ) ) ) != 0 )
|
||||
goto err_undi_get_information;
|
||||
memcpy ( netdev->hw_addr, undi_info.PermNodeAddress, ETH_ALEN );
|
||||
undinic->irq = undi_info.IntNumber;
|
||||
if ( undinic->irq > IRQ_MAX ) {
|
||||
DBGC ( undinic, "UNDINIC %p invalid IRQ %d\n",
|
||||
undinic, undinic->irq );
|
||||
goto err_bad_irq;
|
||||
}
|
||||
DBGC ( undinic, "UNDINIC %p is %s on IRQ %d\n",
|
||||
undinic, eth_ntoa ( netdev->hw_addr ), undinic->irq );
|
||||
|
||||
/* Get interface information */
|
||||
memset ( &undi_iface, 0, sizeof ( undi_iface ) );
|
||||
if ( ( rc = pxeparent_call ( undinet_entry, PXENV_UNDI_GET_IFACE_INFO,
|
||||
&undi_iface,
|
||||
sizeof ( undi_iface ) ) ) != 0 )
|
||||
goto err_undi_get_iface_info;
|
||||
DBGC ( undinic, "UNDINIC %p has type %s, speed %d, flags %08x\n",
|
||||
undinic, undi_iface.IfaceType, undi_iface.LinkSpeed,
|
||||
undi_iface.ServiceFlags );
|
||||
if ( strncmp ( ( ( char * ) undi_iface.IfaceType ), "Etherboot",
|
||||
sizeof ( undi_iface.IfaceType ) ) == 0 ) {
|
||||
DBGC ( undinic, "UNDINIC %p Etherboot 5.4 workaround enabled\n",
|
||||
undinic );
|
||||
undinic->hacks |= UNDI_HACK_EB54;
|
||||
}
|
||||
|
||||
/* Register network device */
|
||||
if ( ( rc = register_netdev ( netdev ) ) != 0 )
|
||||
goto err_register;
|
||||
|
||||
/* Mark as link up; we don't handle link state */
|
||||
netdev_link_up ( netdev );
|
||||
|
||||
DBGC ( undinic, "UNDINIC %p added\n", undinic );
|
||||
return 0;
|
||||
|
||||
err_register:
|
||||
err_undi_get_iface_info:
|
||||
err_bad_irq:
|
||||
err_undi_get_information:
|
||||
err_undi_initialize:
|
||||
/* Shut down UNDI stack */
|
||||
memset ( &undi_shutdown, 0, sizeof ( undi_shutdown ) );
|
||||
pxeparent_call ( undinet_entry, PXENV_UNDI_SHUTDOWN, &undi_shutdown,
|
||||
sizeof ( undi_shutdown ) );
|
||||
memset ( &undi_cleanup, 0, sizeof ( undi_cleanup ) );
|
||||
pxeparent_call ( undinet_entry, PXENV_UNDI_CLEANUP, &undi_cleanup,
|
||||
sizeof ( undi_cleanup ) );
|
||||
undi->flags &= ~UNDI_FL_INITIALIZED;
|
||||
err_undi_startup:
|
||||
/* Unhook UNDI stack */
|
||||
memset ( &stop_undi, 0, sizeof ( stop_undi ) );
|
||||
pxeparent_call ( undinet_entry, PXENV_STOP_UNDI, &stop_undi,
|
||||
sizeof ( stop_undi ) );
|
||||
undi->flags &= ~UNDI_FL_STARTED;
|
||||
err_start_undi:
|
||||
netdev_nullify ( netdev );
|
||||
netdev_put ( netdev );
|
||||
undi_set_drvdata ( undi, NULL );
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove UNDI device
|
||||
*
|
||||
* @v undi UNDI device
|
||||
*/
|
||||
void undinet_remove ( struct undi_device *undi ) {
|
||||
struct net_device *netdev = undi_get_drvdata ( undi );
|
||||
struct undi_nic *undinic = netdev->priv;
|
||||
struct s_PXENV_UNDI_SHUTDOWN undi_shutdown;
|
||||
struct s_PXENV_UNDI_CLEANUP undi_cleanup;
|
||||
struct s_PXENV_STOP_UNDI stop_undi;
|
||||
|
||||
/* Unregister net device */
|
||||
unregister_netdev ( netdev );
|
||||
|
||||
/* If we are preparing for an OS boot, or if we cannot exit
|
||||
* via the PXE stack, then shut down the PXE stack.
|
||||
*/
|
||||
if ( ! ( undi->flags & UNDI_FL_KEEP_ALL ) ) {
|
||||
|
||||
/* Shut down UNDI stack */
|
||||
memset ( &undi_shutdown, 0, sizeof ( undi_shutdown ) );
|
||||
pxeparent_call ( undinet_entry, PXENV_UNDI_SHUTDOWN,
|
||||
&undi_shutdown, sizeof ( undi_shutdown ) );
|
||||
memset ( &undi_cleanup, 0, sizeof ( undi_cleanup ) );
|
||||
pxeparent_call ( undinet_entry, PXENV_UNDI_CLEANUP,
|
||||
&undi_cleanup, sizeof ( undi_cleanup ) );
|
||||
undi->flags &= ~UNDI_FL_INITIALIZED;
|
||||
|
||||
/* Unhook UNDI stack */
|
||||
memset ( &stop_undi, 0, sizeof ( stop_undi ) );
|
||||
pxeparent_call ( undinet_entry, PXENV_STOP_UNDI, &stop_undi,
|
||||
sizeof ( stop_undi ) );
|
||||
undi->flags &= ~UNDI_FL_STARTED;
|
||||
}
|
||||
|
||||
/* Clear entry point */
|
||||
memset ( &undinet_entry, 0, sizeof ( undinet_entry ) );
|
||||
|
||||
/* Free network device */
|
||||
netdev_nullify ( netdev );
|
||||
netdev_put ( netdev );
|
||||
|
||||
DBGC ( undinic, "UNDINIC %p removed\n", undinic );
|
||||
}
|
@@ -1,129 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2007 Michael Brown <mbrown@fensystems.co.uk>.
|
||||
*
|
||||
* 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 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER );
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ipxe/device.h>
|
||||
#include <ipxe/init.h>
|
||||
#include <undi.h>
|
||||
#include <undinet.h>
|
||||
#include <undipreload.h>
|
||||
|
||||
/** @file
|
||||
*
|
||||
* "Pure" UNDI driver
|
||||
*
|
||||
* This is the UNDI driver without explicit support for PCI or any
|
||||
* other bus type. It is capable only of using the preloaded UNDI
|
||||
* device. It must not be combined in an image with any other
|
||||
* drivers.
|
||||
*
|
||||
* If you want a PXE-loadable image that contains only the UNDI
|
||||
* driver, build "bin/undionly.kpxe".
|
||||
*
|
||||
* If you want any other image format, or any other drivers in
|
||||
* addition to the UNDI driver, build e.g. "bin/undi.dsk".
|
||||
*/
|
||||
|
||||
/**
|
||||
* Probe UNDI root bus
|
||||
*
|
||||
* @v rootdev UNDI bus root device
|
||||
*
|
||||
* Scans the UNDI bus for devices and registers all devices it can
|
||||
* find.
|
||||
*/
|
||||
static int undibus_probe ( struct root_device *rootdev ) {
|
||||
struct undi_device *undi = &preloaded_undi;
|
||||
int rc;
|
||||
|
||||
/* Check for a valie preloaded UNDI device */
|
||||
if ( ! undi->entry.segment ) {
|
||||
DBG ( "No preloaded UNDI device found!\n" );
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/* Add to device hierarchy */
|
||||
strncpy ( undi->dev.name, "UNDI",
|
||||
( sizeof ( undi->dev.name ) - 1 ) );
|
||||
if ( undi->pci_busdevfn != UNDI_NO_PCI_BUSDEVFN ) {
|
||||
undi->dev.desc.bus_type = BUS_TYPE_PCI;
|
||||
undi->dev.desc.location = undi->pci_busdevfn;
|
||||
undi->dev.desc.vendor = undi->pci_vendor;
|
||||
undi->dev.desc.device = undi->pci_device;
|
||||
} else if ( undi->isapnp_csn != UNDI_NO_ISAPNP_CSN ) {
|
||||
undi->dev.desc.bus_type = BUS_TYPE_ISAPNP;
|
||||
}
|
||||
undi->dev.parent = &rootdev->dev;
|
||||
list_add ( &undi->dev.siblings, &rootdev->dev.children);
|
||||
INIT_LIST_HEAD ( &undi->dev.children );
|
||||
|
||||
/* Create network device */
|
||||
if ( ( rc = undinet_probe ( undi ) ) != 0 )
|
||||
goto err;
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
list_del ( &undi->dev.siblings );
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove UNDI root bus
|
||||
*
|
||||
* @v rootdev UNDI bus root device
|
||||
*/
|
||||
static void undibus_remove ( struct root_device *rootdev __unused ) {
|
||||
struct undi_device *undi = &preloaded_undi;
|
||||
|
||||
undinet_remove ( undi );
|
||||
list_del ( &undi->dev.siblings );
|
||||
}
|
||||
|
||||
/** UNDI bus root device driver */
|
||||
static struct root_driver undi_root_driver = {
|
||||
.probe = undibus_probe,
|
||||
.remove = undibus_remove,
|
||||
};
|
||||
|
||||
/** UNDI bus root device */
|
||||
struct root_device undi_root_device __root_device = {
|
||||
.dev = { .name = "UNDI" },
|
||||
.driver = &undi_root_driver,
|
||||
};
|
||||
|
||||
/**
|
||||
* Prepare for exit
|
||||
*
|
||||
* @v flags Shutdown flags
|
||||
*/
|
||||
static void undionly_shutdown ( int flags ) {
|
||||
/* If we are shutting down to boot an OS, clear the "keep PXE
|
||||
* stack" flag.
|
||||
*/
|
||||
if ( flags & SHUTDOWN_BOOT )
|
||||
preloaded_undi.flags &= ~UNDI_FL_KEEP_ALL;
|
||||
}
|
||||
|
||||
struct startup_fn startup_undionly __startup_fn ( STARTUP_LATE ) = {
|
||||
.shutdown = undionly_shutdown,
|
||||
};
|
@@ -1,37 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2007 Michael Brown <mbrown@fensystems.co.uk>.
|
||||
*
|
||||
* 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 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER );
|
||||
|
||||
#include <realmode.h>
|
||||
#include <undipreload.h>
|
||||
|
||||
/** @file
|
||||
*
|
||||
* Preloaded UNDI stack
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Preloaded UNDI device
|
||||
*
|
||||
* This is the UNDI device that was present when Etherboot started
|
||||
* execution (i.e. when loading a .kpxe image). The first driver to
|
||||
* claim this device must zero out this data structure.
|
||||
*/
|
||||
struct undi_device __data16 ( preloaded_undi );
|
@@ -1,234 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2007 Michael Brown <mbrown@fensystems.co.uk>.
|
||||
*
|
||||
* 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 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER );
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <pxe.h>
|
||||
#include <realmode.h>
|
||||
#include <undirom.h>
|
||||
|
||||
/** @file
|
||||
*
|
||||
* UNDI expansion ROMs
|
||||
*
|
||||
*/
|
||||
|
||||
/** List of all UNDI ROMs */
|
||||
static LIST_HEAD ( undiroms );
|
||||
|
||||
/**
|
||||
* Parse PXE ROM ID structure
|
||||
*
|
||||
* @v undirom UNDI ROM
|
||||
* @v pxeromid Offset within ROM to PXE ROM ID structure
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int undirom_parse_pxeromid ( struct undi_rom *undirom,
|
||||
unsigned int pxeromid ) {
|
||||
struct undi_rom_id undi_rom_id;
|
||||
unsigned int undiloader;
|
||||
|
||||
DBGC ( undirom, "UNDIROM %p has PXE ROM ID at %04x:%04x\n", undirom,
|
||||
undirom->rom_segment, pxeromid );
|
||||
|
||||
/* Read PXE ROM ID structure and verify */
|
||||
copy_from_real ( &undi_rom_id, undirom->rom_segment, pxeromid,
|
||||
sizeof ( undi_rom_id ) );
|
||||
if ( undi_rom_id.Signature != UNDI_ROM_ID_SIGNATURE ) {
|
||||
DBGC ( undirom, "UNDIROM %p has bad PXE ROM ID signature "
|
||||
"%08x\n", undirom, undi_rom_id.Signature );
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Check for UNDI loader */
|
||||
undiloader = undi_rom_id.UNDILoader;
|
||||
if ( ! undiloader ) {
|
||||
DBGC ( undirom, "UNDIROM %p has no UNDI loader\n", undirom );
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Fill in UNDI ROM loader fields */
|
||||
undirom->loader_entry.segment = undirom->rom_segment;
|
||||
undirom->loader_entry.offset = undiloader;
|
||||
undirom->code_size = undi_rom_id.CodeSize;
|
||||
undirom->data_size = undi_rom_id.DataSize;
|
||||
|
||||
DBGC ( undirom, "UNDIROM %p has UNDI loader at %04x:%04x "
|
||||
"(code %04zx data %04zx)\n", undirom,
|
||||
undirom->loader_entry.segment, undirom->loader_entry.offset,
|
||||
undirom->code_size, undirom->data_size );
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse PCI expansion header
|
||||
*
|
||||
* @v undirom UNDI ROM
|
||||
* @v pcirheader Offset within ROM to PCI expansion header
|
||||
*/
|
||||
static int undirom_parse_pcirheader ( struct undi_rom *undirom,
|
||||
unsigned int pcirheader ) {
|
||||
struct pcir_header pcir_header;
|
||||
|
||||
DBGC ( undirom, "UNDIROM %p has PCI expansion header at %04x:%04x\n",
|
||||
undirom, undirom->rom_segment, pcirheader );
|
||||
|
||||
/* Read PCI expansion header and verify */
|
||||
copy_from_real ( &pcir_header, undirom->rom_segment, pcirheader,
|
||||
sizeof ( pcir_header ) );
|
||||
if ( pcir_header.signature != PCIR_SIGNATURE ) {
|
||||
DBGC ( undirom, "UNDIROM %p has bad PCI expansion header "
|
||||
"signature %08x\n", undirom, pcir_header.signature );
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Fill in UNDI ROM PCI device fields */
|
||||
undirom->bus_type = PCI_NIC;
|
||||
undirom->bus_id.pci.vendor_id = pcir_header.vendor_id;
|
||||
undirom->bus_id.pci.device_id = pcir_header.device_id;
|
||||
|
||||
DBGC ( undirom, "UNDIROM %p is for PCI devices %04x:%04x\n", undirom,
|
||||
undirom->bus_id.pci.vendor_id, undirom->bus_id.pci.device_id );
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Probe UNDI ROM
|
||||
*
|
||||
* @v rom_segment ROM segment address
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int undirom_probe ( unsigned int rom_segment ) {
|
||||
struct undi_rom *undirom = NULL;
|
||||
struct undi_rom_header romheader;
|
||||
size_t rom_len;
|
||||
unsigned int pxeromid;
|
||||
unsigned int pcirheader;
|
||||
int rc;
|
||||
|
||||
/* Read expansion ROM header and verify */
|
||||
copy_from_real ( &romheader, rom_segment, 0, sizeof ( romheader ) );
|
||||
if ( romheader.Signature != ROM_SIGNATURE ) {
|
||||
rc = -EINVAL;
|
||||
goto err;
|
||||
}
|
||||
rom_len = ( romheader.ROMLength * 512 );
|
||||
|
||||
/* Allocate memory for UNDI ROM */
|
||||
undirom = zalloc ( sizeof ( *undirom ) );
|
||||
if ( ! undirom ) {
|
||||
DBG ( "Could not allocate UNDI ROM structure\n" );
|
||||
rc = -ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
DBGC ( undirom, "UNDIROM %p trying expansion ROM at %04x:0000 "
|
||||
"(%zdkB)\n", undirom, rom_segment, ( rom_len / 1024 ) );
|
||||
undirom->rom_segment = rom_segment;
|
||||
|
||||
/* Check for and parse PXE ROM ID */
|
||||
pxeromid = romheader.PXEROMID;
|
||||
if ( ! pxeromid ) {
|
||||
DBGC ( undirom, "UNDIROM %p has no PXE ROM ID\n", undirom );
|
||||
rc = -EINVAL;
|
||||
goto err;
|
||||
}
|
||||
if ( pxeromid > rom_len ) {
|
||||
DBGC ( undirom, "UNDIROM %p PXE ROM ID outside ROM\n",
|
||||
undirom );
|
||||
rc = -EINVAL;
|
||||
goto err;
|
||||
}
|
||||
if ( ( rc = undirom_parse_pxeromid ( undirom, pxeromid ) ) != 0 )
|
||||
goto err;
|
||||
|
||||
/* Parse PCIR header, if present */
|
||||
pcirheader = romheader.PCIRHeader;
|
||||
if ( pcirheader )
|
||||
undirom_parse_pcirheader ( undirom, pcirheader );
|
||||
|
||||
/* Add to UNDI ROM list and return */
|
||||
DBGC ( undirom, "UNDIROM %p registered\n", undirom );
|
||||
list_add ( &undirom->list, &undiroms );
|
||||
return 0;
|
||||
|
||||
err:
|
||||
free ( undirom );
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create UNDI ROMs for all possible expansion ROMs
|
||||
*
|
||||
* @ret
|
||||
*/
|
||||
static void undirom_probe_all_roms ( void ) {
|
||||
static int probed = 0;
|
||||
unsigned int rom_segment;
|
||||
|
||||
/* Perform probe only once */
|
||||
if ( probed )
|
||||
return;
|
||||
|
||||
DBG ( "Scanning for PXE expansion ROMs\n" );
|
||||
|
||||
/* Scan through expansion ROM region at 512 byte intervals */
|
||||
for ( rom_segment = 0xc000 ; rom_segment < 0x10000 ;
|
||||
rom_segment += 0x20 ) {
|
||||
undirom_probe ( rom_segment );
|
||||
}
|
||||
|
||||
probed = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find UNDI ROM for PCI device
|
||||
*
|
||||
* @v vendor_id PCI vendor ID
|
||||
* @v device_id PCI device ID
|
||||
* @v rombase ROM base address, or 0 for any
|
||||
* @ret undirom UNDI ROM, or NULL
|
||||
*/
|
||||
struct undi_rom * undirom_find_pci ( unsigned int vendor_id,
|
||||
unsigned int device_id,
|
||||
unsigned int rombase ) {
|
||||
struct undi_rom *undirom;
|
||||
|
||||
undirom_probe_all_roms();
|
||||
|
||||
list_for_each_entry ( undirom, &undiroms, list ) {
|
||||
if ( undirom->bus_type != PCI_NIC )
|
||||
continue;
|
||||
if ( undirom->bus_id.pci.vendor_id != vendor_id )
|
||||
continue;
|
||||
if ( undirom->bus_id.pci.device_id != device_id )
|
||||
continue;
|
||||
if ( rombase && ( ( undirom->rom_segment << 4 ) != rombase ) )
|
||||
continue;
|
||||
DBGC ( undirom, "UNDIROM %p matched PCI %04x:%04x (%08x)\n",
|
||||
undirom, vendor_id, device_id, rombase );
|
||||
return undirom;
|
||||
}
|
||||
|
||||
DBG ( "No UNDI ROM matched PCI %04x:%04x (%08x)\n",
|
||||
vendor_id, device_id, rombase );
|
||||
return NULL;
|
||||
}
|
@@ -1,46 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2007 Michael Brown <mbrown@fensystems.co.uk>.
|
||||
*
|
||||
* 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 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER );
|
||||
|
||||
#include <stdint.h>
|
||||
#include <realmode.h>
|
||||
#include <bios.h>
|
||||
#include <basemem.h>
|
||||
#include <ipxe/hidemem.h>
|
||||
|
||||
/** @file
|
||||
*
|
||||
* Base memory allocation
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Set the BIOS free base memory counter
|
||||
*
|
||||
* @v new_fbms New free base memory counter (in kB)
|
||||
*/
|
||||
void set_fbms ( unsigned int new_fbms ) {
|
||||
uint16_t fbms = new_fbms;
|
||||
|
||||
/* Update the BIOS memory counter */
|
||||
put_real ( fbms, BDA_SEG, BDA_FBMS );
|
||||
|
||||
/* Update our hidden memory region map */
|
||||
hide_basemem();
|
||||
}
|
@@ -1,298 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2006 Michael Brown <mbrown@fensystems.co.uk>.
|
||||
*
|
||||
* 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 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER );
|
||||
|
||||
#include <assert.h>
|
||||
#include <realmode.h>
|
||||
#include <console.h>
|
||||
#include <ipxe/ansiesc.h>
|
||||
|
||||
#define ATTR_BOLD 0x08
|
||||
|
||||
#define ATTR_FCOL_MASK 0x07
|
||||
#define ATTR_FCOL_BLACK 0x00
|
||||
#define ATTR_FCOL_BLUE 0x01
|
||||
#define ATTR_FCOL_GREEN 0x02
|
||||
#define ATTR_FCOL_CYAN 0x03
|
||||
#define ATTR_FCOL_RED 0x04
|
||||
#define ATTR_FCOL_MAGENTA 0x05
|
||||
#define ATTR_FCOL_YELLOW 0x06
|
||||
#define ATTR_FCOL_WHITE 0x07
|
||||
|
||||
#define ATTR_BCOL_MASK 0x70
|
||||
#define ATTR_BCOL_BLACK 0x00
|
||||
#define ATTR_BCOL_BLUE 0x10
|
||||
#define ATTR_BCOL_GREEN 0x20
|
||||
#define ATTR_BCOL_CYAN 0x30
|
||||
#define ATTR_BCOL_RED 0x40
|
||||
#define ATTR_BCOL_MAGENTA 0x50
|
||||
#define ATTR_BCOL_YELLOW 0x60
|
||||
#define ATTR_BCOL_WHITE 0x70
|
||||
|
||||
#define ATTR_DEFAULT ATTR_FCOL_WHITE
|
||||
|
||||
/** Current character attribute */
|
||||
static unsigned int bios_attr = ATTR_DEFAULT;
|
||||
|
||||
/**
|
||||
* Handle ANSI CUP (cursor position)
|
||||
*
|
||||
* @v count Parameter count
|
||||
* @v params[0] Row (1 is top)
|
||||
* @v params[1] Column (1 is left)
|
||||
*/
|
||||
static void bios_handle_cup ( unsigned int count __unused, int params[] ) {
|
||||
int cx = ( params[1] - 1 );
|
||||
int cy = ( params[0] - 1 );
|
||||
|
||||
if ( cx < 0 )
|
||||
cx = 0;
|
||||
if ( cy < 0 )
|
||||
cy = 0;
|
||||
|
||||
__asm__ __volatile__ ( REAL_CODE ( "sti\n\t"
|
||||
"int $0x10\n\t"
|
||||
"cli\n\t" )
|
||||
: : "a" ( 0x0200 ), "b" ( 1 ),
|
||||
"d" ( ( cy << 8 ) | cx ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle ANSI ED (erase in page)
|
||||
*
|
||||
* @v count Parameter count
|
||||
* @v params[0] Region to erase
|
||||
*/
|
||||
static void bios_handle_ed ( unsigned int count __unused,
|
||||
int params[] __unused ) {
|
||||
/* We assume that we always clear the whole screen */
|
||||
assert ( params[0] == ANSIESC_ED_ALL );
|
||||
|
||||
__asm__ __volatile__ ( REAL_CODE ( "sti\n\t"
|
||||
"int $0x10\n\t"
|
||||
"cli\n\t" )
|
||||
: : "a" ( 0x0600 ), "b" ( bios_attr << 8 ),
|
||||
"c" ( 0 ), "d" ( 0xffff ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle ANSI SGR (set graphics rendition)
|
||||
*
|
||||
* @v count Parameter count
|
||||
* @v params List of graphic rendition aspects
|
||||
*/
|
||||
static void bios_handle_sgr ( unsigned int count, int params[] ) {
|
||||
static const uint8_t bios_attr_fcols[10] = {
|
||||
ATTR_FCOL_BLACK, ATTR_FCOL_RED, ATTR_FCOL_GREEN,
|
||||
ATTR_FCOL_YELLOW, ATTR_FCOL_BLUE, ATTR_FCOL_MAGENTA,
|
||||
ATTR_FCOL_CYAN, ATTR_FCOL_WHITE,
|
||||
ATTR_FCOL_WHITE, ATTR_FCOL_WHITE /* defaults */
|
||||
};
|
||||
static const uint8_t bios_attr_bcols[10] = {
|
||||
ATTR_BCOL_BLACK, ATTR_BCOL_RED, ATTR_BCOL_GREEN,
|
||||
ATTR_BCOL_YELLOW, ATTR_BCOL_BLUE, ATTR_BCOL_MAGENTA,
|
||||
ATTR_BCOL_CYAN, ATTR_BCOL_WHITE,
|
||||
ATTR_BCOL_BLACK, ATTR_BCOL_BLACK /* defaults */
|
||||
};
|
||||
unsigned int i;
|
||||
int aspect;
|
||||
|
||||
for ( i = 0 ; i < count ; i++ ) {
|
||||
aspect = params[i];
|
||||
if ( aspect == 0 ) {
|
||||
bios_attr = ATTR_DEFAULT;
|
||||
} else if ( aspect == 1 ) {
|
||||
bios_attr |= ATTR_BOLD;
|
||||
} else if ( aspect == 22 ) {
|
||||
bios_attr &= ~ATTR_BOLD;
|
||||
} else if ( ( aspect >= 30 ) && ( aspect <= 39 ) ) {
|
||||
bios_attr &= ~ATTR_FCOL_MASK;
|
||||
bios_attr |= bios_attr_fcols[ aspect - 30 ];
|
||||
} else if ( ( aspect >= 40 ) && ( aspect <= 49 ) ) {
|
||||
bios_attr &= ~ATTR_BCOL_MASK;
|
||||
bios_attr |= bios_attr_bcols[ aspect - 40 ];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** BIOS console ANSI escape sequence handlers */
|
||||
static struct ansiesc_handler bios_ansiesc_handlers[] = {
|
||||
{ ANSIESC_CUP, bios_handle_cup },
|
||||
{ ANSIESC_ED, bios_handle_ed },
|
||||
{ ANSIESC_SGR, bios_handle_sgr },
|
||||
{ 0, NULL }
|
||||
};
|
||||
|
||||
/** BIOS console ANSI escape sequence context */
|
||||
static struct ansiesc_context bios_ansiesc_ctx = {
|
||||
.handlers = bios_ansiesc_handlers,
|
||||
};
|
||||
|
||||
/**
|
||||
* Print a character to BIOS console
|
||||
*
|
||||
* @v character Character to be printed
|
||||
*/
|
||||
static void bios_putchar ( int character ) {
|
||||
int discard_a, discard_b, discard_c;
|
||||
|
||||
/* Intercept ANSI escape sequences */
|
||||
character = ansiesc_process ( &bios_ansiesc_ctx, character );
|
||||
if ( character < 0 )
|
||||
return;
|
||||
|
||||
/* Print character with attribute */
|
||||
__asm__ __volatile__ ( REAL_CODE ( "sti\n\t"
|
||||
/* Skip non-printable characters */
|
||||
"cmpb $0x20, %%al\n\t"
|
||||
"jb 1f\n\t"
|
||||
/* Set attribute */
|
||||
"movw $0x0001, %%cx\n\t"
|
||||
"movb $0x09, %%ah\n\t"
|
||||
"int $0x10\n\t"
|
||||
"\n1:\n\t"
|
||||
/* Print character */
|
||||
"xorw %%bx, %%bx\n\t"
|
||||
"movb $0x0e, %%ah\n\t"
|
||||
"int $0x10\n\t"
|
||||
"cli\n\t" )
|
||||
: "=a" ( discard_a ), "=b" ( discard_b ),
|
||||
"=c" ( discard_c )
|
||||
: "a" ( character ), "b" ( bios_attr )
|
||||
: "ebp" );
|
||||
}
|
||||
|
||||
/**
|
||||
* Pointer to current ANSI output sequence
|
||||
*
|
||||
* While we are in the middle of returning an ANSI sequence for a
|
||||
* special key, this will point to the next character to return. When
|
||||
* not in the middle of such a sequence, this will point to a NUL
|
||||
* (note: not "will be NULL").
|
||||
*/
|
||||
static const char *ansi_input = "";
|
||||
|
||||
/**
|
||||
* Lowest BIOS scancode of interest
|
||||
*
|
||||
* Most of the BIOS key scancodes that we are interested in are in a
|
||||
* dense range, so subtracting a constant and treating them as offsets
|
||||
* into an array works efficiently.
|
||||
*/
|
||||
#define BIOS_KEY_MIN 0x42
|
||||
|
||||
/** Offset into list of interesting BIOS scancodes */
|
||||
#define BIOS_KEY(scancode) ( (scancode) - BIOS_KEY_MIN )
|
||||
|
||||
/** Mapping from BIOS scan codes to ANSI escape sequences */
|
||||
static const char *ansi_sequences[] = {
|
||||
[ BIOS_KEY ( 0x42 ) ] = "[19~", /* F8 (required for PXE) */
|
||||
[ BIOS_KEY ( 0x47 ) ] = "[H", /* Home */
|
||||
[ BIOS_KEY ( 0x48 ) ] = "[A", /* Up arrow */
|
||||
[ BIOS_KEY ( 0x4b ) ] = "[D", /* Left arrow */
|
||||
[ BIOS_KEY ( 0x4d ) ] = "[C", /* Right arrow */
|
||||
[ BIOS_KEY ( 0x4f ) ] = "[F", /* End */
|
||||
[ BIOS_KEY ( 0x50 ) ] = "[B", /* Down arrow */
|
||||
[ BIOS_KEY ( 0x53 ) ] = "[3~", /* Delete */
|
||||
};
|
||||
|
||||
/**
|
||||
* Get ANSI escape sequence corresponding to BIOS scancode
|
||||
*
|
||||
* @v scancode BIOS scancode
|
||||
* @ret ansi_seq ANSI escape sequence, if any, otherwise NULL
|
||||
*/
|
||||
static const char * scancode_to_ansi_seq ( unsigned int scancode ) {
|
||||
unsigned int bios_key = BIOS_KEY ( scancode );
|
||||
|
||||
if ( bios_key < ( sizeof ( ansi_sequences ) /
|
||||
sizeof ( ansi_sequences[0] ) ) ) {
|
||||
return ansi_sequences[bios_key];
|
||||
}
|
||||
DBG ( "Unrecognised BIOS scancode %02x\n", scancode );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get character from BIOS console
|
||||
*
|
||||
* @ret character Character read from console
|
||||
*/
|
||||
static int bios_getchar ( void ) {
|
||||
uint16_t keypress;
|
||||
unsigned int character;
|
||||
const char *ansi_seq;
|
||||
|
||||
/* If we are mid-sequence, pass out the next byte */
|
||||
if ( ( character = *ansi_input ) ) {
|
||||
ansi_input++;
|
||||
return character;
|
||||
}
|
||||
|
||||
/* Read character from real BIOS console */
|
||||
__asm__ __volatile__ ( REAL_CODE ( "sti\n\t"
|
||||
"int $0x16\n\t"
|
||||
"cli\n\t" )
|
||||
: "=a" ( keypress ) : "a" ( 0x1000 ) );
|
||||
character = ( keypress & 0xff );
|
||||
|
||||
/* If it's a normal character, just return it */
|
||||
if ( character && ( character < 0x80 ) )
|
||||
return character;
|
||||
|
||||
/* Otherwise, check for a special key that we know about */
|
||||
if ( ( ansi_seq = scancode_to_ansi_seq ( keypress >> 8 ) ) ) {
|
||||
/* Start of escape sequence: return ESC (0x1b) */
|
||||
ansi_input = ansi_seq;
|
||||
return 0x1b;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check for character ready to read from BIOS console
|
||||
*
|
||||
* @ret True Character available to read
|
||||
* @ret False No character available to read
|
||||
*/
|
||||
static int bios_iskey ( void ) {
|
||||
unsigned int discard_a;
|
||||
unsigned int flags;
|
||||
|
||||
/* If we are mid-sequence, we are always ready */
|
||||
if ( *ansi_input )
|
||||
return 1;
|
||||
|
||||
/* Otherwise check the real BIOS console */
|
||||
__asm__ __volatile__ ( REAL_CODE ( "sti\n\t"
|
||||
"int $0x16\n\t"
|
||||
"pushfw\n\t"
|
||||
"popw %w0\n\t"
|
||||
"cli\n\t" )
|
||||
: "=r" ( flags ), "=a" ( discard_a )
|
||||
: "a" ( 0x0100 ) );
|
||||
return ( ! ( flags & ZF ) );
|
||||
}
|
||||
|
||||
struct console_driver bios_console __console_driver = {
|
||||
.putchar = bios_putchar,
|
||||
.getchar = bios_getchar,
|
||||
.iskey = bios_iskey,
|
||||
};
|
@@ -1,584 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2006 Michael Brown <mbrown@fensystems.co.uk>.
|
||||
*
|
||||
* 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 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER )
|
||||
|
||||
.text
|
||||
.arch i386
|
||||
.code16
|
||||
|
||||
#define SMAP 0x534d4150
|
||||
|
||||
/* Most documentation refers to the E820 buffer as being 20 bytes, and
|
||||
* the API makes it perfectly legitimate to pass only a 20-byte buffer
|
||||
* and expect to get valid data. However, some morons at ACPI decided
|
||||
* to extend the data structure by adding an extra "extended
|
||||
* attributes" field and by including critical information within this
|
||||
* field, such as whether or not the region is enabled. A caller who
|
||||
* passes in only a 20-byte buffer therefore risks getting very, very
|
||||
* misleading information.
|
||||
*
|
||||
* I have personally witnessed an HP BIOS that returns a value of
|
||||
* 0x0009 in the extended attributes field. If we don't pass this
|
||||
* value through to the caller, 32-bit WinPE will die, usually with a
|
||||
* PAGE_FAULT_IN_NONPAGED_AREA blue screen of death.
|
||||
*
|
||||
* Allow a ridiculously large maximum value (64 bytes) for the E820
|
||||
* buffer as a guard against insufficiently creative idiots in the
|
||||
* future.
|
||||
*/
|
||||
#define E820MAXSIZE 64
|
||||
|
||||
/****************************************************************************
|
||||
*
|
||||
* Allowed memory windows
|
||||
*
|
||||
* There are two ways to view this list. The first is as a list of
|
||||
* (non-overlapping) allowed memory regions, sorted by increasing
|
||||
* address. The second is as a list of (non-overlapping) hidden
|
||||
* memory regions, again sorted by increasing address. The second
|
||||
* view is offset by half an entry from the first: think about this
|
||||
* for a moment and it should make sense.
|
||||
*
|
||||
* xxx_memory_window is used to indicate an "allowed region"
|
||||
* structure, hidden_xxx_memory is used to indicate a "hidden region"
|
||||
* structure. Each structure is 16 bytes in length.
|
||||
*
|
||||
****************************************************************************
|
||||
*/
|
||||
.section ".data16", "aw", @progbits
|
||||
.align 16
|
||||
.globl hidemem_base
|
||||
.globl hidemem_umalloc
|
||||
.globl hidemem_textdata
|
||||
memory_windows:
|
||||
base_memory_window: .long 0x00000000, 0x00000000 /* Start of memory */
|
||||
|
||||
hidemem_base: .long 0x000a0000, 0x00000000 /* Changes at runtime */
|
||||
ext_memory_window: .long 0x000a0000, 0x00000000 /* 640kB mark */
|
||||
|
||||
hidemem_umalloc: .long 0xffffffff, 0xffffffff /* Changes at runtime */
|
||||
.long 0xffffffff, 0xffffffff /* Changes at runtime */
|
||||
|
||||
hidemem_textdata: .long 0xffffffff, 0xffffffff /* Changes at runtime */
|
||||
.long 0xffffffff, 0xffffffff /* Changes at runtime */
|
||||
|
||||
.long 0xffffffff, 0xffffffff /* End of memory */
|
||||
memory_windows_end:
|
||||
|
||||
/****************************************************************************
|
||||
* Truncate region to memory window
|
||||
*
|
||||
* Parameters:
|
||||
* %edx:%eax Start of region
|
||||
* %ecx:%ebx Length of region
|
||||
* %si Memory window
|
||||
* Returns:
|
||||
* %edx:%eax Start of windowed region
|
||||
* %ecx:%ebx Length of windowed region
|
||||
****************************************************************************
|
||||
*/
|
||||
.section ".text16", "ax", @progbits
|
||||
window_region:
|
||||
/* Convert (start,len) to (start, end) */
|
||||
addl %eax, %ebx
|
||||
adcl %edx, %ecx
|
||||
/* Truncate to window start */
|
||||
cmpl 4(%si), %edx
|
||||
jne 1f
|
||||
cmpl 0(%si), %eax
|
||||
1: jae 2f
|
||||
movl 4(%si), %edx
|
||||
movl 0(%si), %eax
|
||||
2: /* Truncate to window end */
|
||||
cmpl 12(%si), %ecx
|
||||
jne 1f
|
||||
cmpl 8(%si), %ebx
|
||||
1: jbe 2f
|
||||
movl 12(%si), %ecx
|
||||
movl 8(%si), %ebx
|
||||
2: /* Convert (start, end) back to (start, len) */
|
||||
subl %eax, %ebx
|
||||
sbbl %edx, %ecx
|
||||
/* If length is <0, set length to 0 */
|
||||
jae 1f
|
||||
xorl %ebx, %ebx
|
||||
xorl %ecx, %ecx
|
||||
ret
|
||||
.size window_region, . - window_region
|
||||
|
||||
/****************************************************************************
|
||||
* Patch "memory above 1MB" figure
|
||||
*
|
||||
* Parameters:
|
||||
* %ax Memory above 1MB, in 1kB blocks
|
||||
* Returns:
|
||||
* %ax Modified memory above 1M in 1kB blocks
|
||||
****************************************************************************
|
||||
*/
|
||||
.section ".text16", "ax", @progbits
|
||||
patch_1m:
|
||||
pushal
|
||||
/* Convert to (start,len) format and call truncate */
|
||||
xorl %ecx, %ecx
|
||||
movzwl %ax, %ebx
|
||||
shll $10, %ebx
|
||||
xorl %edx, %edx
|
||||
movl $0x100000, %eax
|
||||
movw $ext_memory_window, %si
|
||||
call window_region
|
||||
/* Convert back to "memory above 1MB" format and return via %ax */
|
||||
pushfw
|
||||
shrl $10, %ebx
|
||||
popfw
|
||||
movw %sp, %bp
|
||||
movw %bx, 28(%bp)
|
||||
popal
|
||||
ret
|
||||
.size patch_1m, . - patch_1m
|
||||
|
||||
/****************************************************************************
|
||||
* Patch "memory above 16MB" figure
|
||||
*
|
||||
* Parameters:
|
||||
* %bx Memory above 16MB, in 64kB blocks
|
||||
* Returns:
|
||||
* %bx Modified memory above 16M in 64kB blocks
|
||||
****************************************************************************
|
||||
*/
|
||||
.section ".text16", "ax", @progbits
|
||||
patch_16m:
|
||||
pushal
|
||||
/* Convert to (start,len) format and call truncate */
|
||||
xorl %ecx, %ecx
|
||||
shll $16, %ebx
|
||||
xorl %edx, %edx
|
||||
movl $0x1000000, %eax
|
||||
movw $ext_memory_window, %si
|
||||
call window_region
|
||||
/* Convert back to "memory above 16MB" format and return via %bx */
|
||||
pushfw
|
||||
shrl $16, %ebx
|
||||
popfw
|
||||
movw %sp, %bp
|
||||
movw %bx, 16(%bp)
|
||||
popal
|
||||
ret
|
||||
.size patch_16m, . - patch_16m
|
||||
|
||||
/****************************************************************************
|
||||
* Patch "memory between 1MB and 16MB" and "memory above 16MB" figures
|
||||
*
|
||||
* Parameters:
|
||||
* %ax Memory between 1MB and 16MB, in 1kB blocks
|
||||
* %bx Memory above 16MB, in 64kB blocks
|
||||
* Returns:
|
||||
* %ax Modified memory between 1MB and 16MB, in 1kB blocks
|
||||
* %bx Modified memory above 16MB, in 64kB blocks
|
||||
****************************************************************************
|
||||
*/
|
||||
.section ".text16", "ax", @progbits
|
||||
patch_1m_16m:
|
||||
call patch_1m
|
||||
call patch_16m
|
||||
/* If 1M region is no longer full-length, kill off the 16M region */
|
||||
cmpw $( 15 * 1024 ), %ax
|
||||
je 1f
|
||||
xorw %bx, %bx
|
||||
1: ret
|
||||
.size patch_1m_16m, . - patch_1m_16m
|
||||
|
||||
/****************************************************************************
|
||||
* Get underlying e820 memory region to underlying_e820 buffer
|
||||
*
|
||||
* Parameters:
|
||||
* As for INT 15,e820
|
||||
* Returns:
|
||||
* As for INT 15,e820
|
||||
*
|
||||
* Wraps the underlying INT 15,e820 call so that the continuation
|
||||
* value (%ebx) is a 16-bit simple sequence counter (with the high 16
|
||||
* bits ignored), and termination is always via CF=1 rather than
|
||||
* %ebx=0.
|
||||
*
|
||||
****************************************************************************
|
||||
*/
|
||||
.section ".text16", "ax", @progbits
|
||||
get_underlying_e820:
|
||||
|
||||
/* If the requested region is in the cache, return it */
|
||||
cmpw %bx, underlying_e820_index
|
||||
jne 2f
|
||||
pushw %di
|
||||
pushw %si
|
||||
movw $underlying_e820_cache, %si
|
||||
cmpl underlying_e820_cache_size, %ecx
|
||||
jbe 1f
|
||||
movl underlying_e820_cache_size, %ecx
|
||||
1: pushl %ecx
|
||||
rep movsb
|
||||
popl %ecx
|
||||
popw %si
|
||||
popw %di
|
||||
incw %bx
|
||||
movl %edx, %eax
|
||||
clc
|
||||
ret
|
||||
2:
|
||||
/* If the requested region is earlier than the cached region,
|
||||
* invalidate the cache.
|
||||
*/
|
||||
cmpw %bx, underlying_e820_index
|
||||
jbe 1f
|
||||
movw $0xffff, underlying_e820_index
|
||||
1:
|
||||
/* If the cache is invalid, reset the underlying %ebx */
|
||||
cmpw $0xffff, underlying_e820_index
|
||||
jne 1f
|
||||
andl $0, underlying_e820_ebx
|
||||
1:
|
||||
/* If the cache is valid but the continuation value is zero,
|
||||
* this means that the previous underlying call returned with
|
||||
* %ebx=0. Return with CF=1 in this case.
|
||||
*/
|
||||
cmpw $0xffff, underlying_e820_index
|
||||
je 1f
|
||||
cmpl $0, underlying_e820_ebx
|
||||
jne 1f
|
||||
stc
|
||||
ret
|
||||
1:
|
||||
/* Get the next region into the cache */
|
||||
pushl %eax
|
||||
pushl %ebx
|
||||
pushl %ecx
|
||||
pushl %edx
|
||||
pushl %esi /* Some implementations corrupt %esi, so we */
|
||||
pushl %edi /* preserve %esi, %edi and %ebp to be paranoid */
|
||||
pushl %ebp
|
||||
pushw %es
|
||||
pushw %ds
|
||||
popw %es
|
||||
movw $underlying_e820_cache, %di
|
||||
cmpl $E820MAXSIZE, %ecx
|
||||
jbe 1f
|
||||
movl $E820MAXSIZE, %ecx
|
||||
1: movl underlying_e820_ebx, %ebx
|
||||
stc
|
||||
pushfw
|
||||
lcall *%cs:int15_vector
|
||||
popw %es
|
||||
popl %ebp
|
||||
popl %edi
|
||||
popl %esi
|
||||
/* Check for error return from underlying e820 call */
|
||||
jc 2f /* CF set: error */
|
||||
cmpl $SMAP, %eax
|
||||
je 3f /* 'SMAP' missing: error */
|
||||
2: /* An error occurred: return values returned by underlying e820 call */
|
||||
stc /* Force CF set if SMAP was missing */
|
||||
addr32 leal 16(%esp), %esp /* avoid changing other flags */
|
||||
ret
|
||||
3: /* No error occurred */
|
||||
movl %ebx, underlying_e820_ebx
|
||||
movl %ecx, underlying_e820_cache_size
|
||||
popl %edx
|
||||
popl %ecx
|
||||
popl %ebx
|
||||
popl %eax
|
||||
/* Mark cache as containing this result */
|
||||
incw underlying_e820_index
|
||||
|
||||
/* Loop until found */
|
||||
jmp get_underlying_e820
|
||||
.size get_underlying_e820, . - get_underlying_e820
|
||||
|
||||
.section ".data16", "aw", @progbits
|
||||
underlying_e820_index:
|
||||
.word 0xffff /* Initialise to an invalid value */
|
||||
.size underlying_e820_index, . - underlying_e820_index
|
||||
|
||||
.section ".bss16", "aw", @nobits
|
||||
underlying_e820_ebx:
|
||||
.long 0
|
||||
.size underlying_e820_ebx, . - underlying_e820_ebx
|
||||
|
||||
.section ".bss16", "aw", @nobits
|
||||
underlying_e820_cache:
|
||||
.space E820MAXSIZE
|
||||
.size underlying_e820_cache, . - underlying_e820_cache
|
||||
|
||||
.section ".bss16", "aw", @nobits
|
||||
underlying_e820_cache_size:
|
||||
.long 0
|
||||
.size underlying_e820_cache_size, . - underlying_e820_cache_size
|
||||
|
||||
/****************************************************************************
|
||||
* Get windowed e820 region, without empty region stripping
|
||||
*
|
||||
* Parameters:
|
||||
* As for INT 15,e820
|
||||
* Returns:
|
||||
* As for INT 15,e820
|
||||
*
|
||||
* Wraps the underlying INT 15,e820 call so that each underlying
|
||||
* region is returned N times, windowed to fit within N visible-memory
|
||||
* windows. Termination is always via CF=1.
|
||||
*
|
||||
****************************************************************************
|
||||
*/
|
||||
.section ".text16", "ax", @progbits
|
||||
get_windowed_e820:
|
||||
|
||||
/* Preserve registers */
|
||||
pushl %esi
|
||||
pushw %bp
|
||||
|
||||
/* Split %ebx into %si:%bx, store original %bx in %bp */
|
||||
pushl %ebx
|
||||
popw %bp
|
||||
popw %si
|
||||
|
||||
/* %si == 0 => start of memory_windows list */
|
||||
testw %si, %si
|
||||
jne 1f
|
||||
movw $memory_windows, %si
|
||||
1:
|
||||
/* Get (cached) underlying e820 region to buffer */
|
||||
call get_underlying_e820
|
||||
jc 99f /* Abort on error */
|
||||
|
||||
/* Preserve registers */
|
||||
pushal
|
||||
/* start => %edx:%eax, len => %ecx:%ebx */
|
||||
movl %es:0(%di), %eax
|
||||
movl %es:4(%di), %edx
|
||||
movl %es:8(%di), %ebx
|
||||
movl %es:12(%di), %ecx
|
||||
/* Truncate region to current window */
|
||||
call window_region
|
||||
1: /* Store modified values in e820 map entry */
|
||||
movl %eax, %es:0(%di)
|
||||
movl %edx, %es:4(%di)
|
||||
movl %ebx, %es:8(%di)
|
||||
movl %ecx, %es:12(%di)
|
||||
/* Restore registers */
|
||||
popal
|
||||
|
||||
/* Derive continuation value for next call */
|
||||
addw $16, %si
|
||||
cmpw $memory_windows_end, %si
|
||||
jne 1f
|
||||
/* End of memory windows: reset %si and allow %bx to continue */
|
||||
xorw %si, %si
|
||||
jmp 2f
|
||||
1: /* More memory windows to go: restore original %bx */
|
||||
movw %bp, %bx
|
||||
2: /* Construct %ebx from %si:%bx */
|
||||
pushw %si
|
||||
pushw %bx
|
||||
popl %ebx
|
||||
|
||||
98: /* Clear CF */
|
||||
clc
|
||||
99: /* Restore registers and return */
|
||||
popw %bp
|
||||
popl %esi
|
||||
ret
|
||||
.size get_windowed_e820, . - get_windowed_e820
|
||||
|
||||
/****************************************************************************
|
||||
* Get windowed e820 region, with empty region stripping
|
||||
*
|
||||
* Parameters:
|
||||
* As for INT 15,e820
|
||||
* Returns:
|
||||
* As for INT 15,e820
|
||||
*
|
||||
* Wraps the underlying INT 15,e820 call so that each underlying
|
||||
* region is returned up to N times, windowed to fit within N
|
||||
* visible-memory windows. Empty windows are never returned.
|
||||
* Termination is always via CF=1.
|
||||
*
|
||||
****************************************************************************
|
||||
*/
|
||||
.section ".text16", "ax", @progbits
|
||||
get_nonempty_e820:
|
||||
|
||||
/* Record entry parameters */
|
||||
pushl %eax
|
||||
pushl %ecx
|
||||
pushl %edx
|
||||
|
||||
/* Get next windowed region */
|
||||
call get_windowed_e820
|
||||
jc 99f /* abort on error */
|
||||
|
||||
/* If region is non-empty, finish here */
|
||||
cmpl $0, %es:8(%di)
|
||||
jne 98f
|
||||
cmpl $0, %es:12(%di)
|
||||
jne 98f
|
||||
|
||||
/* Region was empty: restore entry parameters and go to next region */
|
||||
popl %edx
|
||||
popl %ecx
|
||||
popl %eax
|
||||
jmp get_nonempty_e820
|
||||
|
||||
98: /* Clear CF */
|
||||
clc
|
||||
99: /* Return values from underlying call */
|
||||
addr32 leal 12(%esp), %esp /* avoid changing flags */
|
||||
ret
|
||||
.size get_nonempty_e820, . - get_nonempty_e820
|
||||
|
||||
/****************************************************************************
|
||||
* Get mangled e820 region, with empty region stripping
|
||||
*
|
||||
* Parameters:
|
||||
* As for INT 15,e820
|
||||
* Returns:
|
||||
* As for INT 15,e820
|
||||
*
|
||||
* Wraps the underlying INT 15,e820 call so that underlying regions
|
||||
* are windowed to the allowed memory regions. Empty regions are
|
||||
* stripped from the map. Termination is always via %ebx=0.
|
||||
*
|
||||
****************************************************************************
|
||||
*/
|
||||
.section ".text16", "ax", @progbits
|
||||
get_mangled_e820:
|
||||
|
||||
/* Get a nonempty region */
|
||||
call get_nonempty_e820
|
||||
jc 99f /* Abort on error */
|
||||
|
||||
/* Peek ahead to see if there are any further nonempty regions */
|
||||
pushal
|
||||
pushw %es
|
||||
movw %sp, %bp
|
||||
subw %cx, %sp
|
||||
movl $0xe820, %eax
|
||||
movl $SMAP, %edx
|
||||
pushw %ss
|
||||
popw %es
|
||||
movw %sp, %di
|
||||
call get_nonempty_e820
|
||||
movw %bp, %sp
|
||||
popw %es
|
||||
popal
|
||||
jnc 99f /* There are further nonempty regions */
|
||||
|
||||
/* No futher nonempty regions: zero %ebx and clear CF */
|
||||
xorl %ebx, %ebx
|
||||
|
||||
99: /* Return */
|
||||
ret
|
||||
.size get_mangled_e820, . - get_mangled_e820
|
||||
|
||||
/****************************************************************************
|
||||
* INT 15,e820 handler
|
||||
****************************************************************************
|
||||
*/
|
||||
.section ".text16", "ax", @progbits
|
||||
int15_e820:
|
||||
pushw %ds
|
||||
pushw %cs:rm_ds
|
||||
popw %ds
|
||||
call get_mangled_e820
|
||||
popw %ds
|
||||
call patch_cf
|
||||
iret
|
||||
.size int15_e820, . - int15_e820
|
||||
|
||||
/****************************************************************************
|
||||
* INT 15,e801 handler
|
||||
****************************************************************************
|
||||
*/
|
||||
.section ".text16", "ax", @progbits
|
||||
int15_e801:
|
||||
/* Call previous handler */
|
||||
pushfw
|
||||
lcall *%cs:int15_vector
|
||||
call patch_cf
|
||||
/* Edit result */
|
||||
pushw %ds
|
||||
pushw %cs:rm_ds
|
||||
popw %ds
|
||||
call patch_1m_16m
|
||||
xchgw %ax, %cx
|
||||
xchgw %bx, %dx
|
||||
call patch_1m_16m
|
||||
xchgw %ax, %cx
|
||||
xchgw %bx, %dx
|
||||
popw %ds
|
||||
iret
|
||||
.size int15_e801, . - int15_e801
|
||||
|
||||
/****************************************************************************
|
||||
* INT 15,88 handler
|
||||
****************************************************************************
|
||||
*/
|
||||
.section ".text16", "ax", @progbits
|
||||
int15_88:
|
||||
/* Call previous handler */
|
||||
pushfw
|
||||
lcall *%cs:int15_vector
|
||||
call patch_cf
|
||||
/* Edit result */
|
||||
pushw %ds
|
||||
pushw %cs:rm_ds
|
||||
popw %ds
|
||||
call patch_1m
|
||||
popw %ds
|
||||
iret
|
||||
.size int15_88, . - int15_88
|
||||
|
||||
/****************************************************************************
|
||||
* INT 15 handler
|
||||
****************************************************************************
|
||||
*/
|
||||
.section ".text16", "ax", @progbits
|
||||
.globl int15
|
||||
int15:
|
||||
/* See if we want to intercept this call */
|
||||
pushfw
|
||||
cmpw $0xe820, %ax
|
||||
jne 1f
|
||||
cmpl $SMAP, %edx
|
||||
jne 1f
|
||||
popfw
|
||||
jmp int15_e820
|
||||
1: cmpw $0xe801, %ax
|
||||
jne 2f
|
||||
popfw
|
||||
jmp int15_e801
|
||||
2: cmpb $0x88, %ah
|
||||
jne 3f
|
||||
popfw
|
||||
jmp int15_88
|
||||
3: popfw
|
||||
ljmp *%cs:int15_vector
|
||||
.size int15, . - int15
|
||||
|
||||
.section ".text16.data", "aw", @progbits
|
||||
.globl int15_vector
|
||||
int15_vector:
|
||||
.long 0
|
||||
.size int15_vector, . - int15_vector
|
@@ -1,93 +0,0 @@
|
||||
/* Copyright (C) 2008 Michael Brown <mbrown@fensystems.co.uk>.
|
||||
*
|
||||
* 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 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER );
|
||||
|
||||
#include <realmode.h>
|
||||
#include <biosint.h>
|
||||
|
||||
/** Assembly routine in inline asm */
|
||||
extern void int15_fakee820();
|
||||
|
||||
/** Original INT 15 handler */
|
||||
static struct segoff __text16 ( real_int15_vector );
|
||||
#define real_int15_vector __use_text16 ( real_int15_vector )
|
||||
|
||||
/** An INT 15,e820 memory map entry */
|
||||
struct e820_entry {
|
||||
/** Start of region */
|
||||
uint64_t start;
|
||||
/** Length of region */
|
||||
uint64_t len;
|
||||
/** Type of region */
|
||||
uint32_t type;
|
||||
} __attribute__ (( packed ));
|
||||
|
||||
#define E820_TYPE_RAM 1 /**< Normal memory */
|
||||
#define E820_TYPE_RSVD 2 /**< Reserved and unavailable */
|
||||
#define E820_TYPE_ACPI 3 /**< ACPI reclaim memory */
|
||||
#define E820_TYPE_NVS 4 /**< ACPI NVS memory */
|
||||
|
||||
/** Fake e820 map */
|
||||
static struct e820_entry __text16_array ( e820map, [] ) __used = {
|
||||
{ 0x00000000ULL, ( 0x000a0000ULL - 0x00000000ULL ), E820_TYPE_RAM },
|
||||
{ 0x00100000ULL, ( 0xcfb50000ULL - 0x00100000ULL ), E820_TYPE_RAM },
|
||||
{ 0xcfb50000ULL, ( 0xcfb64000ULL - 0xcfb50000ULL ), E820_TYPE_RSVD },
|
||||
{ 0xcfb64000ULL, ( 0xcfb66000ULL - 0xcfb64000ULL ), E820_TYPE_RSVD },
|
||||
{ 0xcfb66000ULL, ( 0xcfb85c00ULL - 0xcfb66000ULL ), E820_TYPE_ACPI },
|
||||
{ 0xcfb85c00ULL, ( 0xd0000000ULL - 0xcfb85c00ULL ), E820_TYPE_RSVD },
|
||||
{ 0xe0000000ULL, ( 0xf0000000ULL - 0xe0000000ULL ), E820_TYPE_RSVD },
|
||||
{ 0xfe000000ULL, (0x100000000ULL - 0xfe000000ULL ), E820_TYPE_RSVD },
|
||||
{0x100000000ULL, (0x230000000ULL -0x100000000ULL ), E820_TYPE_RAM },
|
||||
};
|
||||
#define e820map __use_text16 ( e820map )
|
||||
|
||||
void fake_e820 ( void ) {
|
||||
__asm__ __volatile__ (
|
||||
TEXT16_CODE ( "\nint15_fakee820:\n\t"
|
||||
"pushfw\n\t"
|
||||
"cmpl $0xe820, %%eax\n\t"
|
||||
"jne 99f\n\t"
|
||||
"cmpl $0x534d4150, %%edx\n\t"
|
||||
"jne 99f\n\t"
|
||||
"pushaw\n\t"
|
||||
"movw %%sp, %%bp\n\t"
|
||||
"andb $~0x01, 22(%%bp)\n\t" /* Clear return CF */
|
||||
"leaw e820map(%%bx), %%si\n\t"
|
||||
"cs rep movsb\n\t"
|
||||
"popaw\n\t"
|
||||
"movl %%edx, %%eax\n\t"
|
||||
"addl $20, %%ebx\n\t"
|
||||
"cmpl %0, %%ebx\n\t"
|
||||
"jne 1f\n\t"
|
||||
"xorl %%ebx,%%ebx\n\t"
|
||||
"\n1:\n\t"
|
||||
"popfw\n\t"
|
||||
"iret\n\t"
|
||||
"\n99:\n\t"
|
||||
"popfw\n\t"
|
||||
"ljmp *%%cs:real_int15_vector\n\t" )
|
||||
: : "i" ( sizeof ( e820map ) ) );
|
||||
|
||||
hook_bios_interrupt ( 0x15, ( unsigned int ) int15_fakee820,
|
||||
&real_int15_vector );
|
||||
}
|
||||
|
||||
void unfake_e820 ( void ) {
|
||||
unhook_bios_interrupt ( 0x15, ( unsigned int ) int15_fakee820,
|
||||
&real_int15_vector );
|
||||
}
|
@@ -1,220 +0,0 @@
|
||||
/* Copyright (C) 2006 Michael Brown <mbrown@fensystems.co.uk>.
|
||||
*
|
||||
* 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 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER );
|
||||
|
||||
#include <assert.h>
|
||||
#include <realmode.h>
|
||||
#include <biosint.h>
|
||||
#include <basemem.h>
|
||||
#include <fakee820.h>
|
||||
#include <ipxe/init.h>
|
||||
#include <ipxe/io.h>
|
||||
#include <ipxe/hidemem.h>
|
||||
|
||||
/** Set to true if you want to test a fake E820 map */
|
||||
#define FAKE_E820 0
|
||||
|
||||
/** Alignment for hidden memory regions */
|
||||
#define ALIGN_HIDDEN 4096 /* 4kB page alignment should be enough */
|
||||
|
||||
/**
|
||||
* A hidden region of iPXE
|
||||
*
|
||||
* This represents a region that will be edited out of the system's
|
||||
* memory map.
|
||||
*
|
||||
* This structure is accessed by assembly code, so must not be
|
||||
* changed.
|
||||
*/
|
||||
struct hidden_region {
|
||||
/** Physical start address */
|
||||
uint64_t start;
|
||||
/** Physical end address */
|
||||
uint64_t end;
|
||||
};
|
||||
|
||||
/** Hidden base memory */
|
||||
extern struct hidden_region __data16 ( hidemem_base );
|
||||
#define hidemem_base __use_data16 ( hidemem_base )
|
||||
|
||||
/** Hidden umalloc memory */
|
||||
extern struct hidden_region __data16 ( hidemem_umalloc );
|
||||
#define hidemem_umalloc __use_data16 ( hidemem_umalloc )
|
||||
|
||||
/** Hidden text memory */
|
||||
extern struct hidden_region __data16 ( hidemem_textdata );
|
||||
#define hidemem_textdata __use_data16 ( hidemem_textdata )
|
||||
|
||||
/** Assembly routine in e820mangler.S */
|
||||
extern void int15();
|
||||
|
||||
/** Vector for storing original INT 15 handler */
|
||||
extern struct segoff __text16 ( int15_vector );
|
||||
#define int15_vector __use_text16 ( int15_vector )
|
||||
|
||||
/* The linker defines these symbols for us */
|
||||
extern char _textdata[];
|
||||
extern char _etextdata[];
|
||||
extern char _text16_memsz[];
|
||||
#define _text16_memsz ( ( unsigned int ) _text16_memsz )
|
||||
extern char _data16_memsz[];
|
||||
#define _data16_memsz ( ( unsigned int ) _data16_memsz )
|
||||
|
||||
/**
|
||||
* Hide region of memory from system memory map
|
||||
*
|
||||
* @v region Hidden memory region
|
||||
* @v start Start of region
|
||||
* @v end End of region
|
||||
*/
|
||||
static void hide_region ( struct hidden_region *region,
|
||||
physaddr_t start, physaddr_t end ) {
|
||||
|
||||
/* Some operating systems get a nasty shock if a region of the
|
||||
* E820 map seems to start on a non-page boundary. Make life
|
||||
* safer by rounding out our edited region.
|
||||
*/
|
||||
region->start = ( start & ~( ALIGN_HIDDEN - 1 ) );
|
||||
region->end = ( ( end + ALIGN_HIDDEN - 1 ) & ~( ALIGN_HIDDEN - 1 ) );
|
||||
|
||||
DBG ( "Hiding region [%llx,%llx)\n", region->start, region->end );
|
||||
}
|
||||
|
||||
/**
|
||||
* Hide used base memory
|
||||
*
|
||||
*/
|
||||
void hide_basemem ( void ) {
|
||||
/* Hide from the top of free base memory to 640kB. Don't use
|
||||
* hide_region(), because we don't want this rounded to the
|
||||
* nearest page boundary.
|
||||
*/
|
||||
hidemem_base.start = ( get_fbms() * 1024 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Hide umalloc() region
|
||||
*
|
||||
*/
|
||||
void hide_umalloc ( physaddr_t start, physaddr_t end ) {
|
||||
assert ( end <= virt_to_phys ( _textdata ) );
|
||||
hide_region ( &hidemem_umalloc, start, end );
|
||||
}
|
||||
|
||||
/**
|
||||
* Hide .text and .data
|
||||
*
|
||||
*/
|
||||
void hide_textdata ( void ) {
|
||||
hide_region ( &hidemem_textdata, virt_to_phys ( _textdata ),
|
||||
virt_to_phys ( _etextdata ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Hide Etherboot
|
||||
*
|
||||
* Installs an INT 15 handler to edit Etherboot out of the memory map
|
||||
* returned by the BIOS.
|
||||
*/
|
||||
static void hide_etherboot ( void ) {
|
||||
struct memory_map memmap;
|
||||
unsigned int rm_ds_top;
|
||||
unsigned int rm_cs_top;
|
||||
unsigned int fbms;
|
||||
|
||||
/* Dump memory map before mangling */
|
||||
DBG ( "Hiding iPXE from system memory map\n" );
|
||||
get_memmap ( &memmap );
|
||||
|
||||
/* Hook in fake E820 map, if we're testing one */
|
||||
if ( FAKE_E820 ) {
|
||||
DBG ( "Hooking in fake E820 map\n" );
|
||||
fake_e820();
|
||||
get_memmap ( &memmap );
|
||||
}
|
||||
|
||||
/* Initialise the hidden regions */
|
||||
hide_basemem();
|
||||
hide_umalloc ( virt_to_phys ( _textdata ), virt_to_phys ( _textdata ) );
|
||||
hide_textdata();
|
||||
|
||||
/* Some really moronic BIOSes bring up the PXE stack via the
|
||||
* UNDI loader entry point and then don't bother to unload it
|
||||
* before overwriting the code and data segments. If this
|
||||
* happens, we really don't want to leave INT 15 hooked,
|
||||
* because that will cause any loaded OS to die horribly as
|
||||
* soon as it attempts to fetch the system memory map.
|
||||
*
|
||||
* We use a heuristic to guess whether or not we are being
|
||||
* loaded sensibly.
|
||||
*/
|
||||
rm_cs_top = ( ( ( rm_cs << 4 ) + _text16_memsz + 1024 - 1 ) >> 10 );
|
||||
rm_ds_top = ( ( ( rm_ds << 4 ) + _data16_memsz + 1024 - 1 ) >> 10 );
|
||||
fbms = get_fbms();
|
||||
if ( ( rm_cs_top < fbms ) && ( rm_ds_top < fbms ) ) {
|
||||
DBG ( "Detected potentially unsafe UNDI load at CS=%04x "
|
||||
"DS=%04x FBMS=%dkB\n", rm_cs, rm_ds, fbms );
|
||||
DBG ( "Disabling INT 15 memory hiding\n" );
|
||||
return;
|
||||
}
|
||||
|
||||
/* Hook INT 15 */
|
||||
hook_bios_interrupt ( 0x15, ( unsigned int ) int15,
|
||||
&int15_vector );
|
||||
|
||||
/* Dump memory map after mangling */
|
||||
DBG ( "Hidden iPXE from system memory map\n" );
|
||||
get_memmap ( &memmap );
|
||||
}
|
||||
|
||||
/**
|
||||
* Unhide Etherboot
|
||||
*
|
||||
* Uninstalls the INT 15 handler installed by hide_etherboot(), if
|
||||
* possible.
|
||||
*/
|
||||
static void unhide_etherboot ( int flags __unused ) {
|
||||
|
||||
/* If we have more than one hooked interrupt at this point, it
|
||||
* means that some other vector is still hooked, in which case
|
||||
* we can't safely unhook INT 15 because we need to keep our
|
||||
* memory protected. (We expect there to be at least one
|
||||
* hooked interrupt, because INT 15 itself is still hooked).
|
||||
*/
|
||||
if ( hooked_bios_interrupts > 1 ) {
|
||||
DBG ( "Cannot unhide: %d interrupt vectors still hooked\n",
|
||||
hooked_bios_interrupts );
|
||||
return;
|
||||
}
|
||||
|
||||
/* Try to unhook INT 15. If it fails, then just leave it
|
||||
* hooked; it takes care of protecting itself. :)
|
||||
*/
|
||||
unhook_bios_interrupt ( 0x15, ( unsigned int ) int15,
|
||||
&int15_vector );
|
||||
|
||||
/* Unhook fake E820 map, if used */
|
||||
if ( FAKE_E820 )
|
||||
unfake_e820();
|
||||
}
|
||||
|
||||
/** Hide Etherboot startup function */
|
||||
struct startup_fn hide_etherboot_startup_fn __startup_fn ( STARTUP_EARLY ) = {
|
||||
.startup = hide_etherboot,
|
||||
.shutdown = unhide_etherboot,
|
||||
};
|
@@ -1,314 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2006 Michael Brown <mbrown@fensystems.co.uk>.
|
||||
*
|
||||
* 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 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER );
|
||||
|
||||
#include <stdint.h>
|
||||
#include <errno.h>
|
||||
#include <realmode.h>
|
||||
#include <bios.h>
|
||||
#include <memsizes.h>
|
||||
#include <ipxe/io.h>
|
||||
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
* Memory mapping
|
||||
*
|
||||
*/
|
||||
|
||||
/** Magic value for INT 15,e820 calls */
|
||||
#define SMAP ( 0x534d4150 )
|
||||
|
||||
/** An INT 15,e820 memory map entry */
|
||||
struct e820_entry {
|
||||
/** Start of region */
|
||||
uint64_t start;
|
||||
/** Length of region */
|
||||
uint64_t len;
|
||||
/** Type of region */
|
||||
uint32_t type;
|
||||
/** Extended attributes (optional) */
|
||||
uint32_t attrs;
|
||||
} __attribute__ (( packed ));
|
||||
|
||||
#define E820_TYPE_RAM 1 /**< Normal memory */
|
||||
#define E820_TYPE_RESERVED 2 /**< Reserved and unavailable */
|
||||
#define E820_TYPE_ACPI 3 /**< ACPI reclaim memory */
|
||||
#define E820_TYPE_NVS 4 /**< ACPI NVS memory */
|
||||
|
||||
#define E820_ATTR_ENABLED 0x00000001UL
|
||||
#define E820_ATTR_NONVOLATILE 0x00000002UL
|
||||
#define E820_ATTR_UNKNOWN 0xfffffffcUL
|
||||
|
||||
#define E820_MIN_SIZE 20
|
||||
|
||||
/** Buffer for INT 15,e820 calls */
|
||||
static struct e820_entry __bss16 ( e820buf );
|
||||
#define e820buf __use_data16 ( e820buf )
|
||||
|
||||
/**
|
||||
* Get size of extended memory via INT 15,e801
|
||||
*
|
||||
* @ret extmem Extended memory size, in kB, or 0
|
||||
*/
|
||||
static unsigned int extmemsize_e801 ( void ) {
|
||||
uint16_t extmem_1m_to_16m_k, extmem_16m_plus_64k;
|
||||
uint16_t confmem_1m_to_16m_k, confmem_16m_plus_64k;
|
||||
unsigned int flags;
|
||||
unsigned int extmem;
|
||||
|
||||
__asm__ __volatile__ ( REAL_CODE ( "stc\n\t"
|
||||
"int $0x15\n\t"
|
||||
"pushfw\n\t"
|
||||
"popw %w0\n\t" )
|
||||
: "=r" ( flags ),
|
||||
"=a" ( extmem_1m_to_16m_k ),
|
||||
"=b" ( extmem_16m_plus_64k ),
|
||||
"=c" ( confmem_1m_to_16m_k ),
|
||||
"=d" ( confmem_16m_plus_64k )
|
||||
: "a" ( 0xe801 ) );
|
||||
|
||||
if ( flags & CF ) {
|
||||
DBG ( "INT 15,e801 failed with CF set\n" );
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ( ! ( extmem_1m_to_16m_k | extmem_16m_plus_64k ) ) {
|
||||
DBG ( "INT 15,e801 extmem=0, using confmem\n" );
|
||||
extmem_1m_to_16m_k = confmem_1m_to_16m_k;
|
||||
extmem_16m_plus_64k = confmem_16m_plus_64k;
|
||||
}
|
||||
|
||||
extmem = ( extmem_1m_to_16m_k + ( extmem_16m_plus_64k * 64 ) );
|
||||
DBG ( "INT 15,e801 extended memory size %d+64*%d=%d kB "
|
||||
"[100000,%llx)\n", extmem_1m_to_16m_k, extmem_16m_plus_64k,
|
||||
extmem, ( 0x100000 + ( ( ( uint64_t ) extmem ) * 1024 ) ) );
|
||||
|
||||
/* Sanity check. Some BIOSes report the entire 4GB address
|
||||
* space as available, which cannot be correct (since that
|
||||
* would leave no address space available for 32-bit PCI
|
||||
* BARs).
|
||||
*/
|
||||
if ( extmem == ( 0x400000 - 0x400 ) ) {
|
||||
DBG ( "INT 15,e801 reported whole 4GB; assuming insane\n" );
|
||||
return 0;
|
||||
}
|
||||
|
||||
return extmem;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get size of extended memory via INT 15,88
|
||||
*
|
||||
* @ret extmem Extended memory size, in kB
|
||||
*/
|
||||
static unsigned int extmemsize_88 ( void ) {
|
||||
uint16_t extmem;
|
||||
|
||||
/* Ignore CF; it is not reliable for this call */
|
||||
__asm__ __volatile__ ( REAL_CODE ( "int $0x15" )
|
||||
: "=a" ( extmem ) : "a" ( 0x8800 ) );
|
||||
|
||||
DBG ( "INT 15,88 extended memory size %d kB [100000, %x)\n",
|
||||
extmem, ( 0x100000 + ( extmem * 1024 ) ) );
|
||||
return extmem;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get size of extended memory
|
||||
*
|
||||
* @ret extmem Extended memory size, in kB
|
||||
*
|
||||
* Note that this is only an approximation; for an accurate picture,
|
||||
* use the E820 memory map obtained via get_memmap();
|
||||
*/
|
||||
unsigned int extmemsize ( void ) {
|
||||
unsigned int extmem_e801;
|
||||
unsigned int extmem_88;
|
||||
|
||||
/* Try INT 15,e801 first, then fall back to INT 15,88 */
|
||||
extmem_88 = extmemsize_88();
|
||||
extmem_e801 = extmemsize_e801();
|
||||
return ( extmem_e801 ? extmem_e801 : extmem_88 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get e820 memory map
|
||||
*
|
||||
* @v memmap Memory map to fill in
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int meme820 ( struct memory_map *memmap ) {
|
||||
struct memory_region *region = memmap->regions;
|
||||
uint32_t next = 0;
|
||||
uint32_t smap;
|
||||
size_t size;
|
||||
unsigned int flags;
|
||||
unsigned int discard_D;
|
||||
|
||||
/* Clear the E820 buffer. Do this once before starting,
|
||||
* rather than on each call; some BIOSes rely on the contents
|
||||
* being preserved between calls.
|
||||
*/
|
||||
memset ( &e820buf, 0, sizeof ( e820buf ) );
|
||||
|
||||
do {
|
||||
/* Some BIOSes corrupt %esi for fun. Guard against
|
||||
* this by telling gcc that all non-output registers
|
||||
* may be corrupted.
|
||||
*/
|
||||
__asm__ __volatile__ ( REAL_CODE ( "pushl %%ebp\n\t"
|
||||
"stc\n\t"
|
||||
"int $0x15\n\t"
|
||||
"pushfw\n\t"
|
||||
"popw %%dx\n\t"
|
||||
"popl %%ebp\n\t" )
|
||||
: "=a" ( smap ), "=b" ( next ),
|
||||
"=c" ( size ), "=d" ( flags ),
|
||||
"=D" ( discard_D )
|
||||
: "a" ( 0xe820 ), "b" ( next ),
|
||||
"D" ( __from_data16 ( &e820buf ) ),
|
||||
"c" ( sizeof ( e820buf ) ),
|
||||
"d" ( SMAP )
|
||||
: "esi", "memory" );
|
||||
|
||||
if ( smap != SMAP ) {
|
||||
DBG ( "INT 15,e820 failed SMAP signature check\n" );
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
if ( size < E820_MIN_SIZE ) {
|
||||
DBG ( "INT 15,e820 returned only %zd bytes\n", size );
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if ( flags & CF ) {
|
||||
DBG ( "INT 15,e820 terminated on CF set\n" );
|
||||
break;
|
||||
}
|
||||
|
||||
/* If first region is not RAM, assume map is invalid */
|
||||
if ( ( memmap->count == 0 ) &&
|
||||
( e820buf.type != E820_TYPE_RAM ) ) {
|
||||
DBG ( "INT 15,e820 failed, first entry not RAM\n" );
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
DBG ( "INT 15,e820 region [%llx,%llx) type %d",
|
||||
e820buf.start, ( e820buf.start + e820buf.len ),
|
||||
( int ) e820buf.type );
|
||||
if ( size > offsetof ( typeof ( e820buf ), attrs ) ) {
|
||||
DBG ( " (%s", ( ( e820buf.attrs & E820_ATTR_ENABLED )
|
||||
? "enabled" : "disabled" ) );
|
||||
if ( e820buf.attrs & E820_ATTR_NONVOLATILE )
|
||||
DBG ( ", non-volatile" );
|
||||
if ( e820buf.attrs & E820_ATTR_UNKNOWN )
|
||||
DBG ( ", other [%08x]", e820buf.attrs );
|
||||
DBG ( ")" );
|
||||
}
|
||||
DBG ( "\n" );
|
||||
|
||||
/* Discard non-RAM regions */
|
||||
if ( e820buf.type != E820_TYPE_RAM )
|
||||
continue;
|
||||
|
||||
/* Check extended attributes, if present */
|
||||
if ( size > offsetof ( typeof ( e820buf ), attrs ) ) {
|
||||
if ( ! ( e820buf.attrs & E820_ATTR_ENABLED ) )
|
||||
continue;
|
||||
if ( e820buf.attrs & E820_ATTR_NONVOLATILE )
|
||||
continue;
|
||||
}
|
||||
|
||||
region->start = e820buf.start;
|
||||
region->end = e820buf.start + e820buf.len;
|
||||
region++;
|
||||
memmap->count++;
|
||||
|
||||
if ( memmap->count >= ( sizeof ( memmap->regions ) /
|
||||
sizeof ( memmap->regions[0] ) ) ) {
|
||||
DBG ( "INT 15,e820 too many regions returned\n" );
|
||||
/* Not a fatal error; what we've got so far at
|
||||
* least represents valid regions of memory,
|
||||
* even if we couldn't get them all.
|
||||
*/
|
||||
break;
|
||||
}
|
||||
} while ( next != 0 );
|
||||
|
||||
/* Sanity checks. Some BIOSes report complete garbage via INT
|
||||
* 15,e820 (especially at POST time), despite passing the
|
||||
* signature checks. We currently check for a base memory
|
||||
* region (starting at 0) and at least one high memory region
|
||||
* (starting at 0x100000).
|
||||
*/
|
||||
if ( memmap->count < 2 ) {
|
||||
DBG ( "INT 15,e820 returned only %d regions; assuming "
|
||||
"insane\n", memmap->count );
|
||||
return -EINVAL;
|
||||
}
|
||||
if ( memmap->regions[0].start != 0 ) {
|
||||
DBG ( "INT 15,e820 region 0 starts at %llx (expected 0); "
|
||||
"assuming insane\n", memmap->regions[0].start );
|
||||
return -EINVAL;
|
||||
}
|
||||
if ( memmap->regions[1].start != 0x100000 ) {
|
||||
DBG ( "INT 15,e820 region 1 starts at %llx (expected 100000); "
|
||||
"assuming insane\n", memmap->regions[0].start );
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get memory map
|
||||
*
|
||||
* @v memmap Memory map to fill in
|
||||
*/
|
||||
void x86_get_memmap ( struct memory_map *memmap ) {
|
||||
unsigned int basemem, extmem;
|
||||
int rc;
|
||||
|
||||
DBG ( "Fetching system memory map\n" );
|
||||
|
||||
/* Clear memory map */
|
||||
memset ( memmap, 0, sizeof ( *memmap ) );
|
||||
|
||||
/* Get base and extended memory sizes */
|
||||
basemem = basememsize();
|
||||
DBG ( "FBMS base memory size %d kB [0,%x)\n",
|
||||
basemem, ( basemem * 1024 ) );
|
||||
extmem = extmemsize();
|
||||
|
||||
/* Try INT 15,e820 first */
|
||||
if ( ( rc = meme820 ( memmap ) ) == 0 ) {
|
||||
DBG ( "Obtained system memory map via INT 15,e820\n" );
|
||||
return;
|
||||
}
|
||||
|
||||
/* Fall back to constructing a map from basemem and extmem sizes */
|
||||
DBG ( "INT 15,e820 failed; constructing map\n" );
|
||||
memmap->regions[0].end = ( basemem * 1024 );
|
||||
memmap->regions[1].start = 0x100000;
|
||||
memmap->regions[1].end = 0x100000 + ( extmem * 1024 );
|
||||
memmap->count = 2;
|
||||
}
|
||||
|
||||
PROVIDE_IOAPI ( x86, get_memmap, x86_get_memmap );
|
@@ -1,109 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2007 Michael Brown <mbrown@fensystems.co.uk>.
|
||||
*
|
||||
* 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 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER );
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <realmode.h>
|
||||
#include <pnpbios.h>
|
||||
|
||||
/** @file
|
||||
*
|
||||
* PnP BIOS
|
||||
*
|
||||
*/
|
||||
|
||||
/** PnP BIOS structure */
|
||||
struct pnp_bios {
|
||||
/** Signature
|
||||
*
|
||||
* Must be equal to @c PNP_BIOS_SIGNATURE
|
||||
*/
|
||||
uint32_t signature;
|
||||
/** Version as BCD (e.g. 1.0 is 0x10) */
|
||||
uint8_t version;
|
||||
/** Length of this structure */
|
||||
uint8_t length;
|
||||
/** System capabilities */
|
||||
uint16_t control;
|
||||
/** Checksum */
|
||||
uint8_t checksum;
|
||||
} __attribute__ (( packed ));
|
||||
|
||||
/** Signature for a PnP BIOS structure */
|
||||
#define PNP_BIOS_SIGNATURE \
|
||||
( ( '$' << 0 ) + ( 'P' << 8 ) + ( 'n' << 16 ) + ( 'P' << 24 ) )
|
||||
|
||||
/**
|
||||
* Test address for PnP BIOS structure
|
||||
*
|
||||
* @v offset Offset within BIOS segment to test
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int is_pnp_bios ( unsigned int offset ) {
|
||||
union {
|
||||
struct pnp_bios pnp_bios;
|
||||
uint8_t bytes[256]; /* 256 is maximum length possible */
|
||||
} u;
|
||||
size_t len;
|
||||
unsigned int i;
|
||||
uint8_t sum = 0;
|
||||
|
||||
/* Read start of header and verify signature */
|
||||
copy_from_real ( &u.pnp_bios, BIOS_SEG, offset, sizeof ( u.pnp_bios ));
|
||||
if ( u.pnp_bios.signature != PNP_BIOS_SIGNATURE )
|
||||
return -EINVAL;
|
||||
|
||||
/* Read whole header and verify checksum */
|
||||
len = u.pnp_bios.length;
|
||||
copy_from_real ( &u.bytes, BIOS_SEG, offset, len );
|
||||
for ( i = 0 ; i < len ; i++ ) {
|
||||
sum += u.bytes[i];
|
||||
}
|
||||
if ( sum != 0 )
|
||||
return -EINVAL;
|
||||
|
||||
DBG ( "Found PnP BIOS at %04x:%04x\n", BIOS_SEG, offset );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Locate Plug-and-Play BIOS
|
||||
*
|
||||
* @ret pnp_offset Offset of PnP BIOS structure within BIOS segment
|
||||
*
|
||||
* The PnP BIOS structure will be at BIOS_SEG:pnp_offset. If no PnP
|
||||
* BIOS is found, -1 is returned.
|
||||
*/
|
||||
int find_pnp_bios ( void ) {
|
||||
static int pnp_offset = 0;
|
||||
|
||||
if ( pnp_offset )
|
||||
return pnp_offset;
|
||||
|
||||
for ( pnp_offset = 0 ; pnp_offset < 0x10000 ; pnp_offset += 0x10 ) {
|
||||
if ( is_pnp_bios ( pnp_offset ) == 0 )
|
||||
return pnp_offset;
|
||||
}
|
||||
|
||||
pnp_offset = -1;
|
||||
return pnp_offset;
|
||||
}
|
@@ -1,33 +0,0 @@
|
||||
#include <ipxe/netdevice.h>
|
||||
#include <ipxe/command.h>
|
||||
#include <hci/ifmgmt_cmd.h>
|
||||
#include <pxe_call.h>
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER );
|
||||
|
||||
static int startpxe_payload ( struct net_device *netdev ) {
|
||||
if ( netdev_is_open ( netdev ) )
|
||||
pxe_activate ( netdev );
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int startpxe_exec ( int argc, char **argv ) {
|
||||
return ifcommon_exec ( argc, argv, startpxe_payload,
|
||||
"Activate PXE on" );
|
||||
}
|
||||
|
||||
static int stoppxe_exec ( int argc __unused, char **argv __unused ) {
|
||||
pxe_deactivate();
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct command pxe_commands[] __command = {
|
||||
{
|
||||
.name = "startpxe",
|
||||
.exec = startpxe_exec,
|
||||
},
|
||||
{
|
||||
.name = "stoppxe",
|
||||
.exec = stoppxe_exec,
|
||||
},
|
||||
};
|
@@ -1,114 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2007 Michael Brown <mbrown@fensystems.co.uk>.
|
||||
*
|
||||
* 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 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER );
|
||||
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
* x86 bootsector image format
|
||||
*
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <realmode.h>
|
||||
#include <biosint.h>
|
||||
#include <bootsector.h>
|
||||
|
||||
/** Vector for storing original INT 18 handler
|
||||
*
|
||||
* We do not chain to this vector, so there is no need to place it in
|
||||
* .text16.
|
||||
*/
|
||||
static struct segoff int18_vector;
|
||||
|
||||
/** Vector for storing original INT 19 handler
|
||||
*
|
||||
* We do not chain to this vector, so there is no need to place it in
|
||||
* .text16.
|
||||
*/
|
||||
static struct segoff int19_vector;
|
||||
|
||||
/** Restart point for INT 18 or 19 */
|
||||
extern void bootsector_exec_fail ( void );
|
||||
|
||||
/**
|
||||
* Jump to preloaded bootsector
|
||||
*
|
||||
* @v segment Real-mode segment
|
||||
* @v offset Real-mode offset
|
||||
* @v drive Drive number to pass to boot sector
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
int call_bootsector ( unsigned int segment, unsigned int offset,
|
||||
unsigned int drive ) {
|
||||
int discard_b, discard_D, discard_d;
|
||||
|
||||
DBG ( "Booting from boot sector at %04x:%04x\n", segment, offset );
|
||||
|
||||
/* Hook INTs 18 and 19 to capture failure paths */
|
||||
hook_bios_interrupt ( 0x18, ( unsigned int ) bootsector_exec_fail,
|
||||
&int18_vector );
|
||||
hook_bios_interrupt ( 0x19, ( unsigned int ) bootsector_exec_fail,
|
||||
&int19_vector );
|
||||
|
||||
/* Boot the loaded sector
|
||||
*
|
||||
* We assume that the boot sector may completely destroy our
|
||||
* real-mode stack, so we preserve everything we need in
|
||||
* static storage.
|
||||
*/
|
||||
__asm__ __volatile__ ( REAL_CODE ( /* Save return address off-stack */
|
||||
"popw %%cs:saved_retaddr\n\t"
|
||||
/* Save stack pointer */
|
||||
"movw %%ss, %%ax\n\t"
|
||||
"movw %%ax, %%cs:saved_ss\n\t"
|
||||
"movw %%sp, %%cs:saved_sp\n\t"
|
||||
/* Jump to boot sector */
|
||||
"pushw %%bx\n\t"
|
||||
"pushw %%di\n\t"
|
||||
"sti\n\t"
|
||||
"lret\n\t"
|
||||
/* Preserved variables */
|
||||
"\nsaved_ss: .word 0\n\t"
|
||||
"\nsaved_sp: .word 0\n\t"
|
||||
"\nsaved_retaddr: .word 0\n\t"
|
||||
/* Boot failure return point */
|
||||
"\nbootsector_exec_fail:\n\t"
|
||||
/* Restore stack pointer */
|
||||
"movw %%cs:saved_ss, %%ax\n\t"
|
||||
"movw %%ax, %%ss\n\t"
|
||||
"movw %%cs:saved_sp, %%sp\n\t"
|
||||
/* Return via saved address */
|
||||
"jmp *%%cs:saved_retaddr\n\t" )
|
||||
: "=b" ( discard_b ), "=D" ( discard_D ),
|
||||
"=d" ( discard_d )
|
||||
: "b" ( segment ), "D" ( offset ),
|
||||
"d" ( drive )
|
||||
: "eax", "ecx", "esi", "ebp" );
|
||||
|
||||
DBG ( "Booted disk returned via INT 18 or 19\n" );
|
||||
|
||||
/* Unhook INTs 18 and 19 */
|
||||
unhook_bios_interrupt ( 0x18, ( unsigned int ) bootsector_exec_fail,
|
||||
&int18_vector );
|
||||
unhook_bios_interrupt ( 0x19, ( unsigned int ) bootsector_exec_fail,
|
||||
&int19_vector );
|
||||
|
||||
return -ECANCELED;
|
||||
}
|
@@ -1,561 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2007 Michael Brown <mbrown@fensystems.co.uk>.
|
||||
*
|
||||
* 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 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER );
|
||||
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
* Linux bzImage image format
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
#include <realmode.h>
|
||||
#include <bzimage.h>
|
||||
#include <ipxe/uaccess.h>
|
||||
#include <ipxe/image.h>
|
||||
#include <ipxe/segment.h>
|
||||
#include <ipxe/init.h>
|
||||
#include <ipxe/cpio.h>
|
||||
#include <ipxe/features.h>
|
||||
|
||||
FEATURE ( FEATURE_IMAGE, "bzImage", DHCP_EB_FEATURE_BZIMAGE, 1 );
|
||||
|
||||
struct image_type bzimage_image_type __image_type ( PROBE_NORMAL );
|
||||
|
||||
/**
|
||||
* bzImage context
|
||||
*/
|
||||
struct bzimage_context {
|
||||
/** Boot protocol version */
|
||||
unsigned int version;
|
||||
/** Real-mode kernel portion load segment address */
|
||||
unsigned int rm_kernel_seg;
|
||||
/** Real-mode kernel portion load address */
|
||||
userptr_t rm_kernel;
|
||||
/** Real-mode kernel portion file size */
|
||||
size_t rm_filesz;
|
||||
/** Real-mode heap top (offset from rm_kernel) */
|
||||
size_t rm_heap;
|
||||
/** Command line (offset from rm_kernel) */
|
||||
size_t rm_cmdline;
|
||||
/** Command line maximum length */
|
||||
size_t cmdline_size;
|
||||
/** Real-mode kernel portion total memory size */
|
||||
size_t rm_memsz;
|
||||
/** Non-real-mode kernel portion load address */
|
||||
userptr_t pm_kernel;
|
||||
/** Non-real-mode kernel portion file and memory size */
|
||||
size_t pm_sz;
|
||||
/** Video mode */
|
||||
unsigned int vid_mode;
|
||||
/** Memory limit */
|
||||
uint64_t mem_limit;
|
||||
/** Initrd address */
|
||||
physaddr_t ramdisk_image;
|
||||
/** Initrd size */
|
||||
physaddr_t ramdisk_size;
|
||||
|
||||
/** Command line magic block */
|
||||
struct bzimage_cmdline cmdline_magic;
|
||||
/** bzImage header */
|
||||
struct bzimage_header bzhdr;
|
||||
};
|
||||
|
||||
/**
|
||||
* Parse bzImage header
|
||||
*
|
||||
* @v image bzImage file
|
||||
* @v bzimg bzImage context
|
||||
* @v src bzImage to parse
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int bzimage_parse_header ( struct image *image,
|
||||
struct bzimage_context *bzimg,
|
||||
userptr_t src ) {
|
||||
unsigned int syssize;
|
||||
int is_bzimage;
|
||||
|
||||
/* Sanity check */
|
||||
if ( image->len < ( BZI_HDR_OFFSET + sizeof ( bzimg->bzhdr ) ) ) {
|
||||
DBGC ( image, "bzImage %p too short for kernel header\n",
|
||||
image );
|
||||
return -ENOEXEC;
|
||||
}
|
||||
|
||||
/* Read in header structures */
|
||||
memset ( bzimg, 0, sizeof ( *bzimg ) );
|
||||
copy_from_user ( &bzimg->cmdline_magic, src, BZI_CMDLINE_OFFSET,
|
||||
sizeof ( bzimg->cmdline_magic ) );
|
||||
copy_from_user ( &bzimg->bzhdr, src, BZI_HDR_OFFSET,
|
||||
sizeof ( bzimg->bzhdr ) );
|
||||
|
||||
/* Calculate size of real-mode portion */
|
||||
bzimg->rm_filesz =
|
||||
( ( bzimg->bzhdr.setup_sects ? bzimg->bzhdr.setup_sects : 4 ) + 1 ) << 9;
|
||||
if ( bzimg->rm_filesz > image->len ) {
|
||||
DBGC ( image, "bzImage %p too short for %zd byte of setup\n",
|
||||
image, bzimg->rm_filesz );
|
||||
return -ENOEXEC;
|
||||
}
|
||||
bzimg->rm_memsz = BZI_ASSUMED_RM_SIZE;
|
||||
|
||||
/* Calculate size of protected-mode portion */
|
||||
bzimg->pm_sz = ( image->len - bzimg->rm_filesz );
|
||||
syssize = ( ( bzimg->pm_sz + 15 ) / 16 );
|
||||
|
||||
/* Check for signatures and determine version */
|
||||
if ( bzimg->bzhdr.boot_flag != BZI_BOOT_FLAG ) {
|
||||
DBGC ( image, "bzImage %p missing 55AA signature\n", image );
|
||||
return -ENOEXEC;
|
||||
}
|
||||
if ( bzimg->bzhdr.header == BZI_SIGNATURE ) {
|
||||
/* 2.00+ */
|
||||
bzimg->version = bzimg->bzhdr.version;
|
||||
} else {
|
||||
/* Pre-2.00. Check that the syssize field is correct,
|
||||
* as a guard against accepting arbitrary binary data,
|
||||
* since the 55AA check is pretty lax. Note that the
|
||||
* syssize field is unreliable for protocols between
|
||||
* 2.00 and 2.03 inclusive, so we should not always
|
||||
* check this field.
|
||||
*/
|
||||
bzimg->version = 0x0100;
|
||||
if ( bzimg->bzhdr.syssize != syssize ) {
|
||||
DBGC ( image, "bzImage %p bad syssize %x (expected "
|
||||
"%x)\n", image, bzimg->bzhdr.syssize, syssize );
|
||||
return -ENOEXEC;
|
||||
}
|
||||
}
|
||||
|
||||
/* Determine image type */
|
||||
is_bzimage = ( ( bzimg->version >= 0x0200 ) ?
|
||||
( bzimg->bzhdr.loadflags & BZI_LOAD_HIGH ) : 0 );
|
||||
|
||||
/* Calculate load address of real-mode portion */
|
||||
bzimg->rm_kernel_seg = ( is_bzimage ? 0x1000 : 0x9000 );
|
||||
bzimg->rm_kernel = real_to_user ( bzimg->rm_kernel_seg, 0 );
|
||||
|
||||
/* Allow space for the stack and heap */
|
||||
bzimg->rm_memsz += BZI_STACK_SIZE;
|
||||
bzimg->rm_heap = bzimg->rm_memsz;
|
||||
|
||||
/* Allow space for the command line */
|
||||
bzimg->rm_cmdline = bzimg->rm_memsz;
|
||||
bzimg->rm_memsz += BZI_CMDLINE_SIZE;
|
||||
|
||||
/* Calculate load address of protected-mode portion */
|
||||
bzimg->pm_kernel = phys_to_user ( is_bzimage ? BZI_LOAD_HIGH_ADDR
|
||||
: BZI_LOAD_LOW_ADDR );
|
||||
|
||||
/* Extract video mode */
|
||||
bzimg->vid_mode = bzimg->bzhdr.vid_mode;
|
||||
|
||||
/* Extract memory limit */
|
||||
bzimg->mem_limit = ( ( bzimg->version >= 0x0203 ) ?
|
||||
bzimg->bzhdr.initrd_addr_max : BZI_INITRD_MAX );
|
||||
|
||||
/* Extract command line size */
|
||||
bzimg->cmdline_size = ( ( bzimg->version >= 0x0206 ) ?
|
||||
bzimg->bzhdr.cmdline_size : BZI_CMDLINE_SIZE );
|
||||
|
||||
DBGC ( image, "bzImage %p version %04x RM %#lx+%#zx PM %#lx+%#zx "
|
||||
"cmdlen %zd\n", image, bzimg->version,
|
||||
user_to_phys ( bzimg->rm_kernel, 0 ), bzimg->rm_filesz,
|
||||
user_to_phys ( bzimg->pm_kernel, 0 ), bzimg->pm_sz,
|
||||
bzimg->cmdline_size );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update bzImage header in loaded kernel
|
||||
*
|
||||
* @v image bzImage file
|
||||
* @v bzimg bzImage context
|
||||
* @v dst bzImage to update
|
||||
*/
|
||||
static void bzimage_update_header ( struct image *image,
|
||||
struct bzimage_context *bzimg,
|
||||
userptr_t dst ) {
|
||||
|
||||
/* Set loader type */
|
||||
if ( bzimg->version >= 0x0200 )
|
||||
bzimg->bzhdr.type_of_loader = BZI_LOADER_TYPE_IPXE;
|
||||
|
||||
/* Set heap end pointer */
|
||||
if ( bzimg->version >= 0x0201 ) {
|
||||
bzimg->bzhdr.heap_end_ptr = ( bzimg->rm_heap - 0x200 );
|
||||
bzimg->bzhdr.loadflags |= BZI_CAN_USE_HEAP;
|
||||
}
|
||||
|
||||
/* Set command line */
|
||||
if ( bzimg->version >= 0x0202 ) {
|
||||
bzimg->bzhdr.cmd_line_ptr = user_to_phys ( bzimg->rm_kernel,
|
||||
bzimg->rm_cmdline );
|
||||
} else {
|
||||
bzimg->cmdline_magic.magic = BZI_CMDLINE_MAGIC;
|
||||
bzimg->cmdline_magic.offset = bzimg->rm_cmdline;
|
||||
bzimg->bzhdr.setup_move_size = bzimg->rm_memsz;
|
||||
}
|
||||
|
||||
/* Set video mode */
|
||||
bzimg->bzhdr.vid_mode = bzimg->vid_mode;
|
||||
|
||||
/* Set initrd address */
|
||||
if ( bzimg->version >= 0x0200 ) {
|
||||
bzimg->bzhdr.ramdisk_image = bzimg->ramdisk_image;
|
||||
bzimg->bzhdr.ramdisk_size = bzimg->ramdisk_size;
|
||||
}
|
||||
|
||||
/* Write out header structures */
|
||||
copy_to_user ( dst, BZI_CMDLINE_OFFSET, &bzimg->cmdline_magic,
|
||||
sizeof ( bzimg->cmdline_magic ) );
|
||||
copy_to_user ( dst, BZI_HDR_OFFSET, &bzimg->bzhdr,
|
||||
sizeof ( bzimg->bzhdr ) );
|
||||
|
||||
DBGC ( image, "bzImage %p vidmode %d\n", image, bzimg->vid_mode );
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse kernel command line for bootloader parameters
|
||||
*
|
||||
* @v image bzImage file
|
||||
* @v bzimg bzImage context
|
||||
* @v cmdline Kernel command line
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int bzimage_parse_cmdline ( struct image *image,
|
||||
struct bzimage_context *bzimg,
|
||||
const char *cmdline ) {
|
||||
char *vga;
|
||||
char *mem;
|
||||
|
||||
/* Look for "vga=" */
|
||||
if ( ( vga = strstr ( cmdline, "vga=" ) ) ) {
|
||||
vga += 4;
|
||||
if ( strcmp ( vga, "normal" ) == 0 ) {
|
||||
bzimg->vid_mode = BZI_VID_MODE_NORMAL;
|
||||
} else if ( strcmp ( vga, "ext" ) == 0 ) {
|
||||
bzimg->vid_mode = BZI_VID_MODE_EXT;
|
||||
} else if ( strcmp ( vga, "ask" ) == 0 ) {
|
||||
bzimg->vid_mode = BZI_VID_MODE_ASK;
|
||||
} else {
|
||||
bzimg->vid_mode = strtoul ( vga, &vga, 0 );
|
||||
if ( *vga && ( *vga != ' ' ) ) {
|
||||
DBGC ( image, "bzImage %p strange \"vga=\""
|
||||
"terminator '%c'\n", image, *vga );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Look for "mem=" */
|
||||
if ( ( mem = strstr ( cmdline, "mem=" ) ) ) {
|
||||
mem += 4;
|
||||
bzimg->mem_limit = strtoul ( mem, &mem, 0 );
|
||||
switch ( *mem ) {
|
||||
case 'G':
|
||||
case 'g':
|
||||
bzimg->mem_limit <<= 10;
|
||||
case 'M':
|
||||
case 'm':
|
||||
bzimg->mem_limit <<= 10;
|
||||
case 'K':
|
||||
case 'k':
|
||||
bzimg->mem_limit <<= 10;
|
||||
break;
|
||||
case '\0':
|
||||
case ' ':
|
||||
break;
|
||||
default:
|
||||
DBGC ( image, "bzImage %p strange \"mem=\" "
|
||||
"terminator '%c'\n", image, *mem );
|
||||
break;
|
||||
}
|
||||
bzimg->mem_limit -= 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set command line
|
||||
*
|
||||
* @v image bzImage image
|
||||
* @v bzimg bzImage context
|
||||
* @v cmdline Kernel command line
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int bzimage_set_cmdline ( struct image *image,
|
||||
struct bzimage_context *bzimg,
|
||||
const char *cmdline ) {
|
||||
size_t cmdline_len;
|
||||
|
||||
/* Copy command line down to real-mode portion */
|
||||
cmdline_len = ( strlen ( cmdline ) + 1 );
|
||||
if ( cmdline_len > bzimg->cmdline_size )
|
||||
cmdline_len = bzimg->cmdline_size;
|
||||
copy_to_user ( bzimg->rm_kernel, bzimg->rm_cmdline,
|
||||
cmdline, cmdline_len );
|
||||
DBGC ( image, "bzImage %p command line \"%s\"\n", image, cmdline );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load initrd
|
||||
*
|
||||
* @v image bzImage image
|
||||
* @v initrd initrd image
|
||||
* @v address Address at which to load, or UNULL
|
||||
* @ret len Length of loaded image, rounded up to 4 bytes
|
||||
*/
|
||||
static size_t bzimage_load_initrd ( struct image *image,
|
||||
struct image *initrd,
|
||||
userptr_t address ) {
|
||||
char *filename = initrd->cmdline;
|
||||
struct cpio_header cpio;
|
||||
size_t offset = 0;
|
||||
|
||||
/* Do not include kernel image itself as an initrd */
|
||||
if ( initrd == image )
|
||||
return 0;
|
||||
|
||||
/* Create cpio header before non-prebuilt images */
|
||||
if ( filename && filename[0] ) {
|
||||
size_t name_len = ( strlen ( filename ) + 1 );
|
||||
|
||||
DBGC ( image, "bzImage %p inserting initrd %p as %s\n",
|
||||
image, initrd, filename );
|
||||
memset ( &cpio, '0', sizeof ( cpio ) );
|
||||
memcpy ( cpio.c_magic, CPIO_MAGIC, sizeof ( cpio.c_magic ) );
|
||||
cpio_set_field ( cpio.c_mode, 0100644 );
|
||||
cpio_set_field ( cpio.c_nlink, 1 );
|
||||
cpio_set_field ( cpio.c_filesize, initrd->len );
|
||||
cpio_set_field ( cpio.c_namesize, name_len );
|
||||
if ( address ) {
|
||||
copy_to_user ( address, offset, &cpio,
|
||||
sizeof ( cpio ) );
|
||||
}
|
||||
offset += sizeof ( cpio );
|
||||
if ( address ) {
|
||||
copy_to_user ( address, offset, filename,
|
||||
name_len );
|
||||
}
|
||||
offset += name_len;
|
||||
offset = ( ( offset + 0x03 ) & ~0x03 );
|
||||
}
|
||||
|
||||
/* Copy in initrd image body */
|
||||
if ( address )
|
||||
memcpy_user ( address, offset, initrd->data, 0, initrd->len );
|
||||
offset += initrd->len;
|
||||
if ( address ) {
|
||||
DBGC ( image, "bzImage %p has initrd %p at [%lx,%lx)\n",
|
||||
image, initrd, user_to_phys ( address, 0 ),
|
||||
user_to_phys ( address, offset ) );
|
||||
}
|
||||
|
||||
/* Round up to 4-byte boundary */
|
||||
offset = ( ( offset + 0x03 ) & ~0x03 );
|
||||
return offset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load initrds, if any
|
||||
*
|
||||
* @v image bzImage image
|
||||
* @v bzimg bzImage context
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int bzimage_load_initrds ( struct image *image,
|
||||
struct bzimage_context *bzimg ) {
|
||||
struct image *initrd;
|
||||
size_t total_len = 0;
|
||||
physaddr_t address;
|
||||
int rc;
|
||||
|
||||
/* Add up length of all initrd images */
|
||||
for_each_image ( initrd )
|
||||
total_len += bzimage_load_initrd ( image, initrd, UNULL );
|
||||
|
||||
/* Give up if no initrd images found */
|
||||
if ( ! total_len )
|
||||
return 0;
|
||||
|
||||
/* Find a suitable start address. Try 1MB boundaries,
|
||||
* starting from the downloaded kernel image itself and
|
||||
* working downwards until we hit an available region.
|
||||
*/
|
||||
for ( address = ( user_to_phys ( image->data, 0 ) & ~0xfffff ) ; ;
|
||||
address -= 0x100000 ) {
|
||||
/* Check that we're not going to overwrite the
|
||||
* kernel itself. This check isn't totally
|
||||
* accurate, but errs on the side of caution.
|
||||
*/
|
||||
if ( address <= ( BZI_LOAD_HIGH_ADDR + image->len ) ) {
|
||||
DBGC ( image, "bzImage %p could not find a location "
|
||||
"for initrd\n", image );
|
||||
return -ENOBUFS;
|
||||
}
|
||||
/* Check that we are within the kernel's range */
|
||||
if ( ( address + total_len - 1 ) > bzimg->mem_limit )
|
||||
continue;
|
||||
/* Prepare and verify segment */
|
||||
if ( ( rc = prep_segment ( phys_to_user ( address ), 0,
|
||||
total_len ) ) != 0 )
|
||||
continue;
|
||||
/* Use this address */
|
||||
break;
|
||||
}
|
||||
|
||||
/* Record initrd location */
|
||||
bzimg->ramdisk_image = address;
|
||||
bzimg->ramdisk_size = total_len;
|
||||
|
||||
/* Construct initrd */
|
||||
DBGC ( image, "bzImage %p constructing initrd at [%lx,%lx)\n",
|
||||
image, address, ( address + total_len ) );
|
||||
for_each_image ( initrd ) {
|
||||
address += bzimage_load_initrd ( image, initrd,
|
||||
phys_to_user ( address ) );
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute bzImage image
|
||||
*
|
||||
* @v image bzImage image
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int bzimage_exec ( struct image *image ) {
|
||||
struct bzimage_context bzimg;
|
||||
const char *cmdline = ( image->cmdline ? image->cmdline : "" );
|
||||
int rc;
|
||||
|
||||
/* Read and parse header from loaded kernel */
|
||||
if ( ( rc = bzimage_parse_header ( image, &bzimg,
|
||||
image->priv.user ) ) != 0 )
|
||||
return rc;
|
||||
assert ( bzimg.rm_kernel == image->priv.user );
|
||||
|
||||
/* Parse command line for bootloader parameters */
|
||||
if ( ( rc = bzimage_parse_cmdline ( image, &bzimg, cmdline ) ) != 0)
|
||||
return rc;
|
||||
|
||||
/* Store command line */
|
||||
if ( ( rc = bzimage_set_cmdline ( image, &bzimg, cmdline ) ) != 0 )
|
||||
return rc;
|
||||
|
||||
/* Load any initrds */
|
||||
if ( ( rc = bzimage_load_initrds ( image, &bzimg ) ) != 0 )
|
||||
return rc;
|
||||
|
||||
/* Update kernel header */
|
||||
bzimage_update_header ( image, &bzimg, bzimg.rm_kernel );
|
||||
|
||||
/* Prepare for exiting */
|
||||
shutdown ( SHUTDOWN_BOOT );
|
||||
|
||||
DBGC ( image, "bzImage %p jumping to RM kernel at %04x:0000 "
|
||||
"(stack %04x:%04zx)\n", image, ( bzimg.rm_kernel_seg + 0x20 ),
|
||||
bzimg.rm_kernel_seg, bzimg.rm_heap );
|
||||
|
||||
/* Jump to the kernel */
|
||||
__asm__ __volatile__ ( REAL_CODE ( "movw %w0, %%ds\n\t"
|
||||
"movw %w0, %%es\n\t"
|
||||
"movw %w0, %%fs\n\t"
|
||||
"movw %w0, %%gs\n\t"
|
||||
"movw %w0, %%ss\n\t"
|
||||
"movw %w1, %%sp\n\t"
|
||||
"pushw %w2\n\t"
|
||||
"pushw $0\n\t"
|
||||
"lret\n\t" )
|
||||
: : "r" ( bzimg.rm_kernel_seg ),
|
||||
"r" ( bzimg.rm_heap ),
|
||||
"r" ( bzimg.rm_kernel_seg + 0x20 ) );
|
||||
|
||||
/* There is no way for the image to return, since we provide
|
||||
* no return address.
|
||||
*/
|
||||
assert ( 0 );
|
||||
|
||||
return -ECANCELED; /* -EIMPOSSIBLE */
|
||||
}
|
||||
|
||||
/**
|
||||
* Load bzImage image into memory
|
||||
*
|
||||
* @v image bzImage file
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
int bzimage_load ( struct image *image ) {
|
||||
struct bzimage_context bzimg;
|
||||
int rc;
|
||||
|
||||
/* Read and parse header from image */
|
||||
if ( ( rc = bzimage_parse_header ( image, &bzimg,
|
||||
image->data ) ) != 0 )
|
||||
return rc;
|
||||
|
||||
/* This is a bzImage image, valid or otherwise */
|
||||
if ( ! image->type )
|
||||
image->type = &bzimage_image_type;
|
||||
|
||||
/* Prepare segments */
|
||||
if ( ( rc = prep_segment ( bzimg.rm_kernel, bzimg.rm_filesz,
|
||||
bzimg.rm_memsz ) ) != 0 ) {
|
||||
DBGC ( image, "bzImage %p could not prepare RM segment: %s\n",
|
||||
image, strerror ( rc ) );
|
||||
return rc;
|
||||
}
|
||||
if ( ( rc = prep_segment ( bzimg.pm_kernel, bzimg.pm_sz,
|
||||
bzimg.pm_sz ) ) != 0 ) {
|
||||
DBGC ( image, "bzImage %p could not prepare PM segment: %s\n",
|
||||
image, strerror ( rc ) );
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Load segments */
|
||||
memcpy_user ( bzimg.rm_kernel, 0, image->data,
|
||||
0, bzimg.rm_filesz );
|
||||
memcpy_user ( bzimg.pm_kernel, 0, image->data,
|
||||
bzimg.rm_filesz, bzimg.pm_sz );
|
||||
|
||||
/* Update and write out header */
|
||||
bzimage_update_header ( image, &bzimg, bzimg.rm_kernel );
|
||||
|
||||
/* Record real-mode segment in image private data field */
|
||||
image->priv.user = bzimg.rm_kernel;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Linux bzImage image type */
|
||||
struct image_type bzimage_image_type __image_type ( PROBE_NORMAL ) = {
|
||||
.name = "bzImage",
|
||||
.load = bzimage_load,
|
||||
.exec = bzimage_exec,
|
||||
};
|
@@ -1,327 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Daniel Verkamp <daniel@drv.nu>.
|
||||
*
|
||||
* 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 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
* SYSLINUX COM32 image format
|
||||
*
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER );
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
#include <realmode.h>
|
||||
#include <basemem.h>
|
||||
#include <comboot.h>
|
||||
#include <ipxe/uaccess.h>
|
||||
#include <ipxe/image.h>
|
||||
#include <ipxe/segment.h>
|
||||
#include <ipxe/init.h>
|
||||
#include <ipxe/io.h>
|
||||
|
||||
struct image_type com32_image_type __image_type ( PROBE_NORMAL );
|
||||
|
||||
struct idt_register com32_external_idtr = {
|
||||
.limit = COM32_NUM_IDT_ENTRIES * sizeof ( struct idt_descriptor ) - 1,
|
||||
.base = COM32_IDT
|
||||
};
|
||||
|
||||
struct idt_register com32_internal_idtr;
|
||||
|
||||
/**
|
||||
* Execute COMBOOT image
|
||||
*
|
||||
* @v image COM32 image
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int com32_exec ( struct image *image ) {
|
||||
struct memory_map memmap;
|
||||
unsigned int i;
|
||||
int state;
|
||||
uint32_t avail_mem_top;
|
||||
|
||||
state = rmsetjmp ( comboot_return );
|
||||
|
||||
switch ( state ) {
|
||||
case 0: /* First time through; invoke COM32 program */
|
||||
|
||||
/* Get memory map */
|
||||
get_memmap ( &memmap );
|
||||
|
||||
/* Find end of block covering COM32 image loading area */
|
||||
for ( i = 0, avail_mem_top = 0 ; i < memmap.count ; i++ ) {
|
||||
if ( (memmap.regions[i].start <= COM32_START_PHYS) &&
|
||||
(memmap.regions[i].end > COM32_START_PHYS + image->len) ) {
|
||||
avail_mem_top = memmap.regions[i].end;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
DBGC ( image, "COM32 %p: available memory top = 0x%x\n",
|
||||
image, avail_mem_top );
|
||||
|
||||
assert ( avail_mem_top != 0 );
|
||||
|
||||
com32_external_esp = phys_to_virt ( avail_mem_top );
|
||||
|
||||
/* Hook COMBOOT API interrupts */
|
||||
hook_comboot_interrupts();
|
||||
|
||||
/* Unregister image, so that a "boot" command doesn't
|
||||
* throw us into an execution loop. We never
|
||||
* reregister ourselves; COMBOOT images expect to be
|
||||
* removed on exit.
|
||||
*/
|
||||
unregister_image ( image );
|
||||
|
||||
__asm__ __volatile__ (
|
||||
"sidt com32_internal_idtr\n\t"
|
||||
"lidt com32_external_idtr\n\t" /* Set up IDT */
|
||||
"movl %%esp, (com32_internal_esp)\n\t" /* Save internal virtual address space ESP */
|
||||
"movl (com32_external_esp), %%esp\n\t" /* Switch to COM32 ESP (top of available memory) */
|
||||
"call _virt_to_phys\n\t" /* Switch to flat physical address space */
|
||||
"sti\n\t" /* Enable interrupts */
|
||||
"pushl %0\n\t" /* Pointer to CDECL helper function */
|
||||
"pushl %1\n\t" /* Pointer to FAR call helper function */
|
||||
"pushl %2\n\t" /* Size of low memory bounce buffer */
|
||||
"pushl %3\n\t" /* Pointer to low memory bounce buffer */
|
||||
"pushl %4\n\t" /* Pointer to INT call helper function */
|
||||
"pushl %5\n\t" /* Pointer to the command line arguments */
|
||||
"pushl $6\n\t" /* Number of additional arguments */
|
||||
"call *%6\n\t" /* Execute image */
|
||||
"cli\n\t" /* Disable interrupts */
|
||||
"call _phys_to_virt\n\t" /* Switch back to internal virtual address space */
|
||||
"lidt com32_internal_idtr\n\t" /* Switch back to internal IDT (for debugging) */
|
||||
"movl (com32_internal_esp), %%esp\n\t" /* Switch back to internal stack */
|
||||
:
|
||||
:
|
||||
/* %0 */ "r" ( virt_to_phys ( com32_cfarcall_wrapper ) ),
|
||||
/* %1 */ "r" ( virt_to_phys ( com32_farcall_wrapper ) ),
|
||||
/* %2 */ "r" ( get_fbms() * 1024 - (COM32_BOUNCE_SEG << 4) ),
|
||||
/* %3 */ "i" ( COM32_BOUNCE_SEG << 4 ),
|
||||
/* %4 */ "r" ( virt_to_phys ( com32_intcall_wrapper ) ),
|
||||
/* %5 */ "r" ( virt_to_phys ( image->cmdline ) ),
|
||||
/* %6 */ "r" ( COM32_START_PHYS )
|
||||
:
|
||||
"memory" );
|
||||
DBGC ( image, "COM32 %p: returned\n", image );
|
||||
break;
|
||||
|
||||
case COMBOOT_EXIT:
|
||||
DBGC ( image, "COM32 %p: exited\n", image );
|
||||
break;
|
||||
|
||||
case COMBOOT_EXIT_RUN_KERNEL:
|
||||
DBGC ( image, "COM32 %p: exited to run kernel %p\n",
|
||||
image, comboot_replacement_image );
|
||||
image->replacement = comboot_replacement_image;
|
||||
comboot_replacement_image = NULL;
|
||||
image_autoload ( image->replacement );
|
||||
break;
|
||||
|
||||
case COMBOOT_EXIT_COMMAND:
|
||||
DBGC ( image, "COM32 %p: exited after executing command\n",
|
||||
image );
|
||||
break;
|
||||
|
||||
default:
|
||||
assert ( 0 );
|
||||
break;
|
||||
}
|
||||
|
||||
unhook_comboot_interrupts();
|
||||
comboot_force_text_mode();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check image name extension
|
||||
*
|
||||
* @v image COM32 image
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int com32_identify ( struct image *image ) {
|
||||
const char *ext;
|
||||
static const uint8_t magic[] = { 0xB8, 0xFF, 0x4C, 0xCD, 0x21 };
|
||||
uint8_t buf[5];
|
||||
|
||||
if ( image->len >= 5 ) {
|
||||
/* Check for magic number
|
||||
* mov eax,21cd4cffh
|
||||
* B8 FF 4C CD 21
|
||||
*/
|
||||
copy_from_user ( buf, image->data, 0, sizeof(buf) );
|
||||
if ( ! memcmp ( buf, magic, sizeof(buf) ) ) {
|
||||
DBGC ( image, "COM32 %p: found magic number\n",
|
||||
image );
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Magic number not found; check filename extension */
|
||||
|
||||
ext = strrchr( image->name, '.' );
|
||||
|
||||
if ( ! ext ) {
|
||||
DBGC ( image, "COM32 %p: no extension\n",
|
||||
image );
|
||||
return -ENOEXEC;
|
||||
}
|
||||
|
||||
++ext;
|
||||
|
||||
if ( strcasecmp( ext, "c32" ) ) {
|
||||
DBGC ( image, "COM32 %p: unrecognized extension %s\n",
|
||||
image, ext );
|
||||
return -ENOEXEC;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Load COM32 image into memory and set up the IDT
|
||||
* @v image COM32 image
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int comboot_load_image ( struct image *image ) {
|
||||
physaddr_t com32_irq_wrapper_phys;
|
||||
struct idt_descriptor *idt;
|
||||
struct ijb_entry *ijb;
|
||||
size_t filesz, memsz;
|
||||
userptr_t buffer;
|
||||
int rc, i;
|
||||
|
||||
/* The interrupt descriptor table, interrupt jump buffer, and
|
||||
* image data are all contiguous in memory. Prepare them all at once.
|
||||
*/
|
||||
filesz = image->len +
|
||||
COM32_NUM_IDT_ENTRIES * sizeof ( struct idt_descriptor ) +
|
||||
COM32_NUM_IDT_ENTRIES * sizeof ( struct ijb_entry );
|
||||
memsz = filesz;
|
||||
buffer = phys_to_user ( COM32_IDT );
|
||||
if ( ( rc = prep_segment ( buffer, filesz, memsz ) ) != 0 ) {
|
||||
DBGC ( image, "COM32 %p: could not prepare segment: %s\n",
|
||||
image, strerror ( rc ) );
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Write the IDT and IJB */
|
||||
idt = phys_to_virt ( COM32_IDT );
|
||||
ijb = phys_to_virt ( COM32_IJB );
|
||||
com32_irq_wrapper_phys = virt_to_phys ( com32_irq_wrapper );
|
||||
|
||||
for ( i = 0; i < COM32_NUM_IDT_ENTRIES; i++ ) {
|
||||
uint32_t ijb_address = virt_to_phys ( &ijb[i] );
|
||||
|
||||
idt[i].offset_low = ijb_address & 0xFFFF;
|
||||
idt[i].selector = PHYSICAL_CS;
|
||||
idt[i].flags = IDT_INTERRUPT_GATE_FLAGS;
|
||||
idt[i].offset_high = ijb_address >> 16;
|
||||
|
||||
ijb[i].pusha_instruction = IJB_PUSHA;
|
||||
ijb[i].mov_instruction = IJB_MOV_AL_IMM8;
|
||||
ijb[i].mov_value = i;
|
||||
ijb[i].jump_instruction = IJB_JMP_REL32;
|
||||
ijb[i].jump_destination = com32_irq_wrapper_phys -
|
||||
virt_to_phys ( &ijb[i + 1] );
|
||||
}
|
||||
|
||||
/* Copy image to segment */
|
||||
buffer = phys_to_user ( COM32_START_PHYS );
|
||||
memcpy_user ( buffer, 0, image->data, 0, filesz );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare COM32 low memory bounce buffer
|
||||
* @v image COM32 image
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int comboot_prepare_bounce_buffer ( struct image * image ) {
|
||||
unsigned int seg;
|
||||
userptr_t seg_userptr;
|
||||
size_t filesz, memsz;
|
||||
int rc;
|
||||
|
||||
seg = COM32_BOUNCE_SEG;
|
||||
seg_userptr = real_to_user ( seg, 0 );
|
||||
|
||||
/* Ensure the entire 64k segment is free */
|
||||
memsz = 0xFFFF;
|
||||
filesz = 0;
|
||||
|
||||
/* Prepare, verify, and load the real-mode segment */
|
||||
if ( ( rc = prep_segment ( seg_userptr, filesz, memsz ) ) != 0 ) {
|
||||
DBGC ( image, "COM32 %p: could not prepare bounce buffer segment: %s\n",
|
||||
image, strerror ( rc ) );
|
||||
return rc;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load COM32 image into memory
|
||||
*
|
||||
* @v image COM32 image
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int com32_load ( struct image *image ) {
|
||||
int rc;
|
||||
|
||||
DBGC ( image, "COM32 %p: name '%s', cmdline '%s'\n",
|
||||
image, image->name, image->cmdline );
|
||||
|
||||
/* Check if this is a COMBOOT image */
|
||||
if ( ( rc = com32_identify ( image ) ) != 0 ) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* This is a COM32 image, valid or otherwise */
|
||||
if ( ! image->type )
|
||||
image->type = &com32_image_type;
|
||||
|
||||
/* Load image */
|
||||
if ( ( rc = comboot_load_image ( image ) ) != 0 ) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Prepare bounce buffer segment */
|
||||
if ( ( rc = comboot_prepare_bounce_buffer ( image ) ) != 0 ) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** SYSLINUX COM32 image type */
|
||||
struct image_type com32_image_type __image_type ( PROBE_NORMAL ) = {
|
||||
.name = "COM32",
|
||||
.load = com32_load,
|
||||
.exec = com32_exec,
|
||||
};
|
@@ -1,322 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Daniel Verkamp <daniel@drv.nu>.
|
||||
*
|
||||
* 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 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
* SYSLINUX COMBOOT (16-bit) image format
|
||||
*
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER );
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
#include <realmode.h>
|
||||
#include <basemem.h>
|
||||
#include <comboot.h>
|
||||
#include <ipxe/uaccess.h>
|
||||
#include <ipxe/image.h>
|
||||
#include <ipxe/segment.h>
|
||||
#include <ipxe/init.h>
|
||||
#include <ipxe/features.h>
|
||||
|
||||
FEATURE ( FEATURE_IMAGE, "COMBOOT", DHCP_EB_FEATURE_COMBOOT, 1 );
|
||||
|
||||
struct image_type comboot_image_type __image_type ( PROBE_NORMAL );
|
||||
|
||||
/**
|
||||
* COMBOOT PSP, copied to offset 0 of code segment
|
||||
*/
|
||||
struct comboot_psp {
|
||||
/** INT 20 instruction, executed if COMBOOT image returns with RET */
|
||||
uint16_t int20;
|
||||
/** Segment of first non-free paragraph of memory */
|
||||
uint16_t first_non_free_para;
|
||||
};
|
||||
|
||||
/** Offset in PSP of command line */
|
||||
#define COMBOOT_PSP_CMDLINE_OFFSET 0x81
|
||||
|
||||
/** Maximum length of command line in PSP
|
||||
* (127 bytes minus space and CR) */
|
||||
#define COMBOOT_MAX_CMDLINE_LEN 125
|
||||
|
||||
|
||||
/**
|
||||
* Copy command line to PSP
|
||||
*
|
||||
* @v image COMBOOT image
|
||||
*/
|
||||
static void comboot_copy_cmdline ( struct image * image, userptr_t seg_userptr ) {
|
||||
const char *cmdline = ( image->cmdline ? image->cmdline : "" );
|
||||
int cmdline_len = strlen ( cmdline );
|
||||
if( cmdline_len > COMBOOT_MAX_CMDLINE_LEN )
|
||||
cmdline_len = COMBOOT_MAX_CMDLINE_LEN;
|
||||
uint8_t len_byte = cmdline_len;
|
||||
char spc = ' ', cr = '\r';
|
||||
|
||||
/* Copy length to byte before command line */
|
||||
copy_to_user ( seg_userptr, COMBOOT_PSP_CMDLINE_OFFSET - 1,
|
||||
&len_byte, 1 );
|
||||
|
||||
/* Command line starts with space */
|
||||
copy_to_user ( seg_userptr,
|
||||
COMBOOT_PSP_CMDLINE_OFFSET,
|
||||
&spc, 1 );
|
||||
|
||||
/* Copy command line */
|
||||
copy_to_user ( seg_userptr,
|
||||
COMBOOT_PSP_CMDLINE_OFFSET + 1,
|
||||
cmdline, cmdline_len );
|
||||
|
||||
/* Command line ends with CR */
|
||||
copy_to_user ( seg_userptr,
|
||||
COMBOOT_PSP_CMDLINE_OFFSET + cmdline_len + 1,
|
||||
&cr, 1 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize PSP
|
||||
*
|
||||
* @v image COMBOOT image
|
||||
* @v seg_userptr segment to initialize
|
||||
*/
|
||||
static void comboot_init_psp ( struct image * image, userptr_t seg_userptr ) {
|
||||
struct comboot_psp psp;
|
||||
|
||||
/* Fill PSP */
|
||||
|
||||
/* INT 20h instruction, byte order reversed */
|
||||
psp.int20 = 0x20CD;
|
||||
|
||||
/* get_fbms() returns BIOS free base memory counter, which is in
|
||||
* kilobytes; x * 1024 / 16 == x * 64 == x << 6 */
|
||||
psp.first_non_free_para = get_fbms() << 6;
|
||||
|
||||
DBGC ( image, "COMBOOT %p: first non-free paragraph = 0x%x\n",
|
||||
image, psp.first_non_free_para );
|
||||
|
||||
/* Copy the PSP to offset 0 of segment.
|
||||
* The rest of the PSP was already zeroed by
|
||||
* comboot_prepare_segment. */
|
||||
copy_to_user ( seg_userptr, 0, &psp, sizeof( psp ) );
|
||||
|
||||
/* Copy the command line to the PSP */
|
||||
comboot_copy_cmdline ( image, seg_userptr );
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute COMBOOT image
|
||||
*
|
||||
* @v image COMBOOT image
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int comboot_exec ( struct image *image ) {
|
||||
userptr_t seg_userptr = real_to_user ( COMBOOT_PSP_SEG, 0 );
|
||||
int state;
|
||||
|
||||
state = rmsetjmp ( comboot_return );
|
||||
|
||||
switch ( state ) {
|
||||
case 0: /* First time through; invoke COMBOOT program */
|
||||
|
||||
/* Initialize PSP */
|
||||
comboot_init_psp ( image, seg_userptr );
|
||||
|
||||
/* Hook COMBOOT API interrupts */
|
||||
hook_comboot_interrupts();
|
||||
|
||||
DBGC ( image, "executing 16-bit COMBOOT image at %4x:0100\n",
|
||||
COMBOOT_PSP_SEG );
|
||||
|
||||
/* Unregister image, so that a "boot" command doesn't
|
||||
* throw us into an execution loop. We never
|
||||
* reregister ourselves; COMBOOT images expect to be
|
||||
* removed on exit.
|
||||
*/
|
||||
unregister_image ( image );
|
||||
|
||||
/* Store stack segment at 0x38 and stack pointer at 0x3A
|
||||
* in the PSP and jump to the image */
|
||||
__asm__ __volatile__ (
|
||||
REAL_CODE ( /* Save return address with segment on old stack */
|
||||
"popw %%ax\n\t"
|
||||
"pushw %%cs\n\t"
|
||||
"pushw %%ax\n\t"
|
||||
/* Set DS=ES=segment with image */
|
||||
"movw %w0, %%ds\n\t"
|
||||
"movw %w0, %%es\n\t"
|
||||
/* Set SS:SP to new stack (end of image segment) */
|
||||
"movw %w0, %%ss\n\t"
|
||||
"xor %%sp, %%sp\n\t"
|
||||
"pushw $0\n\t"
|
||||
"pushw %w0\n\t"
|
||||
"pushw $0x100\n\t"
|
||||
/* Zero registers (some COM files assume GP regs are 0) */
|
||||
"xorw %%ax, %%ax\n\t"
|
||||
"xorw %%bx, %%bx\n\t"
|
||||
"xorw %%cx, %%cx\n\t"
|
||||
"xorw %%dx, %%dx\n\t"
|
||||
"xorw %%si, %%si\n\t"
|
||||
"xorw %%di, %%di\n\t"
|
||||
"xorw %%bp, %%bp\n\t"
|
||||
"lret\n\t" )
|
||||
: : "r" ( COMBOOT_PSP_SEG ) : "eax" );
|
||||
DBGC ( image, "COMBOOT %p: returned\n", image );
|
||||
break;
|
||||
|
||||
case COMBOOT_EXIT:
|
||||
DBGC ( image, "COMBOOT %p: exited\n", image );
|
||||
break;
|
||||
|
||||
case COMBOOT_EXIT_RUN_KERNEL:
|
||||
DBGC ( image, "COMBOOT %p: exited to run kernel %p\n",
|
||||
image, comboot_replacement_image );
|
||||
image->replacement = comboot_replacement_image;
|
||||
comboot_replacement_image = NULL;
|
||||
image_autoload ( image->replacement );
|
||||
break;
|
||||
|
||||
case COMBOOT_EXIT_COMMAND:
|
||||
DBGC ( image, "COMBOOT %p: exited after executing command\n",
|
||||
image );
|
||||
break;
|
||||
|
||||
default:
|
||||
assert ( 0 );
|
||||
break;
|
||||
}
|
||||
|
||||
unhook_comboot_interrupts();
|
||||
comboot_force_text_mode();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check image name extension
|
||||
*
|
||||
* @v image COMBOOT image
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int comboot_identify ( struct image *image ) {
|
||||
const char *ext;
|
||||
|
||||
ext = strrchr( image->name, '.' );
|
||||
|
||||
if ( ! ext ) {
|
||||
DBGC ( image, "COMBOOT %p: no extension\n",
|
||||
image );
|
||||
return -ENOEXEC;
|
||||
}
|
||||
|
||||
++ext;
|
||||
|
||||
if ( strcasecmp( ext, "com" ) && strcasecmp( ext, "cbt" ) ) {
|
||||
DBGC ( image, "COMBOOT %p: unrecognized extension %s\n",
|
||||
image, ext );
|
||||
return -ENOEXEC;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load COMBOOT image into memory, preparing a segment and returning it
|
||||
* @v image COMBOOT image
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int comboot_prepare_segment ( struct image *image )
|
||||
{
|
||||
userptr_t seg_userptr;
|
||||
size_t filesz, memsz;
|
||||
int rc;
|
||||
|
||||
/* Load image in segment */
|
||||
seg_userptr = real_to_user ( COMBOOT_PSP_SEG, 0 );
|
||||
|
||||
/* Allow etra 0x100 bytes before image for PSP */
|
||||
filesz = image->len + 0x100;
|
||||
|
||||
/* Ensure the entire 64k segment is free */
|
||||
memsz = 0xFFFF;
|
||||
|
||||
/* Prepare, verify, and load the real-mode segment */
|
||||
if ( ( rc = prep_segment ( seg_userptr, filesz, memsz ) ) != 0 ) {
|
||||
DBGC ( image, "COMBOOT %p: could not prepare segment: %s\n",
|
||||
image, strerror ( rc ) );
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Zero PSP */
|
||||
memset_user ( seg_userptr, 0, 0, 0x100 );
|
||||
|
||||
/* Copy image to segment:0100 */
|
||||
memcpy_user ( seg_userptr, 0x100, image->data, 0, image->len );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load COMBOOT image into memory
|
||||
*
|
||||
* @v image COMBOOT image
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int comboot_load ( struct image *image ) {
|
||||
int rc;
|
||||
|
||||
DBGC ( image, "COMBOOT %p: name '%s'\n",
|
||||
image, image->name );
|
||||
|
||||
/* Check if this is a COMBOOT image */
|
||||
if ( ( rc = comboot_identify ( image ) ) != 0 ) {
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* This is a 16-bit COMBOOT image, valid or otherwise */
|
||||
if ( ! image->type )
|
||||
image->type = &comboot_image_type;
|
||||
|
||||
/* Sanity check for filesize */
|
||||
if( image->len >= 0xFF00 ) {
|
||||
DBGC( image, "COMBOOT %p: image too large\n",
|
||||
image );
|
||||
return -ENOEXEC;
|
||||
}
|
||||
|
||||
/* Prepare segment and load image */
|
||||
if ( ( rc = comboot_prepare_segment ( image ) ) != 0 ) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** SYSLINUX COMBOOT (16-bit) image type */
|
||||
struct image_type comboot_image_type __image_type ( PROBE_NORMAL ) = {
|
||||
.name = "COMBOOT",
|
||||
.load = comboot_load,
|
||||
.exec = comboot_exec,
|
||||
};
|
@@ -1,113 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Michael Brown <mbrown@fensystems.co.uk>.
|
||||
*
|
||||
* 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 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER );
|
||||
|
||||
#include <errno.h>
|
||||
#include <elf.h>
|
||||
#include <ipxe/image.h>
|
||||
#include <ipxe/elf.h>
|
||||
#include <ipxe/features.h>
|
||||
#include <ipxe/init.h>
|
||||
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
* ELF bootable image
|
||||
*
|
||||
*/
|
||||
|
||||
FEATURE ( FEATURE_IMAGE, "ELF", DHCP_EB_FEATURE_ELF, 1 );
|
||||
|
||||
struct image_type elfboot_image_type __image_type ( PROBE_NORMAL );
|
||||
|
||||
/**
|
||||
* Execute ELF image
|
||||
*
|
||||
* @v image ELF image
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int elfboot_exec ( struct image *image ) {
|
||||
physaddr_t entry = image->priv.phys;
|
||||
|
||||
/* An ELF image has no callback interface, so we need to shut
|
||||
* down before invoking it.
|
||||
*/
|
||||
shutdown ( SHUTDOWN_BOOT );
|
||||
|
||||
/* Jump to OS with flat physical addressing */
|
||||
DBGC ( image, "ELF %p starting execution at %lx\n", image, entry );
|
||||
__asm__ __volatile__ ( PHYS_CODE ( "call *%%edi\n\t" )
|
||||
: : "D" ( entry )
|
||||
: "eax", "ebx", "ecx", "edx", "esi", "ebp",
|
||||
"memory" );
|
||||
|
||||
DBGC ( image, "ELF %p returned\n", image );
|
||||
|
||||
/* It isn't safe to continue after calling shutdown() */
|
||||
while ( 1 ) {}
|
||||
|
||||
return -ECANCELED; /* -EIMPOSSIBLE, anyone? */
|
||||
}
|
||||
|
||||
/**
|
||||
* Load ELF image into memory
|
||||
*
|
||||
* @v image ELF file
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int elfboot_load ( struct image *image ) {
|
||||
Elf32_Ehdr ehdr;
|
||||
static const uint8_t e_ident[] = {
|
||||
[EI_MAG0] = ELFMAG0,
|
||||
[EI_MAG1] = ELFMAG1,
|
||||
[EI_MAG2] = ELFMAG2,
|
||||
[EI_MAG3] = ELFMAG3,
|
||||
[EI_CLASS] = ELFCLASS32,
|
||||
[EI_DATA] = ELFDATA2LSB,
|
||||
[EI_VERSION] = EV_CURRENT,
|
||||
};
|
||||
int rc;
|
||||
|
||||
/* Read ELF header */
|
||||
copy_from_user ( &ehdr, image->data, 0, sizeof ( ehdr ) );
|
||||
if ( memcmp ( ehdr.e_ident, e_ident, sizeof ( e_ident ) ) != 0 ) {
|
||||
DBG ( "Invalid ELF identifier\n" );
|
||||
return -ENOEXEC;
|
||||
}
|
||||
|
||||
/* This is an ELF image, valid or otherwise */
|
||||
if ( ! image->type )
|
||||
image->type = &elfboot_image_type;
|
||||
|
||||
/* Load the image using core ELF support */
|
||||
if ( ( rc = elf_load ( image ) ) != 0 ) {
|
||||
DBGC ( image, "ELF %p could not load: %s\n",
|
||||
image, strerror ( rc ) );
|
||||
return rc;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** ELF image type */
|
||||
struct image_type elfboot_image_type __image_type ( PROBE_NORMAL ) = {
|
||||
.name = "ELF",
|
||||
.load = elfboot_load,
|
||||
.exec = elfboot_exec,
|
||||
};
|
@@ -1,466 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2007 Michael Brown <mbrown@fensystems.co.uk>.
|
||||
*
|
||||
* 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 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER );
|
||||
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
* Multiboot image format
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
#include <realmode.h>
|
||||
#include <multiboot.h>
|
||||
#include <ipxe/uaccess.h>
|
||||
#include <ipxe/image.h>
|
||||
#include <ipxe/segment.h>
|
||||
#include <ipxe/io.h>
|
||||
#include <ipxe/elf.h>
|
||||
#include <ipxe/init.h>
|
||||
#include <ipxe/features.h>
|
||||
|
||||
FEATURE ( FEATURE_IMAGE, "MBOOT", DHCP_EB_FEATURE_MULTIBOOT, 1 );
|
||||
|
||||
struct image_type multiboot_image_type __image_type ( PROBE_MULTIBOOT );
|
||||
|
||||
/**
|
||||
* Maximum number of modules we will allow for
|
||||
*
|
||||
* If this has bitten you: sorry. I did have a perfect scheme with a
|
||||
* dynamically allocated list of modules on the protected-mode stack,
|
||||
* but it was incompatible with some broken OSes that can only access
|
||||
* low memory at boot time (even though we kindly set up 4GB flat
|
||||
* physical addressing as per the multiboot specification.
|
||||
*
|
||||
*/
|
||||
#define MAX_MODULES 8
|
||||
|
||||
/**
|
||||
* Maximum combined length of command lines
|
||||
*
|
||||
* Again; sorry. Some broken OSes zero out any non-base memory that
|
||||
* isn't part of the loaded module set, so we can't just use
|
||||
* virt_to_phys(cmdline) to point to the command lines, even though
|
||||
* this would comply with the Multiboot spec.
|
||||
*/
|
||||
#define MB_MAX_CMDLINE 512
|
||||
|
||||
/** Multiboot flags that we support */
|
||||
#define MB_SUPPORTED_FLAGS ( MB_FLAG_PGALIGN | MB_FLAG_MEMMAP | \
|
||||
MB_FLAG_VIDMODE | MB_FLAG_RAW )
|
||||
|
||||
/** Compulsory feature multiboot flags */
|
||||
#define MB_COMPULSORY_FLAGS 0x0000ffff
|
||||
|
||||
/** Optional feature multiboot flags */
|
||||
#define MB_OPTIONAL_FLAGS 0xffff0000
|
||||
|
||||
/**
|
||||
* Multiboot flags that we don't support
|
||||
*
|
||||
* We only care about the compulsory feature flags (bits 0-15); we are
|
||||
* allowed to ignore the optional feature flags.
|
||||
*/
|
||||
#define MB_UNSUPPORTED_FLAGS ( MB_COMPULSORY_FLAGS & ~MB_SUPPORTED_FLAGS )
|
||||
|
||||
/** A multiboot header descriptor */
|
||||
struct multiboot_header_info {
|
||||
/** The actual multiboot header */
|
||||
struct multiboot_header mb;
|
||||
/** Offset of header within the multiboot image */
|
||||
size_t offset;
|
||||
};
|
||||
|
||||
/** Multiboot module command lines */
|
||||
static char __bss16_array ( mb_cmdlines, [MB_MAX_CMDLINE] );
|
||||
#define mb_cmdlines __use_data16 ( mb_cmdlines )
|
||||
|
||||
/** Offset within module command lines */
|
||||
static unsigned int mb_cmdline_offset;
|
||||
|
||||
/**
|
||||
* Build multiboot memory map
|
||||
*
|
||||
* @v image Multiboot image
|
||||
* @v mbinfo Multiboot information structure
|
||||
* @v mbmemmap Multiboot memory map
|
||||
* @v limit Maxmimum number of memory map entries
|
||||
*/
|
||||
static void multiboot_build_memmap ( struct image *image,
|
||||
struct multiboot_info *mbinfo,
|
||||
struct multiboot_memory_map *mbmemmap,
|
||||
unsigned int limit ) {
|
||||
struct memory_map memmap;
|
||||
unsigned int i;
|
||||
|
||||
/* Get memory map */
|
||||
get_memmap ( &memmap );
|
||||
|
||||
/* Translate into multiboot format */
|
||||
memset ( mbmemmap, 0, sizeof ( *mbmemmap ) );
|
||||
for ( i = 0 ; i < memmap.count ; i++ ) {
|
||||
if ( i >= limit ) {
|
||||
DBGC ( image, "MULTIBOOT %p limit of %d memmap "
|
||||
"entries reached\n", image, limit );
|
||||
break;
|
||||
}
|
||||
mbmemmap[i].size = ( sizeof ( mbmemmap[i] ) -
|
||||
sizeof ( mbmemmap[i].size ) );
|
||||
mbmemmap[i].base_addr = memmap.regions[i].start;
|
||||
mbmemmap[i].length = ( memmap.regions[i].end -
|
||||
memmap.regions[i].start );
|
||||
mbmemmap[i].type = MBMEM_RAM;
|
||||
mbinfo->mmap_length += sizeof ( mbmemmap[i] );
|
||||
if ( memmap.regions[i].start == 0 )
|
||||
mbinfo->mem_lower = ( memmap.regions[i].end / 1024 );
|
||||
if ( memmap.regions[i].start == 0x100000 )
|
||||
mbinfo->mem_upper = ( ( memmap.regions[i].end -
|
||||
0x100000 ) / 1024 );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add command line in base memory
|
||||
*
|
||||
* @v imgname Image name
|
||||
* @v cmdline Command line
|
||||
* @ret physaddr Physical address of command line
|
||||
*/
|
||||
physaddr_t multiboot_add_cmdline ( const char *imgname, const char *cmdline ) {
|
||||
char *mb_cmdline;
|
||||
|
||||
if ( ! cmdline )
|
||||
cmdline = "";
|
||||
|
||||
/* Copy command line to base memory buffer */
|
||||
mb_cmdline = ( mb_cmdlines + mb_cmdline_offset );
|
||||
mb_cmdline_offset +=
|
||||
( snprintf ( mb_cmdline,
|
||||
( sizeof ( mb_cmdlines ) - mb_cmdline_offset ),
|
||||
"%s %s", imgname, cmdline ) + 1 );
|
||||
|
||||
/* Truncate to terminating NUL in buffer if necessary */
|
||||
if ( mb_cmdline_offset > sizeof ( mb_cmdlines ) )
|
||||
mb_cmdline_offset = ( sizeof ( mb_cmdlines ) - 1 );
|
||||
|
||||
return virt_to_phys ( mb_cmdline );
|
||||
}
|
||||
|
||||
/**
|
||||
* Build multiboot module list
|
||||
*
|
||||
* @v image Multiboot image
|
||||
* @v modules Module list to fill, or NULL
|
||||
* @ret count Number of modules
|
||||
*/
|
||||
static unsigned int
|
||||
multiboot_build_module_list ( struct image *image,
|
||||
struct multiboot_module *modules,
|
||||
unsigned int limit ) {
|
||||
struct image *module_image;
|
||||
struct multiboot_module *module;
|
||||
unsigned int count = 0;
|
||||
unsigned int insert;
|
||||
physaddr_t start;
|
||||
physaddr_t end;
|
||||
unsigned int i;
|
||||
|
||||
/* Add each image as a multiboot module */
|
||||
for_each_image ( module_image ) {
|
||||
|
||||
if ( count >= limit ) {
|
||||
DBGC ( image, "MULTIBOOT %p limit of %d modules "
|
||||
"reached\n", image, limit );
|
||||
break;
|
||||
}
|
||||
|
||||
/* Do not include kernel image itself as a module */
|
||||
if ( module_image == image )
|
||||
continue;
|
||||
|
||||
/* At least some OSes expect the multiboot modules to
|
||||
* be in ascending order, so we have to support it.
|
||||
*/
|
||||
start = user_to_phys ( module_image->data, 0 );
|
||||
end = user_to_phys ( module_image->data, module_image->len );
|
||||
for ( insert = 0 ; insert < count ; insert++ ) {
|
||||
if ( start < modules[insert].mod_start )
|
||||
break;
|
||||
}
|
||||
module = &modules[insert];
|
||||
memmove ( ( module + 1 ), module,
|
||||
( ( count - insert ) * sizeof ( *module ) ) );
|
||||
module->mod_start = start;
|
||||
module->mod_end = end;
|
||||
module->string = multiboot_add_cmdline ( module_image->name,
|
||||
module_image->cmdline );
|
||||
module->reserved = 0;
|
||||
|
||||
/* We promise to page-align modules */
|
||||
assert ( ( module->mod_start & 0xfff ) == 0 );
|
||||
|
||||
count++;
|
||||
}
|
||||
|
||||
/* Dump module configuration */
|
||||
for ( i = 0 ; i < count ; i++ ) {
|
||||
DBGC ( image, "MULTIBOOT %p module %d is [%x,%x)\n",
|
||||
image, i, modules[i].mod_start,
|
||||
modules[i].mod_end );
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
/**
|
||||
* The multiboot information structure
|
||||
*
|
||||
* Kept in base memory because some OSes won't find it elsewhere,
|
||||
* along with the other structures belonging to the Multiboot
|
||||
* information table.
|
||||
*/
|
||||
static struct multiboot_info __bss16 ( mbinfo );
|
||||
#define mbinfo __use_data16 ( mbinfo )
|
||||
|
||||
/** The multiboot bootloader name */
|
||||
static char __data16_array ( mb_bootloader_name, [] ) = "iPXE " VERSION;
|
||||
#define mb_bootloader_name __use_data16 ( mb_bootloader_name )
|
||||
|
||||
/** The multiboot memory map */
|
||||
static struct multiboot_memory_map
|
||||
__bss16_array ( mbmemmap, [MAX_MEMORY_REGIONS] );
|
||||
#define mbmemmap __use_data16 ( mbmemmap )
|
||||
|
||||
/** The multiboot module list */
|
||||
static struct multiboot_module __bss16_array ( mbmodules, [MAX_MODULES] );
|
||||
#define mbmodules __use_data16 ( mbmodules )
|
||||
|
||||
/**
|
||||
* Execute multiboot image
|
||||
*
|
||||
* @v image Multiboot image
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int multiboot_exec ( struct image *image ) {
|
||||
physaddr_t entry = image->priv.phys;
|
||||
|
||||
/* Populate multiboot information structure */
|
||||
memset ( &mbinfo, 0, sizeof ( mbinfo ) );
|
||||
mbinfo.flags = ( MBI_FLAG_LOADER | MBI_FLAG_MEM | MBI_FLAG_MMAP |
|
||||
MBI_FLAG_CMDLINE | MBI_FLAG_MODS );
|
||||
mb_cmdline_offset = 0;
|
||||
mbinfo.cmdline = multiboot_add_cmdline ( image->name, image->cmdline );
|
||||
mbinfo.mods_count = multiboot_build_module_list ( image, mbmodules,
|
||||
( sizeof(mbmodules) / sizeof(mbmodules[0]) ) );
|
||||
mbinfo.mods_addr = virt_to_phys ( mbmodules );
|
||||
mbinfo.mmap_addr = virt_to_phys ( mbmemmap );
|
||||
mbinfo.boot_loader_name = virt_to_phys ( mb_bootloader_name );
|
||||
|
||||
/* Multiboot images may not return and have no callback
|
||||
* interface, so shut everything down prior to booting the OS.
|
||||
*/
|
||||
shutdown ( SHUTDOWN_BOOT );
|
||||
|
||||
/* Build memory map after unhiding bootloader memory regions as part of
|
||||
* shutting everything down.
|
||||
*/
|
||||
multiboot_build_memmap ( image, &mbinfo, mbmemmap,
|
||||
( sizeof(mbmemmap) / sizeof(mbmemmap[0]) ) );
|
||||
|
||||
/* Jump to OS with flat physical addressing */
|
||||
DBGC ( image, "MULTIBOOT %p starting execution at %lx\n",
|
||||
image, entry );
|
||||
__asm__ __volatile__ ( PHYS_CODE ( "pushl %%ebp\n\t"
|
||||
"call *%%edi\n\t"
|
||||
"popl %%ebp\n\t" )
|
||||
: : "a" ( MULTIBOOT_BOOTLOADER_MAGIC ),
|
||||
"b" ( virt_to_phys ( &mbinfo ) ),
|
||||
"D" ( entry )
|
||||
: "ecx", "edx", "esi", "memory" );
|
||||
|
||||
DBGC ( image, "MULTIBOOT %p returned\n", image );
|
||||
|
||||
/* It isn't safe to continue after calling shutdown() */
|
||||
while ( 1 ) {}
|
||||
|
||||
return -ECANCELED; /* -EIMPOSSIBLE, anyone? */
|
||||
}
|
||||
|
||||
/**
|
||||
* Find multiboot header
|
||||
*
|
||||
* @v image Multiboot file
|
||||
* @v hdr Multiboot header descriptor to fill in
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int multiboot_find_header ( struct image *image,
|
||||
struct multiboot_header_info *hdr ) {
|
||||
uint32_t buf[64];
|
||||
size_t offset;
|
||||
unsigned int buf_idx;
|
||||
uint32_t checksum;
|
||||
|
||||
/* Scan through first 8kB of image file 256 bytes at a time.
|
||||
* (Use the buffering to avoid the overhead of a
|
||||
* copy_from_user() for every dword.)
|
||||
*/
|
||||
for ( offset = 0 ; offset < 8192 ; offset += sizeof ( buf[0] ) ) {
|
||||
/* Check for end of image */
|
||||
if ( offset > image->len )
|
||||
break;
|
||||
/* Refill buffer if applicable */
|
||||
buf_idx = ( ( offset % sizeof ( buf ) ) / sizeof ( buf[0] ) );
|
||||
if ( buf_idx == 0 ) {
|
||||
copy_from_user ( buf, image->data, offset,
|
||||
sizeof ( buf ) );
|
||||
}
|
||||
/* Check signature */
|
||||
if ( buf[buf_idx] != MULTIBOOT_HEADER_MAGIC )
|
||||
continue;
|
||||
/* Copy header and verify checksum */
|
||||
copy_from_user ( &hdr->mb, image->data, offset,
|
||||
sizeof ( hdr->mb ) );
|
||||
checksum = ( hdr->mb.magic + hdr->mb.flags +
|
||||
hdr->mb.checksum );
|
||||
if ( checksum != 0 )
|
||||
continue;
|
||||
/* Record offset of multiboot header and return */
|
||||
hdr->offset = offset;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* No multiboot header found */
|
||||
return -ENOEXEC;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load raw multiboot image into memory
|
||||
*
|
||||
* @v image Multiboot file
|
||||
* @v hdr Multiboot header descriptor
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int multiboot_load_raw ( struct image *image,
|
||||
struct multiboot_header_info *hdr ) {
|
||||
size_t offset;
|
||||
size_t filesz;
|
||||
size_t memsz;
|
||||
userptr_t buffer;
|
||||
int rc;
|
||||
|
||||
/* Sanity check */
|
||||
if ( ! ( hdr->mb.flags & MB_FLAG_RAW ) ) {
|
||||
DBGC ( image, "MULTIBOOT %p is not flagged as a raw image\n",
|
||||
image );
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Verify and prepare segment */
|
||||
offset = ( hdr->offset - hdr->mb.header_addr + hdr->mb.load_addr );
|
||||
filesz = ( hdr->mb.load_end_addr ?
|
||||
( hdr->mb.load_end_addr - hdr->mb.load_addr ) :
|
||||
( image->len - offset ) );
|
||||
memsz = ( hdr->mb.bss_end_addr ?
|
||||
( hdr->mb.bss_end_addr - hdr->mb.load_addr ) : filesz );
|
||||
buffer = phys_to_user ( hdr->mb.load_addr );
|
||||
if ( ( rc = prep_segment ( buffer, filesz, memsz ) ) != 0 ) {
|
||||
DBGC ( image, "MULTIBOOT %p could not prepare segment: %s\n",
|
||||
image, strerror ( rc ) );
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Copy image to segment */
|
||||
memcpy_user ( buffer, 0, image->data, offset, filesz );
|
||||
|
||||
/* Record execution entry point in image private data field */
|
||||
image->priv.phys = hdr->mb.entry_addr;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load ELF multiboot image into memory
|
||||
*
|
||||
* @v image Multiboot file
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int multiboot_load_elf ( struct image *image ) {
|
||||
int rc;
|
||||
|
||||
/* Load ELF image*/
|
||||
if ( ( rc = elf_load ( image ) ) != 0 ) {
|
||||
DBGC ( image, "MULTIBOOT %p ELF image failed to load: %s\n",
|
||||
image, strerror ( rc ) );
|
||||
return rc;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load multiboot image into memory
|
||||
*
|
||||
* @v image Multiboot file
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int multiboot_load ( struct image *image ) {
|
||||
struct multiboot_header_info hdr;
|
||||
int rc;
|
||||
|
||||
/* Locate multiboot header, if present */
|
||||
if ( ( rc = multiboot_find_header ( image, &hdr ) ) != 0 ) {
|
||||
DBGC ( image, "MULTIBOOT %p has no multiboot header\n",
|
||||
image );
|
||||
return rc;
|
||||
}
|
||||
DBGC ( image, "MULTIBOOT %p found header with flags %08x\n",
|
||||
image, hdr.mb.flags );
|
||||
|
||||
/* This is a multiboot image, valid or otherwise */
|
||||
if ( ! image->type )
|
||||
image->type = &multiboot_image_type;
|
||||
|
||||
/* Abort if we detect flags that we cannot support */
|
||||
if ( hdr.mb.flags & MB_UNSUPPORTED_FLAGS ) {
|
||||
DBGC ( image, "MULTIBOOT %p flags %08x not supported\n",
|
||||
image, ( hdr.mb.flags & MB_UNSUPPORTED_FLAGS ) );
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
/* There is technically a bit MB_FLAG_RAW to indicate whether
|
||||
* this is an ELF or a raw image. In practice, grub will use
|
||||
* the ELF header if present, and Solaris relies on this
|
||||
* behaviour.
|
||||
*/
|
||||
if ( ( ( rc = multiboot_load_elf ( image ) ) != 0 ) &&
|
||||
( ( rc = multiboot_load_raw ( image, &hdr ) ) != 0 ) )
|
||||
return rc;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Multiboot image type */
|
||||
struct image_type multiboot_image_type __image_type ( PROBE_MULTIBOOT ) = {
|
||||
.name = "Multiboot",
|
||||
.load = multiboot_load,
|
||||
.exec = multiboot_exec,
|
||||
};
|
@@ -1,435 +0,0 @@
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
#include <realmode.h>
|
||||
#include <memsizes.h>
|
||||
#include <basemem_packet.h>
|
||||
#include <ipxe/uaccess.h>
|
||||
#include <ipxe/segment.h>
|
||||
#include <ipxe/init.h>
|
||||
#include <ipxe/netdevice.h>
|
||||
#include <ipxe/fakedhcp.h>
|
||||
#include <ipxe/image.h>
|
||||
#include <ipxe/features.h>
|
||||
|
||||
/** @file
|
||||
*
|
||||
* NBI image format.
|
||||
*
|
||||
* The Net Boot Image format is defined by the "Draft Net Boot Image
|
||||
* Proposal 0.3" by Jamie Honan, Gero Kuhlmann and Ken Yap. It is now
|
||||
* considered to be a legacy format, but it still included because a
|
||||
* large amount of software (e.g. nymph, LTSP) makes use of NBI files.
|
||||
*
|
||||
* Etherboot does not implement the INT 78 callback interface
|
||||
* described by the NBI specification. For a callback interface on
|
||||
* x86 architecture, use PXE.
|
||||
*
|
||||
*/
|
||||
|
||||
FEATURE ( FEATURE_IMAGE, "NBI", DHCP_EB_FEATURE_NBI, 1 );
|
||||
|
||||
struct image_type nbi_image_type __image_type ( PROBE_NORMAL );
|
||||
|
||||
/**
|
||||
* An NBI image header
|
||||
*
|
||||
* Note that the length field uses a peculiar encoding; use the
|
||||
* NBI_LENGTH() macro to decode the actual header length.
|
||||
*
|
||||
*/
|
||||
struct imgheader {
|
||||
unsigned long magic; /**< Magic number (NBI_MAGIC) */
|
||||
union {
|
||||
unsigned char length; /**< Nibble-coded header length */
|
||||
unsigned long flags; /**< Image flags */
|
||||
};
|
||||
segoff_t location; /**< 16-bit seg:off header location */
|
||||
union {
|
||||
segoff_t segoff; /**< 16-bit seg:off entry point */
|
||||
unsigned long linear; /**< 32-bit entry point */
|
||||
} execaddr;
|
||||
} __attribute__ (( packed ));
|
||||
|
||||
/** NBI magic number */
|
||||
#define NBI_MAGIC 0x1B031336UL
|
||||
|
||||
/* Interpretation of the "length" fields */
|
||||
#define NBI_NONVENDOR_LENGTH(len) ( ( (len) & 0x0f ) << 2 )
|
||||
#define NBI_VENDOR_LENGTH(len) ( ( (len) & 0xf0 ) >> 2 )
|
||||
#define NBI_LENGTH(len) ( NBI_NONVENDOR_LENGTH(len) + NBI_VENDOR_LENGTH(len) )
|
||||
|
||||
/* Interpretation of the "flags" fields */
|
||||
#define NBI_PROGRAM_RETURNS(flags) ( (flags) & ( 1 << 8 ) )
|
||||
#define NBI_LINEAR_EXEC_ADDR(flags) ( (flags) & ( 1 << 31 ) )
|
||||
|
||||
/** NBI header length */
|
||||
#define NBI_HEADER_LENGTH 512
|
||||
|
||||
/**
|
||||
* An NBI segment header
|
||||
*
|
||||
* Note that the length field uses a peculiar encoding; use the
|
||||
* NBI_LENGTH() macro to decode the actual header length.
|
||||
*
|
||||
*/
|
||||
struct segheader {
|
||||
unsigned char length; /**< Nibble-coded header length */
|
||||
unsigned char vendortag; /**< Vendor-defined private tag */
|
||||
unsigned char reserved;
|
||||
unsigned char flags; /**< Segment flags */
|
||||
unsigned long loadaddr; /**< Load address */
|
||||
unsigned long imglength; /**< Segment length in NBI file */
|
||||
unsigned long memlength; /**< Segment length in memory */
|
||||
};
|
||||
|
||||
/* Interpretation of the "flags" fields */
|
||||
#define NBI_LOADADDR_FLAGS(flags) ( (flags) & 0x03 )
|
||||
#define NBI_LOADADDR_ABS 0x00
|
||||
#define NBI_LOADADDR_AFTER 0x01
|
||||
#define NBI_LOADADDR_END 0x02
|
||||
#define NBI_LOADADDR_BEFORE 0x03
|
||||
#define NBI_LAST_SEGHEADER(flags) ( (flags) & ( 1 << 2 ) )
|
||||
|
||||
/* Define a type for passing info to a loaded program */
|
||||
struct ebinfo {
|
||||
uint8_t major, minor; /* Version */
|
||||
uint16_t flags; /* Bit flags */
|
||||
};
|
||||
|
||||
/** Info passed to NBI image */
|
||||
static struct ebinfo loaderinfo = {
|
||||
VERSION_MAJOR, VERSION_MINOR,
|
||||
0
|
||||
};
|
||||
|
||||
/**
|
||||
* Prepare a segment for an NBI image
|
||||
*
|
||||
* @v image NBI image
|
||||
* @v offset Offset within NBI image
|
||||
* @v filesz Length of initialised-data portion of the segment
|
||||
* @v memsz Total length of the segment
|
||||
* @v src Source for initialised data
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int nbi_prepare_segment ( struct image *image, size_t offset __unused,
|
||||
userptr_t dest, size_t filesz, size_t memsz ){
|
||||
int rc;
|
||||
|
||||
if ( ( rc = prep_segment ( dest, filesz, memsz ) ) != 0 ) {
|
||||
DBGC ( image, "NBI %p could not prepare segment: %s\n",
|
||||
image, strerror ( rc ) );
|
||||
return rc;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load a segment for an NBI image
|
||||
*
|
||||
* @v image NBI image
|
||||
* @v offset Offset within NBI image
|
||||
* @v filesz Length of initialised-data portion of the segment
|
||||
* @v memsz Total length of the segment
|
||||
* @v src Source for initialised data
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int nbi_load_segment ( struct image *image, size_t offset,
|
||||
userptr_t dest, size_t filesz,
|
||||
size_t memsz __unused ) {
|
||||
memcpy_user ( dest, 0, image->data, offset, filesz );
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process segments of an NBI image
|
||||
*
|
||||
* @v image NBI image
|
||||
* @v imgheader Image header information
|
||||
* @v process Function to call for each segment
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int nbi_process_segments ( struct image *image,
|
||||
struct imgheader *imgheader,
|
||||
int ( * process ) ( struct image *image,
|
||||
size_t offset,
|
||||
userptr_t dest,
|
||||
size_t filesz,
|
||||
size_t memsz ) ) {
|
||||
struct segheader sh;
|
||||
size_t offset = 0;
|
||||
size_t sh_off;
|
||||
userptr_t dest;
|
||||
size_t filesz;
|
||||
size_t memsz;
|
||||
int rc;
|
||||
|
||||
/* Copy image header to target location */
|
||||
dest = real_to_user ( imgheader->location.segment,
|
||||
imgheader->location.offset );
|
||||
filesz = memsz = NBI_HEADER_LENGTH;
|
||||
if ( ( rc = process ( image, offset, dest, filesz, memsz ) ) != 0 )
|
||||
return rc;
|
||||
offset += filesz;
|
||||
|
||||
/* Process segments in turn */
|
||||
sh_off = NBI_LENGTH ( imgheader->length );
|
||||
do {
|
||||
/* Read segment header */
|
||||
copy_from_user ( &sh, image->data, sh_off, sizeof ( sh ) );
|
||||
if ( sh.length == 0 ) {
|
||||
/* Avoid infinite loop? */
|
||||
DBGC ( image, "NBI %p invalid segheader length 0\n",
|
||||
image );
|
||||
return -ENOEXEC;
|
||||
}
|
||||
|
||||
/* Calculate segment load address */
|
||||
switch ( NBI_LOADADDR_FLAGS ( sh.flags ) ) {
|
||||
case NBI_LOADADDR_ABS:
|
||||
dest = phys_to_user ( sh.loadaddr );
|
||||
break;
|
||||
case NBI_LOADADDR_AFTER:
|
||||
dest = userptr_add ( dest, memsz + sh.loadaddr );
|
||||
break;
|
||||
case NBI_LOADADDR_BEFORE:
|
||||
dest = userptr_add ( dest, -sh.loadaddr );
|
||||
break;
|
||||
case NBI_LOADADDR_END:
|
||||
/* Not correct according to the spec, but
|
||||
* maintains backwards compatibility with
|
||||
* previous versions of Etherboot.
|
||||
*/
|
||||
dest = phys_to_user ( ( extmemsize() + 1024 ) * 1024
|
||||
- sh.loadaddr );
|
||||
break;
|
||||
default:
|
||||
/* Cannot be reached */
|
||||
assert ( 0 );
|
||||
}
|
||||
|
||||
/* Process this segment */
|
||||
filesz = sh.imglength;
|
||||
memsz = sh.memlength;
|
||||
if ( ( offset + filesz ) > image->len ) {
|
||||
DBGC ( image, "NBI %p segment outside file\n", image );
|
||||
return -ENOEXEC;
|
||||
}
|
||||
if ( ( rc = process ( image, offset, dest,
|
||||
filesz, memsz ) ) != 0 ) {
|
||||
return rc;
|
||||
}
|
||||
offset += filesz;
|
||||
|
||||
/* Next segheader */
|
||||
sh_off += NBI_LENGTH ( sh.length );
|
||||
if ( sh_off >= NBI_HEADER_LENGTH ) {
|
||||
DBGC ( image, "NBI %p header overflow\n", image );
|
||||
return -ENOEXEC;
|
||||
}
|
||||
|
||||
} while ( ! NBI_LAST_SEGHEADER ( sh.flags ) );
|
||||
|
||||
if ( offset != image->len ) {
|
||||
DBGC ( image, "NBI %p length wrong (file %zd, metadata %zd)\n",
|
||||
image, image->len, offset );
|
||||
return -ENOEXEC;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load an NBI image into memory
|
||||
*
|
||||
* @v image NBI image
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int nbi_load ( struct image *image ) {
|
||||
struct imgheader imgheader;
|
||||
int rc;
|
||||
|
||||
/* If we don't have enough data give up */
|
||||
if ( image->len < NBI_HEADER_LENGTH ) {
|
||||
DBGC ( image, "NBI %p too short for an NBI image\n", image );
|
||||
return -ENOEXEC;
|
||||
}
|
||||
|
||||
/* Check image header */
|
||||
copy_from_user ( &imgheader, image->data, 0, sizeof ( imgheader ) );
|
||||
if ( imgheader.magic != NBI_MAGIC ) {
|
||||
DBGC ( image, "NBI %p has no NBI signature\n", image );
|
||||
return -ENOEXEC;
|
||||
}
|
||||
|
||||
/* This is an NBI image, valid or otherwise */
|
||||
if ( ! image->type )
|
||||
image->type = &nbi_image_type;
|
||||
|
||||
DBGC ( image, "NBI %p placing header at %hx:%hx\n", image,
|
||||
imgheader.location.segment, imgheader.location.offset );
|
||||
|
||||
/* NBI files can have overlaps between segments; the bss of
|
||||
* one segment may overlap the initialised data of another. I
|
||||
* assume this is a design flaw, but there are images out
|
||||
* there that we need to work with. We therefore do two
|
||||
* passes: first to initialise the segments, then to copy the
|
||||
* data. This avoids zeroing out already-copied data.
|
||||
*/
|
||||
if ( ( rc = nbi_process_segments ( image, &imgheader,
|
||||
nbi_prepare_segment ) ) != 0 )
|
||||
return rc;
|
||||
if ( ( rc = nbi_process_segments ( image, &imgheader,
|
||||
nbi_load_segment ) ) != 0 )
|
||||
return rc;
|
||||
|
||||
/* Record header address in image private data field */
|
||||
image->priv.user = real_to_user ( imgheader.location.segment,
|
||||
imgheader.location.offset );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Boot a 16-bit NBI image
|
||||
*
|
||||
* @v imgheader Image header information
|
||||
* @ret rc Return status code, if image returns
|
||||
*/
|
||||
static int nbi_boot16 ( struct image *image, struct imgheader *imgheader ) {
|
||||
int discard_D, discard_S, discard_b;
|
||||
int rc;
|
||||
|
||||
DBGC ( image, "NBI %p executing 16-bit image at %04x:%04x\n", image,
|
||||
imgheader->execaddr.segoff.segment,
|
||||
imgheader->execaddr.segoff.offset );
|
||||
|
||||
__asm__ __volatile__ (
|
||||
REAL_CODE ( "pushw %%ds\n\t" /* far pointer to bootp data */
|
||||
"pushw %%bx\n\t"
|
||||
"pushl %%esi\n\t" /* location */
|
||||
"pushw %%cs\n\t" /* lcall execaddr */
|
||||
"call 1f\n\t"
|
||||
"jmp 2f\n\t"
|
||||
"\n1:\n\t"
|
||||
"pushl %%edi\n\t"
|
||||
"lret\n\t"
|
||||
"\n2:\n\t"
|
||||
"addw $8,%%sp\n\t" /* clean up stack */ )
|
||||
: "=a" ( rc ), "=D" ( discard_D ), "=S" ( discard_S ),
|
||||
"=b" ( discard_b )
|
||||
: "D" ( imgheader->execaddr.segoff ),
|
||||
"S" ( imgheader->location ),
|
||||
"b" ( __from_data16 ( basemem_packet ) )
|
||||
: "ecx", "edx", "ebp" );
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Boot a 32-bit NBI image
|
||||
*
|
||||
* @v imgheader Image header information
|
||||
* @ret rc Return status code, if image returns
|
||||
*/
|
||||
static int nbi_boot32 ( struct image *image, struct imgheader *imgheader ) {
|
||||
int discard_D, discard_S, discard_b;
|
||||
int rc;
|
||||
|
||||
DBGC ( image, "NBI %p executing 32-bit image at %lx\n",
|
||||
image, imgheader->execaddr.linear );
|
||||
|
||||
/* Jump to OS with flat physical addressing */
|
||||
__asm__ __volatile__ (
|
||||
PHYS_CODE ( "pushl %%ebx\n\t" /* bootp data */
|
||||
"pushl %%esi\n\t" /* imgheader */
|
||||
"pushl %%eax\n\t" /* loaderinfo */
|
||||
"call *%%edi\n\t"
|
||||
"addl $12, %%esp\n\t" /* clean up stack */ )
|
||||
: "=a" ( rc ), "=D" ( discard_D ), "=S" ( discard_S ),
|
||||
"=b" ( discard_b )
|
||||
: "D" ( imgheader->execaddr.linear ),
|
||||
"S" ( ( imgheader->location.segment << 4 ) +
|
||||
imgheader->location.offset ),
|
||||
"b" ( virt_to_phys ( basemem_packet ) ),
|
||||
"a" ( virt_to_phys ( &loaderinfo ) )
|
||||
: "ecx", "edx", "ebp", "memory" );
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare DHCP parameter block for NBI image
|
||||
*
|
||||
* @v image NBI image
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int nbi_prepare_dhcp ( struct image *image ) {
|
||||
struct net_device *boot_netdev;
|
||||
int rc;
|
||||
|
||||
boot_netdev = last_opened_netdev();
|
||||
if ( ! boot_netdev ) {
|
||||
DBGC ( image, "NBI %p could not identify a network device\n",
|
||||
image );
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if ( ( rc = create_fakedhcpack ( boot_netdev, basemem_packet,
|
||||
sizeof ( basemem_packet ) ) ) != 0 ) {
|
||||
DBGC ( image, "NBI %p failed to build DHCP packet\n", image );
|
||||
return rc;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a loaded NBI image
|
||||
*
|
||||
* @v image NBI image
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int nbi_exec ( struct image *image ) {
|
||||
struct imgheader imgheader;
|
||||
int may_return;
|
||||
int rc;
|
||||
|
||||
copy_from_user ( &imgheader, image->priv.user, 0,
|
||||
sizeof ( imgheader ) );
|
||||
|
||||
/* Prepare DHCP option block */
|
||||
if ( ( rc = nbi_prepare_dhcp ( image ) ) != 0 )
|
||||
return rc;
|
||||
|
||||
/* Shut down now if NBI image will not return */
|
||||
may_return = NBI_PROGRAM_RETURNS ( imgheader.flags );
|
||||
if ( ! may_return )
|
||||
shutdown ( SHUTDOWN_BOOT );
|
||||
|
||||
/* Execute NBI image */
|
||||
if ( NBI_LINEAR_EXEC_ADDR ( imgheader.flags ) ) {
|
||||
rc = nbi_boot32 ( image, &imgheader );
|
||||
} else {
|
||||
rc = nbi_boot16 ( image, &imgheader );
|
||||
}
|
||||
|
||||
if ( ! may_return ) {
|
||||
/* Cannot continue after shutdown() called */
|
||||
DBGC ( image, "NBI %p returned %d from non-returnable image\n",
|
||||
image, rc );
|
||||
while ( 1 ) {}
|
||||
}
|
||||
|
||||
DBGC ( image, "NBI %p returned %d\n", image, rc );
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/** NBI image type */
|
||||
struct image_type nbi_image_type __image_type ( PROBE_NORMAL ) = {
|
||||
.name = "NBI",
|
||||
.load = nbi_load,
|
||||
.exec = nbi_exec,
|
||||
};
|
@@ -1,117 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2007 Michael Brown <mbrown@fensystems.co.uk>.
|
||||
*
|
||||
* 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 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER );
|
||||
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
* PXE image format
|
||||
*
|
||||
*/
|
||||
|
||||
#include <pxe.h>
|
||||
#include <pxe_call.h>
|
||||
#include <ipxe/uaccess.h>
|
||||
#include <ipxe/image.h>
|
||||
#include <ipxe/segment.h>
|
||||
#include <ipxe/netdevice.h>
|
||||
#include <ipxe/features.h>
|
||||
|
||||
FEATURE ( FEATURE_IMAGE, "PXE", DHCP_EB_FEATURE_PXE, 1 );
|
||||
|
||||
struct image_type pxe_image_type __image_type ( PROBE_PXE );
|
||||
|
||||
/**
|
||||
* Execute PXE image
|
||||
*
|
||||
* @v image PXE image
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int pxe_exec ( struct image *image ) {
|
||||
struct net_device *netdev;
|
||||
int rc;
|
||||
|
||||
/* Arbitrarily pick the most recently opened network device */
|
||||
if ( ( netdev = last_opened_netdev() ) == NULL ) {
|
||||
DBGC ( image, "IMAGE %p could not locate PXE net device\n",
|
||||
image );
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/* Activate PXE */
|
||||
pxe_activate ( netdev );
|
||||
|
||||
/* Start PXE NBP */
|
||||
rc = pxe_start_nbp();
|
||||
|
||||
/* Deactivate PXE */
|
||||
pxe_deactivate();
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load PXE image into memory
|
||||
*
|
||||
* @v image PXE file
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
int pxe_load ( struct image *image ) {
|
||||
userptr_t buffer = real_to_user ( 0, 0x7c00 );
|
||||
size_t filesz = image->len;
|
||||
size_t memsz = image->len;
|
||||
int rc;
|
||||
|
||||
/* Images too large to fit in base memory cannot be PXE
|
||||
* images. We include this check to help prevent unrecognised
|
||||
* images from being marked as PXE images, since PXE images
|
||||
* have no signature we can check against.
|
||||
*/
|
||||
if ( filesz > ( 0xa0000 - 0x7c00 ) )
|
||||
return -ENOEXEC;
|
||||
|
||||
/* Rejecting zero-length images is also useful, since these
|
||||
* end up looking to the user like bugs in iPXE.
|
||||
*/
|
||||
if ( ! filesz )
|
||||
return -ENOEXEC;
|
||||
|
||||
/* There are no signature checks for PXE; we will accept anything */
|
||||
if ( ! image->type )
|
||||
image->type = &pxe_image_type;
|
||||
|
||||
/* Verify and prepare segment */
|
||||
if ( ( rc = prep_segment ( buffer, filesz, memsz ) ) != 0 ) {
|
||||
DBGC ( image, "IMAGE %p could not prepare segment: %s\n",
|
||||
image, strerror ( rc ) );
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Copy image to segment */
|
||||
memcpy_user ( buffer, 0, image->data, 0, filesz );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** PXE image type */
|
||||
struct image_type pxe_image_type __image_type ( PROBE_PXE ) = {
|
||||
.name = "PXE",
|
||||
.load = pxe_load,
|
||||
.exec = pxe_exec,
|
||||
};
|
@@ -1,35 +0,0 @@
|
||||
#ifndef _BASEMEM_H
|
||||
#define _BASEMEM_H
|
||||
|
||||
/** @file
|
||||
*
|
||||
* Base memory allocation
|
||||
*
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER );
|
||||
|
||||
#include <stdint.h>
|
||||
#include <realmode.h>
|
||||
#include <bios.h>
|
||||
|
||||
/**
|
||||
* Read the BIOS free base memory counter
|
||||
*
|
||||
* @ret fbms Free base memory counter (in kB)
|
||||
*/
|
||||
static inline unsigned int get_fbms ( void ) {
|
||||
uint16_t fbms;
|
||||
|
||||
get_real ( fbms, BDA_SEG, BDA_FBMS );
|
||||
return fbms;
|
||||
}
|
||||
|
||||
extern void set_fbms ( unsigned int new_fbms );
|
||||
|
||||
/* Actually in hidemem.c, but putting it here avoids polluting the
|
||||
* architecture-independent include/hidemem.h.
|
||||
*/
|
||||
extern void hide_basemem ( void );
|
||||
|
||||
#endif /* _BASEMEM_H */
|
@@ -1,15 +0,0 @@
|
||||
#ifndef BASEMEM_PACKET_H
|
||||
#define BASEMEM_PACKET_H
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER );
|
||||
|
||||
#include <realmode.h>
|
||||
|
||||
/** Maximum length of base memory packet buffer */
|
||||
#define BASEMEM_PACKET_LEN 1514
|
||||
|
||||
/** Base memory packet buffer */
|
||||
extern char __bss16_array ( basemem_packet, [BASEMEM_PACKET_LEN] );
|
||||
#define basemem_packet __use_data16 ( basemem_packet )
|
||||
|
||||
#endif /* BASEMEM_PACKET_H */
|
@@ -1,10 +0,0 @@
|
||||
#ifndef BIOS_H
|
||||
#define BIOS_H
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER );
|
||||
|
||||
#define BDA_SEG 0x0040
|
||||
#define BDA_FBMS 0x0013
|
||||
#define BDA_NUM_DRIVES 0x0075
|
||||
|
||||
#endif /* BIOS_H */
|
@@ -1,69 +0,0 @@
|
||||
#ifndef BIOS_DISKS_H
|
||||
#define BIOS_DISKS_H
|
||||
|
||||
#include "dev.h"
|
||||
|
||||
/*
|
||||
* Constants
|
||||
*
|
||||
*/
|
||||
|
||||
#define BIOS_DISK_MAX_NAME_LEN 6
|
||||
|
||||
struct bios_disk_sector {
|
||||
char data[512];
|
||||
};
|
||||
|
||||
/*
|
||||
* The location of a BIOS disk
|
||||
*
|
||||
*/
|
||||
struct bios_disk_loc {
|
||||
uint8_t drive;
|
||||
};
|
||||
|
||||
/*
|
||||
* A physical BIOS disk device
|
||||
*
|
||||
*/
|
||||
struct bios_disk_device {
|
||||
char name[BIOS_DISK_MAX_NAME_LEN];
|
||||
uint8_t drive;
|
||||
uint8_t type;
|
||||
};
|
||||
|
||||
/*
|
||||
* A BIOS disk driver, with a valid device ID range and naming
|
||||
* function.
|
||||
*
|
||||
*/
|
||||
struct bios_disk_driver {
|
||||
void ( *fill_drive_name ) ( char *buf, uint8_t drive );
|
||||
uint8_t min_drive;
|
||||
uint8_t max_drive;
|
||||
};
|
||||
|
||||
/*
|
||||
* Define a BIOS disk driver
|
||||
*
|
||||
*/
|
||||
#define BIOS_DISK_DRIVER( _name, _fill_drive_name, _min_drive, _max_drive ) \
|
||||
static struct bios_disk_driver _name = { \
|
||||
.fill_drive_name = _fill_drive_name, \
|
||||
.min_drive = _min_drive, \
|
||||
.max_drive = _max_drive, \
|
||||
}
|
||||
|
||||
/*
|
||||
* Functions in bios_disks.c
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* bios_disk bus global definition
|
||||
*
|
||||
*/
|
||||
extern struct bus_driver bios_disk_driver;
|
||||
|
||||
#endif /* BIOS_DISKS_H */
|
@@ -1,33 +0,0 @@
|
||||
#ifndef BIOSINT_H
|
||||
#define BIOSINT_H
|
||||
|
||||
/**
|
||||
* @file BIOS interrupts
|
||||
*
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER );
|
||||
|
||||
#include <realmode.h>
|
||||
|
||||
struct segoff;
|
||||
|
||||
/**
|
||||
* Hooked interrupt count
|
||||
*
|
||||
* At exit, after unhooking all possible interrupts, this counter
|
||||
* should be examined. If it is non-zero, it means that we failed to
|
||||
* unhook at least one interrupt vector, and so must not free up the
|
||||
* memory we are using. (Note that this also implies that we should
|
||||
* re-hook INT 15 in order to hide ourselves from the memory map).
|
||||
*/
|
||||
extern uint16_t __text16 ( hooked_bios_interrupts );
|
||||
#define hooked_bios_interrupts __use_text16 ( hooked_bios_interrupts )
|
||||
|
||||
extern void hook_bios_interrupt ( unsigned int interrupt, unsigned int handler,
|
||||
struct segoff *chain_vector );
|
||||
extern int unhook_bios_interrupt ( unsigned int interrupt,
|
||||
unsigned int handler,
|
||||
struct segoff *chain_vector );
|
||||
|
||||
#endif /* BIOSINT_H */
|
@@ -1,43 +1,70 @@
|
||||
#ifndef ETHERBOOT_BITS_BYTESWAP_H
|
||||
#define ETHERBOOT_BITS_BYTESWAP_H
|
||||
#ifndef _BITS_BYTESWAP_H
|
||||
#define _BITS_BYTESWAP_H
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER );
|
||||
/** @file
|
||||
*
|
||||
* Byte-order swapping functions
|
||||
*
|
||||
*/
|
||||
|
||||
static inline __attribute__ ((always_inline, const)) uint16_t
|
||||
__bswap_variable_16(uint16_t x)
|
||||
{
|
||||
__asm__("xchgb %b0,%h0\n\t"
|
||||
: "=q" (x)
|
||||
: "0" (x));
|
||||
#include <stdint.h>
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
static inline __attribute__ (( always_inline, const )) uint16_t
|
||||
__bswap_variable_16 ( uint16_t x ) {
|
||||
__asm__ ( "xchgb %b0,%h0" : "=q" ( x ) : "0" ( x ) );
|
||||
return x;
|
||||
}
|
||||
|
||||
static inline __attribute__ ((always_inline, const)) uint32_t
|
||||
__bswap_variable_32(uint32_t x)
|
||||
{
|
||||
__asm__("xchgb %b0,%h0\n\t"
|
||||
"rorl $16,%0\n\t"
|
||||
"xchgb %b0,%h0"
|
||||
: "=q" (x)
|
||||
: "0" (x));
|
||||
static inline __attribute__ (( always_inline )) void
|
||||
__bswap_16s ( uint16_t *x ) {
|
||||
__asm__ ( "rorw $8, %0" : "+m" ( *x ) );
|
||||
}
|
||||
|
||||
static inline __attribute__ (( always_inline, const )) uint32_t
|
||||
__bswap_variable_32 ( uint32_t x ) {
|
||||
__asm__ ( "bswapl %0" : "=r" ( x ) : "0" ( x ) );
|
||||
return x;
|
||||
}
|
||||
|
||||
static inline __attribute__ ((always_inline, const)) uint64_t
|
||||
__bswap_variable_64(uint64_t x)
|
||||
{
|
||||
union {
|
||||
uint64_t qword;
|
||||
uint32_t dword[2];
|
||||
} u;
|
||||
|
||||
u.qword = x;
|
||||
u.dword[0] = __bswap_variable_32(u.dword[0]);
|
||||
u.dword[1] = __bswap_variable_32(u.dword[1]);
|
||||
__asm__("xchgl %0,%1"
|
||||
: "=r" ( u.dword[0] ), "=r" ( u.dword[1] )
|
||||
: "0" ( u.dword[0] ), "1" ( u.dword[1] ) );
|
||||
return u.qword;
|
||||
static inline __attribute__ (( always_inline )) void
|
||||
__bswap_32s ( uint32_t *x ) {
|
||||
__asm__ ( "bswapl %0" : "=r" ( *x ) : "0" ( *x ) );
|
||||
}
|
||||
|
||||
#endif /* ETHERBOOT_BITS_BYTESWAP_H */
|
||||
static inline __attribute__ (( always_inline, const )) uint64_t
|
||||
__bswap_variable_64 ( uint64_t x ) {
|
||||
uint32_t in_high = ( x >> 32 );
|
||||
uint32_t in_low = ( x & 0xffffffffUL );
|
||||
uint32_t out_high;
|
||||
uint32_t out_low;
|
||||
|
||||
__asm__ ( "bswapl %0\n\t"
|
||||
"bswapl %1\n\t"
|
||||
"xchgl %0,%1\n\t"
|
||||
: "=r" ( out_high ), "=r" ( out_low )
|
||||
: "0" ( in_high ), "1" ( in_low ) );
|
||||
|
||||
return ( ( ( ( uint64_t ) out_high ) << 32 ) |
|
||||
( ( uint64_t ) out_low ) );
|
||||
}
|
||||
|
||||
static inline __attribute__ (( always_inline )) void
|
||||
__bswap_64s ( uint64_t *x ) {
|
||||
struct {
|
||||
uint32_t __attribute__ (( may_alias )) low;
|
||||
uint32_t __attribute__ (( may_alias )) high;
|
||||
} __attribute__ (( may_alias )) *dwords = ( ( void * ) x );
|
||||
uint32_t discard;
|
||||
|
||||
__asm__ ( "movl %0,%2\n\t"
|
||||
"bswapl %2\n\t"
|
||||
"xchgl %2,%1\n\t"
|
||||
"bswapl %2\n\t"
|
||||
"movl %2,%0\n\t"
|
||||
: "+m" ( dwords->low ), "+m" ( dwords->high ),
|
||||
"=r" ( discard ) );
|
||||
}
|
||||
|
||||
#endif /* _BITS_BYTESWAP_H */
|
||||
|
@@ -1,12 +1,15 @@
|
||||
#ifndef _BITS_COMPILER_H
|
||||
#define _BITS_COMPILER_H
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER );
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
/** Dummy relocation type */
|
||||
#define RELOC_TYPE_NONE R_386_NONE
|
||||
|
||||
#ifndef ASSEMBLY
|
||||
|
||||
/** Declare a function with standard calling conventions */
|
||||
#define __asmcall __attribute__ (( cdecl, regparm(0) ))
|
||||
#define __asmcall __attribute__ (( used, cdecl, regparm(0) ))
|
||||
|
||||
/**
|
||||
* Declare a function with libgcc implicit linkage
|
||||
@@ -19,8 +22,19 @@ FILE_LICENCE ( GPL2_OR_LATER );
|
||||
* The implicit calls to memcpy() and memset() which gcc can generate
|
||||
* do not seem to have this inconsistency; -mregparm and -mrtd affect
|
||||
* them in the same way as any other function.
|
||||
*
|
||||
* Update (25/4/14): it appears that more recent gcc versions do allow
|
||||
* -mrtd to affect calls to the implicit arithmetic functions. There
|
||||
* is nothing obvious in the gcc changelogs to indicate precisely when
|
||||
* this happened. From experimentation with available gcc versions,
|
||||
* the change occurred sometime between v4.6.3 and v4.7.2. We assume
|
||||
* that only versions up to v4.6.x require the special treatment.
|
||||
*/
|
||||
#if ( __GNUC__ < 4 ) || ( ( __GNUC__ == 4 ) && ( __GNUC_MINOR__ <= 6 ) )
|
||||
#define __libgcc __attribute__ (( cdecl ))
|
||||
#else
|
||||
#define __libgcc
|
||||
#endif
|
||||
|
||||
#endif /* ASSEMBLY */
|
||||
|
||||
|
@@ -1,86 +0,0 @@
|
||||
#ifndef I386_BITS_CPU_H
|
||||
#define I386_BITS_CPU_H
|
||||
|
||||
/* Intel-defined CPU features, CPUID level 0x00000001, word 0 */
|
||||
#define X86_FEATURE_FPU 0 /* Onboard FPU */
|
||||
#define X86_FEATURE_VME 1 /* Virtual Mode Extensions */
|
||||
#define X86_FEATURE_DE 2 /* Debugging Extensions */
|
||||
#define X86_FEATURE_PSE 3 /* Page Size Extensions */
|
||||
#define X86_FEATURE_TSC 4 /* Time Stamp Counter */
|
||||
#define X86_FEATURE_MSR 5 /* Model-Specific Registers, RDMSR, WRMSR */
|
||||
#define X86_FEATURE_PAE 6 /* Physical Address Extensions */
|
||||
#define X86_FEATURE_MCE 7 /* Machine Check Architecture */
|
||||
#define X86_FEATURE_CX8 8 /* CMPXCHG8 instruction */
|
||||
#define X86_FEATURE_APIC 9 /* Onboard APIC */
|
||||
#define X86_FEATURE_SEP 11 /* SYSENTER/SYSEXIT */
|
||||
#define X86_FEATURE_MTRR 12 /* Memory Type Range Registers */
|
||||
#define X86_FEATURE_PGE 13 /* Page Global Enable */
|
||||
#define X86_FEATURE_MCA 14 /* Machine Check Architecture */
|
||||
#define X86_FEATURE_CMOV 15 /* CMOV instruction (FCMOVCC and FCOMI too if FPU present) */
|
||||
#define X86_FEATURE_PAT 16 /* Page Attribute Table */
|
||||
#define X86_FEATURE_PSE36 17 /* 36-bit PSEs */
|
||||
#define X86_FEATURE_PN 18 /* Processor serial number */
|
||||
#define X86_FEATURE_CLFLSH 19 /* Supports the CLFLUSH instruction */
|
||||
#define X86_FEATURE_DTES 21 /* Debug Trace Store */
|
||||
#define X86_FEATURE_ACPI 22 /* ACPI via MSR */
|
||||
#define X86_FEATURE_MMX 23 /* Multimedia Extensions */
|
||||
#define X86_FEATURE_FXSR 24 /* FXSAVE and FXRSTOR instructions (fast save and restore */
|
||||
/* of FPU context), and CR4.OSFXSR available */
|
||||
#define X86_FEATURE_XMM 25 /* Streaming SIMD Extensions */
|
||||
#define X86_FEATURE_XMM2 26 /* Streaming SIMD Extensions-2 */
|
||||
#define X86_FEATURE_SELFSNOOP 27 /* CPU self snoop */
|
||||
#define X86_FEATURE_HT 28 /* Hyper-Threading */
|
||||
#define X86_FEATURE_ACC 29 /* Automatic clock control */
|
||||
#define X86_FEATURE_IA64 30 /* IA-64 processor */
|
||||
|
||||
/* AMD-defined CPU features, CPUID level 0x80000001, word 1 */
|
||||
/* Don't duplicate feature flags which are redundant with Intel! */
|
||||
#define X86_FEATURE_SYSCALL 11 /* SYSCALL/SYSRET */
|
||||
#define X86_FEATURE_MMXEXT 22 /* AMD MMX extensions */
|
||||
#define X86_FEATURE_LM 29 /* Long Mode (x86-64) */
|
||||
#define X86_FEATURE_3DNOWEXT 30 /* AMD 3DNow! extensions */
|
||||
#define X86_FEATURE_3DNOW 31 /* 3DNow! */
|
||||
|
||||
/** x86 CPU information */
|
||||
struct cpuinfo_x86 {
|
||||
/** CPU features */
|
||||
unsigned int features;
|
||||
/** 64-bit CPU features */
|
||||
unsigned int amd_features;
|
||||
};
|
||||
|
||||
/*
|
||||
* EFLAGS bits
|
||||
*/
|
||||
#define X86_EFLAGS_CF 0x00000001 /* Carry Flag */
|
||||
#define X86_EFLAGS_PF 0x00000004 /* Parity Flag */
|
||||
#define X86_EFLAGS_AF 0x00000010 /* Auxillary carry Flag */
|
||||
#define X86_EFLAGS_ZF 0x00000040 /* Zero Flag */
|
||||
#define X86_EFLAGS_SF 0x00000080 /* Sign Flag */
|
||||
#define X86_EFLAGS_TF 0x00000100 /* Trap Flag */
|
||||
#define X86_EFLAGS_IF 0x00000200 /* Interrupt Flag */
|
||||
#define X86_EFLAGS_DF 0x00000400 /* Direction Flag */
|
||||
#define X86_EFLAGS_OF 0x00000800 /* Overflow Flag */
|
||||
#define X86_EFLAGS_IOPL 0x00003000 /* IOPL mask */
|
||||
#define X86_EFLAGS_NT 0x00004000 /* Nested Task */
|
||||
#define X86_EFLAGS_RF 0x00010000 /* Resume Flag */
|
||||
#define X86_EFLAGS_VM 0x00020000 /* Virtual Mode */
|
||||
#define X86_EFLAGS_AC 0x00040000 /* Alignment Check */
|
||||
#define X86_EFLAGS_VIF 0x00080000 /* Virtual Interrupt Flag */
|
||||
#define X86_EFLAGS_VIP 0x00100000 /* Virtual Interrupt Pending */
|
||||
#define X86_EFLAGS_ID 0x00200000 /* CPUID detection flag */
|
||||
|
||||
/*
|
||||
* Generic CPUID function
|
||||
*/
|
||||
static inline __attribute__ (( always_inline )) void
|
||||
cpuid ( int op, unsigned int *eax, unsigned int *ebx,
|
||||
unsigned int *ecx, unsigned int *edx ) {
|
||||
__asm__ ( "cpuid" :
|
||||
"=a" ( *eax ), "=b" ( *ebx ), "=c" ( *ecx ), "=d" ( *edx )
|
||||
: "0" ( op ) );
|
||||
}
|
||||
|
||||
extern void get_cpuinfo ( struct cpuinfo_x86 *cpu );
|
||||
|
||||
#endif /* I386_BITS_CPU_H */
|
@@ -1,8 +0,0 @@
|
||||
#ifndef ETHERBOOT_BITS_ENDIAN_H
|
||||
#define ETHERBOOT_BITS_ENDIAN_H
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER );
|
||||
|
||||
#define __BYTE_ORDER __LITTLE_ENDIAN
|
||||
|
||||
#endif /* ETHERBOOT_BITS_ENDIAN_H */
|
@@ -1,42 +0,0 @@
|
||||
#ifndef _BITS_ERRFILE_H
|
||||
#define _BITS_ERRFILE_H
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER );
|
||||
|
||||
/**
|
||||
* @addtogroup errfile Error file identifiers
|
||||
* @{
|
||||
*/
|
||||
|
||||
#define ERRFILE_memtop_umalloc ( ERRFILE_ARCH | ERRFILE_CORE | 0x00000000 )
|
||||
#define ERRFILE_memmap ( ERRFILE_ARCH | ERRFILE_CORE | 0x00010000 )
|
||||
#define ERRFILE_pnpbios ( ERRFILE_ARCH | ERRFILE_CORE | 0x00020000 )
|
||||
#define ERRFILE_bios_smbios ( ERRFILE_ARCH | ERRFILE_CORE | 0x00030000 )
|
||||
#define ERRFILE_biosint ( ERRFILE_ARCH | ERRFILE_CORE | 0x00040000 )
|
||||
#define ERRFILE_int13 ( ERRFILE_ARCH | ERRFILE_CORE | 0x00050000 )
|
||||
#define ERRFILE_pxeparent ( ERRFILE_ARCH | ERRFILE_CORE | 0x00060000 )
|
||||
|
||||
#define ERRFILE_bootsector ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x00000000 )
|
||||
#define ERRFILE_bzimage ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x00010000 )
|
||||
#define ERRFILE_eltorito ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x00020000 )
|
||||
#define ERRFILE_multiboot ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x00030000 )
|
||||
#define ERRFILE_nbi ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x00040000 )
|
||||
#define ERRFILE_pxe_image ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x00050000 )
|
||||
#define ERRFILE_elfboot ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x00060000 )
|
||||
#define ERRFILE_comboot ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x00070000 )
|
||||
#define ERRFILE_com32 ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x00080000 )
|
||||
#define ERRFILE_comboot_resolv ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x00090000 )
|
||||
#define ERRFILE_comboot_call ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x000a0000 )
|
||||
|
||||
#define ERRFILE_undi ( ERRFILE_ARCH | ERRFILE_NET | 0x00000000 )
|
||||
#define ERRFILE_undiload ( ERRFILE_ARCH | ERRFILE_NET | 0x00010000 )
|
||||
#define ERRFILE_undinet ( ERRFILE_ARCH | ERRFILE_NET | 0x00020000 )
|
||||
#define ERRFILE_undionly ( ERRFILE_ARCH | ERRFILE_NET | 0x00030000 )
|
||||
#define ERRFILE_undirom ( ERRFILE_ARCH | ERRFILE_NET | 0x00040000 )
|
||||
|
||||
#define ERRFILE_timer_rdtsc ( ERRFILE_ARCH | ERRFILE_DRIVER | 0x00000000 )
|
||||
#define ERRFILE_timer_bios ( ERRFILE_ARCH | ERRFILE_DRIVER | 0x00010000 )
|
||||
|
||||
/** @} */
|
||||
|
||||
#endif /* _BITS_ERRFILE_H */
|
@@ -1,14 +0,0 @@
|
||||
#ifndef _BITS_IO_H
|
||||
#define _BITS_IO_H
|
||||
|
||||
/** @file
|
||||
*
|
||||
* i386-specific I/O API implementations
|
||||
*
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER );
|
||||
|
||||
#include <ipxe/x86_io.h>
|
||||
|
||||
#endif /* _BITS_IO_H */
|
@@ -1,15 +0,0 @@
|
||||
#ifndef _BITS_NAP_H
|
||||
#define _BITS_NAP_H
|
||||
|
||||
/** @file
|
||||
*
|
||||
* i386-specific CPU sleeping API implementations
|
||||
*
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER );
|
||||
|
||||
#include <ipxe/bios_nap.h>
|
||||
#include <ipxe/efi/efix86_nap.h>
|
||||
|
||||
#endif /* _BITS_MAP_H */
|
@@ -1,14 +0,0 @@
|
||||
#ifndef _BITS_SANBOOT_H
|
||||
#define _BITS_SANBOOT_H
|
||||
|
||||
/** @file
|
||||
*
|
||||
* i386-specific sanboot API implementations
|
||||
*
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER );
|
||||
|
||||
#include <ipxe/bios_sanboot.h>
|
||||
|
||||
#endif /* _BITS_SANBOOT_H */
|
@@ -1,14 +0,0 @@
|
||||
#ifndef _BITS_SMBIOS_H
|
||||
#define _BITS_SMBIOS_H
|
||||
|
||||
/** @file
|
||||
*
|
||||
* i386-specific SMBIOS API implementations
|
||||
*
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER );
|
||||
|
||||
#include <ipxe/bios_smbios.h>
|
||||
|
||||
#endif /* _BITS_SMBIOS_H */
|
@@ -1,7 +1,7 @@
|
||||
#ifndef _BITS_STDINT_H
|
||||
#define _BITS_STDINT_H
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER );
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
typedef __SIZE_TYPE__ size_t;
|
||||
typedef signed long ssize_t;
|
||||
|
@@ -1,15 +0,0 @@
|
||||
#ifndef _BITS_TIMER_H
|
||||
#define _BITS_TIMER_H
|
||||
|
||||
/** @file
|
||||
*
|
||||
* i386-specific timer API implementations
|
||||
*
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER );
|
||||
|
||||
#include <ipxe/bios_timer.h>
|
||||
#include <ipxe/rdtsc_timer.h>
|
||||
|
||||
#endif /* _BITS_TIMER_H */
|
@@ -1,14 +0,0 @@
|
||||
#ifndef _BITS_UACCESS_H
|
||||
#define _BITS_UACCESS_H
|
||||
|
||||
/** @file
|
||||
*
|
||||
* i386-specific user access API implementations
|
||||
*
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER );
|
||||
|
||||
#include <librm.h>
|
||||
|
||||
#endif /* _BITS_UACCESS_H */
|
@@ -1,14 +0,0 @@
|
||||
#ifndef _BITS_UMALLOC_H
|
||||
#define _BITS_UMALLOC_H
|
||||
|
||||
/** @file
|
||||
*
|
||||
* i386-specific user memory allocation API implementations
|
||||
*
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER );
|
||||
|
||||
#include <ipxe/memtop_umalloc.h>
|
||||
|
||||
#endif /* _BITS_UMALLOC_H */
|
@@ -1,34 +0,0 @@
|
||||
#ifndef BOCHS_H
|
||||
#define BOCHS_H
|
||||
|
||||
/** @file
|
||||
*
|
||||
* bochs breakpoints
|
||||
*
|
||||
* This file defines @c bochsbp, the magic breakpoint instruction that
|
||||
* is incredibly useful when debugging under bochs. This file should
|
||||
* never be included in production code.
|
||||
*
|
||||
* Use the pseudo-instruction @c bochsbp in assembly code, or the
|
||||
* bochsbp() function in C code.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef ASSEMBLY
|
||||
|
||||
/* Breakpoint for when debugging under bochs */
|
||||
#define bochsbp xchgw %bx, %bx
|
||||
#define BOCHSBP bochsbp
|
||||
|
||||
#else /* ASSEMBLY */
|
||||
|
||||
/** Breakpoint for when debugging under bochs */
|
||||
static inline void bochsbp ( void ) {
|
||||
__asm__ __volatile__ ( "xchgw %bx, %bx" );
|
||||
}
|
||||
|
||||
#endif /* ASSEMBLY */
|
||||
|
||||
#warning "bochs.h should not be included into production code"
|
||||
|
||||
#endif /* BOCHS_H */
|
@@ -1,14 +0,0 @@
|
||||
#ifndef _BOOTSECTOR_H
|
||||
#define _BOOTSECTOR_H
|
||||
|
||||
/** @file
|
||||
*
|
||||
* x86 bootsector image format
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER );
|
||||
|
||||
extern int call_bootsector ( unsigned int segment, unsigned int offset,
|
||||
unsigned int drive );
|
||||
|
||||
#endif /* _BOOTSECTOR_H */
|
@@ -1,142 +0,0 @@
|
||||
#ifndef _BZIMAGE_H
|
||||
#define _BZIMAGE_H
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER );
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/**
|
||||
* A bzImage header
|
||||
*
|
||||
* As documented in Documentation/i386/boot.txt
|
||||
*/
|
||||
struct bzimage_header {
|
||||
/** The size of the setup in sectors
|
||||
*
|
||||
* If this field contains 0, assume it contains 4.
|
||||
*/
|
||||
uint8_t setup_sects;
|
||||
/** If set, the root is mounted readonly */
|
||||
uint16_t root_flags;
|
||||
/** DO NOT USE - for bootsect.S use only */
|
||||
uint16_t syssize;
|
||||
/** DO NOT USE - obsolete */
|
||||
uint16_t swap_dev;
|
||||
/** DO NOT USE - for bootsect.S use only */
|
||||
uint16_t ram_size;
|
||||
/** Video mode control */
|
||||
uint16_t vid_mode;
|
||||
/** Default root device number */
|
||||
uint16_t root_dev;
|
||||
/** 0xAA55 magic number */
|
||||
uint16_t boot_flag;
|
||||
/** Jump instruction */
|
||||
uint16_t jump;
|
||||
/** Magic signature "HdrS" */
|
||||
uint32_t header;
|
||||
/** Boot protocol version supported */
|
||||
uint16_t version;
|
||||
/** Boot loader hook (see below) */
|
||||
uint32_t realmode_swtch;
|
||||
/** The load-low segment (0x1000) (obsolete) */
|
||||
uint16_t start_sys;
|
||||
/** Pointer to kernel version string */
|
||||
uint16_t kernel_version;
|
||||
/** Boot loader identifier */
|
||||
uint8_t type_of_loader;
|
||||
/** Boot protocol option flags */
|
||||
uint8_t loadflags;
|
||||
/** Move to high memory size (used with hooks) */
|
||||
uint16_t setup_move_size;
|
||||
/** Boot loader hook (see below) */
|
||||
uint32_t code32_start;
|
||||
/** initrd load address (set by boot loader) */
|
||||
uint32_t ramdisk_image;
|
||||
/** initrd size (set by boot loader) */
|
||||
uint32_t ramdisk_size;
|
||||
/** DO NOT USE - for bootsect.S use only */
|
||||
uint32_t bootsect_kludge;
|
||||
/** Free memory after setup end */
|
||||
uint16_t heap_end_ptr;
|
||||
/** Unused */
|
||||
uint16_t pad1;
|
||||
/** 32-bit pointer to the kernel command line */
|
||||
uint32_t cmd_line_ptr;
|
||||
/** Highest legal initrd address */
|
||||
uint32_t initrd_addr_max;
|
||||
/** Physical addr alignment required for kernel */
|
||||
uint32_t kernel_alignment;
|
||||
/** Whether kernel is relocatable or not */
|
||||
uint8_t relocatable_kernel;
|
||||
/** Unused */
|
||||
uint8_t pad2[3];
|
||||
/** Maximum size of the kernel command line */
|
||||
uint32_t cmdline_size;
|
||||
} __attribute__ (( packed ));
|
||||
|
||||
/** Offset of bzImage header within kernel image */
|
||||
#define BZI_HDR_OFFSET 0x1f1
|
||||
|
||||
/** bzImage boot flag value */
|
||||
#define BZI_BOOT_FLAG 0xaa55
|
||||
|
||||
/** bzImage magic signature value */
|
||||
#define BZI_SIGNATURE 0x53726448
|
||||
|
||||
/** bzImage boot loader identifier for Etherboot */
|
||||
#define BZI_LOADER_TYPE_ETHERBOOT 0x40
|
||||
|
||||
/** bzImage boot loader identifier for iPXE
|
||||
*
|
||||
* We advertise ourselves as Etherboot version 6.
|
||||
*/
|
||||
#define BZI_LOADER_TYPE_IPXE ( BZI_LOADER_TYPE_ETHERBOOT | 0x06 )
|
||||
|
||||
/** bzImage "load high" flag */
|
||||
#define BZI_LOAD_HIGH 0x01
|
||||
|
||||
/** Load address for high-loaded kernels */
|
||||
#define BZI_LOAD_HIGH_ADDR 0x100000
|
||||
|
||||
/** Load address for low-loaded kernels */
|
||||
#define BZI_LOAD_LOW_ADDR 0x10000
|
||||
|
||||
/** bzImage "kernel can use heap" flag */
|
||||
#define BZI_CAN_USE_HEAP 0x80
|
||||
|
||||
/** bzImage special video mode "normal" */
|
||||
#define BZI_VID_MODE_NORMAL 0xffff
|
||||
|
||||
/** bzImage special video mode "ext" */
|
||||
#define BZI_VID_MODE_EXT 0xfffe
|
||||
|
||||
/** bzImage special video mode "ask" */
|
||||
#define BZI_VID_MODE_ASK 0xfffd
|
||||
|
||||
/** bzImage maximum initrd address for versions < 2.03 */
|
||||
#define BZI_INITRD_MAX 0x37ffffff
|
||||
|
||||
/** bzImage command-line structure used by older kernels */
|
||||
struct bzimage_cmdline {
|
||||
/** Magic signature */
|
||||
uint16_t magic;
|
||||
/** Offset to command line */
|
||||
uint16_t offset;
|
||||
} __attribute__ (( packed ));
|
||||
|
||||
/** Offset of bzImage command-line structure within kernel image */
|
||||
#define BZI_CMDLINE_OFFSET 0x20
|
||||
|
||||
/** bzImage command line present magic marker value */
|
||||
#define BZI_CMDLINE_MAGIC 0xa33f
|
||||
|
||||
/** Assumed size of real-mode portion (including .bss) */
|
||||
#define BZI_ASSUMED_RM_SIZE 0x8000
|
||||
|
||||
/** Amount of stack space to provide */
|
||||
#define BZI_STACK_SIZE 0x1000
|
||||
|
||||
/** Maximum size of command line */
|
||||
#define BZI_CMDLINE_SIZE 0x100
|
||||
|
||||
#endif /* _BZIMAGE_H */
|
@@ -1,180 +0,0 @@
|
||||
#ifndef COMBOOT_H
|
||||
#define COMBOOT_H
|
||||
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
* SYSLINUX COMBOOT
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER );
|
||||
|
||||
#include <stdint.h>
|
||||
#include <setjmp.h>
|
||||
#include <ipxe/in.h>
|
||||
|
||||
/** Descriptor in a 32-bit IDT */
|
||||
struct idt_descriptor {
|
||||
uint16_t offset_low;
|
||||
uint16_t selector;
|
||||
uint16_t flags;
|
||||
uint16_t offset_high;
|
||||
} __attribute__ (( packed ));
|
||||
|
||||
/** Operand for the LIDT instruction */
|
||||
struct idt_register {
|
||||
uint16_t limit;
|
||||
uint32_t base;
|
||||
} __attribute__ (( packed ));
|
||||
|
||||
/** Entry in the interrupt jump buffer */
|
||||
struct ijb_entry {
|
||||
uint8_t pusha_instruction;
|
||||
uint8_t mov_instruction;
|
||||
uint8_t mov_value;
|
||||
uint8_t jump_instruction;
|
||||
uint32_t jump_destination;
|
||||
} __attribute__ (( packed ));
|
||||
|
||||
/** The x86 opcode for "pushal" */
|
||||
#define IJB_PUSHA 0x60
|
||||
|
||||
/** The x86 opcode for "movb $imm8,%al" */
|
||||
#define IJB_MOV_AL_IMM8 0xB0
|
||||
|
||||
/** The x86 opcode for "jmp rel32" */
|
||||
#define IJB_JMP_REL32 0xE9
|
||||
|
||||
/** Flags that specify a 32-bit interrupt gate with DPL=0 */
|
||||
#define IDT_INTERRUPT_GATE_FLAGS 0x8E00
|
||||
|
||||
/** Address of COM32 interrupt descriptor table */
|
||||
#define COM32_IDT 0x100000
|
||||
|
||||
/** Number of entries in a fully populated IDT */
|
||||
#define COM32_NUM_IDT_ENTRIES 256
|
||||
|
||||
/** Address of COM32 interrupt jump buffer */
|
||||
#define COM32_IJB 0x100800
|
||||
|
||||
/** Segment used for COMBOOT PSP and image */
|
||||
#define COMBOOT_PSP_SEG 0x07C0
|
||||
|
||||
/** Entry point address of COM32 images */
|
||||
#define COM32_START_PHYS 0x101000
|
||||
|
||||
/** COM32 bounce buffer segment */
|
||||
#define COM32_BOUNCE_SEG 0x07C0
|
||||
|
||||
/** Size of SYSLINUX file block in bytes */
|
||||
#define COMBOOT_FILE_BLOCKSZ 512
|
||||
|
||||
/** COMBOOT feature flags (INT 22h AX=15h) */
|
||||
#define COMBOOT_FEATURE_LOCAL_BOOT (1 << 0)
|
||||
#define COMBOOT_FEATURE_IDLE_LOOP (1 << 1)
|
||||
|
||||
/** Maximum number of shuffle descriptors for
|
||||
* shuffle and boot functions
|
||||
* (INT 22h AX=0012h, 001Ah, 001Bh)
|
||||
*/
|
||||
#define COMBOOT_MAX_SHUFFLE_DESCRIPTORS 682
|
||||
|
||||
typedef union {
|
||||
uint32_t l;
|
||||
uint16_t w[2];
|
||||
uint8_t b[4];
|
||||
} com32_reg32_t;
|
||||
|
||||
typedef struct {
|
||||
uint16_t gs; /* Offset 0 */
|
||||
uint16_t fs; /* Offset 2 */
|
||||
uint16_t es; /* Offset 4 */
|
||||
uint16_t ds; /* Offset 6 */
|
||||
|
||||
com32_reg32_t edi; /* Offset 8 */
|
||||
com32_reg32_t esi; /* Offset 12 */
|
||||
com32_reg32_t ebp; /* Offset 16 */
|
||||
com32_reg32_t _unused_esp; /* Offset 20 */
|
||||
com32_reg32_t ebx; /* Offset 24 */
|
||||
com32_reg32_t edx; /* Offset 28 */
|
||||
com32_reg32_t ecx; /* Offset 32 */
|
||||
com32_reg32_t eax; /* Offset 36 */
|
||||
|
||||
com32_reg32_t eflags; /* Offset 40 */
|
||||
} com32sys_t;
|
||||
|
||||
typedef struct {
|
||||
uint32_t eax; /* Offset 0 */
|
||||
uint32_t ecx; /* Offset 4 */
|
||||
uint32_t edx; /* Offset 8 */
|
||||
uint32_t ebx; /* Offset 12 */
|
||||
uint32_t esp; /* Offset 16 */
|
||||
uint32_t ebp; /* Offset 20 */
|
||||
uint32_t esi; /* Offset 24 */
|
||||
uint32_t edi; /* Offset 28 */
|
||||
|
||||
uint32_t eip; /* Offset 32 */
|
||||
} syslinux_pm_regs;
|
||||
|
||||
typedef struct {
|
||||
uint16_t es; /* Offset 0 */
|
||||
uint16_t _unused_cs; /* Offset 2 */
|
||||
uint16_t ds; /* Offset 4 */
|
||||
uint16_t ss; /* Offset 6 */
|
||||
uint16_t fs; /* Offset 8 */
|
||||
uint16_t gs; /* Offset 10 */
|
||||
|
||||
uint32_t eax; /* Offset 12 */
|
||||
uint32_t ecx; /* Offset 16 */
|
||||
uint32_t edx; /* Offset 20 */
|
||||
uint32_t ebx; /* Offset 24 */
|
||||
uint32_t esp; /* Offset 28 */
|
||||
uint32_t ebp; /* Offset 32 */
|
||||
uint32_t esi; /* Offset 36 */
|
||||
uint32_t edi; /* Offset 40 */
|
||||
|
||||
uint16_t ip; /* Offset 44 */
|
||||
uint16_t cs; /* Offset 46 */
|
||||
} syslinux_rm_regs;
|
||||
|
||||
typedef struct {
|
||||
uint32_t dest;
|
||||
uint32_t src;
|
||||
uint32_t len;
|
||||
} comboot_shuffle_descriptor;
|
||||
|
||||
extern void hook_comboot_interrupts ( );
|
||||
extern void unhook_comboot_interrupts ( );
|
||||
|
||||
/* These are not the correct prototypes, but it doens't matter,
|
||||
* as we only ever get the address of these functions;
|
||||
* they are only called from COM32 code running in PHYS_CODE
|
||||
*/
|
||||
extern void com32_intcall_wrapper ( );
|
||||
extern void com32_farcall_wrapper ( );
|
||||
extern void com32_cfarcall_wrapper ( );
|
||||
extern void com32_irq_wrapper ( );
|
||||
|
||||
/* Resolve a hostname to an (IPv4) address */
|
||||
extern int comboot_resolv ( const char *name, struct in_addr *address );
|
||||
|
||||
/* setjmp/longjmp context buffer used to return after loading an image */
|
||||
extern rmjmp_buf comboot_return;
|
||||
|
||||
/* Replacement image when exiting with COMBOOT_EXIT_RUN_KERNEL */
|
||||
extern struct image *comboot_replacement_image;
|
||||
|
||||
extern void *com32_external_esp;
|
||||
|
||||
#define COMBOOT_EXIT 1
|
||||
#define COMBOOT_EXIT_RUN_KERNEL 2
|
||||
#define COMBOOT_EXIT_COMMAND 3
|
||||
|
||||
extern void comboot_force_text_mode ( void );
|
||||
|
||||
#define COMBOOT_VIDEO_GRAPHICS 0x01
|
||||
#define COMBOOT_VIDEO_NONSTANDARD 0x02
|
||||
#define COMBOOT_VIDEO_VESA 0x04
|
||||
#define COMBOOT_VIDEO_NOTEXT 0x08
|
||||
|
||||
#endif
|
@@ -4,7 +4,7 @@
|
||||
* 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 any later version.
|
||||
* 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
|
||||
@@ -13,7 +13,12 @@
|
||||
*
|
||||
* 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 St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA.
|
||||
*
|
||||
* You can also choose to distribute this program under the terms of
|
||||
* the Unmodified Binary Distribution Licence (as given in the file
|
||||
* COPYING.UBDL), provided that you have satisfied its requirements.
|
||||
*/
|
||||
|
||||
#ifndef _DHCP_ARCH_H
|
||||
@@ -24,17 +29,12 @@
|
||||
* Architecture-specific DHCP options
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER );
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
#include <ipxe/dhcp.h>
|
||||
|
||||
#define DHCP_ARCH_VENDOR_CLASS_ID \
|
||||
DHCP_STRING ( 'P', 'X', 'E', 'C', 'l', 'i', 'e', 'n', 't', ':', \
|
||||
'A', 'r', 'c', 'h', ':', '0', '0', '0', '0', '6', ':', \
|
||||
'U', 'N', 'D', 'I', ':', '0', '0', '3', '0', '1', '0' )
|
||||
#define DHCP_ARCH_CLIENT_ARCHITECTURE DHCP_CLIENT_ARCHITECTURE_IA32
|
||||
|
||||
#define DHCP_ARCH_CLIENT_ARCHITECTURE DHCP_WORD ( 6 )
|
||||
|
||||
#define DHCP_ARCH_CLIENT_NDI DHCP_OPTION ( 1 /* UNDI */ , 3, 10 /* v3.10 */ )
|
||||
#define DHCP_ARCH_CLIENT_NDI 1 /* UNDI */ , 3, 10 /* v3.10 */
|
||||
|
||||
#endif
|
||||
|
@@ -1,9 +0,0 @@
|
||||
#ifndef _FAKEE820_H
|
||||
#define _FAKEE820_H
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER );
|
||||
|
||||
extern void fake_e820 ( void );
|
||||
extern void unfake_e820 ( void );
|
||||
|
||||
#endif /* _FAKEE820_H */
|
@@ -46,6 +46,12 @@ enum {
|
||||
GDBMACH_AWATCH,
|
||||
};
|
||||
|
||||
/* Interrupt vectors */
|
||||
extern void gdbmach_sigfpe ( void );
|
||||
extern void gdbmach_sigtrap ( void );
|
||||
extern void gdbmach_sigstkflt ( void );
|
||||
extern void gdbmach_sigill ( void );
|
||||
|
||||
static inline void gdbmach_set_pc ( gdbreg_t *regs, gdbreg_t pc ) {
|
||||
regs [ GDBMACH_EIP ] = pc;
|
||||
}
|
||||
@@ -61,4 +67,6 @@ static inline void gdbmach_breakpoint ( void ) {
|
||||
|
||||
extern int gdbmach_set_breakpoint ( int type, unsigned long addr, size_t len, int enable );
|
||||
|
||||
extern void gdbmach_init ( void );
|
||||
|
||||
#endif /* GDBMACH_H */
|
||||
|
@@ -1,267 +0,0 @@
|
||||
#ifndef INT13_H
|
||||
#define INT13_H
|
||||
|
||||
/** @file
|
||||
*
|
||||
* INT 13 emulation
|
||||
*
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER );
|
||||
|
||||
#include <stdint.h>
|
||||
#include <ipxe/list.h>
|
||||
#include <ipxe/edd.h>
|
||||
#include <realmode.h>
|
||||
|
||||
/**
|
||||
* @defgroup int13ops INT 13 operation codes
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** Reset disk system */
|
||||
#define INT13_RESET 0x00
|
||||
/** Get status of last operation */
|
||||
#define INT13_GET_LAST_STATUS 0x01
|
||||
/** Read sectors */
|
||||
#define INT13_READ_SECTORS 0x02
|
||||
/** Write sectors */
|
||||
#define INT13_WRITE_SECTORS 0x03
|
||||
/** Get drive parameters */
|
||||
#define INT13_GET_PARAMETERS 0x08
|
||||
/** Get disk type */
|
||||
#define INT13_GET_DISK_TYPE 0x15
|
||||
/** Extensions installation check */
|
||||
#define INT13_EXTENSION_CHECK 0x41
|
||||
/** Extended read */
|
||||
#define INT13_EXTENDED_READ 0x42
|
||||
/** Extended write */
|
||||
#define INT13_EXTENDED_WRITE 0x43
|
||||
/** Verify sectors */
|
||||
#define INT13_EXTENDED_VERIFY 0x44
|
||||
/** Extended seek */
|
||||
#define INT13_EXTENDED_SEEK 0x47
|
||||
/** Get extended drive parameters */
|
||||
#define INT13_GET_EXTENDED_PARAMETERS 0x48
|
||||
/** Get CD-ROM status / terminate emulation */
|
||||
#define INT13_CDROM_STATUS_TERMINATE 0x4b
|
||||
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @defgroup int13status INT 13 status codes
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** Operation completed successfully */
|
||||
#define INT13_STATUS_SUCCESS 0x00
|
||||
/** Invalid function or parameter */
|
||||
#define INT13_STATUS_INVALID 0x01
|
||||
/** Read error */
|
||||
#define INT13_STATUS_READ_ERROR 0x04
|
||||
/** Reset failed */
|
||||
#define INT13_STATUS_RESET_FAILED 0x05
|
||||
/** Write error */
|
||||
#define INT13_STATUS_WRITE_ERROR 0xcc
|
||||
|
||||
/** @} */
|
||||
|
||||
/** Block size for non-extended INT 13 calls */
|
||||
#define INT13_BLKSIZE 512
|
||||
|
||||
/** An INT 13 disk address packet */
|
||||
struct int13_disk_address {
|
||||
/** Size of the packet, in bytes */
|
||||
uint8_t bufsize;
|
||||
/** Reserved */
|
||||
uint8_t reserved_a;
|
||||
/** Block count */
|
||||
uint8_t count;
|
||||
/** Reserved */
|
||||
uint8_t reserved_b;
|
||||
/** Data buffer */
|
||||
struct segoff buffer;
|
||||
/** Starting block number */
|
||||
uint64_t lba;
|
||||
/** Data buffer (EDD 3.0+ only) */
|
||||
uint64_t buffer_phys;
|
||||
/** Block count (EDD 4.0+ only) */
|
||||
uint32_t long_count;
|
||||
/** Reserved */
|
||||
uint32_t reserved_c;
|
||||
} __attribute__ (( packed ));
|
||||
|
||||
/** INT 13 disk parameters */
|
||||
struct int13_disk_parameters {
|
||||
/** Size of this structure */
|
||||
uint16_t bufsize;
|
||||
/** Flags */
|
||||
uint16_t flags;
|
||||
/** Number of cylinders */
|
||||
uint32_t cylinders;
|
||||
/** Number of heads */
|
||||
uint32_t heads;
|
||||
/** Number of sectors per track */
|
||||
uint32_t sectors_per_track;
|
||||
/** Total number of sectors on drive */
|
||||
uint64_t sectors;
|
||||
/** Bytes per sector */
|
||||
uint16_t sector_size;
|
||||
/** Device parameter table extension */
|
||||
struct segoff dpte;
|
||||
/** Device path information */
|
||||
struct edd_device_path_information dpi;
|
||||
} __attribute__ (( packed ));
|
||||
|
||||
/**
|
||||
* @defgroup int13types INT 13 disk types
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** No such drive */
|
||||
#define INT13_DISK_TYPE_NONE 0x00
|
||||
/** Floppy without change-line support */
|
||||
#define INT13_DISK_TYPE_FDD 0x01
|
||||
/** Floppy with change-line support */
|
||||
#define INT13_DISK_TYPE_FDD_CL 0x02
|
||||
/** Hard disk */
|
||||
#define INT13_DISK_TYPE_HDD 0x03
|
||||
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @defgroup int13flags INT 13 disk parameter flags
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** DMA boundary errors handled transparently */
|
||||
#define INT13_FL_DMA_TRANSPARENT 0x01
|
||||
/** CHS information is valid */
|
||||
#define INT13_FL_CHS_VALID 0x02
|
||||
/** Removable drive */
|
||||
#define INT13_FL_REMOVABLE 0x04
|
||||
/** Write with verify supported */
|
||||
#define INT13_FL_VERIFIABLE 0x08
|
||||
/** Has change-line supported (valid only for removable drives) */
|
||||
#define INT13_FL_CHANGE_LINE 0x10
|
||||
/** Drive can be locked (valid only for removable drives) */
|
||||
#define INT13_FL_LOCKABLE 0x20
|
||||
/** CHS is max possible, not current media (valid only for removable drives) */
|
||||
#define INT13_FL_CHS_MAX 0x40
|
||||
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @defgroup int13exts INT 13 extension flags
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** Extended disk access functions supported */
|
||||
#define INT13_EXTENSION_LINEAR 0x01
|
||||
/** Removable drive functions supported */
|
||||
#define INT13_EXTENSION_REMOVABLE 0x02
|
||||
/** EDD functions supported */
|
||||
#define INT13_EXTENSION_EDD 0x04
|
||||
/** 64-bit extensions are present */
|
||||
#define INT13_EXTENSION_64BIT 0x08
|
||||
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @defgroup int13vers INT 13 extension versions
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** INT13 extensions version 1.x */
|
||||
#define INT13_EXTENSION_VER_1_X 0x01
|
||||
/** INT13 extensions version 2.0 (EDD-1.0) */
|
||||
#define INT13_EXTENSION_VER_2_0 0x20
|
||||
/** INT13 extensions version 2.1 (EDD-1.1) */
|
||||
#define INT13_EXTENSION_VER_2_1 0x21
|
||||
/** INT13 extensions version 3.0 (EDD-3.0) */
|
||||
#define INT13_EXTENSION_VER_3_0 0x30
|
||||
|
||||
/** @} */
|
||||
|
||||
/** Maximum number of sectors for which CHS geometry is allowed to be valid
|
||||
*
|
||||
* This number is taken from the EDD specification.
|
||||
*/
|
||||
#define INT13_MAX_CHS_SECTORS 15482880
|
||||
|
||||
/** Bootable CD-ROM specification packet */
|
||||
struct int13_cdrom_specification {
|
||||
/** Size of packet in bytes */
|
||||
uint8_t size;
|
||||
/** Boot media type */
|
||||
uint8_t media_type;
|
||||
/** Drive number */
|
||||
uint8_t drive;
|
||||
/** CD-ROM controller number */
|
||||
uint8_t controller;
|
||||
/** LBA of disk image to emulate */
|
||||
uint32_t lba;
|
||||
/** Device specification */
|
||||
uint16_t device;
|
||||
/** Segment of 3K buffer for caching CD-ROM reads */
|
||||
uint16_t cache_segment;
|
||||
/** Load segment for initial boot image */
|
||||
uint16_t load_segment;
|
||||
/** Number of 512-byte sectors to load */
|
||||
uint16_t load_sectors;
|
||||
/** Low 8 bits of cylinder number */
|
||||
uint8_t cyl;
|
||||
/** Sector number, plus high 2 bits of cylinder number */
|
||||
uint8_t cyl_sector;
|
||||
/** Head number */
|
||||
uint8_t head;
|
||||
} __attribute__ (( packed ));
|
||||
|
||||
/** A C/H/S address within a partition table entry */
|
||||
struct partition_chs {
|
||||
/** Head number */
|
||||
uint8_t head;
|
||||
/** Sector number, plus high 2 bits of cylinder number */
|
||||
uint8_t cyl_sector;
|
||||
/** Low 8 bits of cylinder number */
|
||||
uint8_t cyl;
|
||||
} __attribute__ (( packed ));
|
||||
|
||||
#define PART_HEAD(chs) ( (chs).head )
|
||||
#define PART_SECTOR(chs) ( (chs).cyl_sector & 0x3f )
|
||||
#define PART_CYLINDER(chs) ( (chs).cyl | ( ( (chs).cyl_sector & 0xc0 ) << 2 ) )
|
||||
|
||||
/** A partition table entry within the MBR */
|
||||
struct partition_table_entry {
|
||||
/** Bootable flag */
|
||||
uint8_t bootable;
|
||||
/** C/H/S start address */
|
||||
struct partition_chs chs_start;
|
||||
/** System indicator (partition type) */
|
||||
uint8_t type;
|
||||
/** C/H/S end address */
|
||||
struct partition_chs chs_end;
|
||||
/** Linear start address */
|
||||
uint32_t start;
|
||||
/** Linear length */
|
||||
uint32_t length;
|
||||
} __attribute__ (( packed ));
|
||||
|
||||
/** A Master Boot Record */
|
||||
struct master_boot_record {
|
||||
/** Code area */
|
||||
uint8_t code[440];
|
||||
/** Disk signature */
|
||||
uint32_t signature;
|
||||
/** Padding */
|
||||
uint8_t pad[2];
|
||||
/** Partition table */
|
||||
struct partition_table_entry partitions[4];
|
||||
/** 0x55aa MBR signature */
|
||||
uint16_t magic;
|
||||
} __attribute__ (( packed ));
|
||||
|
||||
/** Use natural BIOS drive number */
|
||||
#define INT13_USE_NATURAL_DRIVE 0xff
|
||||
|
||||
#endif /* INT13_H */
|
@@ -1,18 +0,0 @@
|
||||
#ifndef _IPXE_BIOS_NAP_H
|
||||
#define _IPXE_BIOS_NAP_H
|
||||
|
||||
/** @file
|
||||
*
|
||||
* BIOS CPU sleeping
|
||||
*
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER );
|
||||
|
||||
#ifdef NAP_PCBIOS
|
||||
#define NAP_PREFIX_pcbios
|
||||
#else
|
||||
#define NAP_PREFIX_pcbios __pcbios_
|
||||
#endif
|
||||
|
||||
#endif /* _IPXE_BIOS_NAP_H */
|
@@ -1,18 +0,0 @@
|
||||
#ifndef _IPXE_BIOS_SANBOOT_H
|
||||
#define _IPXE_BIOS_SANBOOT_H
|
||||
|
||||
/** @file
|
||||
*
|
||||
* Standard PC-BIOS sanboot interface
|
||||
*
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER );
|
||||
|
||||
#ifdef SANBOOT_PCBIOS
|
||||
#define SANBOOT_PREFIX_pcbios
|
||||
#else
|
||||
#define SANBOOT_PREFIX_pcbios __pcbios_
|
||||
#endif
|
||||
|
||||
#endif /* _IPXE_BIOS_SANBOOT_H */
|
@@ -1,18 +0,0 @@
|
||||
#ifndef _IPXE_BIOS_SMBIOS_H
|
||||
#define _IPXE_BIOS_SMBIOS_H
|
||||
|
||||
/** @file
|
||||
*
|
||||
* Standard PC-BIOS SMBIOS interface
|
||||
*
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER );
|
||||
|
||||
#ifdef SMBIOS_PCBIOS
|
||||
#define SMBIOS_PREFIX_pcbios
|
||||
#else
|
||||
#define SMBIOS_PREFIX_pcbios __pcbios_
|
||||
#endif
|
||||
|
||||
#endif /* _IPXE_BIOS_SMBIOS_H */
|
@@ -1,44 +0,0 @@
|
||||
#ifndef _IPXE_BIOS_TIMER_H
|
||||
#define _IPXE_BIOS_TIMER_H
|
||||
|
||||
/** @file
|
||||
*
|
||||
* BIOS timer
|
||||
*
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER );
|
||||
|
||||
#ifdef TIMER_PCBIOS
|
||||
#define TIMER_PREFIX_pcbios
|
||||
#else
|
||||
#define TIMER_PREFIX_pcbios __pcbios_
|
||||
#endif
|
||||
|
||||
#include <ipxe/timer2.h>
|
||||
|
||||
/**
|
||||
* Delay for a fixed number of microseconds
|
||||
*
|
||||
* @v usecs Number of microseconds for which to delay
|
||||
*/
|
||||
static inline __always_inline void
|
||||
TIMER_INLINE ( pcbios, udelay ) ( unsigned long usecs ) {
|
||||
/* BIOS timer is not high-resolution enough for udelay(), so
|
||||
* we use timer2
|
||||
*/
|
||||
timer2_udelay ( usecs );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get number of ticks per second
|
||||
*
|
||||
* @ret ticks_per_sec Number of ticks per second
|
||||
*/
|
||||
static inline __always_inline unsigned long
|
||||
TIMER_INLINE ( pcbios, ticks_per_sec ) ( void ) {
|
||||
/* BIOS timer ticks over at 18.2 ticks per second */
|
||||
return 18;
|
||||
}
|
||||
|
||||
#endif /* _IPXE_BIOS_TIMER_H */
|
@@ -1,18 +0,0 @@
|
||||
#ifndef _IPXE_MEMTOP_UMALLOC_H
|
||||
#define _IPXE_MEMTOP_UMALLOC_H
|
||||
|
||||
/** @file
|
||||
*
|
||||
* External memory allocation
|
||||
*
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER );
|
||||
|
||||
#ifdef UMALLOC_MEMTOP
|
||||
#define UMALLOC_PREFIX_memtop
|
||||
#else
|
||||
#define UMALLOC_PREFIX_memtop __memtop_
|
||||
#endif
|
||||
|
||||
#endif /* _IPXE_MEMTOP_UMALLOC_H */
|
@@ -1,39 +0,0 @@
|
||||
#ifndef _IPXE_RDTSC_TIMER_H
|
||||
#define _IPXE_RDTSC_TIMER_H
|
||||
|
||||
/** @file
|
||||
*
|
||||
* RDTSC timer
|
||||
*
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER );
|
||||
|
||||
#ifdef TIMER_RDTSC
|
||||
#define TIMER_PREFIX_rdtsc
|
||||
#else
|
||||
#define TIMER_PREFIX_rdtsc __rdtsc_
|
||||
#endif
|
||||
|
||||
/**
|
||||
* RDTSC values can easily overflow an unsigned long. We discard the
|
||||
* low-order bits in order to obtain sensibly-scaled values.
|
||||
*/
|
||||
#define TSC_SHIFT 8
|
||||
|
||||
/**
|
||||
* Get current system time in ticks
|
||||
*
|
||||
* @ret ticks Current time, in ticks
|
||||
*/
|
||||
static inline __always_inline unsigned long
|
||||
TIMER_INLINE ( rdtsc, currticks ) ( void ) {
|
||||
unsigned long ticks;
|
||||
|
||||
__asm__ __volatile__ ( "rdtsc\n\t"
|
||||
"shrdl %1, %%edx, %%eax\n\t"
|
||||
: "=a" ( ticks ) : "i" ( TSC_SHIFT ) : "edx" );
|
||||
return ticks;
|
||||
}
|
||||
|
||||
#endif /* _IPXE_RDTSC_TIMER_H */
|
@@ -1,14 +0,0 @@
|
||||
#ifndef _IPXE_TIMER2_H
|
||||
#define _IPXE_TIMER2_H
|
||||
|
||||
/** @file
|
||||
*
|
||||
* Timer chip control
|
||||
*
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER );
|
||||
|
||||
extern void timer2_udelay ( unsigned long usecs );
|
||||
|
||||
#endif /* _IPXE_TIMER2_H */
|
@@ -1,153 +0,0 @@
|
||||
#ifndef _IPXE_X86_IO_H
|
||||
#define _IPXE_X86_IO_H
|
||||
|
||||
/** @file
|
||||
*
|
||||
* iPXE I/O API for x86
|
||||
*
|
||||
* i386 uses direct pointer dereferences for accesses to memory-mapped
|
||||
* I/O space, and the inX/outX instructions for accesses to
|
||||
* port-mapped I/O space.
|
||||
*
|
||||
* 64-bit atomic accesses (readq() and writeq()) use MMX instructions,
|
||||
* and will crash original Pentium and earlier CPUs. Fortunately, no
|
||||
* hardware that requires atomic 64-bit accesses will physically fit
|
||||
* into a machine with such an old CPU anyway.
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER );
|
||||
|
||||
#ifdef IOAPI_X86
|
||||
#define IOAPI_PREFIX_x86
|
||||
#else
|
||||
#define IOAPI_PREFIX_x86 __x86_
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Memory space mappings
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Physical<->Bus and Bus<->I/O address mappings
|
||||
*
|
||||
*/
|
||||
|
||||
static inline __always_inline unsigned long
|
||||
IOAPI_INLINE ( x86, phys_to_bus ) ( unsigned long phys_addr ) {
|
||||
return phys_addr;
|
||||
}
|
||||
|
||||
static inline __always_inline unsigned long
|
||||
IOAPI_INLINE ( x86, bus_to_phys ) ( unsigned long bus_addr ) {
|
||||
return bus_addr;
|
||||
}
|
||||
|
||||
static inline __always_inline void *
|
||||
IOAPI_INLINE ( x86, ioremap ) ( unsigned long bus_addr, size_t len __unused ) {
|
||||
return phys_to_virt ( bus_addr );
|
||||
}
|
||||
|
||||
static inline __always_inline void
|
||||
IOAPI_INLINE ( x86, iounmap ) ( volatile const void *io_addr __unused ) {
|
||||
/* Nothing to do */
|
||||
}
|
||||
|
||||
static inline __always_inline unsigned long
|
||||
IOAPI_INLINE ( x86, io_to_bus ) ( volatile const void *io_addr ) {
|
||||
return virt_to_phys ( io_addr );
|
||||
}
|
||||
|
||||
/*
|
||||
* MMIO reads and writes up to 32 bits
|
||||
*
|
||||
*/
|
||||
|
||||
#define X86_READX( _api_func, _type ) \
|
||||
static inline __always_inline _type \
|
||||
IOAPI_INLINE ( x86, _api_func ) ( volatile _type *io_addr ) { \
|
||||
return *io_addr; \
|
||||
}
|
||||
X86_READX ( readb, uint8_t );
|
||||
X86_READX ( readw, uint16_t );
|
||||
X86_READX ( readl, uint32_t );
|
||||
|
||||
#define X86_WRITEX( _api_func, _type ) \
|
||||
static inline __always_inline void \
|
||||
IOAPI_INLINE ( x86, _api_func ) ( _type data, \
|
||||
volatile _type *io_addr ) { \
|
||||
*io_addr = data; \
|
||||
}
|
||||
X86_WRITEX ( writeb, uint8_t );
|
||||
X86_WRITEX ( writew, uint16_t );
|
||||
X86_WRITEX ( writel, uint32_t );
|
||||
|
||||
/*
|
||||
* PIO reads and writes up to 32 bits
|
||||
*
|
||||
*/
|
||||
|
||||
#define X86_INX( _insn_suffix, _type, _reg_prefix ) \
|
||||
static inline __always_inline _type \
|
||||
IOAPI_INLINE ( x86, in ## _insn_suffix ) ( volatile _type *io_addr ) { \
|
||||
_type data; \
|
||||
__asm__ __volatile__ ( "in" #_insn_suffix " %w1, %" _reg_prefix "0" \
|
||||
: "=a" ( data ) : "Nd" ( io_addr ) ); \
|
||||
return data; \
|
||||
} \
|
||||
static inline __always_inline void \
|
||||
IOAPI_INLINE ( x86, ins ## _insn_suffix ) ( volatile _type *io_addr, \
|
||||
_type *data, \
|
||||
unsigned int count ) { \
|
||||
unsigned int discard_D; \
|
||||
__asm__ __volatile__ ( "rep ins" #_insn_suffix \
|
||||
: "=D" ( discard_D ) \
|
||||
: "d" ( io_addr ), "c" ( count ), \
|
||||
"0" ( data ) ); \
|
||||
}
|
||||
X86_INX ( b, uint8_t, "b" );
|
||||
X86_INX ( w, uint16_t, "w" );
|
||||
X86_INX ( l, uint32_t, "k" );
|
||||
|
||||
#define X86_OUTX( _insn_suffix, _type, _reg_prefix ) \
|
||||
static inline __always_inline void \
|
||||
IOAPI_INLINE ( x86, out ## _insn_suffix ) ( _type data, \
|
||||
volatile _type *io_addr ) { \
|
||||
__asm__ __volatile__ ( "out" #_insn_suffix " %" _reg_prefix "0, %w1" \
|
||||
: : "a" ( data ), "Nd" ( io_addr ) ); \
|
||||
} \
|
||||
static inline __always_inline void \
|
||||
IOAPI_INLINE ( x86, outs ## _insn_suffix ) ( volatile _type *io_addr, \
|
||||
const _type *data, \
|
||||
unsigned int count ) { \
|
||||
unsigned int discard_S; \
|
||||
__asm__ __volatile__ ( "rep outs" #_insn_suffix \
|
||||
: "=S" ( discard_S ) \
|
||||
: "d" ( io_addr ), "c" ( count ), \
|
||||
"0" ( data ) ); \
|
||||
}
|
||||
X86_OUTX ( b, uint8_t, "b" );
|
||||
X86_OUTX ( w, uint16_t, "w" );
|
||||
X86_OUTX ( l, uint32_t, "k" );
|
||||
|
||||
/*
|
||||
* Slow down I/O
|
||||
*
|
||||
*/
|
||||
|
||||
static inline __always_inline void
|
||||
IOAPI_INLINE ( x86, iodelay ) ( void ) {
|
||||
__asm__ __volatile__ ( "outb %al, $0x80" );
|
||||
}
|
||||
|
||||
/*
|
||||
* Memory barrier
|
||||
*
|
||||
*/
|
||||
|
||||
static inline __always_inline void
|
||||
IOAPI_INLINE ( x86, mb ) ( void ) {
|
||||
__asm__ __volatile__ ( "lock; addl $0, 0(%%esp)" : : : "memory" );
|
||||
}
|
||||
|
||||
#endif /* _IPXE_X86_IO_H */
|
@@ -1,18 +0,0 @@
|
||||
#ifndef KIR_H
|
||||
#define KIR_H
|
||||
|
||||
#ifndef KEEP_IT_REAL
|
||||
#error "kir.h can be used only with -DKEEP_IT_REAL"
|
||||
#endif
|
||||
|
||||
#ifdef ASSEMBLY
|
||||
|
||||
#define code32 code16gcc
|
||||
|
||||
#else /* ASSEMBLY */
|
||||
|
||||
__asm__ ( ".code16gcc" );
|
||||
|
||||
#endif /* ASSEMBLY */
|
||||
|
||||
#endif /* KIR_H */
|
@@ -1,233 +0,0 @@
|
||||
#ifndef LIBKIR_H
|
||||
#define LIBKIR_H
|
||||
|
||||
#include "realmode.h"
|
||||
|
||||
#ifndef ASSEMBLY
|
||||
|
||||
/*
|
||||
* Full API documentation for these functions is in realmode.h.
|
||||
*
|
||||
*/
|
||||
|
||||
/* Access to variables in .data16 and .text16 in a way compatible with librm */
|
||||
#define __data16( variable ) variable
|
||||
#define __data16_array( variable, array ) variable array
|
||||
#define __bss16( variable ) variable
|
||||
#define __bss16_array( variable, array ) variable array
|
||||
#define __text16( variable ) variable
|
||||
#define __text16_array( variable,array ) variable array
|
||||
#define __use_data16( variable ) variable
|
||||
#define __use_text16( variable ) variable
|
||||
#define __from_data16( pointer ) pointer
|
||||
#define __from_text16( pointer ) pointer
|
||||
|
||||
/* Real-mode data and code segments */
|
||||
static inline __attribute__ (( always_inline )) unsigned int _rm_cs ( void ) {
|
||||
uint16_t cs;
|
||||
__asm__ __volatile__ ( "movw %%cs, %w0" : "=r" ( cs ) );
|
||||
return cs;
|
||||
}
|
||||
|
||||
static inline __attribute__ (( always_inline )) unsigned int _rm_ds ( void ) {
|
||||
uint16_t ds;
|
||||
__asm__ __volatile__ ( "movw %%ds, %w0" : "=r" ( ds ) );
|
||||
return ds;
|
||||
}
|
||||
|
||||
#define rm_cs ( _rm_cs() )
|
||||
#define rm_ds ( _rm_ds() )
|
||||
|
||||
/* Copy to/from base memory */
|
||||
|
||||
static inline void copy_to_real_libkir ( unsigned int dest_seg,
|
||||
unsigned int dest_off,
|
||||
const void *src, size_t n ) {
|
||||
unsigned int discard_D, discard_S, discard_c;
|
||||
|
||||
__asm__ __volatile__ ( "pushw %%es\n\t"
|
||||
"movw %3, %%es\n\t"
|
||||
"rep movsb\n\t"
|
||||
"popw %%es\n\t"
|
||||
: "=D" ( discard_D ), "=S" ( discard_S ),
|
||||
"=c" ( discard_c )
|
||||
: "r" ( dest_seg ), "D" ( dest_off ),
|
||||
"S" ( src ),
|
||||
"c" ( n )
|
||||
: "memory" );
|
||||
}
|
||||
|
||||
static inline void copy_from_real_libkir ( void *dest,
|
||||
unsigned int src_seg,
|
||||
unsigned int src_off,
|
||||
size_t n ) {
|
||||
unsigned int discard_D, discard_S, discard_c;
|
||||
|
||||
__asm__ __volatile__ ( "pushw %%ds\n\t"
|
||||
"movw %4, %%ds\n\t"
|
||||
"rep movsb\n\t"
|
||||
"popw %%ds\n\t"
|
||||
: "=D" ( discard_D ), "=S" ( discard_S ),
|
||||
"=c" ( discard_c )
|
||||
: "D" ( dest ),
|
||||
"r" ( src_seg ), "S" ( src_off ),
|
||||
"c" ( n )
|
||||
: "memory" );
|
||||
}
|
||||
|
||||
#define copy_to_real copy_to_real_libkir
|
||||
#define copy_from_real copy_from_real_libkir
|
||||
|
||||
/*
|
||||
* Transfer individual values to/from base memory. There may well be
|
||||
* a neater way to do this. We have two versions: one for constant
|
||||
* offsets (where the mov instruction must be of the form "mov
|
||||
* %es:123, %xx") and one for non-constant offsets (where the mov
|
||||
* instruction must be of the form "mov %es:(%xx), %yx". If it's
|
||||
* possible to incorporate both forms into one __asm__ instruction, I
|
||||
* don't know how to do it.
|
||||
*
|
||||
* Ideally, the mov instruction should be "mov%z0"; the "%z0" is meant
|
||||
* to expand to either "b", "w" or "l" depending on the size of
|
||||
* operand 0. This would remove the (minor) ambiguity in the mov
|
||||
* instruction. However, gcc on at least my system barfs with an
|
||||
* "internal compiler error" when confronted with %z0.
|
||||
*
|
||||
*/
|
||||
|
||||
#define put_real_kir_const_off( var, seg, off ) \
|
||||
__asm__ ( "movw %w1, %%es\n\t" \
|
||||
"mov %0, %%es:%c2\n\t" \
|
||||
"pushw %%ds\n\t" /* restore %es */ \
|
||||
"popw %%es\n\t" \
|
||||
: \
|
||||
: "r,r" ( var ), "rm,rm" ( seg ), "i,!r" ( off ) \
|
||||
)
|
||||
|
||||
#define put_real_kir_nonconst_off( var, seg, off ) \
|
||||
__asm__ ( "movw %w1, %%es\n\t" \
|
||||
"mov %0, %%es:(%2)\n\t" \
|
||||
"pushw %%ds\n\t" /* restore %es */ \
|
||||
"popw %%es\n\t" \
|
||||
: \
|
||||
: "r" ( var ), "rm" ( seg ), "r" ( off ) \
|
||||
)
|
||||
|
||||
#define put_real_kir( var, seg, off ) \
|
||||
do { \
|
||||
if ( __builtin_constant_p ( off ) ) \
|
||||
put_real_kir_const_off ( var, seg, off ); \
|
||||
else \
|
||||
put_real_kir_nonconst_off ( var, seg, off ); \
|
||||
} while ( 0 )
|
||||
|
||||
#define get_real_kir_const_off( var, seg, off ) \
|
||||
__asm__ ( "movw %w1, %%es\n\t" \
|
||||
"mov %%es:%c2, %0\n\t" \
|
||||
"pushw %%ds\n\t" /* restore %es */ \
|
||||
"popw %%es\n\t" \
|
||||
: "=r,r" ( var ) \
|
||||
: "rm,rm" ( seg ), "i,!r" ( off ) \
|
||||
)
|
||||
|
||||
#define get_real_kir_nonconst_off( var, seg, off ) \
|
||||
__asm__ ( "movw %w1, %%es\n\t" \
|
||||
"mov %%es:(%2), %0\n\t" \
|
||||
"pushw %%ds\n\t" /* restore %es */ \
|
||||
"popw %%es\n\t" \
|
||||
: "=r" ( var ) \
|
||||
: "rm" ( seg ), "r" ( off ) \
|
||||
)
|
||||
|
||||
#define get_real_kir( var, seg, off ) \
|
||||
do { \
|
||||
if ( __builtin_constant_p ( off ) ) \
|
||||
get_real_kir_const_off ( var, seg, off ); \
|
||||
else \
|
||||
get_real_kir_nonconst_off ( var, seg, off ); \
|
||||
} while ( 0 )
|
||||
|
||||
#define put_real put_real_kir
|
||||
#define get_real get_real_kir
|
||||
|
||||
/**
|
||||
* A pointer to a user buffer
|
||||
*
|
||||
* This is actually a struct segoff, but encoded as a uint32_t to
|
||||
* ensure that gcc passes it around efficiently.
|
||||
*/
|
||||
typedef uint32_t userptr_t;
|
||||
|
||||
/**
|
||||
* Copy data to user buffer
|
||||
*
|
||||
* @v buffer User buffer
|
||||
* @v offset Offset within user buffer
|
||||
* @v src Source
|
||||
* @v len Length
|
||||
*/
|
||||
static inline __attribute__ (( always_inline )) void
|
||||
copy_to_user ( userptr_t buffer, off_t offset, const void *src, size_t len ) {
|
||||
copy_to_real ( ( buffer >> 16 ), ( ( buffer & 0xffff ) + offset ),
|
||||
src, len );
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy data from user buffer
|
||||
*
|
||||
* @v dest Destination
|
||||
* @v buffer User buffer
|
||||
* @v offset Offset within user buffer
|
||||
* @v len Length
|
||||
*/
|
||||
static inline __attribute__ (( always_inline )) void
|
||||
copy_from_user ( void *dest, userptr_t buffer, off_t offset, size_t len ) {
|
||||
copy_from_real ( dest, ( buffer >> 16 ),
|
||||
( ( buffer & 0xffff ) + offset ), len );
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert segment:offset address to user buffer
|
||||
*
|
||||
* @v segment Real-mode segment
|
||||
* @v offset Real-mode offset
|
||||
* @ret buffer User buffer
|
||||
*/
|
||||
static inline __attribute__ (( always_inline )) userptr_t
|
||||
real_to_user ( unsigned int segment, unsigned int offset ) {
|
||||
return ( ( segment << 16 ) | offset );
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert virtual address to user buffer
|
||||
*
|
||||
* @v virtual Virtual address
|
||||
* @ret buffer User buffer
|
||||
*
|
||||
* This constructs a user buffer from an ordinary pointer. Use it
|
||||
* when you need to pass a pointer to an internal buffer to a function
|
||||
* that expects a @c userptr_t.
|
||||
*/
|
||||
static inline __attribute__ (( always_inline )) userptr_t
|
||||
virt_to_user ( void * virtual ) {
|
||||
return real_to_user ( rm_ds, ( intptr_t ) virtual );
|
||||
}
|
||||
|
||||
/* TEXT16_CODE: declare a fragment of code that resides in .text16 */
|
||||
#define TEXT16_CODE( asm_code_str ) \
|
||||
".section \".text16\", \"ax\", @progbits\n\t" \
|
||||
".code16\n\t" \
|
||||
".arch i386\n\t" \
|
||||
asm_code_str "\n\t" \
|
||||
".code16gcc\n\t" \
|
||||
".previous\n\t"
|
||||
|
||||
/* REAL_CODE: declare a fragment of code that executes in real mode */
|
||||
#define REAL_CODE( asm_code_str ) \
|
||||
".code16\n\t" \
|
||||
asm_code_str "\n\t" \
|
||||
".code16gcc\n\t"
|
||||
|
||||
#endif /* ASSEMBLY */
|
||||
|
||||
#endif /* LIBKIR_H */
|
@@ -1,201 +0,0 @@
|
||||
#ifndef LIBRM_H
|
||||
#define LIBRM_H
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER );
|
||||
|
||||
/* Segment selectors as used in our protected-mode GDTs.
|
||||
*
|
||||
* Don't change these unless you really know what you're doing.
|
||||
*/
|
||||
|
||||
#define VIRTUAL_CS 0x08
|
||||
#define VIRTUAL_DS 0x10
|
||||
#define PHYSICAL_CS 0x18
|
||||
#define PHYSICAL_DS 0x20
|
||||
#define REAL_CS 0x28
|
||||
#define REAL_DS 0x30
|
||||
#if 0
|
||||
#define LONG_CS 0x38
|
||||
#define LONG_DS 0x40
|
||||
#endif
|
||||
|
||||
#ifndef ASSEMBLY
|
||||
|
||||
#ifdef UACCESS_LIBRM
|
||||
#define UACCESS_PREFIX_librm
|
||||
#else
|
||||
#define UACCESS_PREFIX_librm __librm_
|
||||
#endif
|
||||
|
||||
/* Variables in librm.S */
|
||||
extern unsigned long virt_offset;
|
||||
|
||||
/**
|
||||
* Convert physical address to user pointer
|
||||
*
|
||||
* @v phys_addr Physical address
|
||||
* @ret userptr User pointer
|
||||
*/
|
||||
static inline __always_inline userptr_t
|
||||
UACCESS_INLINE ( librm, phys_to_user ) ( unsigned long phys_addr ) {
|
||||
return ( phys_addr - virt_offset );
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert user buffer to physical address
|
||||
*
|
||||
* @v userptr User pointer
|
||||
* @v offset Offset from user pointer
|
||||
* @ret phys_addr Physical address
|
||||
*/
|
||||
static inline __always_inline unsigned long
|
||||
UACCESS_INLINE ( librm, user_to_phys ) ( userptr_t userptr, off_t offset ) {
|
||||
return ( userptr + offset + virt_offset );
|
||||
}
|
||||
|
||||
static inline __always_inline userptr_t
|
||||
UACCESS_INLINE ( librm, virt_to_user ) ( volatile const void *addr ) {
|
||||
return trivial_virt_to_user ( addr );
|
||||
}
|
||||
|
||||
static inline __always_inline void *
|
||||
UACCESS_INLINE ( librm, user_to_virt ) ( userptr_t userptr, off_t offset ) {
|
||||
return trivial_user_to_virt ( userptr, offset );
|
||||
}
|
||||
|
||||
static inline __always_inline userptr_t
|
||||
UACCESS_INLINE ( librm, userptr_add ) ( userptr_t userptr, off_t offset ) {
|
||||
return trivial_userptr_add ( userptr, offset );
|
||||
}
|
||||
|
||||
static inline __always_inline void
|
||||
UACCESS_INLINE ( librm, memcpy_user ) ( userptr_t dest, off_t dest_off,
|
||||
userptr_t src, off_t src_off,
|
||||
size_t len ) {
|
||||
trivial_memcpy_user ( dest, dest_off, src, src_off, len );
|
||||
}
|
||||
|
||||
static inline __always_inline void
|
||||
UACCESS_INLINE ( librm, memmove_user ) ( userptr_t dest, off_t dest_off,
|
||||
userptr_t src, off_t src_off,
|
||||
size_t len ) {
|
||||
trivial_memmove_user ( dest, dest_off, src, src_off, len );
|
||||
}
|
||||
|
||||
static inline __always_inline void
|
||||
UACCESS_INLINE ( librm, memset_user ) ( userptr_t buffer, off_t offset,
|
||||
int c, size_t len ) {
|
||||
trivial_memset_user ( buffer, offset, c, len );
|
||||
}
|
||||
|
||||
static inline __always_inline size_t
|
||||
UACCESS_INLINE ( librm, strlen_user ) ( userptr_t buffer, off_t offset ) {
|
||||
return trivial_strlen_user ( buffer, offset );
|
||||
}
|
||||
|
||||
static inline __always_inline off_t
|
||||
UACCESS_INLINE ( librm, memchr_user ) ( userptr_t buffer, off_t offset,
|
||||
int c, size_t len ) {
|
||||
return trivial_memchr_user ( buffer, offset, c, len );
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* Access to variables in .data16 and .text16
|
||||
*
|
||||
*/
|
||||
|
||||
extern char *data16;
|
||||
extern char *text16;
|
||||
|
||||
#define __data16( variable ) \
|
||||
__attribute__ (( section ( ".data16" ) )) \
|
||||
_data16_ ## variable __asm__ ( #variable )
|
||||
|
||||
#define __data16_array( variable, array ) \
|
||||
__attribute__ (( section ( ".data16" ) )) \
|
||||
_data16_ ## variable array __asm__ ( #variable )
|
||||
|
||||
#define __bss16( variable ) \
|
||||
__attribute__ (( section ( ".bss16" ) )) \
|
||||
_data16_ ## variable __asm__ ( #variable )
|
||||
|
||||
#define __bss16_array( variable, array ) \
|
||||
__attribute__ (( section ( ".bss16" ) )) \
|
||||
_data16_ ## variable array __asm__ ( #variable )
|
||||
|
||||
#define __text16( variable ) \
|
||||
__attribute__ (( section ( ".text16.data" ) )) \
|
||||
_text16_ ## variable __asm__ ( #variable )
|
||||
|
||||
#define __text16_array( variable, array ) \
|
||||
__attribute__ (( section ( ".text16.data" ) )) \
|
||||
_text16_ ## variable array __asm__ ( #variable )
|
||||
|
||||
#define __use_data16( variable ) \
|
||||
( * ( ( typeof ( _data16_ ## variable ) * ) \
|
||||
& ( data16 [ ( size_t ) & ( _data16_ ## variable ) ] ) ) )
|
||||
|
||||
#define __use_text16( variable ) \
|
||||
( * ( ( typeof ( _text16_ ## variable ) * ) \
|
||||
& ( text16 [ ( size_t ) & ( _text16_ ## variable ) ] ) ) )
|
||||
|
||||
#define __from_data16( pointer ) \
|
||||
( ( unsigned int ) \
|
||||
( ( ( void * ) (pointer) ) - ( ( void * ) data16 ) ) )
|
||||
|
||||
#define __from_text16( pointer ) \
|
||||
( ( unsigned int ) \
|
||||
( ( ( void * ) (pointer) ) - ( ( void * ) text16 ) ) )
|
||||
|
||||
/* Variables in librm.S, present in the normal data segment */
|
||||
extern uint16_t rm_sp;
|
||||
extern uint16_t rm_ss;
|
||||
extern uint16_t __data16 ( rm_cs );
|
||||
#define rm_cs __use_data16 ( rm_cs )
|
||||
extern uint16_t __text16 ( rm_ds );
|
||||
#define rm_ds __use_text16 ( rm_ds )
|
||||
|
||||
/**
|
||||
* Convert segment:offset address to user buffer
|
||||
*
|
||||
* @v segment Real-mode segment
|
||||
* @v offset Real-mode offset
|
||||
* @ret buffer User buffer
|
||||
*/
|
||||
static inline __always_inline userptr_t
|
||||
real_to_user ( unsigned int segment, unsigned int offset ) {
|
||||
return ( phys_to_user ( ( segment << 4 ) + offset ) );
|
||||
}
|
||||
|
||||
extern uint16_t copy_user_to_rm_stack ( userptr_t data, size_t size );
|
||||
extern void remove_user_from_rm_stack ( userptr_t data, size_t size );
|
||||
|
||||
/* TEXT16_CODE: declare a fragment of code that resides in .text16 */
|
||||
#define TEXT16_CODE( asm_code_str ) \
|
||||
".section \".text16\", \"ax\", @progbits\n\t" \
|
||||
".code16\n\t" \
|
||||
asm_code_str "\n\t" \
|
||||
".code32\n\t" \
|
||||
".previous\n\t"
|
||||
|
||||
/* REAL_CODE: declare a fragment of code that executes in real mode */
|
||||
#define REAL_CODE( asm_code_str ) \
|
||||
"pushl $1f\n\t" \
|
||||
"call real_call\n\t" \
|
||||
"addl $4, %%esp\n\t" \
|
||||
TEXT16_CODE ( "\n1:\n\t" \
|
||||
asm_code_str \
|
||||
"\n\t" \
|
||||
"ret\n\t" )
|
||||
|
||||
/* PHYS_CODE: declare a fragment of code that executes in flat physical mode */
|
||||
#define PHYS_CODE( asm_code_str ) \
|
||||
"call _virt_to_phys\n\t" \
|
||||
asm_code_str \
|
||||
"call _phys_to_virt\n\t"
|
||||
|
||||
#endif /* ASSEMBLY */
|
||||
|
||||
#endif /* LIBRM_H */
|
@@ -1,7 +1,7 @@
|
||||
#ifndef LIMITS_H
|
||||
#define LIMITS_H 1
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER );
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
/* Number of bits in a `char' */
|
||||
#define CHAR_BIT 8
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user