2
0
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:
cxhong
2020-11-09 12:33:57 -05:00
parent 7dca24aaf4
commit c9e841278f
901 changed files with 51160 additions and 139011 deletions

View File

@@ -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

View File

@@ -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

View File

@@ -1 +0,0 @@
errors.db

View File

@@ -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} ||= {};

View File

@@ -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>

View File

@@ -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");

View File

@@ -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:
//

View File

@@ -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 ); ?>
&nbsp;&nbsp;
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>

View File

@@ -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:

View File

@@ -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 ?>

View File

@@ -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" ?>&nbsp;
<?php echo "$html_title" ?>&nbsp;
</h1>
<hr>
<h2>
<? echo "$html_tagline" ?>
<?php echo "$html_tagline" ?>
</h2>
</form>
<hr>

View File

@@ -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

View File

@@ -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
View File

@@ -1,4 +0,0 @@
.toolcheck
.echocheck
TAGS*
bin*

View File

@@ -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

View File

@@ -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
#

View File

@@ -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

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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] );

View File

@@ -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 );
}
}
}

View File

@@ -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 );
}

View File

@@ -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

View File

@@ -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

View File

@@ -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();
}

View File

@@ -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

View File

@@ -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 );
}

View File

@@ -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 );

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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:

View File

@@ -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:

View File

@@ -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 */
}
}

View File

@@ -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,
};

View File

@@ -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

View File

@@ -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);
}

View File

@@ -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 );

View File

@@ -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,
};

View File

@@ -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

View File

@@ -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;
}
}

View File

@@ -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 );
}

View File

@@ -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,
};

View File

@@ -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 );

View File

@@ -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;
}

View File

@@ -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();
}

View File

@@ -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,
};

View File

@@ -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

View File

@@ -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 );
}

View File

@@ -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,
};

View File

@@ -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 );

View File

@@ -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;
}

View File

@@ -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,
},
};

View File

@@ -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;
}

View File

@@ -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,
};

View File

@@ -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,
};

View File

@@ -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,
};

View File

@@ -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,
};

View File

@@ -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,
};

View File

@@ -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,
};

View File

@@ -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,
};

View File

@@ -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 */

View File

@@ -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 */

View File

@@ -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 */

View File

@@ -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 */

View File

@@ -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 */

View File

@@ -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 */

View File

@@ -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 */

View File

@@ -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 */

View File

@@ -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 */

View File

@@ -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 */

View File

@@ -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 */

View File

@@ -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 */

View File

@@ -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 */

View File

@@ -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 */

View File

@@ -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;

View File

@@ -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 */

View File

@@ -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 */

View File

@@ -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 */

View File

@@ -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 */

View File

@@ -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 */

View File

@@ -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 */

View File

@@ -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

View File

@@ -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

View File

@@ -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 */

View File

@@ -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 */

View File

@@ -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 */

View File

@@ -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 */

View File

@@ -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 */

View File

@@ -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 */

View File

@@ -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 */

View File

@@ -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 */

View File

@@ -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 */

View File

@@ -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 */

View File

@@ -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 */

View File

@@ -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 */

View File

@@ -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 */

View File

@@ -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 */

View File

@@ -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