mirror of
https://github.com/xcat2/xcat-dep.git
synced 2025-08-18 17:20:20 +00:00
-Check in the current ipxe snapshot we are validating against. If xCAT moves to git, this would be more sane
Former-commit-id: cc8b83545788a2f0260476c9d70cf1a8171e8c6f
This commit is contained in:
339
ipxe/COPYING
Normal file
339
ipxe/COPYING
Normal file
@@ -0,0 +1,339 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
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.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU 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.
|
12
ipxe/COPYRIGHTS
Normal file
12
ipxe/COPYRIGHTS
Normal file
@@ -0,0 +1,12 @@
|
||||
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
|
8
ipxe/README
Normal file
8
ipxe/README
Normal file
@@ -0,0 +1,8 @@
|
||||
iPXE README File
|
||||
|
||||
Quick start guide:
|
||||
|
||||
cd src
|
||||
make
|
||||
|
||||
For any more detailed instructions, see http://ipxe.org
|
9
ipxe/contrib/README
Normal file
9
ipxe/contrib/README
Normal file
@@ -0,0 +1,9 @@
|
||||
Most of the content that was previously in this directory has been
|
||||
moved to a separate git repository:
|
||||
|
||||
http://git.etherboot.org/?p=contrib.git;a=summary
|
||||
|
||||
or the Etherboot Project wiki:
|
||||
|
||||
http://etherboot.org/
|
||||
|
1
ipxe/contrib/errdb/.gitignore
vendored
Normal file
1
ipxe/contrib/errdb/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
errors.db
|
108
ipxe/contrib/errdb/errdb.pl
Executable file
108
ipxe/contrib/errdb/errdb.pl
Executable file
@@ -0,0 +1,108 @@
|
||||
#!/usr/bin/perl -w
|
||||
|
||||
=head1 NAME
|
||||
|
||||
errdb.pl
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
errdb.pl [options] ../../src/bin/errors
|
||||
|
||||
Options:
|
||||
|
||||
-d,--database=db Specify path to errors.db
|
||||
-h,--help Display brief help message
|
||||
-v,--verbose Increase verbosity
|
||||
-q,--quiet Decrease verbosity
|
||||
|
||||
=cut
|
||||
|
||||
use Getopt::Long;
|
||||
use Pod::Usage;
|
||||
use DBI;
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
# Parse command-line options
|
||||
my $verbosity = 0;
|
||||
my $errdb = "errors.db";
|
||||
Getopt::Long::Configure ( 'bundling', 'auto_abbrev' );
|
||||
GetOptions (
|
||||
'database|d=s' => sub { shift; $errdb = shift; },
|
||||
'verbose|v+' => sub { $verbosity++; },
|
||||
'quiet|q+' => sub { $verbosity--; },
|
||||
'help|h' => sub { pod2usage ( 1 ); },
|
||||
) or die "Could not parse command-line options\n";
|
||||
pod2usage ( 1 ) unless @ARGV >= 1;
|
||||
|
||||
# Open database
|
||||
my $dbh = DBI->connect ( "dbi:SQLite:dbname=".$errdb, "", "",
|
||||
{ RaiseError => 1, PrintError => 0 } );
|
||||
$dbh->begin_work();
|
||||
|
||||
# Create errors table if necessary
|
||||
eval {
|
||||
$dbh->selectall_arrayref ( "SELECT * FROM errors LIMIT 1" );
|
||||
};
|
||||
if ( $@ ) {
|
||||
print "Creating errors table\n" if $verbosity >= 1;
|
||||
$dbh->do ( "CREATE TABLE errors (".
|
||||
" errno char(8) NOT NULL,".
|
||||
" description text NOT NULL,".
|
||||
" PRIMARY KEY ( errno ) )" );
|
||||
}
|
||||
|
||||
# Create xrefs table if necessary
|
||||
eval {
|
||||
$dbh->selectall_arrayref ( "SELECT * FROM xrefs LIMIT 1" );
|
||||
};
|
||||
if ( $@ ) {
|
||||
print "Creating xrefs table\n" if $verbosity >= 1;
|
||||
$dbh->do ( "CREATE TABLE xrefs (".
|
||||
" errno char(8) NOT NULL,".
|
||||
" filename text NOT NULL,".
|
||||
" line integer NOT NULL,".
|
||||
" UNIQUE ( errno, filename, line ),".
|
||||
" FOREIGN KEY ( errno ) REFERENCES errors ( errno ) )" );
|
||||
$dbh->do ( "CREATE INDEX xrefs_errno ON xrefs ( errno )" );
|
||||
}
|
||||
|
||||
# Parse input file(s)
|
||||
my $errors = {};
|
||||
my $xrefs = {};
|
||||
while ( <> ) {
|
||||
chomp;
|
||||
( my $errno, my $filename, my $line, my $description ) = split ( /\t/ );
|
||||
$errors->{$errno} = $description;
|
||||
$xrefs->{$errno} ||= {};
|
||||
$xrefs->{$errno}->{$filename} ||= {};
|
||||
$xrefs->{$errno}->{$filename}->{$line} ||= 1;
|
||||
}
|
||||
|
||||
# Ensure all errors are present in database
|
||||
my $error_update =
|
||||
$dbh->prepare ( "UPDATE errors SET description = ? WHERE errno = ?" );
|
||||
my $error_insert = $dbh->prepare ( "INSERT INTO errors VALUES ( ?, ? )" );
|
||||
while ( ( my $errno, my $description ) = each %$errors ) {
|
||||
print "Error ".$errno." is \"".$description."\"\n" if $verbosity >= 2;
|
||||
if ( $error_update->execute ( $description, $errno ) == 0 ) {
|
||||
$error_insert->execute ( $errno, $description );
|
||||
}
|
||||
}
|
||||
|
||||
# Replace xrefs in database
|
||||
$dbh->do ( "DELETE FROM xrefs" );
|
||||
my $xref_insert = $dbh->prepare ( "INSERT INTO xrefs VALUES ( ?, ?, ? )" );
|
||||
while ( ( my $errno, my $xref_errno ) = each %$xrefs ) {
|
||||
while ( ( my $filename, my $xref_filename ) = each %$xref_errno ) {
|
||||
foreach my $line ( keys %$xref_filename ) {
|
||||
print "Error ".$errno." is used at ".$filename." line ".$line."\n"
|
||||
if $verbosity >= 2;
|
||||
$xref_insert->execute ( $errno, $filename, $line );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Close database
|
||||
$dbh->commit();
|
||||
$dbh->disconnect();
|
62
ipxe/contrib/rom-o-matic/README
Normal file
62
ipxe/contrib/rom-o-matic/README
Normal file
@@ -0,0 +1,62 @@
|
||||
ROM-o-matic web interface for building iPXE ROMs
|
||||
------------------------------------------------
|
||||
|
||||
This web application generates iPXE images and sends them to a web
|
||||
browser.
|
||||
|
||||
Available as part of the iPXE source code distribution, which can be
|
||||
downlaoded from http://etherboot.org/
|
||||
|
||||
Author: Marty Connor <mdc@etherboot.org>
|
||||
License: GPLv2
|
||||
Support: http://etherboot.org/mailman/listinfo/ipxe
|
||||
Please send support questions to the iPXE mailing list
|
||||
|
||||
System Requirements
|
||||
-------------------
|
||||
- Apache web server
|
||||
- PHP 4+
|
||||
- Tools required to build iPXE installed on the server
|
||||
- gcc, mtools, syslinux, perl, etc.
|
||||
|
||||
Setup
|
||||
-----
|
||||
As distributed, it is expected that the rom-o-matic source code
|
||||
directory is in the contrib directory of a iPXE source distribution.
|
||||
|
||||
The easiest way to do this is to simply put a iPXE source distribution
|
||||
in a web server accessible directory.
|
||||
|
||||
If this is not the case, you will need to either edit the file
|
||||
|
||||
"globals.php"
|
||||
|
||||
or create a file called
|
||||
|
||||
"local-config.php"
|
||||
|
||||
containing the following lines:
|
||||
|
||||
<?php
|
||||
$src_dir = "../../src";
|
||||
?>
|
||||
|
||||
Then change the line beginning "$src_dir = " to the path of your iPXE
|
||||
source code tree.
|
||||
|
||||
To make build times shorter, before you run rom-o-matic for the first time
|
||||
you should cd to the ipxe "src" directory and enter the following
|
||||
commands:
|
||||
|
||||
$ make
|
||||
$ make bin/NIC
|
||||
|
||||
This will pro-compile most object files and will make your rom-o-matic
|
||||
builds much faster.
|
||||
|
||||
Running rom-o-matic from a web browser
|
||||
--------------------------------------
|
||||
Enter a URL like:
|
||||
|
||||
http://example.com/ipxe-1.x.x/contrib/rom-o-matic
|
||||
|
62
ipxe/contrib/rom-o-matic/bottom.php
Normal file
62
ipxe/contrib/rom-o-matic/bottom.php
Normal file
@@ -0,0 +1,62 @@
|
||||
<?
|
||||
|
||||
/**
|
||||
* Copyright (C) 2009 Marty Connor <mdc@etherboot.org>.
|
||||
* Copyright (C) 2009 Entity Cyber, Inc.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
?>
|
||||
<hr>
|
||||
<h4>
|
||||
Resources:
|
||||
</h4>
|
||||
<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>
|
||||
<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>
|
||||
<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>
|
||||
<br><br>
|
||||
</li>
|
||||
<li>
|
||||
For real-time online iPXE support via IRC please visit the
|
||||
<a href="irc://irc.freenode.net/%23etherboot"> #etherboot channel
|
||||
of irc.freenode.net</a>.
|
||||
<br><br>
|
||||
</li>
|
||||
</ul>
|
||||
<hr>
|
||||
<font size="-1">
|
||||
<br>
|
||||
Please email <a href="mailto:<? echo "${webmaster_email}" ?>"><? echo "${webmaster_email}"?></a>
|
||||
with questions or comments about this website.
|
||||
</font>
|
||||
<br><br>
|
||||
<hr>
|
||||
</body>
|
||||
</html>
|
306
ipxe/contrib/rom-o-matic/build.php
Normal file
306
ipxe/contrib/rom-o-matic/build.php
Normal file
@@ -0,0 +1,306 @@
|
||||
<?php // -*- Mode: PHP; -*-
|
||||
|
||||
/**
|
||||
* Copyright (C) 2009 Marty Connor <mdc@etherboot.org>.
|
||||
* Copyright (C) 2009 Entity Cyber, Inc.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
// Get utility functions and set globals
|
||||
require_once "utils.php";
|
||||
|
||||
// Make sure at least $A (action) was supplied
|
||||
if ( ! isset ( $_POST['A'] ) ) {
|
||||
|
||||
// Present user with form to customize build options
|
||||
require_once "customize-flags.php";
|
||||
|
||||
exit ();
|
||||
|
||||
// If user chose "Customize" option on form
|
||||
} else if ( $_POST['A'] == "Customize" ) {
|
||||
|
||||
// Present user with form to customize build options
|
||||
require_once "customize-flags.php";
|
||||
|
||||
exit ();
|
||||
|
||||
// The following conditional includes all other cases except "Get Image"
|
||||
// particularly the explicit ($A == "Start Over") case
|
||||
} else if ( $_POST['A'] != "Get Image" ) {
|
||||
|
||||
// Note that this method of redirections discards all the
|
||||
// configuration flags, which is intentional in this case.
|
||||
|
||||
$dest = curDirURL ();
|
||||
header ( "Location: $dest" );
|
||||
|
||||
// This next "echo" should normally not be seen, because
|
||||
// the "header" statement above should cause immediate
|
||||
// redirection but just in case...
|
||||
|
||||
echo "Try this link: <a href=\"$dest\">$dest</a>";
|
||||
|
||||
exit ();
|
||||
}
|
||||
|
||||
// OK, we're going to try to use whatever options have been set
|
||||
// to build an image.
|
||||
|
||||
// Make sure at least $nic was supplied
|
||||
if ( ! isset ( $_POST['nic'] ) ) {
|
||||
die ( "No NIC supplied!" );
|
||||
}
|
||||
if ( isset ( $nics[$_POST['nic']] ) ) {
|
||||
$nic = $nics[$_POST['nic']];
|
||||
} else {
|
||||
die ( "Invalid NIC \"${_POST['nic']}\" supplied!" );
|
||||
}
|
||||
|
||||
// Fetch flags
|
||||
$flags = get_flags ();
|
||||
|
||||
// Get requested format
|
||||
$ofmt = isset ( $_POST['ofmt'] ) ? $_POST['ofmt'] : "";
|
||||
$fmt_extension = isset ( $ofmts[$ofmt] ) ? $ofmts[$ofmt] : 'dsk';
|
||||
|
||||
// Handle some special cases
|
||||
|
||||
$pci_vendor_code = "";
|
||||
$pci_device_code = "";
|
||||
|
||||
if ( $nic == 'undionly' && $fmt_extension == "pxe" ) {
|
||||
|
||||
// undionly.pxe can't work because it unloads the PXE stack
|
||||
// that it needs to communicate with, so we set the extension
|
||||
// to .kpxe, which has a chance of working. The extension
|
||||
// .kkpxe is another option.
|
||||
|
||||
$fmt_extension = "kpxe";
|
||||
|
||||
} else if ( $fmt_extension == "rom" ) {
|
||||
|
||||
if ( ! isset ( $_POST['pci_vendor_code'] )
|
||||
|| ! isset ( $_POST['pci_device_code'] ) ) {
|
||||
die ( "rom output format selected but PCI code(s) missing!" );
|
||||
}
|
||||
|
||||
$pci_vendor_code = $_POST['pci_vendor_code'];
|
||||
$pci_device_code = $_POST['pci_device_code'];
|
||||
|
||||
if ( $pci_vendor_code == ""
|
||||
|| $pci_device_code == "" ) {
|
||||
die ( "rom output format selected but PCI code(s) missing!" );
|
||||
}
|
||||
|
||||
// Try to be forgiving of 0xAAAA format
|
||||
if ( strtolower ( substr ( $pci_vendor_code, 0, 2 ) ) == "0x"
|
||||
&& strlen ( $pci_vendor_code ) == 6 ) {
|
||||
$pci_vendor_code = substr ( $pci_vendor_code, 2, 4 );
|
||||
}
|
||||
if ( strtolower ( substr ( $pci_device_code, 0, 2 ) ) == "0x"
|
||||
&& strlen ( $pci_device_code ) == 6 ) {
|
||||
$pci_device_code = substr ( $pci_device_code, 2, 4 );
|
||||
}
|
||||
|
||||
// concatenate the pci codes to get the $nic part of the
|
||||
// Make target
|
||||
$pci_codes = strtolower ( $pci_vendor_code . $pci_device_code );
|
||||
|
||||
$nic = $pci_codes;
|
||||
if ( ! isset ( $roms[$pci_codes] ) ) {
|
||||
die ( "Sorry, no network driver supports PCI codes<br>"
|
||||
. "${_POST['pci_vendor_code']}:"
|
||||
. "${_POST['pci_device_code']}" );
|
||||
}
|
||||
} else if ( $fmt_extension != "rom"
|
||||
&& ( $pci_vendor_code != "" || $pci_device_code != "" ) ) {
|
||||
die ( "'$fmt_extension' format was selected but PCI IDs were"
|
||||
. " also entered.<br>Did you mean to select 'rom' output format"
|
||||
. " instead?" );
|
||||
}
|
||||
|
||||
/**
|
||||
* remove temporary build directory
|
||||
*
|
||||
* @return bool true if removal is successful, false otherwise
|
||||
*/
|
||||
function rm_build_dir ()
|
||||
{
|
||||
global $build_dir;
|
||||
global $keep_build_dir;
|
||||
|
||||
if ( $keep_build_dir !== true ) {
|
||||
rm_file_or_dir ( $build_dir );
|
||||
}
|
||||
}
|
||||
|
||||
// Arrange for the build directory to always be removed on exit.
|
||||
$build_dir = "";
|
||||
$keep_build_dir = false;
|
||||
register_shutdown_function ( 'rm_build_dir' );
|
||||
|
||||
// Make temporary copy of src directory
|
||||
$build_dir = mktempcopy ( "$src_dir", "/tmp", "MDCROM" );
|
||||
$config_dir = $build_dir . "/config";
|
||||
|
||||
// Write config files with supplied flags
|
||||
write_ipxe_config_files ( $config_dir, $flags );
|
||||
|
||||
// Handle a possible embedded script
|
||||
$emb_script_cmd = "";
|
||||
$embedded_script = isset ( $_POST['embedded_script'] ) ? $_POST['embedded_script'] : "";
|
||||
if ( $embedded_script != "" ) {
|
||||
$emb_script_path = "$build_dir" . "/script0.ipxe";
|
||||
|
||||
if ( substr ( $embedded_script, 0, 5 ) != "#!ipxe" ) {
|
||||
$embedded_script = "#!ipxe\n" . $embedded_script;
|
||||
}
|
||||
|
||||
// iPXE 0.9.7 doesn't like '\r\n" in the shebang...
|
||||
$embedded_script = str_replace ( "\r\n", "\n", $embedded_script );
|
||||
|
||||
write_file_from_string ( $emb_script_path, $embedded_script );
|
||||
$emb_script_cmd = "EMBEDDED_IMAGE=${emb_script_path}";
|
||||
}
|
||||
|
||||
// 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";
|
||||
|
||||
exec ( $make_cmd, $maketxt, $status );
|
||||
|
||||
// Uncomment the following section for debugging
|
||||
|
||||
/**
|
||||
|
||||
echo "<h2>build.php:</h2>";
|
||||
echo "<h3>Begin debugging output</h3>";
|
||||
|
||||
//echo "<h3>\$_POST variables</h3>";
|
||||
//echo "<pre>"; var_dump ( $_POST ); echo "</pre>";
|
||||
|
||||
echo "<h3>Build options:</h3>";
|
||||
echo "<strong>Build directory is:</strong> $build_dir" . "<br><br>";
|
||||
echo "\$_POST['ofmt'] = " . "\"${_POST['ofmt']}\"" . "<br>";
|
||||
echo "\$_POST['nic'] = " . "\"${_POST['nic']}\"" . "<br>";
|
||||
echo "\$_POST['pci_vendor_code'] = " . "\"${_POST['pci_vendor_code']}\"" . "<br>";
|
||||
echo "\$_POST['pci_device_code'] = " . "\"${_POST['pci_device_code']}\"" . "<br>";
|
||||
|
||||
echo "<h3>Flags:</h3>";
|
||||
show_flags ( $flags );
|
||||
|
||||
if ( $embedded_script != "" ) {
|
||||
echo "<h3>Embedded script:</h3>";
|
||||
echo "<blockquote>"."<pre>";
|
||||
echo $embedded_script;
|
||||
echo "</pre>"."</blockquote>";
|
||||
}
|
||||
|
||||
echo "<h3>Make output:</h3>";
|
||||
echo "Make command: " . $make_cmd . "<br>";
|
||||
echo "Build status = <? echo $status ?>" . "<br>";
|
||||
echo "<blockquote>"."<pre>";
|
||||
echo htmlentities ( implode ("\n", $maketxt ) );
|
||||
echo "</pre>"."</blockquote>";
|
||||
// Uncomment the next line if you want to keep the
|
||||
// build directory around for inspection after building.
|
||||
$keep_build_dir = true;
|
||||
die ( "<h3>End debugging output</h3>" );
|
||||
|
||||
**/ // End debugging section
|
||||
|
||||
// Send ROM to browser (with extreme prejudice)
|
||||
|
||||
if ( $status == 0 ) {
|
||||
|
||||
$fp = fopen("${build_dir}/${make_target}", "rb" );
|
||||
if ( $fp > 0 ) {
|
||||
|
||||
$len = filesize ( "${build_dir}/${make_target}" );
|
||||
if ( $len > 0 ) {
|
||||
|
||||
$buf = fread ( $fp, $len );
|
||||
fclose ( $fp );
|
||||
|
||||
// Delete build directory as soon as it is not needed
|
||||
rm_build_dir ();
|
||||
|
||||
$output_filename = "ipxe-${version}-${nic}.${fmt_extension}";
|
||||
|
||||
// Try to force IE to handle downloading right.
|
||||
Header ( "Cache-control: private");
|
||||
Header ( "Content-Type: application/x-octet-stream; " .
|
||||
"name=$output_filename");
|
||||
Header ( "Content-Disposition: attachment; " .
|
||||
"Filename=$output_filename");
|
||||
Header ( "Content-Location: $output_filename");
|
||||
Header ( "Content-Length: $len");
|
||||
|
||||
echo $buf;
|
||||
|
||||
exit ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If we reach this point, the build has failed, and we provide
|
||||
* debugging information for a potential bug report
|
||||
*
|
||||
*/
|
||||
|
||||
// Remove build directory
|
||||
rm_build_dir ();
|
||||
|
||||
// Announce failure if $status from make was non-zero
|
||||
echo "<h2>Build failed. Status = " . $status . "</h2>";
|
||||
echo "<h2>build.php:</h2>";
|
||||
echo "<h3>Build options:</h3>";
|
||||
echo "<strong>Build directory is:</strong> $build_dir" . "<br><br>";
|
||||
echo "\$_POST['ofmt'] = " . "\"${_POST['ofmt']}\"" . "<br>";
|
||||
echo "\$_POST['nic'] = " . "\"${_POST['nic']}\"" . "<br>";
|
||||
echo "\$_POST['pci_vendor_code'] = " . "\"${_POST['pci_vendor_code']}\"" . "<br>";
|
||||
echo "\$_POST['pci_device_code'] = " . "\"${_POST['pci_device_code']}\"" . "<br>";
|
||||
|
||||
echo "<h3>Flags:</h3>";
|
||||
show_flags ( $flags );
|
||||
|
||||
if ( $embedded_script != "" ) {
|
||||
echo "<h3>Embedded script:</h3>";
|
||||
echo "<blockquote>"."<pre>";
|
||||
echo $embedded_script;
|
||||
echo "</pre>"."</blockquote>";
|
||||
}
|
||||
|
||||
echo "<h3>Make output:</h3>";
|
||||
echo "Make command: " . $make_cmd . "<br>";
|
||||
echo "<blockquote>"."<pre>";
|
||||
echo htmlentities ( implode ("\n", $maketxt ) );
|
||||
echo "</pre>"."</blockquote>";
|
||||
|
||||
echo "Please let us know that this happened, and paste the above output into your email message.<br>";
|
||||
|
||||
include_once $bottom_inc;
|
||||
|
||||
// For emacs:
|
||||
// Local variables:
|
||||
// c-basic-offset: 4
|
||||
// c-indent-level: 4
|
||||
// tab-width: 4
|
||||
// End:
|
||||
|
||||
?>
|
69
ipxe/contrib/rom-o-matic/customize-flags.php
Normal file
69
ipxe/contrib/rom-o-matic/customize-flags.php
Normal file
@@ -0,0 +1,69 @@
|
||||
<?php // -*- Mode: PHP; -*-
|
||||
|
||||
/**
|
||||
* Copyright (C) 2009 Marty Connor <mdc@etherboot.org>.
|
||||
* Copyright (C) 2009 Entity Cyber, Inc.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
// Get utility functions and set globals
|
||||
require_once "utils.php";
|
||||
|
||||
// Prepare settable compile options for presentation to user
|
||||
$flags = default_flags ();
|
||||
|
||||
$build = "<input type=\"submit\" name=\"A\" value=\"Get Image\">";
|
||||
$restart = "<input type=\"submit\" name=\"A\" value=\"Start Over\">";
|
||||
|
||||
// Begin html output
|
||||
include_once $top_inc;
|
||||
|
||||
?>
|
||||
|
||||
<form action="build.php" method=POST>
|
||||
<input type="hidden" name="version" value = "<? 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.
|
||||
</h3>
|
||||
<hr>
|
||||
<ul>
|
||||
<? require ( "directions.php" ); ?>
|
||||
</ul>
|
||||
<hr>
|
||||
<? echo_flags( $flags ); ?>
|
||||
<hr>
|
||||
<h3>Embedded Script:</h3>
|
||||
<? 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>
|
||||
</tr></table></center>
|
||||
</form>
|
||||
|
||||
<? include_once $bottom_inc; ?>
|
||||
<?
|
||||
// For emacs:
|
||||
//
|
||||
// Local variables:
|
||||
// c-basic-offset: 4
|
||||
// c-indent-level: 4
|
||||
// tab-width: 4
|
||||
// End:
|
||||
?>
|
63
ipxe/contrib/rom-o-matic/directions.php
Normal file
63
ipxe/contrib/rom-o-matic/directions.php
Normal file
@@ -0,0 +1,63 @@
|
||||
<?
|
||||
|
||||
/**
|
||||
* Copyright (C) 2009 Marty Connor <mdc@etherboot.org>.
|
||||
* Copyright (C) 2009 Entity Cyber, Inc.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
?>
|
||||
<li>
|
||||
Choose an output format: <? echo keys_menubox ( "ofmt", $ofmts,
|
||||
isset ( $_POST['ofmt'] ) ? $_POST['ofmt'] : "") ?>
|
||||
<br><br>
|
||||
</li>
|
||||
<li>
|
||||
Choose a NIC type: <? echo keys_menubox ( "nic", $nics,
|
||||
isset ( $_POST['nic'] ) ? $_POST['nic'] : "" ) ?>
|
||||
<br><br>
|
||||
</li>
|
||||
<li>
|
||||
<strong>( optional — for binary ROM image format only )</strong> <br><br>
|
||||
If you choose <em>Binary ROM image</em> as your output format, you must<br>
|
||||
enter <strong>4 hex digits</strong> below for
|
||||
<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"
|
||||
target="_blank">here</a>.
|
||||
<br><br>
|
||||
PCI VENDOR CODE: <? echo textbox ( "pci_vendor_code",
|
||||
isset ( $_POST['pci_vendor_code'] ) ? $_POST['pci_vendor_code']
|
||||
: "", 6 ); ?>
|
||||
|
||||
PCI DEVICE CODE: <? echo textbox ( "pci_device_code",
|
||||
isset ( $_POST['pci_device_code'] ) ? $_POST['pci_device_code']
|
||||
: "", 6 ); ?>
|
||||
<h4>Please note for ROM images:</h4>
|
||||
<ul>
|
||||
<li>
|
||||
If you enter PCI IDs, we will attempt to determine the correct<br>
|
||||
driver to support them, and will ignore any NIC type entered
|
||||
above.<br><br>
|
||||
</li>
|
||||
<li>
|
||||
iPXE does not support all possible PCI IDs for supported
|
||||
NICs.
|
||||
<br><br>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
1
ipxe/contrib/rom-o-matic/doc/AUTOBOOT_CMD.html
Normal file
1
ipxe/contrib/rom-o-matic/doc/AUTOBOOT_CMD.html
Normal file
@@ -0,0 +1 @@
|
||||
Automatic booting
|
1
ipxe/contrib/rom-o-matic/doc/BANNER_TIMEOUT.html
Normal file
1
ipxe/contrib/rom-o-matic/doc/BANNER_TIMEOUT.html
Normal file
@@ -0,0 +1 @@
|
||||
Tenths of a second for which the shell banner should appear
|
3
ipxe/contrib/rom-o-matic/doc/COMCONSOLE.html
Normal file
3
ipxe/contrib/rom-o-matic/doc/COMCONSOLE.html
Normal file
@@ -0,0 +1,3 @@
|
||||
Serial Console I/O port address. Common addresses are:<br>
|
||||
COM1 => 0x3f8, COM2 => 0x2f8, COM3 => 0x3e8, COM4 => 0x2e8
|
||||
|
1
ipxe/contrib/rom-o-matic/doc/COMDATA.html
Normal file
1
ipxe/contrib/rom-o-matic/doc/COMDATA.html
Normal file
@@ -0,0 +1 @@
|
||||
Serial Console Data bits
|
1
ipxe/contrib/rom-o-matic/doc/COMPARITY.html
Normal file
1
ipxe/contrib/rom-o-matic/doc/COMPARITY.html
Normal file
@@ -0,0 +1 @@
|
||||
Serial Console Parity: 0=None, 1=Odd, 2=Even
|
1
ipxe/contrib/rom-o-matic/doc/COMPRESERVE.html
Normal file
1
ipxe/contrib/rom-o-matic/doc/COMPRESERVE.html
Normal file
@@ -0,0 +1 @@
|
||||
Keep settings from a previous user of the serial port
|
1
ipxe/contrib/rom-o-matic/doc/COMSPEED.html
Normal file
1
ipxe/contrib/rom-o-matic/doc/COMSPEED.html
Normal file
@@ -0,0 +1 @@
|
||||
Serial Console Baud rate
|
1
ipxe/contrib/rom-o-matic/doc/COMSTOP.html
Normal file
1
ipxe/contrib/rom-o-matic/doc/COMSTOP.html
Normal file
@@ -0,0 +1 @@
|
||||
Serial Console Stop bits
|
1
ipxe/contrib/rom-o-matic/doc/CONFIG_CMD.html
Normal file
1
ipxe/contrib/rom-o-matic/doc/CONFIG_CMD.html
Normal file
@@ -0,0 +1 @@
|
||||
Option configuration console
|
1
ipxe/contrib/rom-o-matic/doc/CONSOLE_PC_BIOS.html
Normal file
1
ipxe/contrib/rom-o-matic/doc/CONSOLE_PC_BIOS.html
Normal file
@@ -0,0 +1 @@
|
||||
Enable Default BIOS console
|
1
ipxe/contrib/rom-o-matic/doc/CONSOLE_SERIAL.html
Normal file
1
ipxe/contrib/rom-o-matic/doc/CONSOLE_SERIAL.html
Normal file
@@ -0,0 +1 @@
|
||||
Enable Serial port console
|
1
ipxe/contrib/rom-o-matic/doc/CRYPTO_80211_WEP.html
Normal file
1
ipxe/contrib/rom-o-matic/doc/CRYPTO_80211_WEP.html
Normal file
@@ -0,0 +1 @@
|
||||
Wireless WEP encryption support
|
1
ipxe/contrib/rom-o-matic/doc/CRYPTO_80211_WPA.html
Normal file
1
ipxe/contrib/rom-o-matic/doc/CRYPTO_80211_WPA.html
Normal file
@@ -0,0 +1 @@
|
||||
Wireless WPA encryption support
|
1
ipxe/contrib/rom-o-matic/doc/CRYPTO_80211_WPA2.html
Normal file
1
ipxe/contrib/rom-o-matic/doc/CRYPTO_80211_WPA2.html
Normal file
@@ -0,0 +1 @@
|
||||
Wireless WPA2 encryption support
|
1
ipxe/contrib/rom-o-matic/doc/DHCP_CMD.html
Normal file
1
ipxe/contrib/rom-o-matic/doc/DHCP_CMD.html
Normal file
@@ -0,0 +1 @@
|
||||
DHCP management commands
|
1
ipxe/contrib/rom-o-matic/doc/DNS_RESOLVER.html
Normal file
1
ipxe/contrib/rom-o-matic/doc/DNS_RESOLVER.html
Normal file
@@ -0,0 +1 @@
|
||||
DNS resolver
|
1
ipxe/contrib/rom-o-matic/doc/DOWNLOAD_PROTO_FTP.html
Normal file
1
ipxe/contrib/rom-o-matic/doc/DOWNLOAD_PROTO_FTP.html
Normal file
@@ -0,0 +1 @@
|
||||
File Transfer Protocol
|
1
ipxe/contrib/rom-o-matic/doc/DOWNLOAD_PROTO_HTTP.html
Normal file
1
ipxe/contrib/rom-o-matic/doc/DOWNLOAD_PROTO_HTTP.html
Normal file
@@ -0,0 +1 @@
|
||||
Hypertext Transfer Protocol
|
1
ipxe/contrib/rom-o-matic/doc/DOWNLOAD_PROTO_TFTP.html
Normal file
1
ipxe/contrib/rom-o-matic/doc/DOWNLOAD_PROTO_TFTP.html
Normal file
@@ -0,0 +1 @@
|
||||
Trivial File Transfer Protocol
|
1
ipxe/contrib/rom-o-matic/doc/IFMGMT_CMD.html
Normal file
1
ipxe/contrib/rom-o-matic/doc/IFMGMT_CMD.html
Normal file
@@ -0,0 +1 @@
|
||||
Interface management commands
|
1
ipxe/contrib/rom-o-matic/doc/IMAGE_BZIMAGE.html
Normal file
1
ipxe/contrib/rom-o-matic/doc/IMAGE_BZIMAGE.html
Normal file
@@ -0,0 +1 @@
|
||||
Linux bzImage image support
|
1
ipxe/contrib/rom-o-matic/doc/IMAGE_CMD.html
Normal file
1
ipxe/contrib/rom-o-matic/doc/IMAGE_CMD.html
Normal file
@@ -0,0 +1 @@
|
||||
Image management commands
|
1
ipxe/contrib/rom-o-matic/doc/IMAGE_ELF.html
Normal file
1
ipxe/contrib/rom-o-matic/doc/IMAGE_ELF.html
Normal file
@@ -0,0 +1 @@
|
||||
ELF image support
|
1
ipxe/contrib/rom-o-matic/doc/IMAGE_MULTIBOOT.html
Normal file
1
ipxe/contrib/rom-o-matic/doc/IMAGE_MULTIBOOT.html
Normal file
@@ -0,0 +1 @@
|
||||
MultiBoot image support
|
1
ipxe/contrib/rom-o-matic/doc/IMAGE_NBI.html
Normal file
1
ipxe/contrib/rom-o-matic/doc/IMAGE_NBI.html
Normal file
@@ -0,0 +1 @@
|
||||
NBI image support
|
1
ipxe/contrib/rom-o-matic/doc/IMAGE_PXE.html
Normal file
1
ipxe/contrib/rom-o-matic/doc/IMAGE_PXE.html
Normal file
@@ -0,0 +1 @@
|
||||
PXE image support
|
1
ipxe/contrib/rom-o-matic/doc/IMAGE_SCRIPT.html
Normal file
1
ipxe/contrib/rom-o-matic/doc/IMAGE_SCRIPT.html
Normal file
@@ -0,0 +1 @@
|
||||
iPXE script image support
|
1
ipxe/contrib/rom-o-matic/doc/IWMGMT_CMD.html
Normal file
1
ipxe/contrib/rom-o-matic/doc/IWMGMT_CMD.html
Normal file
@@ -0,0 +1 @@
|
||||
Wireless interface management commands
|
1
ipxe/contrib/rom-o-matic/doc/NMB_RESOLVER.html
Normal file
1
ipxe/contrib/rom-o-matic/doc/NMB_RESOLVER.html
Normal file
@@ -0,0 +1 @@
|
||||
NMB resolver
|
1
ipxe/contrib/rom-o-matic/doc/NVO_CMD.html
Normal file
1
ipxe/contrib/rom-o-matic/doc/NVO_CMD.html
Normal file
@@ -0,0 +1 @@
|
||||
Non-volatile option storage commands
|
1
ipxe/contrib/rom-o-matic/doc/ROUTE_CMD.html
Normal file
1
ipxe/contrib/rom-o-matic/doc/ROUTE_CMD.html
Normal file
@@ -0,0 +1 @@
|
||||
Routing table management commands
|
1
ipxe/contrib/rom-o-matic/doc/SANBOOT_CMD.html
Normal file
1
ipxe/contrib/rom-o-matic/doc/SANBOOT_CMD.html
Normal file
@@ -0,0 +1 @@
|
||||
SAN boot commands
|
499
ipxe/contrib/rom-o-matic/flag-table.php
Normal file
499
ipxe/contrib/rom-o-matic/flag-table.php
Normal file
@@ -0,0 +1,499 @@
|
||||
<?php // -*- Mode: PHP; -*-
|
||||
|
||||
/**
|
||||
* Copyright (C) 2009 Marty Connor <mdc@etherboot.org>.
|
||||
* Copyright (C) 2009 Entity Cyber, Inc.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
$ofmts = array
|
||||
( "Floppy bootable image (.dsk)" => "dsk",
|
||||
"SYSLINUX-based bootable floppy image (.sdsk)" => "sdsk",
|
||||
"ISO bootable image (.iso)" => "iso",
|
||||
"ISO bootable image with legacy floppy emulation (.liso)" => "liso",
|
||||
"Linux kernel (SYSLINUX/GRUB/LILO) loadable image (.lkrn)" => "lkrn",
|
||||
"USB Keychain disk image (.usb)" => "usb",
|
||||
"ROM binary (flashable) image (.rom)" => "rom",
|
||||
"ROM binary (flashable) for problem PMM BIOSES (.hrom)" => "hrom",
|
||||
"PXE bootstrap loader image [Unload PXE stack] (.pxe)" => "pxe",
|
||||
"PXE bootstrap loader keep [Keep PXE stack method 1] (.kpxe)" => "kpxe",
|
||||
"PXE bootstrap loader keep [Keep PXE stack method 2] (.kkpxe)" => "kkpxe",
|
||||
);
|
||||
|
||||
$flag_table = array (
|
||||
|
||||
// Begin General Options:
|
||||
|
||||
"HDR_MISC_OPTIONS"
|
||||
=> array (
|
||||
"flag" => "HDR_MISC_OPTIONS",
|
||||
"hide_from_user" => "yes", // Hide even the header
|
||||
"type" => "header",
|
||||
"label" => "Miscellaneous Options"
|
||||
),
|
||||
|
||||
"PRODUCT_NAME"
|
||||
=> array (
|
||||
"flag" => "PRODUCT_NAME",
|
||||
"hide_from_user" => "yes",
|
||||
"type" => "string",
|
||||
"value" => "",
|
||||
"cfgsec" => "general"
|
||||
),
|
||||
|
||||
"PRODUCT_SHORT_NAME"
|
||||
=> array (
|
||||
"flag" => "PRODUCT_SHORT_NAME",
|
||||
"hide_from_user" => "yes",
|
||||
"type" => "string",
|
||||
"value" => "iPXE",
|
||||
"cfgsec" => "general"
|
||||
),
|
||||
|
||||
// End General Options:
|
||||
|
||||
// Begin Console Options:
|
||||
|
||||
"HDR_CONSOLE_OPTIONS"
|
||||
=> array (
|
||||
"flag" => "HDR_CONSOLE_OPTIONS",
|
||||
"type" => "header",
|
||||
"label" => "Console Options"
|
||||
),
|
||||
|
||||
"CONSOLE_PCBIOS"
|
||||
=> array (
|
||||
"flag" => "CONSOLE_PCBIOS",
|
||||
"type" => "on/off",
|
||||
"value" => "on",
|
||||
"cfgsec" => "console"
|
||||
),
|
||||
|
||||
"CONSOLE_SERIAL"
|
||||
=> array (
|
||||
"flag" => "CONSOLE_SERIAL",
|
||||
"type" => "on/off",
|
||||
"value" => "off",
|
||||
"cfgsec" => "console"
|
||||
),
|
||||
|
||||
"BANNER_TIMEOUT"
|
||||
=> array (
|
||||
"flag" => "BANNER_TIMEOUT",
|
||||
"type" => "integer",
|
||||
"value" => "20",
|
||||
"cfgsec" => "general"
|
||||
),
|
||||
|
||||
// End Console Options
|
||||
|
||||
// Begin Network Protocol Options:
|
||||
|
||||
"HDR_NETWORK_PROTOCOL_OPTIONS"
|
||||
=> array (
|
||||
"flag" => "HDR_NETWORK_PROTOCOL_OPTIONS",
|
||||
"hide_from_user" => "yes", // Hide even the header
|
||||
"type" => "header",
|
||||
"label" => "Network Protocol Options"
|
||||
),
|
||||
|
||||
"NET_PROTO_IPV4"
|
||||
=> array (
|
||||
"flag" => "NET_PROTO_IPV4",
|
||||
"type" => "on/off",
|
||||
"value" => "on",
|
||||
"hide_from_user" => "yes",
|
||||
"cfgsec" => "general"
|
||||
),
|
||||
|
||||
// End Network Protocol Options
|
||||
|
||||
// Begin Serial Port configuration
|
||||
|
||||
"HDR_SERIAL_PORT_OPTIONS"
|
||||
=> array (
|
||||
"flag" => "HDR_SERIAL_PORT_OPTIONS",
|
||||
"type" => "header",
|
||||
"label" => "Serial Port Options"
|
||||
),
|
||||
|
||||
"COMCONSOLE"
|
||||
=> array (
|
||||
"flag" => "COMCONSOLE",
|
||||
"type" => "integer-hex", // e.g. 0x378
|
||||
"value" => "0x3F8",
|
||||
"cfgsec" => "serial"
|
||||
),
|
||||
|
||||
"COMPRESERVE"
|
||||
=> array (
|
||||
"flag" => "COMPRESERVE",
|
||||
"type" => "on/off",
|
||||
"value" => "off",
|
||||
"cfgsec" => "serial"
|
||||
),
|
||||
|
||||
"COMSPEED"
|
||||
=> array (
|
||||
"flag" => "COMSPEED",
|
||||
"type" => "integer",
|
||||
"value" => "115200",
|
||||
"cfgsec" => "serial"
|
||||
),
|
||||
|
||||
"COMDATA"
|
||||
=> array (
|
||||
"flag" => "COMDATA",
|
||||
"type" => "integer",
|
||||
"value" => "8",
|
||||
"cfgsec" => "serial"
|
||||
),
|
||||
|
||||
"COMPARITY"
|
||||
=> array (
|
||||
"flag" => "COMPARITY",
|
||||
"type" => "integer",
|
||||
"value" => "0",
|
||||
"cfgsec" => "serial"
|
||||
),
|
||||
|
||||
"COMSTOP"
|
||||
=> array (
|
||||
"flag" => "COMSTOP",
|
||||
"type" => "integer",
|
||||
"value" => "1",
|
||||
"cfgsec" => "serial"
|
||||
),
|
||||
|
||||
// End Serial Options
|
||||
|
||||
// Begin Download Protocols
|
||||
|
||||
"HDR_DOWNLOAD_PROTOCOLS"
|
||||
=> array (
|
||||
"flag" => "HDR_DOWNLOAD_PROTOCOLS",
|
||||
"type" => "header",
|
||||
"label" => "Download Protocols"
|
||||
),
|
||||
|
||||
"DOWNLOAD_PROTO_TFTP"
|
||||
=> array (
|
||||
"flag" => "DOWNLOAD_PROTO_TFTP",
|
||||
"type" => "on/off",
|
||||
"value" => "on",
|
||||
"cfgsec" => "general"
|
||||
),
|
||||
|
||||
"DOWNLOAD_PROTO_HTTP"
|
||||
=> array (
|
||||
"flag" => "DOWNLOAD_PROTO_HTTP",
|
||||
"type" => "on/off",
|
||||
"value" => "on",
|
||||
"cfgsec" => "general"
|
||||
),
|
||||
|
||||
"DOWNLOAD_PROTO_HTTPS"
|
||||
=> array (
|
||||
"flag" => "DOWNLOAD_PROTO_HTTPS",
|
||||
"type" => "on/off",
|
||||
"value" => "off",
|
||||
"cfgsec" => "general"
|
||||
),
|
||||
|
||||
"DOWNLOAD_PROTO_FTP"
|
||||
=> array (
|
||||
"flag" => "DOWNLOAD_PROTO_FTP",
|
||||
"type" => "on/off",
|
||||
"value" => "off",
|
||||
"cfgsec" => "general"
|
||||
),
|
||||
|
||||
// End Download Protocols
|
||||
|
||||
// Begin SAN boot protocols
|
||||
|
||||
"HDR_SANBOOT_PROTOCOLS"
|
||||
=> array (
|
||||
"flag" => "HDR_SANBOOT_PROTOCOLS",
|
||||
"type" => "header",
|
||||
"label" => "SAN Boot Protocols"
|
||||
),
|
||||
|
||||
"SANBOOT_PROTO_ISCSI"
|
||||
=> array (
|
||||
"flag" => "SANBOOT_PROTO_ISCSI",
|
||||
"type" => "on/off",
|
||||
"value" => "on",
|
||||
"cfgsec" => "general"
|
||||
),
|
||||
|
||||
"SANBOOT_PROTO_AOE"
|
||||
=> array (
|
||||
"flag" => "SANBOOT_PROTO_AOE",
|
||||
"type" => "on/off",
|
||||
"value" => "on",
|
||||
"cfgsec" => "general"
|
||||
),
|
||||
|
||||
// End SAN boot protocols
|
||||
|
||||
// Begin Name resolution modules
|
||||
|
||||
"HDR_NAME_RESOLUTION_MODULES"
|
||||
=> array (
|
||||
"flag" => "HDR_NAME_RESOLUTION_MODULES",
|
||||
"type" => "header",
|
||||
"label" => "Name Resolution Modules"
|
||||
),
|
||||
|
||||
"DNS_RESOLVER"
|
||||
=> array (
|
||||
"flag" => "DNS_RESOLVER",
|
||||
"type" => "on/off",
|
||||
"value" => "on",
|
||||
"cfgsec" => "general"
|
||||
),
|
||||
|
||||
"NMB_RESOLVER"
|
||||
=> array (
|
||||
"flag" => "NMB_RESOLVER",
|
||||
"type" => "on/off",
|
||||
"value" => "off",
|
||||
"hide_from_user" => "yes",
|
||||
"cfgsec" => "general"
|
||||
),
|
||||
|
||||
// End Name resolution modules
|
||||
|
||||
// Begin Image types
|
||||
|
||||
"HDR_IMAGE_TYPES"
|
||||
=> array (
|
||||
"flag" => "HDR_IMAGE_TYPES",
|
||||
"type" => "header",
|
||||
"label" => "Image Types",
|
||||
),
|
||||
|
||||
"IMAGE_ELF"
|
||||
=> array (
|
||||
"flag" => "IMAGE_ELF",
|
||||
"type" => "on/off",
|
||||
"value" => "on",
|
||||
"cfgsec" => "general"
|
||||
),
|
||||
|
||||
"IMAGE_NBI"
|
||||
=> array (
|
||||
"flag" => "IMAGE_NBI",
|
||||
"type" => "on/off",
|
||||
"value" => "on",
|
||||
"cfgsec" => "general"
|
||||
),
|
||||
|
||||
"IMAGE_MULTIBOOT"
|
||||
=> array (
|
||||
"flag" => "IMAGE_MULTIBOOT",
|
||||
"type" => "on/off",
|
||||
"value" => "on",
|
||||
"cfgsec" => "general"
|
||||
),
|
||||
|
||||
"IMAGE_PXE"
|
||||
=> array (
|
||||
"flag" => "IMAGE_PXE",
|
||||
"type" => "on/off",
|
||||
"value" => "on",
|
||||
"cfgsec" => "general"
|
||||
),
|
||||
|
||||
"IMAGE_SCRIPT"
|
||||
=> array (
|
||||
"flag" => "IMAGE_SCRIPT",
|
||||
"type" => "on/off",
|
||||
"value" => "on",
|
||||
"cfgsec" => "general"
|
||||
),
|
||||
|
||||
"IMAGE_BZIMAGE"
|
||||
=> array (
|
||||
"flag" => "IMAGE_BZIMAGE",
|
||||
"type" => "on/off",
|
||||
"value" => "on",
|
||||
"cfgsec" => "general"
|
||||
),
|
||||
|
||||
"IMAGE_COMBOOT"
|
||||
=> array (
|
||||
"flag" => "IMAGE_COMBOOT",
|
||||
"type" => "on/off",
|
||||
"value" => "on",
|
||||
"cfgsec" => "general"
|
||||
),
|
||||
|
||||
// End Image types
|
||||
|
||||
// Begin Command-line commands to include
|
||||
|
||||
"HDR_COMMAND_LINE_OPTIONS"
|
||||
=> array (
|
||||
"flag" => "HDR_COMMAND_LINE_OPTIONS",
|
||||
"type" => "header",
|
||||
"label" => "Command Line Options",
|
||||
),
|
||||
|
||||
"AUTOBOOT_CMD"
|
||||
=> array (
|
||||
"flag" => "AUTOBOOT_CMD",
|
||||
"type" => "on/off",
|
||||
"value" => "on",
|
||||
"cfgsec" => "general"
|
||||
),
|
||||
|
||||
"NVO_CMD"
|
||||
=> array (
|
||||
"flag" => "NVO_CMD",
|
||||
"type" => "on/off",
|
||||
"value" => "on",
|
||||
"cfgsec" => "general"
|
||||
),
|
||||
|
||||
"CONFIG_CMD"
|
||||
=> array (
|
||||
"flag" => "CONFIG_CMD",
|
||||
"type" => "on/off",
|
||||
"value" => "on",
|
||||
"cfgsec" => "general"
|
||||
),
|
||||
|
||||
"IFMGMT_CMD"
|
||||
=> array (
|
||||
"flag" => "IFMGMT_CMD",
|
||||
"type" => "on/off",
|
||||
"value" => "on",
|
||||
"cfgsec" => "general"
|
||||
),
|
||||
|
||||
"IWMGMT_CMD"
|
||||
=> array (
|
||||
"flag" => "IWMGMT_CMD",
|
||||
"type" => "on/off",
|
||||
"value" => "on",
|
||||
"cfgsec" => "general"
|
||||
),
|
||||
|
||||
"ROUTE_CMD"
|
||||
=> array (
|
||||
"flag" => "ROUTE_CMD",
|
||||
"type" => "on/off",
|
||||
"value" => "on",
|
||||
"cfgsec" => "general"
|
||||
),
|
||||
|
||||
"IMAGE_CMD"
|
||||
=> array (
|
||||
"flag" => "IMAGE_CMD",
|
||||
"type" => "on/off",
|
||||
"value" => "on",
|
||||
"cfgsec" => "general"
|
||||
),
|
||||
|
||||
"DHCP_CMD"
|
||||
=> array (
|
||||
"flag" => "DHCP_CMD",
|
||||
"type" => "on/off",
|
||||
"value" => "on",
|
||||
"cfgsec" => "general"
|
||||
),
|
||||
|
||||
"SANBOOT_CMD"
|
||||
=> array (
|
||||
"flag" => "SANBOOT_CMD",
|
||||
"type" => "on/off",
|
||||
"value" => "on",
|
||||
"cfgsec" => "general"
|
||||
),
|
||||
|
||||
"LOGIN_CMD"
|
||||
=> array (
|
||||
"flag" => "LOGIN_CMD",
|
||||
"type" => "on/off",
|
||||
"value" => "on",
|
||||
"cfgsec" => "general"
|
||||
),
|
||||
|
||||
"TIME_CMD"
|
||||
=> array (
|
||||
"flag" => "TIME_CMD",
|
||||
"type" => "on/off",
|
||||
"value" => "off",
|
||||
"cfgsec" => "general"
|
||||
),
|
||||
|
||||
"DIGEST_CMD"
|
||||
=> array (
|
||||
"flag" => "DIGEST_CMD",
|
||||
"type" => "on/off",
|
||||
"value" => "off",
|
||||
"cfgsec" => "general"
|
||||
),
|
||||
|
||||
// End Command-line commands to include
|
||||
|
||||
// Begin Wireless options
|
||||
|
||||
"HDR_WIRELESS_OPTIONS"
|
||||
=> array (
|
||||
"flag" => "HDR_WIRELESS_OPTIONS",
|
||||
"type" => "header",
|
||||
"label" => "Wireless Interface Options",
|
||||
),
|
||||
|
||||
"CRYPTO_80211_WEP"
|
||||
=> array (
|
||||
"flag" => "CRYPTO_80211_WEP",
|
||||
"type" => "on/off",
|
||||
"value" => "on",
|
||||
"cfgsec" => "general"
|
||||
),
|
||||
|
||||
"CRYPTO_80211_WPA"
|
||||
=> array (
|
||||
"flag" => "CRYPTO_80211_WPA",
|
||||
"type" => "on/off",
|
||||
"value" => "on",
|
||||
"cfgsec" => "general"
|
||||
),
|
||||
|
||||
"CRYPTO_80211_WPA2"
|
||||
=> array (
|
||||
"flag" => "CRYPTO_80211_WPA2",
|
||||
"type" => "on/off",
|
||||
"value" => "on",
|
||||
"cfgsec" => "general"
|
||||
),
|
||||
|
||||
// End Wireless options
|
||||
|
||||
);
|
||||
|
||||
// For emacs:
|
||||
// Local variables:
|
||||
// c-basic-offset: 4
|
||||
// c-indent-level: 4
|
||||
// tab-width: 4
|
||||
// End:
|
||||
|
||||
?>
|
51
ipxe/contrib/rom-o-matic/globals.php
Normal file
51
ipxe/contrib/rom-o-matic/globals.php
Normal file
@@ -0,0 +1,51 @@
|
||||
<?php // -*- Mode: PHP; -*-
|
||||
|
||||
/**
|
||||
* Copyright (C) 2009 Marty Connor <mdc@etherboot.org>.
|
||||
* Copyright (C) 2009 Entity Cyber, Inc.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
// Directory containing iPXE source code tree
|
||||
$src_dir = "../../src";
|
||||
|
||||
// Compute iPXE version based on source tree
|
||||
exec ( "make -C '$src_dir' version 2>&1", $make_output, $status );
|
||||
$version = ( $status == 0 && count ( $make_output ) > 1 )
|
||||
? trim ( $make_output[count ( $make_output ) - 2] )
|
||||
: "";
|
||||
|
||||
// Email address of person responsible for this website
|
||||
$webmaster_email = "webmaster@example.com";
|
||||
|
||||
// Files that header and footer text
|
||||
$top_inc = "top.php";
|
||||
$bottom_inc = "bottom.php";
|
||||
|
||||
// Descriptive strings
|
||||
$header_title = "ROM-o-matic for iPXE $version";
|
||||
$html_tagline = "ROM-o-matic dynamically generates iPXE images";
|
||||
$html_title = "ROM-o-matic for iPXE $version";
|
||||
$description = "a dynamic iPXE image generator";
|
||||
|
||||
// For emacs:
|
||||
// Local variables:
|
||||
// c-basic-offset: 4
|
||||
// c-indent-level: 4
|
||||
// tab-width: 4
|
||||
// End:
|
||||
|
||||
?>
|
47
ipxe/contrib/rom-o-matic/index.php
Normal file
47
ipxe/contrib/rom-o-matic/index.php
Normal file
@@ -0,0 +1,47 @@
|
||||
<?php // -*- Mode: PHP; -*-
|
||||
|
||||
/**
|
||||
* Copyright (C) 2009 Marty Connor <mdc@etherboot.org>.
|
||||
* Copyright (C) 2009 Entity Cyber, Inc.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
// Get utility functions and set globals
|
||||
require_once "utils.php";
|
||||
|
||||
// Begin html output
|
||||
include_once $top_inc;
|
||||
|
||||
?>
|
||||
<form action="build.php" method=POST>
|
||||
<input type="hidden" name="version" value = "<? echo $version ?>">
|
||||
<h3>To create an image:</h3>
|
||||
<ol>
|
||||
<? require ( "directions.php" ); ?>
|
||||
<li>
|
||||
Generate and download an image:
|
||||
<input type="submit" name="A" value="Get Image">
|
||||
<br><br>
|
||||
</li>
|
||||
<li>
|
||||
(optional) Customize image configuration options:
|
||||
<input type="submit" name="A" value="Customize">
|
||||
<br><br>
|
||||
</li>
|
||||
</ol>
|
||||
</form>
|
||||
|
||||
<? include_once $bottom_inc ?>
|
41
ipxe/contrib/rom-o-matic/top.php
Normal file
41
ipxe/contrib/rom-o-matic/top.php
Normal file
@@ -0,0 +1,41 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||
|
||||
<?
|
||||
|
||||
/**
|
||||
* Copyright (C) 2009 Marty Connor <mdc@etherboot.org>.
|
||||
* Copyright (C) 2009 Entity Cyber, Inc.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
?>
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<link rev="made" href="mailto:<? 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 ?>">
|
||||
</head>
|
||||
<h1>
|
||||
<? echo "$html_title" ?>
|
||||
</h1>
|
||||
<hr>
|
||||
<h2>
|
||||
<? echo "$html_tagline" ?>
|
||||
</h2>
|
||||
</form>
|
||||
<hr>
|
683
ipxe/contrib/rom-o-matic/utils.php
Normal file
683
ipxe/contrib/rom-o-matic/utils.php
Normal file
@@ -0,0 +1,683 @@
|
||||
<? // -*- Mode: PHP; -*-
|
||||
|
||||
/**
|
||||
* Copyright (C) 2009 Marty Connor <mdc@etherboot.org>.
|
||||
* Copyright (C) 2009 Entity Cyber, Inc.
|
||||
*
|
||||
* 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 table of user-configurable iPXE options
|
||||
require_once "flag-table.php";
|
||||
|
||||
// Include user-shadowable globals
|
||||
require_once "globals.php";
|
||||
|
||||
// Allow user to shadow globals
|
||||
if ( is_file ( 'local-config.php' ) ) {
|
||||
include_once "local-config.php";
|
||||
}
|
||||
|
||||
////
|
||||
// General utility functions
|
||||
////
|
||||
|
||||
/**
|
||||
* Remove undesirable characters from a given string
|
||||
*
|
||||
* Certain characters have the potential to be used for
|
||||
* malicious purposes by web-based attackers. This routine
|
||||
* filters out such characters.
|
||||
*
|
||||
* @param string $s supplied string
|
||||
*
|
||||
* @return string returned string with unwanted characters
|
||||
* removed
|
||||
*/
|
||||
function cleanstring ( $s )
|
||||
{
|
||||
$len = strlen ( $s );
|
||||
if ( $len > 80 ) {
|
||||
$s = substr ( $s, 0, 80 );
|
||||
}
|
||||
|
||||
$s = trim ( $s );
|
||||
$pos = 0;
|
||||
$result = "";
|
||||
|
||||
while ( $pos < $len ) {
|
||||
$ltr = ord ( ucfirst ( $s[$pos] ) );
|
||||
if ( ( $ltr >= ord ( "A" ) ) && ( $ltr <= ord ( "Z" ) ) ||
|
||||
( $ltr >= ord ( "0" ) ) && ( $ltr <= ord ( "9" ) ) ||
|
||||
( $ltr == ord ( "." ) ) && ( strlen ( $result ) > 0 ) ||
|
||||
( $ltr == ord ( "_" ) ) ||
|
||||
( $ltr == ord ( "+" ) ) ||
|
||||
( $ltr == ord ( ":" ) ) ||
|
||||
( $ltr == ord ( "/" ) ) ||
|
||||
( $ltr == ord ( "-" ) ) ) {
|
||||
$result .= $s[$pos];
|
||||
}
|
||||
$pos++;
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return URL of the currently running script, minus the filename
|
||||
*
|
||||
* @return string the URL of the currently running script, minus the filename
|
||||
*/
|
||||
function curDirURL ()
|
||||
{
|
||||
$dir = dirname ( $_SERVER['PHP_SELF'] );
|
||||
|
||||
if ( $dir == "." || $dir == "/" ) {
|
||||
$dir = "";
|
||||
}
|
||||
|
||||
$isHTTPS = ( isset ( $_SERVER["HTTPS"] ) && $_SERVER["HTTPS"] == "on" );
|
||||
$port = ( isset($_SERVER["SERVER_PORT"] ) &&
|
||||
( ( !$isHTTPS && $_SERVER["SERVER_PORT"] != "80" ) ||
|
||||
( $isHTTPS && $_SERVER["SERVER_PORT"] != "443" ) ) );
|
||||
|
||||
$port = ( $port ) ? ':' . $_SERVER["SERVER_PORT"] : '';
|
||||
|
||||
$dest = ( $isHTTPS ? 'https://' : 'http://' ) .
|
||||
$_SERVER["SERVER_NAME"] . $dir . "/";
|
||||
|
||||
return $dest;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract NIC families and associated ROM PCI IDs from the src/bin/NIC file.
|
||||
*
|
||||
* $src_dir must contain the path of the iPXE src directory for this build
|
||||
*
|
||||
* @return array[0] array $new_nics
|
||||
* @return array[1] array $roms
|
||||
*/
|
||||
function parse_nic_file ()
|
||||
{
|
||||
global $src_dir;
|
||||
|
||||
$fd = fopen ( "$src_dir/bin/NIC", "r" );
|
||||
if ( ! $fd ) {
|
||||
die ( "Missing src/bin/NIC file. 'make bin/NIC'" );
|
||||
}
|
||||
|
||||
$nics = array ();
|
||||
$roms = array ();
|
||||
$nic = "";
|
||||
|
||||
while ( !feof ( $fd ) ) {
|
||||
|
||||
$line = trim ( fgets ( $fd, 200 ) );
|
||||
|
||||
$first_eight_chars = substr ( $line, 0, 8 );
|
||||
settype ( $first_eight_chars, "string" );
|
||||
|
||||
if ( strpos ( $first_eight_chars, "family" ) === 0 ) {
|
||||
|
||||
// get pathname of NIC driver
|
||||
list ( $dummy, $nic ) = split( "[ \t]+", $line );
|
||||
settype ( $nic, "string" );
|
||||
|
||||
// extract filename name of driver from pathname
|
||||
$nic = substr ( $nic, strrpos ( $nic, "/" ) + 1,
|
||||
strlen ( $nic ) - strrpos ( $nic, "/" ) + 1 );
|
||||
|
||||
$nics[$nic] = $nic;
|
||||
|
||||
// For each ISA NIC, there can only be one ROM variant
|
||||
$roms[$nic] = $nic;
|
||||
}
|
||||
|
||||
// If the first 8 digits of the line are hex digits
|
||||
// add this rom to the current nic family.
|
||||
|
||||
if ( ( strlen ( $first_eight_chars ) == 8 )
|
||||
&& ( ctype_xdigit ( $first_eight_chars ) )
|
||||
&& ( $nic != "" ) ) {
|
||||
|
||||
$roms[$first_eight_chars] = $nic;
|
||||
}
|
||||
}
|
||||
fclose ( $fd );
|
||||
|
||||
// put most NICs in nice alpha order for menu
|
||||
ksort ( $nics );
|
||||
|
||||
// add special cases to the top
|
||||
|
||||
$new_nics = array ( "all-drivers" => "ipxe",
|
||||
"undionly" => "undionly",
|
||||
"undi" => "undi",
|
||||
);
|
||||
|
||||
foreach ( $nics as $key => $value ) {
|
||||
// skip the undi driver
|
||||
if ( $key != "undi" ) {
|
||||
$new_nics[$key] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
return array ( $new_nics, $roms );
|
||||
}
|
||||
|
||||
////
|
||||
// HTML form utility functions
|
||||
////
|
||||
|
||||
/**
|
||||
* Return html code to create hidden form input fields
|
||||
*
|
||||
* @param string $flag name of form variable to set
|
||||
* @param string $value value to give form variable
|
||||
*
|
||||
* @return string html code for given hidden form input field
|
||||
*/
|
||||
function hidden ( $flag, $value )
|
||||
{
|
||||
$value = htmlentities ( $value );
|
||||
return "<input type=\"hidden\" value=\"$value\" name=\"$flag\"></input>";
|
||||
}
|
||||
|
||||
/**
|
||||
* Return html code to create checkbox form input fields
|
||||
*
|
||||
* @param string $flag name of form variable to set
|
||||
* @param string $value "on" means box should be checked
|
||||
*
|
||||
* @return string html code for given hidden form input field
|
||||
*/
|
||||
function checkbox ( $flag, $value )
|
||||
{
|
||||
return "<input type=\"checkbox\" value=\"on\" name=\"$flag\"" .
|
||||
($value == "on" ? " checked>" : ">" );
|
||||
}
|
||||
|
||||
/**
|
||||
* Return html code to create text form input fields
|
||||
*
|
||||
* @param string $flag name of form variable to set
|
||||
* @param string $value initial contents of field
|
||||
* @param string $size size in characters of text box
|
||||
*
|
||||
* @return string html code for given text input field
|
||||
*/
|
||||
function textbox ( $flag, $value, $size )
|
||||
{
|
||||
$value = htmlentities ( $value );
|
||||
return "<input type=\"text\" size=\"$size\" value=\"$value\" name=\"$flag\">";
|
||||
}
|
||||
|
||||
/**
|
||||
* Return html code to create textarea form fields
|
||||
*
|
||||
* @param string $flag name of form variable to set
|
||||
* @param string $value initial contents of textarea
|
||||
* @param string $rows height of text area in rows
|
||||
* @param string $cols width of text area in columns
|
||||
*
|
||||
* @return string html code for given textarea input field
|
||||
*/
|
||||
function textarea ( $flag, $value, $rows, $cols )
|
||||
{
|
||||
$value = htmlentities ( $value );
|
||||
return "<textarea name=\"$flag\" rows=\"$rows\" cols=\"$cols\">"
|
||||
. $value . "</textarea>";
|
||||
}
|
||||
|
||||
/**
|
||||
* Return html code to create select (menu) form fields
|
||||
*
|
||||
* Use array of strings as menu choices
|
||||
*
|
||||
* @param string $flag name of form variable to set
|
||||
* @param array $options array of strings representing choices
|
||||
* @param string $value value of choice to select in menu
|
||||
*
|
||||
* @return string html code for given select (menu) input field
|
||||
*/
|
||||
function menubox ( $name, $options, $value )
|
||||
{
|
||||
$s="<select name=\"$name\">";
|
||||
|
||||
foreach ( $options as $ignore => $option ) {
|
||||
if ( !$value ) $value = $option;
|
||||
$s .= "<option" . ( $option == $value ? " selected>" : ">" ) .
|
||||
htmlentities ( $option ) . "</option>";
|
||||
}
|
||||
return $s . "</select>";
|
||||
}
|
||||
|
||||
/**
|
||||
* Return html code to create select (menu) form fields
|
||||
*
|
||||
* Use indices of array of strings as menu choices rather than
|
||||
* the values pointed to by the indicies.
|
||||
*
|
||||
* @param string $flag name of form variable to set
|
||||
* @param array $options array of strings representing choices
|
||||
* @param string $value value of choice to select in menu
|
||||
*
|
||||
* @return string html code for given select (menu) input field
|
||||
*/
|
||||
function keys_menubox ( $name, $options, $value )
|
||||
{
|
||||
$s="<select name=\"$name\">";
|
||||
|
||||
foreach ( $options as $option => $ignore ) {
|
||||
if ( !$value ) $value = $option;
|
||||
$s .= "<option" . ( $option == $value ? " selected>" : ">" ) .
|
||||
htmlentities ( $option ) . "</option>";
|
||||
}
|
||||
return $s . "</select>";
|
||||
}
|
||||
|
||||
////
|
||||
// Flag (compile option) handling functions
|
||||
////
|
||||
|
||||
/**
|
||||
* Return default compile options (flags)
|
||||
*
|
||||
* Initial compile options are in a global called $flag_table.
|
||||
* Create and return an array containing the ones we want.
|
||||
*
|
||||
* @return array default compile options (flags)
|
||||
*/
|
||||
function default_flags ()
|
||||
{
|
||||
global $flag_table;
|
||||
|
||||
$flags = array ();
|
||||
|
||||
foreach ( $flag_table as $key => $props ) {
|
||||
|
||||
$flag = $props["flag"];
|
||||
$type = $props["type"];
|
||||
|
||||
// Fields like headers have no "value" property
|
||||
if ( isset ( $props["value"] ) ) {
|
||||
$flags[$flag] = $props["value"];
|
||||
}
|
||||
}
|
||||
return $flags;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return combination of default and user compile options (flags)
|
||||
*
|
||||
* Initial compile options are in a global called $flag_table.
|
||||
* Compile options may have been changed via form input. We return
|
||||
* an array with either the default value of each option or a user
|
||||
* supplied value from form input.
|
||||
*
|
||||
* @return array combined default and user supplied compile options (flags)
|
||||
*/
|
||||
function get_flags ()
|
||||
{
|
||||
global $flag_table;
|
||||
|
||||
$flags = default_flags ();
|
||||
|
||||
if ( ! isset ( $_POST["use_flags"] ) )
|
||||
return $flags;
|
||||
|
||||
foreach ( $flag_table as $key => $props ) {
|
||||
|
||||
$flag = $props["flag"];
|
||||
$type = $props["type"];
|
||||
|
||||
if ( isset ( $_POST["$flag"] ) ) {
|
||||
$flags[$flag] = $_POST["$flag"];
|
||||
if ( $type == "integer-hex" ) {
|
||||
if ( strtolower ( substr ( $flags[$flag], 0, 2 ) ) != "0x" ) {
|
||||
$flags[$flag] = "0x" . $flags[$flag];
|
||||
}
|
||||
}
|
||||
} else if ( $type == "on/off" ) {
|
||||
// Unchecked checkboxes don't pass any POST value
|
||||
// so we must check for them specially. At this
|
||||
// point we know that there is no $_POST value set
|
||||
// for this option. If it is a checkbox, this means
|
||||
// it is unchecked, so record that in $flags so we
|
||||
// can later generate an #undef for this option.
|
||||
$flags[$flag] = "off";
|
||||
}
|
||||
}
|
||||
return $flags;
|
||||
}
|
||||
|
||||
/**
|
||||
* Output given value in appropriate format for iPXE config file
|
||||
*
|
||||
* iPXE config/*.h files use C pre-processor syntax. Output the given
|
||||
* compile option in a format appropriate to its type
|
||||
*
|
||||
* @param string $key index into $flag_table for given compile option
|
||||
* @param string $value value we wish to set compile option to
|
||||
*
|
||||
* @return string code to set compile option to given value
|
||||
*/
|
||||
function pprint_flag ( $key, $value )
|
||||
{
|
||||
global $flag_table;
|
||||
|
||||
// Determine type of given compile option (flag)
|
||||
$type = $flag_table[$key]["type"];
|
||||
$s = "";
|
||||
|
||||
if ( $type == "on/off" && $value == "on" ) {
|
||||
$s = "#define $key";
|
||||
} else if ( $type == "on/off" && $value != "on" ) {
|
||||
$s = "#undef $key";
|
||||
} else if ( $type == "string" ) {
|
||||
$s = ( "#define $key \"" . cleanstring ( $value ) . "\"" );
|
||||
} else if ($type == "qstring" ) {
|
||||
$s = ( "#define $key \\\"" . cleanstring ( $value ) . "\\\"" );
|
||||
} else {
|
||||
$s = "#define $key " . cleanstring ( $value );
|
||||
}
|
||||
|
||||
return $s;
|
||||
}
|
||||
|
||||
/**
|
||||
* Output html code to display all compile options as a table
|
||||
*
|
||||
* @param array $flags array of compile options
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function echo_flags ( $flags )
|
||||
{
|
||||
global $flag_table;
|
||||
|
||||
echo "<table>\n";
|
||||
|
||||
foreach ( $flag_table as $key => $props ) {
|
||||
|
||||
// Hide parameters from users that should not be changed.
|
||||
$hide_from_user = isset ( $props["hide_from_user"] ) ? $props["hide_from_user"] : "no";
|
||||
|
||||
$flag = $props["flag"];
|
||||
$type = $props["type"];
|
||||
|
||||
$value = isset ( $flags[$flag] ) ? $flags[$flag] : '';
|
||||
|
||||
if ( $hide_from_user == "yes" ) {
|
||||
|
||||
// Hidden flags cannot not be set by the user. We use hidden form
|
||||
// fields to keep them at their default values.
|
||||
if ( $type != "header" ) {
|
||||
echo hidden ( $flag, $value );
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
// Flag (iPXE compile option) should be displayed to user
|
||||
|
||||
if ( $type == "header" ) {
|
||||
|
||||
$label = $props["label"];
|
||||
echo "<td colspan=2><hr><h3>$label</h3><hr></td>";
|
||||
|
||||
} else if ($type == "on/off" ) {
|
||||
|
||||
echo "<td>", checkbox ( $flag, $value ), "</td><td><strong>$flag</strong></td>";
|
||||
|
||||
} else { // don't display checkbox for non-on/off flags
|
||||
|
||||
echo "<td> </td><td><strong>$flag: </strong>";
|
||||
|
||||
if ($type == "choice" ) {
|
||||
$options = $props["options"];
|
||||
echo menubox($flag, $options, $value);
|
||||
|
||||
} else {
|
||||
|
||||
echo textbox($flag, $value, ($type == "integer" ||
|
||||
$type == "integer-hex"
|
||||
? 7 : 25));
|
||||
}
|
||||
echo "</td>";
|
||||
}
|
||||
echo "</tr>\n";
|
||||
|
||||
if ( $type != "header" ) {
|
||||
echo "<tr><td> </td>";
|
||||
echo "<td>\n";
|
||||
if ( is_file ( "doc/$flag.html" ) ) {
|
||||
include_once "doc/$flag.html";
|
||||
}
|
||||
echo "\n</td></tr>\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
echo "</table>";
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an array of configuration sections used in all compile options
|
||||
*
|
||||
* $flag_table, the global list of compile options contains a 'cfgsec'
|
||||
* property for each flag we are interested in. We return a list of
|
||||
* all the unique cfgsec options we find in $flag_table.
|
||||
*
|
||||
* @return array an array of strings representing all unique cfgsec values
|
||||
* found in $flag_table
|
||||
*/
|
||||
function get_flag_cfgsecs ()
|
||||
{
|
||||
global $flag_table;
|
||||
$cfgsecs = array ();
|
||||
|
||||
foreach ( $flag_table as $key => $props ) {
|
||||
if ( isset ( $props['cfgsec'] ) ) {
|
||||
$cfgsec = $props["cfgsec"];
|
||||
$cfgsecs[$cfgsec] = $cfgsec;
|
||||
}
|
||||
}
|
||||
return $cfgsecs;
|
||||
}
|
||||
|
||||
////
|
||||
// File and directory handling functions
|
||||
////
|
||||
|
||||
/**
|
||||
* Create a copy of a given source directory to a given destination
|
||||
*
|
||||
* Since we are going to modify the source directory, we create a copy
|
||||
* of the directory with a unique name in the given destination directory.
|
||||
* We supply a prefix for the tempnam call to prepend to the random filename
|
||||
* it generates.
|
||||
*
|
||||
* @param string $src source directory
|
||||
* @param string $dst destination directory
|
||||
* @param string $prefix string to append to directory created
|
||||
*
|
||||
* @return string absolute path to destination directory
|
||||
*/
|
||||
function mktempcopy ( $src, $dst, $prefix )
|
||||
{
|
||||
if ( $src[0] != "/" ) {
|
||||
$src = dirname ( $_SERVER['SCRIPT_FILENAME'] ) . "/" . $src;
|
||||
}
|
||||
|
||||
// Create a file in the given destination directory with a unique name
|
||||
$dir = tempnam ( $dst, $prefix );
|
||||
|
||||
// Delete the file just created, since it would interfere with the copy we
|
||||
// are about to do. We only care that the dir name we copy to is unique.
|
||||
unlink ( $dir );
|
||||
|
||||
exec ( "/bin/cp -a '$src' '$dir' 2>&1", $cpytxt, $status );
|
||||
|
||||
if ( $status != 0 ) {
|
||||
die ( "src directory copy failed!" );
|
||||
}
|
||||
return $dir;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write iPXE config files based on value of given flags
|
||||
*
|
||||
* iPXE compile options are stored in src/config/*.h .
|
||||
* We write out a config file for each set of options.
|
||||
*
|
||||
* @param string $config_dir directory to write .h files to
|
||||
* @param array $flags array of compile options for this build
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function write_ipxe_config_files ( $config_dir, $flags )
|
||||
{
|
||||
global $flag_table;
|
||||
|
||||
$cfgsecs = get_flag_cfgsecs ();
|
||||
|
||||
foreach ( $cfgsecs as $cfgsec ) {
|
||||
|
||||
$fname = $config_dir . "/" . $cfgsec . ".h";
|
||||
|
||||
$fp = fopen ( $fname, "wb" );
|
||||
if ( $fp <= 0 ) {
|
||||
die ( "Unable to open $fname file for output!" );
|
||||
}
|
||||
|
||||
$ifdef_secname = "CONFIG_" . strtoupper ( $cfgsec ) . "_H";
|
||||
|
||||
fwrite ( $fp, "#ifndef ${ifdef_secname}\n" );
|
||||
fwrite ( $fp, "#define ${ifdef_secname}\n" );
|
||||
fwrite ( $fp, "#include <config/defaults.h>\n" );
|
||||
|
||||
foreach ( $flags as $key => $value ) {
|
||||
// When the flag matches this section name, write it out
|
||||
if ( $flag_table[$key]["cfgsec"] == $cfgsec ) {
|
||||
fwrite ( $fp, pprint_flag ( $key, $value ) . "\n" );
|
||||
}
|
||||
}
|
||||
fwrite ( $fp, "#endif /* ${ifdef_secname} */\n" );
|
||||
fclose ( $fp );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Output a string to a file
|
||||
*
|
||||
* Output a given string to a given pathname. The file will be created if
|
||||
* necessary, and the string will replace the file's contents in all cases.
|
||||
*
|
||||
* @param string $fname pathname of file to output string to
|
||||
* @param string $ftext text to output to file
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function write_file_from_string ( $fname, $ftext )
|
||||
{
|
||||
$fp = fopen ( $fname, "wb" );
|
||||
if ( ! $fp ) {
|
||||
die ( "Unable to open $fname file for output!" );
|
||||
}
|
||||
fwrite ( $fp, $ftext );
|
||||
fclose ( $fp );
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a file or recursively delete a directory tree
|
||||
*
|
||||
* @param string $file_or_dir_name name of file or directory to delete
|
||||
* @return bool Returns TRUE on success, FALSE on failure
|
||||
*/
|
||||
function rm_file_or_dir ( $file_or_dir_name )
|
||||
{
|
||||
if ( ! file_exists ( $file_or_dir_name ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( is_file ( $file_or_dir_name ) || is_link ( $file_or_dir_name ) ) {
|
||||
return unlink ( $file_or_dir_name );
|
||||
}
|
||||
|
||||
$dir = dir ( $file_or_dir_name );
|
||||
while ( ( $dir_entry = $dir->read () ) !== false ) {
|
||||
|
||||
if ( $dir_entry == '.' || $dir_entry == '..') {
|
||||
continue;
|
||||
}
|
||||
rm_file_or_dir ( $file_or_dir_name . '/' . $dir_entry );
|
||||
}
|
||||
$dir->close();
|
||||
|
||||
return rmdir ( $file_or_dir_name );
|
||||
}
|
||||
|
||||
////
|
||||
// Debugging functions
|
||||
////
|
||||
|
||||
/**
|
||||
* Emit html code to display given array of compile options (flags)
|
||||
*
|
||||
* @param array $flags array of compile options for this build
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function show_flags ( $flags )
|
||||
{
|
||||
echo ( "\$flags contains " . count ( $flags ) . " elements:" . "<br>" );
|
||||
|
||||
foreach ( $flags as $key => $flag ) {
|
||||
echo ( "\$flags[" . $key . "]=" . "\"$flag\"" . "<br>" );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Emit HTML code to display default array of compile options (flags)
|
||||
*
|
||||
* $flag_table contains default compile options and properties. This
|
||||
* routine outputs HTML code to display all properties of $flag_table.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function dump_flag_table ()
|
||||
{
|
||||
global $flag_table;
|
||||
|
||||
echo ( "\$flag_table contains " . count ( $flag_table ) . " elements:" . "<br>" );
|
||||
|
||||
foreach ( $flag_table as $key => $props ) {
|
||||
print ( "flag_table[" . $key . "] = " . "<br>" );
|
||||
|
||||
foreach ( $props as $key2 => $props2 ) {
|
||||
print ( " " . $key2 . " = " . $props2 . "<br>" );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Parse src/bin/NIC file
|
||||
list ( $nics, $roms ) = parse_nic_file ();
|
||||
|
||||
// For emacs:
|
||||
// Local variables:
|
||||
// c-basic-offset: 4
|
||||
// c-indent-level: 4
|
||||
// tab-width: 4
|
||||
// End:
|
||||
|
||||
?>
|
6
ipxe/contrib/vm/.gitignore
vendored
Normal file
6
ipxe/contrib/vm/.gitignore
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
bochsout.txt
|
||||
parport.out
|
||||
ne2k-tx.log
|
||||
ne2k-txdump.txt
|
||||
bochs
|
||||
qemu
|
7
ipxe/contrib/vm/Makefile
Normal file
7
ipxe/contrib/vm/Makefile
Normal file
@@ -0,0 +1,7 @@
|
||||
all : serial-console.1
|
||||
|
||||
%.1 : %
|
||||
pod2man $< > $@
|
||||
|
||||
clean :
|
||||
rm -f serial-console.1
|
15
ipxe/contrib/vm/bochs-writable-ROM-patch
Normal file
15
ipxe/contrib/vm/bochs-writable-ROM-patch
Normal file
@@ -0,0 +1,15 @@
|
||||
--- memory/memory.cc 18 Oct 2008 18:10:14 -0000 1.71
|
||||
+++ memory/memory.cc 21 Oct 2008 19:47:07 -0000
|
||||
@@ -172,7 +172,11 @@
|
||||
break;
|
||||
|
||||
case 0x0: // Writes to ROM, Inhibit
|
||||
- BX_DEBUG(("Write to ROM ignored: address 0x" FMT_PHY_ADDRX ", data %02x", a20addr, *data_ptr));
|
||||
+ if ((a20addr & 0xfffe0000) == 0x000e0000) {
|
||||
+ BX_DEBUG(("Write to ROM ignored: address 0x" FMT_PHY_ADDRX ", data %02x", a20addr, *data_ptr));
|
||||
+ } else {
|
||||
+ BX_MEM_THIS rom[(a20addr & EXROM_MASK) + BIOSROMSZ] = *data_ptr;
|
||||
+ }
|
||||
break;
|
||||
|
||||
default:
|
750
ipxe/contrib/vm/bochsrc.txt
Normal file
750
ipxe/contrib/vm/bochsrc.txt
Normal file
@@ -0,0 +1,750 @@
|
||||
# You may now use double quotes around pathnames, in case
|
||||
# your pathname includes spaces.
|
||||
|
||||
#=======================================================================
|
||||
# CONFIG_INTERFACE
|
||||
#
|
||||
# The configuration interface is a series of menus or dialog boxes that
|
||||
# allows you to change all the settings that control Bochs's behavior.
|
||||
# There are two choices of configuration interface: a text mode version
|
||||
# called "textconfig" and a graphical version called "wx". The text
|
||||
# mode version uses stdin/stdout and is always compiled in. The graphical
|
||||
# version is only available when you use "--with-wx" on the configure
|
||||
# command. If you do not write a config_interface line, Bochs will
|
||||
# choose a default for you.
|
||||
#
|
||||
# NOTE: if you use the "wx" configuration interface, you must also use
|
||||
# the "wx" display library.
|
||||
#=======================================================================
|
||||
#config_interface: textconfig
|
||||
#config_interface: wx
|
||||
|
||||
#=======================================================================
|
||||
# DISPLAY_LIBRARY
|
||||
#
|
||||
# The display library is the code that displays the Bochs VGA screen. Bochs
|
||||
# has a selection of about 10 different display library implementations for
|
||||
# different platforms. If you run configure with multiple --with-* options,
|
||||
# the display_library command lets you choose which one you want to run with.
|
||||
# If you do not write a display_library line, Bochs will choose a default for
|
||||
# you.
|
||||
#
|
||||
# The choices are:
|
||||
# x use X windows interface, cross platform
|
||||
# win32 use native win32 libraries
|
||||
# carbon use Carbon library (for MacOS X)
|
||||
# beos use native BeOS libraries
|
||||
# macintosh use MacOS pre-10
|
||||
# amigaos use native AmigaOS libraries
|
||||
# sdl use SDL library, cross platform
|
||||
# svga use SVGALIB library for Linux, allows graphics without X11
|
||||
# term text only, uses curses/ncurses library, cross platform
|
||||
# rfb provides an interface to AT&T's VNC viewer, cross platform
|
||||
# wx use wxWidgets library, cross platform
|
||||
# nogui no display at all
|
||||
#
|
||||
# NOTE: if you use the "wx" configuration interface, you must also use
|
||||
# the "wx" display library.
|
||||
#
|
||||
# Specific options:
|
||||
# Some display libraries now support specific option to control their
|
||||
# behaviour. See the examples below for currently supported options.
|
||||
#=======================================================================
|
||||
#display_library: amigaos
|
||||
#display_library: beos
|
||||
#display_library: carbon
|
||||
#display_library: macintosh
|
||||
#display_library: nogui
|
||||
#display_library: rfb, options="timeout=60" # time to wait for client
|
||||
#display_library: sdl, options="fullscreen" # startup in fullscreen mode
|
||||
#display_library: term
|
||||
#display_library: win32, options="legacyF12" # use F12 to toggle mouse
|
||||
#display_library: wx
|
||||
#display_library: x
|
||||
|
||||
#=======================================================================
|
||||
# ROMIMAGE:
|
||||
# The ROM BIOS controls what the PC does when it first powers on.
|
||||
# Normally, you can use a precompiled BIOS in the source or binary
|
||||
# distribution called BIOS-bochs-latest. The ROM BIOS is usually loaded
|
||||
# starting at address 0xf0000, and it is exactly 64k long.
|
||||
# You can also use the environment variable $BXSHARE to specify the
|
||||
# location of the BIOS.
|
||||
# The usage of external large BIOS images (up to 512k) at memory top is
|
||||
# now supported, but we still recommend to use the BIOS distributed with
|
||||
# Bochs. Now the start address can be calculated from image size.
|
||||
#=======================================================================
|
||||
romimage: file=bochs/bios/BIOS-bochs-latest, address=0xe0000
|
||||
#romimage: file=mybios.bin, address=0xfff80000 # 512k at memory top
|
||||
#romimage: file=mybios.bin # calculate start address from image size
|
||||
|
||||
#=======================================================================
|
||||
# CPU:
|
||||
# This defines cpu-related parameters inside Bochs:
|
||||
#
|
||||
# COUNT:
|
||||
# Set the number of processors:cores per processor:threads per core
|
||||
# when Bochs is compiled for SMP emulation.
|
||||
# Bochs currently supports up to 8 threads running simultaniosly.
|
||||
# If Bochs is compiled without SMP support, it won't accept values
|
||||
# different from 1.
|
||||
#
|
||||
# RESET_ON_TRIPLE_FAULT:
|
||||
# Reset the CPU when triple fault occur (highly recommended) rather than
|
||||
# PANIC. Remember that if you trying to continue after triple fault the
|
||||
# simulation will be completely bogus !
|
||||
#
|
||||
# IPS:
|
||||
# Emulated Instructions Per Second. This is the number of IPS that bochs
|
||||
# is capable of running on your machine. You can recompile Bochs with
|
||||
# --enable-show-ips option enabled, to find your workstation's capability.
|
||||
# Measured IPS value will then be logged into your log file or status bar
|
||||
# (if supported by the gui).
|
||||
#
|
||||
# IPS is used to calibrate many time-dependent events within the bochs
|
||||
# simulation. For example, changing IPS affects the frequency of VGA
|
||||
# updates, the duration of time before a key starts to autorepeat, and
|
||||
# the measurement of BogoMips and other benchmarks.
|
||||
#
|
||||
# Examples:
|
||||
# Machine Mips
|
||||
# ________________________________________________________________
|
||||
# 2.1Ghz Athlon XP with Linux 2.6/g++ 3.4 12 to 15 Mips
|
||||
# 1.6Ghz Intel P4 with Win2000/g++ 3.3 5 to 7 Mips
|
||||
# 650Mhz Athlon K-7 with Linux 2.4.4/egcs-2.91.66 2 to 2.5 Mips
|
||||
# 400Mhz Pentium II with Linux 2.0.36/egcs-1.0.3 1 to 1.8 Mips
|
||||
#=======================================================================
|
||||
cpu: count=1, ips=10000000, reset_on_triple_fault=1
|
||||
|
||||
#=======================================================================
|
||||
# MEGS
|
||||
# Set the number of Megabytes of physical memory you want to emulate.
|
||||
# The default is 32MB, most OS's won't need more than that.
|
||||
# The maximum amount of memory supported is 2048Mb.
|
||||
#=======================================================================
|
||||
#megs: 256
|
||||
#megs: 128
|
||||
#megs: 64
|
||||
megs: 32
|
||||
#megs: 16
|
||||
#megs: 8
|
||||
|
||||
#=======================================================================
|
||||
# OPTROMIMAGE[1-4]:
|
||||
# You may now load up to 4 optional ROM images. Be sure to use a
|
||||
# read-only area, typically between C8000 and EFFFF. These optional
|
||||
# ROM images should not overwrite the rombios (located at
|
||||
# F0000-FFFFF) and the videobios (located at C0000-C7FFF).
|
||||
# Those ROM images will be initialized by the bios if they contain
|
||||
# the right signature (0x55AA) and a valid checksum.
|
||||
# It can also be a convenient way to upload some arbitrary code/data
|
||||
# in the simulation, that can be retrieved by the boot loader
|
||||
#=======================================================================
|
||||
#optromimage1: file=optionalrom.bin, address=0xd0000
|
||||
#optromimage2: file=optionalrom.bin, address=0xd1000
|
||||
#optromimage3: file=optionalrom.bin, address=0xd2000
|
||||
#optromimage4: file=optionalrom.bin, address=0xd3000
|
||||
optromimage1: file=../../src/bin/pnic.rom, address=0xd0000
|
||||
#optromimage1: file=../../src/bin/rtl8029.rom, address=0xd0000
|
||||
|
||||
#optramimage1: file=/path/file1.img, address=0x0010000
|
||||
#optramimage2: file=/path/file2.img, address=0x0020000
|
||||
#optramimage3: file=/path/file3.img, address=0x0030000
|
||||
#optramimage4: file=/path/file4.img, address=0x0040000
|
||||
|
||||
#=======================================================================
|
||||
# VGAROMIMAGE
|
||||
# You now need to load a VGA ROM BIOS into C0000.
|
||||
#=======================================================================
|
||||
#vgaromimage: file=bios/VGABIOS-elpin-2.40
|
||||
vgaromimage: file=bochs/bios/VGABIOS-lgpl-latest
|
||||
#vgaromimage: file=bios/VGABIOS-lgpl-latest-cirrus
|
||||
|
||||
#=======================================================================
|
||||
# VGA:
|
||||
# Here you can specify the display extension to be used. With the value
|
||||
# 'none' you can use standard VGA with no extension. Other supported
|
||||
# values are 'vbe' for Bochs VBE and 'cirrus' for Cirrus SVGA support.
|
||||
#=======================================================================
|
||||
#vga: extension=cirrus
|
||||
#vga: extension=vbe
|
||||
vga: extension=none
|
||||
|
||||
#=======================================================================
|
||||
# FLOPPYA:
|
||||
# Point this to pathname of floppy image file or device
|
||||
# This should be of a bootable floppy(image/device) if you're
|
||||
# booting from 'a' (or 'floppy').
|
||||
#
|
||||
# You can set the initial status of the media to 'ejected' or 'inserted'.
|
||||
# floppya: 2_88=path, status=ejected (2.88M 3.5" floppy)
|
||||
# floppya: 1_44=path, status=inserted (1.44M 3.5" floppy)
|
||||
# floppya: 1_2=path, status=ejected (1.2M 5.25" floppy)
|
||||
# floppya: 720k=path, status=inserted (720K 3.5" floppy)
|
||||
# floppya: 360k=path, status=inserted (360K 5.25" floppy)
|
||||
# floppya: 320k=path, status=inserted (320K 5.25" floppy)
|
||||
# floppya: 180k=path, status=inserted (180K 5.25" floppy)
|
||||
# floppya: 160k=path, status=inserted (160K 5.25" floppy)
|
||||
# floppya: image=path, status=inserted (guess type from image size)
|
||||
#
|
||||
# The path should be the name of a disk image file. On Unix, you can use a raw
|
||||
# device name such as /dev/fd0 on Linux. On win32 platforms, use drive letters
|
||||
# such as a: or b: as the path. The parameter 'image' works with image files
|
||||
# only. In that case the size must match one of the supported types.
|
||||
#=======================================================================
|
||||
#floppya: 1_44=/dev/fd0, status=inserted
|
||||
#floppya: image=../1.44, status=inserted
|
||||
#floppya: 1_44=/dev/fd0H1440, status=inserted
|
||||
#floppya: 1_2=../1_2, status=inserted
|
||||
#floppya: 1_44=a:, status=inserted
|
||||
#floppya: 1_44=a.img, status=inserted
|
||||
#floppya: 1_44=/dev/rfd0a, status=inserted
|
||||
floppya: 1_44=../../src/bin/pnic.dsk, status=inserted
|
||||
|
||||
#=======================================================================
|
||||
# FLOPPYB:
|
||||
# See FLOPPYA above for syntax
|
||||
#=======================================================================
|
||||
#floppyb: 1_44=b:, status=inserted
|
||||
floppyb: 1_44=b.img, status=inserted
|
||||
|
||||
#=======================================================================
|
||||
# ATA0, ATA1, ATA2, ATA3
|
||||
# ATA controller for hard disks and cdroms
|
||||
#
|
||||
# ata[0-3]: enabled=[0|1], ioaddr1=addr, ioaddr2=addr, irq=number
|
||||
#
|
||||
# These options enables up to 4 ata channels. For each channel
|
||||
# the two base io addresses and the irq must be specified.
|
||||
#
|
||||
# ata0 and ata1 are enabled by default with the values shown below
|
||||
#
|
||||
# Examples:
|
||||
# ata0: enabled=1, ioaddr1=0x1f0, ioaddr2=0x3f0, irq=14
|
||||
# ata1: enabled=1, ioaddr1=0x170, ioaddr2=0x370, irq=15
|
||||
# ata2: enabled=1, ioaddr1=0x1e8, ioaddr2=0x3e0, irq=11
|
||||
# ata3: enabled=1, ioaddr1=0x168, ioaddr2=0x360, irq=9
|
||||
#=======================================================================
|
||||
ata0: enabled=1, ioaddr1=0x1f0, ioaddr2=0x3f0, irq=14
|
||||
ata1: enabled=1, ioaddr1=0x170, ioaddr2=0x370, irq=15
|
||||
ata2: enabled=0, ioaddr1=0x1e8, ioaddr2=0x3e0, irq=11
|
||||
ata3: enabled=0, ioaddr1=0x168, ioaddr2=0x360, irq=9
|
||||
|
||||
#=======================================================================
|
||||
# ATA[0-3]-MASTER, ATA[0-3]-SLAVE
|
||||
#
|
||||
# This defines the type and characteristics of all attached ata devices:
|
||||
# type= type of attached device [disk|cdrom]
|
||||
# mode= only valid for disks [flat|concat|external|dll|sparse|vmware3]
|
||||
# mode= only valid for disks [undoable|growing|volatile]
|
||||
# path= path of the image
|
||||
# cylinders= only valid for disks
|
||||
# heads= only valid for disks
|
||||
# spt= only valid for disks
|
||||
# status= only valid for cdroms [inserted|ejected]
|
||||
# biosdetect= type of biosdetection [none|auto], only for disks on ata0 [cmos]
|
||||
# translation=type of translation of the bios, only for disks [none|lba|large|rechs|auto]
|
||||
# model= string returned by identify device command
|
||||
# journal= optional filename of the redolog for undoable and volatile disks
|
||||
#
|
||||
# Point this at a hard disk image file, cdrom iso file, or physical cdrom
|
||||
# device. To create a hard disk image, try running bximage. It will help you
|
||||
# choose the size and then suggest a line that works with it.
|
||||
#
|
||||
# In UNIX it may be possible to use a raw device as a Bochs hard disk,
|
||||
# but WE DON'T RECOMMEND IT. In Windows there is no easy way.
|
||||
#
|
||||
# In windows, the drive letter + colon notation should be used for cdroms.
|
||||
# Depending on versions of windows and drivers, you may only be able to
|
||||
# access the "first" cdrom in the system. On MacOSX, use path="drive"
|
||||
# to access the physical drive.
|
||||
#
|
||||
# The path is always mandatory. For flat hard disk images created with
|
||||
# bximage geometry autodetection can be used (cylinders=0 -> cylinders are
|
||||
# calculated using heads=16 and spt=63). For other hard disk images and modes
|
||||
# the cylinders, heads, and spt are mandatory.
|
||||
#
|
||||
# Default values are:
|
||||
# mode=flat, biosdetect=auto, translation=auto, model="Generic 1234"
|
||||
#
|
||||
# The biosdetect option has currently no effect on the bios
|
||||
#
|
||||
# Examples:
|
||||
# ata0-master: type=disk, mode=flat, path=10M.sample, cylinders=306, heads=4, spt=17
|
||||
# ata0-slave: type=disk, mode=flat, path=20M.sample, cylinders=615, heads=4, spt=17
|
||||
# ata1-master: type=disk, mode=flat, path=30M.sample, cylinders=615, heads=6, spt=17
|
||||
# ata1-slave: type=disk, mode=flat, path=46M.sample, cylinders=940, heads=6, spt=17
|
||||
# ata2-master: type=disk, mode=flat, path=62M.sample, cylinders=940, heads=8, spt=17
|
||||
# ata2-slave: type=disk, mode=flat, path=112M.sample, cylinders=900, heads=15, spt=17
|
||||
# ata3-master: type=disk, mode=flat, path=483M.sample, cylinders=1024, heads=15, spt=63
|
||||
# ata3-slave: type=cdrom, path=iso.sample, status=inserted
|
||||
#=======================================================================
|
||||
#ata0-master: type=disk, mode=flat, path="30M.sample", cylinders=615, heads=6, spt=17
|
||||
#ata0-slave: type=cdrom, path=D:, status=inserted
|
||||
#ata0-slave: type=cdrom, path=/dev/cdrom, status=inserted
|
||||
#ata0-slave: type=cdrom, path="drive", status=inserted
|
||||
#ata0-slave: type=cdrom, path=/dev/rcd0d, status=inserted
|
||||
|
||||
#=======================================================================
|
||||
# BOOT:
|
||||
# This defines the boot sequence. Now you can specify up to 3 boot drives.
|
||||
# You can either boot from 'floppy', 'disk' or 'cdrom'
|
||||
# legacy 'a' and 'c' are also supported
|
||||
# Examples:
|
||||
# boot: floppy
|
||||
# boot: disk
|
||||
# boot: cdrom
|
||||
# boot: c
|
||||
# boot: a
|
||||
# boot: cdrom, floppy, disk
|
||||
#=======================================================================
|
||||
#boot: floppy
|
||||
#boot: disk
|
||||
|
||||
#=======================================================================
|
||||
# CLOCK:
|
||||
# This defines the parameters of the clock inside Bochs:
|
||||
#
|
||||
# SYNC:
|
||||
# TO BE COMPLETED (see Greg explanation in feature request #536329)
|
||||
#
|
||||
# TIME0:
|
||||
# Specifies the start (boot) time of the virtual machine. Use a time
|
||||
# value as returned by the time(2) system call. If no time0 value is
|
||||
# set or if time0 equal to 1 (special case) or if time0 equal 'local',
|
||||
# the simulation will be started at the current local host time.
|
||||
# If time0 equal to 2 (special case) or if time0 equal 'utc',
|
||||
# the simulation will be started at the current utc time.
|
||||
#
|
||||
# Syntax:
|
||||
# clock: sync=[none|slowdown|realtime|both], time0=[timeValue|local|utc]
|
||||
#
|
||||
# Example:
|
||||
# clock: sync=none, time0=local # Now (localtime)
|
||||
# clock: sync=slowdown, time0=315529200 # Tue Jan 1 00:00:00 1980
|
||||
# clock: sync=none, time0=631148400 # Mon Jan 1 00:00:00 1990
|
||||
# clock: sync=realtime, time0=938581955 # Wed Sep 29 07:12:35 1999
|
||||
# clock: sync=realtime, time0=946681200 # Sat Jan 1 00:00:00 2000
|
||||
# clock: sync=none, time0=1 # Now (localtime)
|
||||
# clock: sync=none, time0=utc # Now (utc/gmt)
|
||||
#
|
||||
# Default value are sync=none, time0=local
|
||||
#=======================================================================
|
||||
#clock: sync=none, time0=local
|
||||
|
||||
|
||||
#=======================================================================
|
||||
# FLOPPY_BOOTSIG_CHECK: disabled=[0|1]
|
||||
# Enables or disables the 0xaa55 signature check on boot floppies
|
||||
# Defaults to disabled=0
|
||||
# Examples:
|
||||
# floppy_bootsig_check: disabled=0
|
||||
# floppy_bootsig_check: disabled=1
|
||||
#=======================================================================
|
||||
#floppy_bootsig_check: disabled=1
|
||||
floppy_bootsig_check: disabled=0
|
||||
|
||||
#=======================================================================
|
||||
# LOG:
|
||||
# Give the path of the log file you'd like Bochs debug and misc. verbiage
|
||||
# to be written to. If you don't use this option or set the filename to
|
||||
# '-' the output is written to the console. If you really don't want it,
|
||||
# make it "/dev/null" (Unix) or "nul" (win32). :^(
|
||||
#
|
||||
# Examples:
|
||||
# log: ./bochs.out
|
||||
# log: /dev/tty
|
||||
#=======================================================================
|
||||
#log: /dev/null
|
||||
log: bochsout.txt
|
||||
|
||||
#=======================================================================
|
||||
# LOGPREFIX:
|
||||
# This handles the format of the string prepended to each log line.
|
||||
# You may use those special tokens :
|
||||
# %t : 11 decimal digits timer tick
|
||||
# %i : 8 hexadecimal digits of cpu current eip (ignored in SMP configuration)
|
||||
# %e : 1 character event type ('i'nfo, 'd'ebug, 'p'anic, 'e'rror)
|
||||
# %d : 5 characters string of the device, between brackets
|
||||
#
|
||||
# Default : %t%e%d
|
||||
# Examples:
|
||||
# logprefix: %t-%e-@%i-%d
|
||||
# logprefix: %i%e%d
|
||||
#=======================================================================
|
||||
#logprefix: %t%e%d
|
||||
|
||||
#=======================================================================
|
||||
# LOG CONTROLS
|
||||
#
|
||||
# Bochs now has four severity levels for event logging.
|
||||
# panic: cannot proceed. If you choose to continue after a panic,
|
||||
# don't be surprised if you get strange behavior or crashes.
|
||||
# error: something went wrong, but it is probably safe to continue the
|
||||
# simulation.
|
||||
# info: interesting or useful messages.
|
||||
# debug: messages useful only when debugging the code. This may
|
||||
# spit out thousands per second.
|
||||
#
|
||||
# For events of each level, you can choose to crash, report, or ignore.
|
||||
# TODO: allow choice based on the facility: e.g. crash on panics from
|
||||
# everything except the cdrom, and only report those.
|
||||
#
|
||||
# If you are experiencing many panics, it can be helpful to change
|
||||
# the panic action to report instead of fatal. However, be aware
|
||||
# that anything executed after a panic is uncharted territory and can
|
||||
# cause bochs to become unstable. The panic is a "graceful exit," so
|
||||
# if you disable it you may get a spectacular disaster instead.
|
||||
#=======================================================================
|
||||
panic: action=ask
|
||||
error: action=report
|
||||
info: action=report
|
||||
debug: action=ignore
|
||||
#pass: action=fatal
|
||||
|
||||
#=======================================================================
|
||||
# DEBUGGER_LOG:
|
||||
# Give the path of the log file you'd like Bochs to log debugger output.
|
||||
# If you really don't want it, make it /dev/null or '-'. :^(
|
||||
#
|
||||
# Examples:
|
||||
# debugger_log: ./debugger.out
|
||||
#=======================================================================
|
||||
#debugger_log: /dev/null
|
||||
#debugger_log: debugger.out
|
||||
debugger_log: -
|
||||
|
||||
#=======================================================================
|
||||
# COM1, COM2, COM3, COM4:
|
||||
# This defines a serial port (UART type 16550A). In the 'term' you can specify
|
||||
# a device to use as com1. This can be a real serial line, or a pty. To use
|
||||
# a pty (under X/Unix), create two windows (xterms, usually). One of them will
|
||||
# run bochs, and the other will act as com1. Find out the tty the com1
|
||||
# window using the `tty' command, and use that as the `dev' parameter.
|
||||
# Then do `sleep 1000000' in the com1 window to keep the shell from
|
||||
# messing with things, and run bochs in the other window. Serial I/O to
|
||||
# com1 (port 0x3f8) will all go to the other window.
|
||||
# Other serial modes are 'null' (no input/output), 'file' (output to a file
|
||||
# specified as the 'dev' parameter), 'raw' (use the real serial port - under
|
||||
# construction for win32), 'mouse' (standard serial mouse - requires
|
||||
# mouse option setting 'type=serial' or 'type=serial_wheel') and 'socket'
|
||||
# (connect a networking socket).
|
||||
#
|
||||
# Examples:
|
||||
# com1: enabled=1, mode=null
|
||||
# com1: enabled=1, mode=mouse
|
||||
# com2: enabled=1, mode=file, dev=serial.out
|
||||
# com3: enabled=1, mode=raw, dev=com1
|
||||
# com3: enabled=1, mode=socket, dev=localhost:8888
|
||||
#=======================================================================
|
||||
#com1: enabled=1, mode=term, dev=/dev/ttyp9
|
||||
|
||||
|
||||
#=======================================================================
|
||||
# PARPORT1, PARPORT2:
|
||||
# This defines a parallel (printer) port. When turned on and an output file is
|
||||
# defined the emulated printer port sends characters printed by the guest OS
|
||||
# into the output file. On some platforms a device filename can be used to
|
||||
# send the data to the real parallel port (e.g. "/dev/lp0" on Linux, "lpt1" on
|
||||
# win32 platforms).
|
||||
#
|
||||
# Examples:
|
||||
# parport1: enabled=1, file="parport.out"
|
||||
# parport2: enabled=1, file="/dev/lp0"
|
||||
# parport1: enabled=0
|
||||
#=======================================================================
|
||||
parport1: enabled=1, file="parport.out"
|
||||
|
||||
#=======================================================================
|
||||
# SB16:
|
||||
# This defines the SB16 sound emulation. It can have several of the
|
||||
# following properties.
|
||||
# All properties are in the format sb16: property=value
|
||||
# midi: The filename is where the midi data is sent. This can be a
|
||||
# device or just a file if you want to record the midi data.
|
||||
# midimode:
|
||||
# 0=no data
|
||||
# 1=output to device (system dependent. midi denotes the device driver)
|
||||
# 2=SMF file output, including headers
|
||||
# 3=output the midi data stream to the file (no midi headers and no
|
||||
# delta times, just command and data bytes)
|
||||
# wave: This is the device/file where wave output is stored
|
||||
# wavemode:
|
||||
# 0=no data
|
||||
# 1=output to device (system dependent. wave denotes the device driver)
|
||||
# 2=VOC file output, incl. headers
|
||||
# 3=output the raw wave stream to the file
|
||||
# log: The file to write the sb16 emulator messages to.
|
||||
# loglevel:
|
||||
# 0=no log
|
||||
# 1=resource changes, midi program and bank changes
|
||||
# 2=severe errors
|
||||
# 3=all errors
|
||||
# 4=all errors plus all port accesses
|
||||
# 5=all errors and port accesses plus a lot of extra info
|
||||
# dmatimer:
|
||||
# microseconds per second for a DMA cycle. Make it smaller to fix
|
||||
# non-continuous sound. 750000 is usually a good value. This needs a
|
||||
# reasonably correct setting for the IPS parameter of the CPU option.
|
||||
#
|
||||
# For an example look at the next line:
|
||||
#=======================================================================
|
||||
|
||||
#sb16: midimode=1, midi=/dev/midi00, wavemode=1, wave=/dev/dsp, loglevel=2, log=sb16.log, dmatimer=600000
|
||||
|
||||
#=======================================================================
|
||||
# VGA_UPDATE_INTERVAL:
|
||||
# Video memory is scanned for updates and screen updated every so many
|
||||
# virtual seconds. The default is 40000, about 25Hz. Keep in mind that
|
||||
# you must tweak the 'cpu: ips=N' directive to be as close to the number
|
||||
# of emulated instructions-per-second your workstation can do, for this
|
||||
# to be accurate.
|
||||
#
|
||||
# Examples:
|
||||
# vga_update_interval: 250000
|
||||
#=======================================================================
|
||||
vga_update_interval: 300000
|
||||
|
||||
# using for Winstone '98 tests
|
||||
#vga_update_interval: 100000
|
||||
|
||||
#=======================================================================
|
||||
# KEYBOARD_SERIAL_DELAY:
|
||||
# Approximate time in microseconds that it takes one character to
|
||||
# be transfered from the keyboard to controller over the serial path.
|
||||
# Examples:
|
||||
# keyboard_serial_delay: 200
|
||||
#=======================================================================
|
||||
keyboard_serial_delay: 250
|
||||
|
||||
#=======================================================================
|
||||
# KEYBOARD_PASTE_DELAY:
|
||||
# Approximate time in microseconds between attempts to paste
|
||||
# characters to the keyboard controller. This leaves time for the
|
||||
# guest os to deal with the flow of characters. The ideal setting
|
||||
# depends on how your operating system processes characters. The
|
||||
# default of 100000 usec (.1 seconds) was chosen because it works
|
||||
# consistently in Windows.
|
||||
#
|
||||
# If your OS is losing characters during a paste, increase the paste
|
||||
# delay until it stops losing characters.
|
||||
#
|
||||
# Examples:
|
||||
# keyboard_paste_delay: 100000
|
||||
#=======================================================================
|
||||
keyboard_paste_delay: 100000
|
||||
|
||||
#=======================================================================
|
||||
# MOUSE:
|
||||
# This option prevents Bochs from creating mouse "events" unless a mouse
|
||||
# is enabled. The hardware emulation itself is not disabled by this.
|
||||
# You can turn the mouse on by setting enabled to 1, or turn it off by
|
||||
# setting enabled to 0. Unless you have a particular reason for enabling
|
||||
# the mouse by default, it is recommended that you leave it off.
|
||||
# You can also toggle the mouse usage at runtime (control key + middle
|
||||
# mouse button on X11, SDL, wxWidgets and Win32).
|
||||
# With the mouse type option you can select the type of mouse to emulate.
|
||||
# The default value is 'ps2'. The other choices are 'imps2' (wheel mouse
|
||||
# on PS/2), 'serial', 'serial_wheel' (one com port requires setting
|
||||
# 'mode=mouse') and 'usb' (3-button mouse - one of the USB ports must be
|
||||
# connected with the 'mouse' device - requires PCI and USB support).
|
||||
#
|
||||
# Examples:
|
||||
# mouse: enabled=1
|
||||
# mouse: enabled=1, type=imps2
|
||||
# mouse: enabled=1, type=serial
|
||||
# mouse: enabled=0
|
||||
#=======================================================================
|
||||
mouse: enabled=0
|
||||
|
||||
#=======================================================================
|
||||
# private_colormap: Request that the GUI create and use it's own
|
||||
# non-shared colormap. This colormap will be used
|
||||
# when in the bochs window. If not enabled, a
|
||||
# shared colormap scheme may be used. Not implemented
|
||||
# on all GUI's.
|
||||
#
|
||||
# Examples:
|
||||
# private_colormap: enabled=1
|
||||
# private_colormap: enabled=0
|
||||
#=======================================================================
|
||||
private_colormap: enabled=0
|
||||
|
||||
#=======================================================================
|
||||
# fullscreen: ONLY IMPLEMENTED ON AMIGA
|
||||
# Request that Bochs occupy the entire screen instead of a
|
||||
# window.
|
||||
#
|
||||
# Examples:
|
||||
# fullscreen: enabled=0
|
||||
# fullscreen: enabled=1
|
||||
#=======================================================================
|
||||
#fullscreen: enabled=0
|
||||
#screenmode: name="sample"
|
||||
|
||||
#=======================================================================
|
||||
# ne2k: NE2000 compatible ethernet adapter
|
||||
#
|
||||
# Examples:
|
||||
# ne2k: ioaddr=IOADDR, irq=IRQ, mac=MACADDR, ethmod=MODULE, ethdev=DEVICE, script=SCRIPT
|
||||
#
|
||||
# ioaddr, irq: You probably won't need to change ioaddr and irq, unless there
|
||||
# are IRQ conflicts.
|
||||
#
|
||||
# mac: The MAC address MUST NOT match the address of any machine on the net.
|
||||
# Also, the first byte must be an even number (bit 0 set means a multicast
|
||||
# address), and you cannot use ff:ff:ff:ff:ff:ff because that's the broadcast
|
||||
# address. For the ethertap module, you must use fe:fd:00:00:00:01. There may
|
||||
# be other restrictions too. To be safe, just use the b0:c4... address.
|
||||
#
|
||||
# ethdev: The ethdev value is the name of the network interface on your host
|
||||
# platform. On UNIX machines, you can get the name by running ifconfig. On
|
||||
# Windows machines, you must run niclist to get the name of the ethdev.
|
||||
# Niclist source code is in misc/niclist.c and it is included in Windows
|
||||
# binary releases.
|
||||
#
|
||||
# script: The script value is optional, and is the name of a script that
|
||||
# is executed after bochs initialize the network interface. You can use
|
||||
# this script to configure this network interface, or enable masquerading.
|
||||
# This is mainly useful for the tun/tap devices that only exist during
|
||||
# Bochs execution. The network interface name is supplied to the script
|
||||
# as first parameter
|
||||
#
|
||||
# If you don't want to make connections to any physical networks,
|
||||
# you can use the following 'ethmod's to simulate a virtual network.
|
||||
# null: All packets are discarded, but logged to a few files.
|
||||
# arpback: ARP is simulated. Disabled by default.
|
||||
# vde: Virtual Distributed Ethernet
|
||||
# vnet: ARP, ICMP-echo(ping), DHCP and read/write TFTP are simulated.
|
||||
# The virtual host uses 192.168.10.1.
|
||||
# DHCP assigns 192.168.10.2 to the guest.
|
||||
# TFTP uses the ethdev value for the root directory and doesn't
|
||||
# overwrite files.
|
||||
#
|
||||
#=======================================================================
|
||||
# ne2k: ioaddr=0x240, irq=9, mac=fe:fd:00:00:00:01, ethmod=fbsd, ethdev=en0 #macosx
|
||||
# ne2k: ioaddr=0x240, irq=9, mac=b0:c4:20:00:00:00, ethmod=fbsd, ethdev=xl0
|
||||
# ne2k: ioaddr=0x240, irq=9, mac=b0:c4:20:00:00:00, ethmod=linux, ethdev=eth0
|
||||
# ne2k: ioaddr=0x240, irq=9, mac=b0:c4:20:00:00:01, ethmod=win32, ethdev=MYCARD
|
||||
# ne2k: ioaddr=0x240, irq=9, mac=fe:fd:00:00:00:01, ethmod=tap, ethdev=tap0
|
||||
# ne2k: ioaddr=0x240, irq=9, mac=fe:fd:00:00:00:01, ethmod=tuntap, ethdev=/dev/net/tun0, script=./tunconfig
|
||||
# ne2k: ioaddr=0x240, irq=9, mac=b0:c4:20:00:00:01, ethmod=null, ethdev=eth0
|
||||
# ne2k: ioaddr=0x240, irq=9, mac=b0:c4:20:00:00:01, ethmod=vde, ethdev="/tmp/vde.ctl"
|
||||
# ne2k: ioaddr=0x240, irq=9, mac=b0:c4:20:00:00:01, ethmod=vnet, ethdev="c:/temp"
|
||||
pnic: mac=fe:fd:00:00:00:01, ethmod=tuntap, ethdev=/dev/net/tun:tap0
|
||||
#ne2k: ioaddr=0x240, irq=9, mac=fe:fd:00:00:00:01, ethmod=tuntap, ethdev=/dev/net/tun:tap0
|
||||
|
||||
#=======================================================================
|
||||
# KEYBOARD_MAPPING:
|
||||
# This enables a remap of a physical localized keyboard to a
|
||||
# virtualized us keyboard, as the PC architecture expects.
|
||||
# If enabled, the keymap file must be specified.
|
||||
#
|
||||
# Examples:
|
||||
# keyboard_mapping: enabled=1, map=gui/keymaps/x11-pc-de.map
|
||||
#=======================================================================
|
||||
keyboard_mapping: enabled=0, map=
|
||||
|
||||
#=======================================================================
|
||||
# KEYBOARD_TYPE:
|
||||
# Type of keyboard return by a "identify keyboard" command to the
|
||||
# keyboard controler. It must be one of "xt", "at" or "mf".
|
||||
# Defaults to "mf". It should be ok for almost everybody. A known
|
||||
# exception is french macs, that do have a "at"-like keyboard.
|
||||
#
|
||||
# Examples:
|
||||
# keyboard_type: mf
|
||||
#=======================================================================
|
||||
#keyboard_type: mf
|
||||
|
||||
#=======================================================================
|
||||
# USER_SHORTCUT:
|
||||
# This defines the keyboard shortcut to be sent when you press the "user"
|
||||
# button in the headerbar. The shortcut string is a combination of maximum
|
||||
# 3 key names (listed below) separated with a '-' character. The old-style
|
||||
# syntax (without the '-') still works for the key combinations supported
|
||||
# in Bochs 2.2.1.
|
||||
# Valid key names:
|
||||
# "alt", "bksl", "bksp", "ctrl", "del", "down", "end", "enter", "esc",
|
||||
# "f1", ... "f12", "home", "ins", "left", "menu", "minus", "pgdwn", "pgup",
|
||||
# "plus", "right", "shift", "space", "tab", "up", and "win".
|
||||
#
|
||||
# Example:
|
||||
# user_shortcut: keys=ctrl-alt-del
|
||||
#=======================================================================
|
||||
user_shortcut: keys=ctrl-alt-del
|
||||
|
||||
#=======================================================================
|
||||
# I440FXSUPPORT:
|
||||
# This option controls the presence of the i440FX PCI chipset. You can
|
||||
# also specify the devices connected to PCI slots. Up to 5 slots are
|
||||
# available now. These devices are currently supported: ne2k, pcivga,
|
||||
# pcidev and pcipnic. If Bochs is compiled with Cirrus SVGA support
|
||||
# you'll have the additional choice 'cirrus'.
|
||||
#
|
||||
# Example:
|
||||
# i440fxsupport: enabled=1, slot1=pcivga, slot2=ne2k
|
||||
#=======================================================================
|
||||
i440fxsupport: enabled=1, slot1=pcipnic
|
||||
#i440fxsupport: enabled=1, slot1=ne2k
|
||||
|
||||
#=======================================================================
|
||||
# USB1:
|
||||
# This option controls the presence of the USB root hub which is a part
|
||||
# of the i440FX PCI chipset. With the portX option you can connect devices
|
||||
# to the hub (currently supported: 'mouse' and 'keypad'). If you connect
|
||||
# the mouse to one of the ports and use the mouse option 'type=usb' you'll
|
||||
# have a 3-button USB mouse.
|
||||
#
|
||||
# Example:
|
||||
# usb1: enabled=1, port1=mouse, port2=keypad
|
||||
#=======================================================================
|
||||
#usb1: enabled=1
|
||||
|
||||
#=======================================================================
|
||||
# CMOSIMAGE:
|
||||
# This defines image file that can be loaded into the CMOS RAM at startup.
|
||||
# The rtc_init parameter controls whether initialize the RTC with values stored
|
||||
# in the image. By default the time0 argument given to the clock option is used.
|
||||
# With 'rtc_init=image' the image is the source for the initial time.
|
||||
#
|
||||
# Example:
|
||||
# cmosimage: file=cmos.img, rtc_init=image
|
||||
#=======================================================================
|
||||
#cmosimage: file=cmos.img, rtc_init=time0
|
||||
|
||||
#=======================================================================
|
||||
# other stuff
|
||||
#=======================================================================
|
||||
magic_break: enabled=1
|
||||
#load32bitOSImage: os=nullkernel, path=../kernel.img, iolog=../vga_io.log
|
||||
#load32bitOSImage: os=linux, path=../linux.img, iolog=../vga_io.log, initrd=../initrd.img
|
||||
#text_snapshot_check: enable
|
||||
|
||||
#-------------------------
|
||||
# PCI host device mapping
|
||||
#-------------------------
|
||||
#pcidev: vendor=0x1234, device=0x5678
|
||||
|
||||
#=======================================================================
|
||||
# GDBSTUB:
|
||||
# Enable GDB stub. See user documentation for details.
|
||||
# Default value is enabled=0.
|
||||
#=======================================================================
|
||||
#gdbstub: enabled=0, port=1234, text_base=0, data_base=0, bss_base=0
|
||||
|
||||
#=======================================================================
|
||||
# IPS:
|
||||
# The IPS directive is DEPRECATED. Use the parameter IPS of the CPU
|
||||
# directive instead.
|
||||
#=======================================================================
|
||||
#ips: 10000000
|
||||
|
||||
#=======================================================================
|
||||
# for Macintosh, use the style of pathnames in the following
|
||||
# examples.
|
||||
#
|
||||
# vgaromimage: :bios:VGABIOS-elpin-2.40
|
||||
# romimage: file=:bios:BIOS-bochs-latest, address=0xf0000
|
||||
# floppya: 1_44=[fd:], status=inserted
|
||||
#=======================================================================
|
49
ipxe/contrib/vm/cow
Executable file
49
ipxe/contrib/vm/cow
Executable file
@@ -0,0 +1,49 @@
|
||||
#!/bin/sh
|
||||
|
||||
set -e
|
||||
|
||||
imgloop=
|
||||
tmpfile=
|
||||
tmploop=
|
||||
dmname=
|
||||
cowlink=
|
||||
|
||||
function cleanup () {
|
||||
set +e
|
||||
[ -n "$cowlink" ] && rm $cowlink
|
||||
[ -n "$dmname" ] && dmsetup remove $dmname
|
||||
[ -n "$tmploop" ] && losetup -d $tmploop
|
||||
[ -n "$tmpfile" ] && rm $tmpfile
|
||||
[ -n "$imgloop" ] && losetup -d $imgloop
|
||||
}
|
||||
|
||||
trap cleanup EXIT
|
||||
|
||||
imgfile=$1 ; shift
|
||||
command=$1 ; shift
|
||||
if [ -z "$imgfile" -o -z "$command" ] ; then
|
||||
echo Syntax: $0 /path/to/image/file command [args..]
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Set up image loop device
|
||||
x=`losetup -f` ; losetup -r $x $imgfile ; imgloop=$x
|
||||
|
||||
# Create temporary file and set up temporary loop device
|
||||
tmpfile=`mktemp $imgfile.XXXXXXXXXX`
|
||||
truncate -r $imgfile $tmpfile
|
||||
x=`losetup -f` ; losetup $x $tmpfile ; tmploop=$x
|
||||
|
||||
# Create snapshot device
|
||||
imgsize=`blockdev --getsz $imgloop`
|
||||
x=`basename $imgfile` ; echo 0 $imgsize snapshot $imgloop $tmploop N 16 | \
|
||||
dmsetup create $x ; dmname=$x
|
||||
chown --reference=$imgfile /dev/mapper/$dmname
|
||||
chmod --reference=$imgfile /dev/mapper/$dmname
|
||||
|
||||
# Create symlink
|
||||
x=$imgfile.cow ; ln -s /dev/mapper/$dmname $x ; cowlink=$x
|
||||
|
||||
# Wait until killed
|
||||
echo "Created $cowlink"
|
||||
$command "$@" $cowlink
|
278
ipxe/contrib/vm/serial-console
Executable file
278
ipxe/contrib/vm/serial-console
Executable file
@@ -0,0 +1,278 @@
|
||||
#!/usr/bin/perl -w
|
||||
|
||||
=head1 NAME
|
||||
|
||||
serial-console
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
serial-console [options]
|
||||
|
||||
Options:
|
||||
|
||||
-h,--help Display brief help message
|
||||
-v,--verbose Increase verbosity
|
||||
-q,--quiet Decrease verbosity
|
||||
-l,--log FILE Log output to file
|
||||
-r,--rcfile FILE Modify specified bochsrc file
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
C<serial-console> provides a virtual serial console for use with
|
||||
Bochs. Running C<serial-console> creates a pseudo-tty. The master
|
||||
side of this pty is made available to the user for interaction; the
|
||||
slave device is written to the Bochs configuration file
|
||||
(C<bochsrc.txt>) for use by a subsequent Bochs session.
|
||||
|
||||
=head1 EXAMPLES
|
||||
|
||||
=over 4
|
||||
|
||||
=item C<serial-console>
|
||||
|
||||
Create a virtual serial console for Bochs, modify C<bochsrc.txt>
|
||||
appropriately.
|
||||
|
||||
=item C<serial-console -r ../.bochsrc -l serial.log>
|
||||
|
||||
Create a virtual serial console for Bochs, modify C<../.bochsrc>
|
||||
appropriately, log output to C<serial.log>.
|
||||
|
||||
=back
|
||||
|
||||
=head1 INVOCATION
|
||||
|
||||
Before starting Bochs, run C<serial-console> in a different session
|
||||
(e.g. a different xterm window). When you subsequently start Bochs,
|
||||
anything that the emulated machine writes to its serial port will
|
||||
appear in the window running C<serial-console>, and anything typed in
|
||||
the C<serial-console> window will arrive on the emulated machine's
|
||||
serial port.
|
||||
|
||||
You do B<not> need to rerun C<serial-console> afresh for each Bochs
|
||||
session.
|
||||
|
||||
=head1 OPTIONS
|
||||
|
||||
=over 4
|
||||
|
||||
=item B<-l,--log FILE>
|
||||
|
||||
Log all output (i.e. everything that is printed in the
|
||||
C<serial-console> window) to the specified file.
|
||||
|
||||
=item B<-r,--rcfile FILE>
|
||||
|
||||
Modify the specified bochsrc file. The file will be updated to
|
||||
contain the path to the slave side of the psuedo tty that we create.
|
||||
The original file will be restored when C<serial-console> exits. The
|
||||
default is to modify the file C<bochsrc.txt> in the current directory.
|
||||
|
||||
To avoid modifying any bochsrc file, use C<--norcfile>.
|
||||
|
||||
=back
|
||||
|
||||
=cut
|
||||
|
||||
use IO::Pty;
|
||||
use IO::Select;
|
||||
use File::Spec::Functions qw ( :ALL );
|
||||
use Getopt::Long;
|
||||
use Pod::Usage;
|
||||
use POSIX qw ( :termios_h );
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
my $o;
|
||||
my $restore_file = {};
|
||||
my $restore_termios;
|
||||
use constant BLOCKSIZE => 8192;
|
||||
|
||||
##############################################################################
|
||||
#
|
||||
# Parse command line options into options hash ($o)
|
||||
#
|
||||
# $o = parse_opts();
|
||||
|
||||
sub parse_opts {
|
||||
# $o is the hash that will hold the options
|
||||
my $o = {
|
||||
verbosity => 1,
|
||||
rcfile => 'bochsrc.txt',
|
||||
};
|
||||
# Special handlers for some options
|
||||
my $opt_handlers = {
|
||||
verbose => sub { $o->{verbosity}++; },
|
||||
quiet => sub { $o->{verbosity}--; },
|
||||
help => sub { pod2usage(1); },
|
||||
norcfile => sub { delete $o->{rcfile}; },
|
||||
};
|
||||
# Merge handlers into main options hash (so that Getopt::Long can find them)
|
||||
$o->{$_} = $opt_handlers->{$_} foreach keys %$opt_handlers;
|
||||
# Option specifiers for Getopt::Long
|
||||
my @optspec = ( 'help|h|?',
|
||||
'quiet|q+',
|
||||
'verbose|v+',
|
||||
'log|l=s',
|
||||
'rcfile|r=s',
|
||||
'norcfile',
|
||||
);
|
||||
# Do option parsing
|
||||
Getopt::Long::Configure ( 'bundling' );
|
||||
pod2usage("Error parsing command-line options") unless GetOptions (
|
||||
$o, @optspec );
|
||||
# Clean up $o by removing the handlers
|
||||
delete $o->{$_} foreach keys %$opt_handlers;
|
||||
return $o;
|
||||
}
|
||||
|
||||
##############################################################################
|
||||
#
|
||||
# Modify bochsrc file
|
||||
|
||||
sub patch_bochsrc {
|
||||
my $active = shift;
|
||||
my $pty = shift;
|
||||
|
||||
# Rename active file to backup file
|
||||
( my $vol, my $dir, my $file ) = splitpath ( $active );
|
||||
$file = '.'.$file.".serial-console";
|
||||
my $backup = catpath ( $vol, $dir, $file );
|
||||
rename $active, $backup
|
||||
or die "Could not back up $active to $backup: $!\n";
|
||||
|
||||
# Derive line to be inserted
|
||||
my $patch = "com1: enabled=1, mode=term, dev=$pty\n";
|
||||
|
||||
# Modify file
|
||||
open my $old, "<$backup" or die "Could not open $backup: $!\n";
|
||||
open my $new, ">$active" or die "Could not open $active: $!\n";
|
||||
print $new <<"EOF";
|
||||
##################################################
|
||||
#
|
||||
# This file has been modified by serial-console.
|
||||
#
|
||||
# Do not modify this file; it will be erased when
|
||||
# serial-console (pid $$) exits and will be
|
||||
# replaced with the backup copy held in
|
||||
# $backup.
|
||||
#
|
||||
##################################################
|
||||
|
||||
|
||||
EOF
|
||||
my $patched;
|
||||
while ( my $line = <$old> ) {
|
||||
if ( $line =~ /^\s*\#?\s*com1:\s*\S/ ) {
|
||||
if ( ! $patched ) {
|
||||
$line = $patch;
|
||||
$patched = 1;
|
||||
} else {
|
||||
$line = '# '.$line unless $line =~ /^\s*\#/;
|
||||
}
|
||||
}
|
||||
print $new $line;
|
||||
}
|
||||
print $new $patch unless $patched;
|
||||
close $old;
|
||||
close $new;
|
||||
|
||||
return $backup;
|
||||
}
|
||||
|
||||
##############################################################################
|
||||
#
|
||||
# Attach/detach message printing and terminal settings
|
||||
|
||||
sub bochs_attached {
|
||||
print STDERR "Bochs attached.\n\n\n"
|
||||
if $o->{verbosity} >= 1;
|
||||
}
|
||||
|
||||
sub bochs_detached {
|
||||
print STDERR "\n\nWaiting for bochs to attach...\n"
|
||||
if $o->{verbosity} >= 1;
|
||||
}
|
||||
|
||||
##############################################################################
|
||||
#
|
||||
# Main program
|
||||
|
||||
$o = parse_opts();
|
||||
pod2usage(1) if @ARGV;
|
||||
|
||||
# Catch signals
|
||||
my $sigdie = sub { die "Exiting via signal\n"; };
|
||||
$SIG{INT} = $sigdie;
|
||||
|
||||
# Create Pty, close slave side
|
||||
my $pty = IO::Pty->new();
|
||||
$pty->close_slave();
|
||||
$pty->set_raw();
|
||||
print STDERR "Slave pty is ".$pty->ttyname."\n" if $o->{verbosity} >= 1;
|
||||
|
||||
# Open logfile
|
||||
my $log;
|
||||
if ( $o->{log} ) {
|
||||
open $log, ">$o->{log}" or die "Could not open $o->{log}: $!\n";
|
||||
}
|
||||
|
||||
# Set up terminal
|
||||
my $termios;
|
||||
if ( -t STDIN ) {
|
||||
$termios = POSIX::Termios->new;
|
||||
$restore_termios = POSIX::Termios->new;
|
||||
$termios->getattr ( fileno(STDIN) );
|
||||
$restore_termios->getattr ( fileno(STDIN) );
|
||||
$termios->setlflag ( $termios->getlflag & ~(ICANON) & ~(ECHO) );
|
||||
$termios->setiflag ( $termios->getiflag & ~(ICRNL) );
|
||||
$termios->setattr ( fileno(STDIN), TCSANOW );
|
||||
}
|
||||
|
||||
# Modify bochsrc file
|
||||
$restore_file = { $o->{rcfile} =>
|
||||
patch_bochsrc ( $o->{rcfile}, $pty->ttyname ) }
|
||||
if $o->{rcfile};
|
||||
|
||||
# Start character shunt
|
||||
my $attached = 1;
|
||||
my $select = IO::Select->new ( \*STDIN, $pty );
|
||||
while ( 1 ) {
|
||||
my %can_read = map { $_ => 1 }
|
||||
$select->can_read ( $attached ? undef : 1 );
|
||||
if ( $can_read{\*STDIN} ) {
|
||||
sysread ( STDIN, my $data, BLOCKSIZE )
|
||||
or die "Cannot read from STDIN: $!\n";
|
||||
$pty->syswrite ( $data );
|
||||
}
|
||||
if ( $can_read{$pty} ) {
|
||||
if ( $pty->sysread ( my $data, BLOCKSIZE ) ) {
|
||||
# Actual data available
|
||||
bochs_attached() if $attached == 0;
|
||||
$attached = 1;
|
||||
syswrite ( STDOUT, $data );
|
||||
$log->syswrite ( $data ) if $log;
|
||||
} else {
|
||||
# No data available but select() says we can read. This almost
|
||||
# certainly indicates that nothing is attached to the slave.
|
||||
bochs_detached() if $attached == 1;
|
||||
$attached = 0;
|
||||
sleep ( 1 );
|
||||
}
|
||||
} else {
|
||||
bochs_attached() if $attached == 0;
|
||||
$attached = 1;
|
||||
}
|
||||
}
|
||||
|
||||
END {
|
||||
# Restore bochsrc file if applicable
|
||||
if ( ( my $orig_file, my $backup_file ) = %$restore_file ) {
|
||||
unlink $orig_file;
|
||||
rename $backup_file, $orig_file;
|
||||
}
|
||||
# Restore terminal settings if applicable
|
||||
if ( $restore_termios ) {
|
||||
$restore_termios->setattr ( fileno(STDIN), TCSANOW );
|
||||
}
|
||||
}
|
190
ipxe/contrib/vm/serial-console.1
Normal file
190
ipxe/contrib/vm/serial-console.1
Normal file
@@ -0,0 +1,190 @@
|
||||
.\" Automatically generated by Pod::Man 2.22 (Pod::Simple 3.07)
|
||||
.\"
|
||||
.\" Standard preamble:
|
||||
.\" ========================================================================
|
||||
.de Sp \" Vertical space (when we can't use .PP)
|
||||
.if t .sp .5v
|
||||
.if n .sp
|
||||
..
|
||||
.de Vb \" Begin verbatim text
|
||||
.ft CW
|
||||
.nf
|
||||
.ne \\$1
|
||||
..
|
||||
.de Ve \" End verbatim text
|
||||
.ft R
|
||||
.fi
|
||||
..
|
||||
.\" Set up some character translations and predefined strings. \*(-- will
|
||||
.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left
|
||||
.\" double quote, and \*(R" will give a right double quote. \*(C+ will
|
||||
.\" give a nicer C++. Capital omega is used to do unbreakable dashes and
|
||||
.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff,
|
||||
.\" nothing in troff, for use with C<>.
|
||||
.tr \(*W-
|
||||
.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p'
|
||||
.ie n \{\
|
||||
. ds -- \(*W-
|
||||
. ds PI pi
|
||||
. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch
|
||||
. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch
|
||||
. ds L" ""
|
||||
. ds R" ""
|
||||
. ds C` ""
|
||||
. ds C' ""
|
||||
'br\}
|
||||
.el\{\
|
||||
. ds -- \|\(em\|
|
||||
. ds PI \(*p
|
||||
. ds L" ``
|
||||
. ds R" ''
|
||||
'br\}
|
||||
.\"
|
||||
.\" Escape single quotes in literal strings from groff's Unicode transform.
|
||||
.ie \n(.g .ds Aq \(aq
|
||||
.el .ds Aq '
|
||||
.\"
|
||||
.\" If the F register is turned on, we'll generate index entries on stderr for
|
||||
.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index
|
||||
.\" entries marked with X<> in POD. Of course, you'll have to process the
|
||||
.\" output yourself in some meaningful fashion.
|
||||
.ie \nF \{\
|
||||
. de IX
|
||||
. tm Index:\\$1\t\\n%\t"\\$2"
|
||||
..
|
||||
. nr % 0
|
||||
. rr F
|
||||
.\}
|
||||
.el \{\
|
||||
. de IX
|
||||
..
|
||||
.\}
|
||||
.\"
|
||||
.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2).
|
||||
.\" Fear. Run. Save yourself. No user-serviceable parts.
|
||||
. \" fudge factors for nroff and troff
|
||||
.if n \{\
|
||||
. ds #H 0
|
||||
. ds #V .8m
|
||||
. ds #F .3m
|
||||
. ds #[ \f1
|
||||
. ds #] \fP
|
||||
.\}
|
||||
.if t \{\
|
||||
. ds #H ((1u-(\\\\n(.fu%2u))*.13m)
|
||||
. ds #V .6m
|
||||
. ds #F 0
|
||||
. ds #[ \&
|
||||
. ds #] \&
|
||||
.\}
|
||||
. \" simple accents for nroff and troff
|
||||
.if n \{\
|
||||
. ds ' \&
|
||||
. ds ` \&
|
||||
. ds ^ \&
|
||||
. ds , \&
|
||||
. ds ~ ~
|
||||
. ds /
|
||||
.\}
|
||||
.if t \{\
|
||||
. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u"
|
||||
. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u'
|
||||
. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u'
|
||||
. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u'
|
||||
. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u'
|
||||
. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u'
|
||||
.\}
|
||||
. \" troff and (daisy-wheel) nroff accents
|
||||
.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V'
|
||||
.ds 8 \h'\*(#H'\(*b\h'-\*(#H'
|
||||
.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#]
|
||||
.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H'
|
||||
.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u'
|
||||
.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#]
|
||||
.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#]
|
||||
.ds ae a\h'-(\w'a'u*4/10)'e
|
||||
.ds Ae A\h'-(\w'A'u*4/10)'E
|
||||
. \" corrections for vroff
|
||||
.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u'
|
||||
.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u'
|
||||
. \" for low resolution devices (crt and lpr)
|
||||
.if \n(.H>23 .if \n(.V>19 \
|
||||
\{\
|
||||
. ds : e
|
||||
. ds 8 ss
|
||||
. ds o a
|
||||
. ds d- d\h'-1'\(ga
|
||||
. ds D- D\h'-1'\(hy
|
||||
. ds th \o'bp'
|
||||
. ds Th \o'LP'
|
||||
. ds ae ae
|
||||
. ds Ae AE
|
||||
.\}
|
||||
.rm #[ #] #H #V #F C
|
||||
.\" ========================================================================
|
||||
.\"
|
||||
.IX Title "SERIAL-CONSOLE 1"
|
||||
.TH SERIAL-CONSOLE 1 "2010-09-22" "perl v5.10.1" "User Contributed Perl Documentation"
|
||||
.\" For nroff, turn off justification. Always turn off hyphenation; it makes
|
||||
.\" way too many mistakes in technical documents.
|
||||
.if n .ad l
|
||||
.nh
|
||||
.SH "NAME"
|
||||
serial\-console
|
||||
.SH "SYNOPSIS"
|
||||
.IX Header "SYNOPSIS"
|
||||
serial-console [options]
|
||||
.PP
|
||||
Options:
|
||||
.PP
|
||||
.Vb 5
|
||||
\& \-h,\-\-help Display brief help message
|
||||
\& \-v,\-\-verbose Increase verbosity
|
||||
\& \-q,\-\-quiet Decrease verbosity
|
||||
\& \-l,\-\-log FILE Log output to file
|
||||
\& \-r,\-\-rcfile FILE Modify specified bochsrc file
|
||||
.Ve
|
||||
.SH "DESCRIPTION"
|
||||
.IX Header "DESCRIPTION"
|
||||
\&\f(CW\*(C`serial\-console\*(C'\fR provides a virtual serial console for use with
|
||||
Bochs. Running \f(CW\*(C`serial\-console\*(C'\fR creates a pseudo-tty. The master
|
||||
side of this pty is made available to the user for interaction; the
|
||||
slave device is written to the Bochs configuration file
|
||||
(\f(CW\*(C`bochsrc.txt\*(C'\fR) for use by a subsequent Bochs session.
|
||||
.SH "EXAMPLES"
|
||||
.IX Header "EXAMPLES"
|
||||
.ie n .IP """serial\-console""" 4
|
||||
.el .IP "\f(CWserial\-console\fR" 4
|
||||
.IX Item "serial-console"
|
||||
Create a virtual serial console for Bochs, modify \f(CW\*(C`bochsrc.txt\*(C'\fR
|
||||
appropriately.
|
||||
.ie n .IP """serial\-console \-r ../.bochsrc \-l serial.log""" 4
|
||||
.el .IP "\f(CWserial\-console \-r ../.bochsrc \-l serial.log\fR" 4
|
||||
.IX Item "serial-console -r ../.bochsrc -l serial.log"
|
||||
Create a virtual serial console for Bochs, modify \f(CW\*(C`../.bochsrc\*(C'\fR
|
||||
appropriately, log output to \f(CW\*(C`serial.log\*(C'\fR.
|
||||
.SH "INVOCATION"
|
||||
.IX Header "INVOCATION"
|
||||
Before starting Bochs, run \f(CW\*(C`serial\-console\*(C'\fR in a different session
|
||||
(e.g. a different xterm window). When you subsequently start Bochs,
|
||||
anything that the emulated machine writes to its serial port will
|
||||
appear in the window running \f(CW\*(C`serial\-console\*(C'\fR, and anything typed in
|
||||
the \f(CW\*(C`serial\-console\*(C'\fR window will arrive on the emulated machine's
|
||||
serial port.
|
||||
.PP
|
||||
You do \fBnot\fR need to rerun \f(CW\*(C`serial\-console\*(C'\fR afresh for each Bochs
|
||||
session.
|
||||
.SH "OPTIONS"
|
||||
.IX Header "OPTIONS"
|
||||
.IP "\fB\-l,\-\-log \s-1FILE\s0\fR" 4
|
||||
.IX Item "-l,--log FILE"
|
||||
Log all output (i.e. everything that is printed in the
|
||||
\&\f(CW\*(C`serial\-console\*(C'\fR window) to the specified file.
|
||||
.IP "\fB\-r,\-\-rcfile \s-1FILE\s0\fR" 4
|
||||
.IX Item "-r,--rcfile FILE"
|
||||
Modify the specified bochsrc file. The file will be updated to
|
||||
contain the path to the slave side of the psuedo tty that we create.
|
||||
The original file will be restored when \f(CW\*(C`serial\-console\*(C'\fR exits. The
|
||||
default is to modify the file \f(CW\*(C`bochsrc.txt\*(C'\fR in the current directory.
|
||||
.Sp
|
||||
To avoid modifying any bochsrc file, use \f(CW\*(C`\-\-norcfile\*(C'\fR.
|
4
ipxe/src/.gitignore
vendored
Normal file
4
ipxe/src/.gitignore
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
.toolcheck
|
||||
.echocheck
|
||||
TAGS*
|
||||
bin*
|
174
ipxe/src/Makefile
Normal file
174
ipxe/src/Makefile
Normal file
@@ -0,0 +1,174 @@
|
||||
###############################################################################
|
||||
#
|
||||
# Initialise various variables
|
||||
#
|
||||
|
||||
CLEANUP :=
|
||||
CFLAGS :=
|
||||
ASFLAGS :=
|
||||
LDFLAGS :=
|
||||
MAKEDEPS := Makefile
|
||||
|
||||
###############################################################################
|
||||
#
|
||||
# Locations of tools
|
||||
#
|
||||
HOST_CC := gcc
|
||||
RM := rm -f
|
||||
TOUCH := touch
|
||||
MKDIR := mkdir
|
||||
CP := cp
|
||||
ECHO := echo
|
||||
PRINTF := printf
|
||||
PERL := perl
|
||||
TRUE := true
|
||||
CC := $(CROSS_COMPILE)gcc
|
||||
CPP := $(CC) -E
|
||||
AS := $(CROSS_COMPILE)as
|
||||
LD := $(CROSS_COMPILE)ld
|
||||
SIZE := $(CROSS_COMPILE)size
|
||||
AR := $(CROSS_COMPILE)ar
|
||||
RANLIB := $(CROSS_COMPILE)ranlib
|
||||
OBJCOPY := $(CROSS_COMPILE)objcopy
|
||||
NM := $(CROSS_COMPILE)nm
|
||||
OBJDUMP := $(CROSS_COMPILE)objdump
|
||||
PARSEROM := ./util/parserom.pl
|
||||
FIXROM := ./util/fixrom.pl
|
||||
SYMCHECK := ./util/symcheck.pl
|
||||
SORTOBJDUMP := ./util/sortobjdump.pl
|
||||
PADIMG := ./util/padimg.pl
|
||||
LICENCE := ./util/licence.pl
|
||||
NRV2B := ./util/nrv2b
|
||||
ZBIN := ./util/zbin
|
||||
ELF2EFI32 := ./util/elf2efi32
|
||||
ELF2EFI64 := ./util/elf2efi64
|
||||
EFIROM := ./util/efirom
|
||||
ICCFIX := ./util/iccfix
|
||||
EINFO := ./util/einfo
|
||||
DOXYGEN := doxygen
|
||||
BINUTILS_DIR := /usr
|
||||
BFD_DIR := $(BINUTILS_DIR)
|
||||
ZLIB_DIR := /usr
|
||||
|
||||
###############################################################################
|
||||
#
|
||||
# SRCDIRS lists all directories containing source files.
|
||||
#
|
||||
SRCDIRS :=
|
||||
SRCDIRS += libgcc
|
||||
SRCDIRS += core
|
||||
SRCDIRS += net net/tcp net/udp net/infiniband net/80211
|
||||
SRCDIRS += image
|
||||
SRCDIRS += drivers/bus
|
||||
SRCDIRS += drivers/net
|
||||
SRCDIRS += drivers/net/e1000
|
||||
SRCDIRS += drivers/net/e1000e
|
||||
SRCDIRS += drivers/net/igb
|
||||
SRCDIRS += drivers/net/phantom
|
||||
SRCDIRS += drivers/net/rtl818x
|
||||
SRCDIRS += drivers/net/ath5k
|
||||
SRCDIRS += drivers/net/vxge
|
||||
SRCDIRS += drivers/net/efi
|
||||
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 += tests
|
||||
SRCDIRS += crypto crypto/axtls crypto/matrixssl
|
||||
SRCDIRS += hci hci/commands hci/tui
|
||||
SRCDIRS += hci/mucurses hci/mucurses/widgets
|
||||
SRCDIRS += usr
|
||||
SRCDIRS += config
|
||||
|
||||
# NON_AUTO_SRCS lists files that are excluded from the normal
|
||||
# automatic build system.
|
||||
#
|
||||
NON_AUTO_SRCS :=
|
||||
NON_AUTO_SRCS += drivers/net/prism2.c
|
||||
|
||||
# INCDIRS lists the include path
|
||||
#
|
||||
INCDIRS :=
|
||||
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 : $(ALL)
|
||||
@$(ECHO) '==========================================================='
|
||||
@$(ECHO)
|
||||
@$(ECHO) 'To create a bootable floppy, type'
|
||||
@$(ECHO) ' cat bin/ipxe.dsk > /dev/fd0'
|
||||
@$(ECHO) 'where /dev/fd0 is your floppy drive. This will erase any'
|
||||
@$(ECHO) 'data already on the disk.'
|
||||
@$(ECHO)
|
||||
@$(ECHO) 'To create a bootable USB key, type'
|
||||
@$(ECHO) ' cat bin/ipxe.usb > /dev/sdX'
|
||||
@$(ECHO) 'where /dev/sdX is your USB key, and is *not* a real hard'
|
||||
@$(ECHO) 'disk on your system. This will erase any data already on'
|
||||
@$(ECHO) 'the USB key.'
|
||||
@$(ECHO)
|
||||
@$(ECHO) 'To create a bootable CD-ROM, burn the ISO image '
|
||||
@$(ECHO) 'bin/ipxe.iso to a blank CD-ROM.'
|
||||
@$(ECHO)
|
||||
@$(ECHO) 'These images contain drivers for all supported cards. You'
|
||||
@$(ECHO) 'can build more customised images, and ROM images, using'
|
||||
@$(ECHO) ' make bin/<rom-name>.<output-format>'
|
||||
@$(ECHO)
|
||||
@$(ECHO) '==========================================================='
|
||||
|
||||
###############################################################################
|
||||
#
|
||||
# Comprehensive build target: build a selection of cross-platform
|
||||
# targets to expose potential build errors that show up only on
|
||||
# certain platforms
|
||||
#
|
||||
everything :
|
||||
$(Q)$(MAKE) --no-print-directory $(ALL) \
|
||||
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
|
||||
|
||||
###############################################################################
|
||||
#
|
||||
# Build targets that do nothing but might be tried by users
|
||||
#
|
||||
configure :
|
||||
@$(ECHO) "No configuration needed."
|
||||
|
||||
install :
|
||||
@$(ECHO) "No installation required."
|
||||
|
||||
###############################################################################
|
||||
#
|
||||
# Version number calculations
|
||||
#
|
||||
VERSION_MAJOR = 1
|
||||
VERSION_MINOR = 0
|
||||
VERSION_PATCH = 0
|
||||
EXTRAVERSION = +
|
||||
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'
|
||||
version :
|
||||
@$(ECHO) $(VERSION)
|
||||
|
||||
###############################################################################
|
||||
#
|
||||
# Drag in the bulk of the build system
|
||||
#
|
||||
|
||||
MAKEDEPS += Makefile.housekeeping
|
||||
include Makefile.housekeeping
|
1082
ipxe/src/Makefile.housekeeping
Normal file
1082
ipxe/src/Makefile.housekeeping
Normal file
File diff suppressed because it is too large
Load Diff
105
ipxe/src/arch/i386/Makefile
Normal file
105
ipxe/src/arch/i386/Makefile
Normal file
@@ -0,0 +1,105 @@
|
||||
# Force i386-only instructions
|
||||
#
|
||||
CFLAGS += -march=i386
|
||||
|
||||
# Code size reduction.
|
||||
#
|
||||
CFLAGS += -fomit-frame-pointer
|
||||
|
||||
# Code size reduction.
|
||||
#
|
||||
ifeq ($(CCTYPE),gcc)
|
||||
CFLAGS += -fstrength-reduce
|
||||
endif
|
||||
|
||||
# Code size reduction. gcc3 needs a different syntax to gcc2 if you
|
||||
# want to avoid spurious warnings.
|
||||
#
|
||||
ifeq ($(CCTYPE),gcc)
|
||||
GCC_VERSION := $(subst ., ,$(shell $(CC) -dumpversion))
|
||||
GCC_MAJOR := $(firstword $(GCC_VERSION))
|
||||
ifeq ($(GCC_MAJOR),2)
|
||||
CFLAGS += -malign-jumps=1 -malign-loops=1 -malign-functions=1
|
||||
else
|
||||
CFLAGS += -falign-jumps=1 -falign-loops=1 -falign-functions=1
|
||||
endif # gcc2
|
||||
endif # gcc
|
||||
|
||||
# Code size reduction. This is almost always a win. The kernel uses
|
||||
# it, too.
|
||||
#
|
||||
ifeq ($(CCTYPE),gcc)
|
||||
CFLAGS += -mpreferred-stack-boundary=2
|
||||
endif
|
||||
|
||||
# Code size reduction. Use regparm for all functions - C functions
|
||||
# called from assembly (or vice versa) need __asmcall now
|
||||
#
|
||||
CFLAGS += -mregparm=3
|
||||
|
||||
# Code size reduction. Use -mrtd (same __asmcall requirements as above)
|
||||
ifeq ($(CCTYPE),gcc)
|
||||
CFLAGS += -mrtd
|
||||
endif
|
||||
|
||||
# Code size reduction. This is the logical complement to -mregparm=3.
|
||||
# It doesn't currently buy us anything, but if anything ever tries to
|
||||
# return small structures, let's be prepared
|
||||
#
|
||||
CFLAGS += -freg-struct-return
|
||||
|
||||
# Force 32-bit code even on an x86-64 machine
|
||||
#
|
||||
CFLAGS += -m32
|
||||
ASFLAGS += --32
|
||||
ifeq ($(HOST_OS),FreeBSD)
|
||||
LDFLAGS += -m elf_i386_fbsd
|
||||
else
|
||||
LDFLAGS += -m elf_i386
|
||||
endif
|
||||
|
||||
# EFI requires -fshort-wchar, and nothing else currently uses wchar_t
|
||||
#
|
||||
CFLAGS += -fshort-wchar
|
||||
|
||||
# We need to undefine the default macro "i386" when compiling .S
|
||||
# files, otherwise ".arch i386" translates to ".arch 1"...
|
||||
#
|
||||
CFLAGS += -Ui386
|
||||
|
||||
# Locations of utilities
|
||||
#
|
||||
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)))
|
||||
|
||||
# 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
|
||||
|
||||
# Include common x86 Makefile
|
||||
#
|
||||
MAKEDEPS += arch/x86/Makefile
|
||||
include arch/x86/Makefile
|
||||
|
||||
# Include platform-specific Makefile
|
||||
#
|
||||
MAKEDEPS += arch/i386/Makefile.$(PLATFORM)
|
||||
include arch/i386/Makefile.$(PLATFORM)
|
10
ipxe/src/arch/i386/Makefile.efi
Normal file
10
ipxe/src/arch/i386/Makefile.efi
Normal file
@@ -0,0 +1,10 @@
|
||||
# -*- makefile -*- : Force emacs to use Makefile mode
|
||||
|
||||
# Specify EFI image builder
|
||||
#
|
||||
ELF2EFI = $(ELF2EFI32)
|
||||
|
||||
# Include generic EFI Makefile
|
||||
#
|
||||
MAKEDEPS += arch/x86/Makefile.efi
|
||||
include arch/x86/Makefile.efi
|
6
ipxe/src/arch/i386/Makefile.linux
Normal file
6
ipxe/src/arch/i386/Makefile.linux
Normal file
@@ -0,0 +1,6 @@
|
||||
LDSCRIPT = arch/i386/scripts/linux.lds
|
||||
|
||||
SRCDIRS += arch/i386/core/linux
|
||||
|
||||
MAKEDEPS += arch/x86/Makefile.linux
|
||||
include arch/x86/Makefile.linux
|
84
ipxe/src/arch/i386/Makefile.pcbios
Normal file
84
ipxe/src/arch/i386/Makefile.pcbios
Normal file
@@ -0,0 +1,84 @@
|
||||
# -*- makefile -*- : Force emacs to use Makefile mode
|
||||
|
||||
# The i386 linker script
|
||||
#
|
||||
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 $@
|
197
ipxe/src/arch/i386/README.i386
Normal file
197
ipxe/src/arch/i386/README.i386
Normal file
@@ -0,0 +1,197 @@
|
||||
Etherboot/NILO i386 initialisation path and external call interface
|
||||
===================================================================
|
||||
|
||||
1. Background
|
||||
|
||||
GCC compiles 32-bit code. It is capable of producing
|
||||
position-independent code, but the resulting binary is about 25%
|
||||
bigger than the corresponding fixed-position code. Since one main use
|
||||
of Etherboot is as firmware to be burned into an EPROM, code size must
|
||||
be kept as small as possible.
|
||||
|
||||
This means that we want to compile fixed-position code with GCC, and
|
||||
link it to have a predetermined start address. The problem then is
|
||||
that we must know the address that the code will be loaded to when it
|
||||
runs. There are several ways to solve this:
|
||||
|
||||
1. Pick an address, link the code with this start address, then make
|
||||
sure that the code gets loaded at that location. This is
|
||||
problematic, because we may pick an address that we later end up
|
||||
wanting to use to load the operating system that we're booting.
|
||||
|
||||
2. Pick an address, link the code with this start address, then set up
|
||||
virtual addressing so that the virtual addresses match the
|
||||
link-time addresses regardless of the real physical address that
|
||||
the code is loaded to. This enables us to relocate Etherboot to
|
||||
the top of high memory, where it will be out of the way of any
|
||||
loading operating system.
|
||||
|
||||
3. Link the code with a text start address of zero and a data start
|
||||
address also of zero. Use 16-bit real mode and the
|
||||
quasi-position-independence it gives you via segment addressing.
|
||||
Doing this requires that we generate 16-bit code, rather than
|
||||
32-bit code, and restricts us to a maximum of 64kB in each segment.
|
||||
|
||||
There are other possible approaches (e.g. including a relocation table
|
||||
and code that performs standard dynamic relocation), but the three
|
||||
options listed above are probably the best available.
|
||||
|
||||
Etherboot can be invoked in a variety of ways (ROM, floppy, as a PXE
|
||||
NBP, etc). Several of these ways involve control being passed to
|
||||
Etherboot with the CPU in 16-bit real mode. Some will involve the CPU
|
||||
being in 32-bit protected mode, and there's an outside chance that
|
||||
some may involve the CPU being in 16-bit protected mode. We will
|
||||
almost certainly have to effect a CPU mode change in order to reach
|
||||
the mode we want to be in to execute the C code.
|
||||
|
||||
Additionally, Etherboot may wish to call external routines, such as
|
||||
BIOS interrupts, which must be called in 16-bit real mode. When
|
||||
providing a PXE API, Etherboot must provide a mechanism for external
|
||||
code to call it from 16-bit real mode.
|
||||
|
||||
Not all i386 builds of Etherboot will want to make real-mode calls.
|
||||
For example, when built for LinuxBIOS rather than the standard PCBIOS,
|
||||
no real-mode calls are necessary.
|
||||
|
||||
For the ultimate in PXE compatibility, we may want to build Etherboot
|
||||
to run permanently in real mode.
|
||||
|
||||
There is a wide variety of potential combinations of mode switches
|
||||
that we may wish to implement. There are additional complications,
|
||||
such as the inability to access a high-memory stack when running in
|
||||
real mode.
|
||||
|
||||
2. Transition libraries
|
||||
|
||||
To handle all these various combinations of mode switches, we have
|
||||
several "transition" libraries in Etherboot. We also have the concept
|
||||
of an "internal" and an "external" environment. The internal
|
||||
environment is the environment within which we can execute C code.
|
||||
The external environment is the environment of whatever external code
|
||||
we're trying to interface to, such as the system BIOS or a PXE NBP.
|
||||
|
||||
As well as having a separate addressing scheme, the internal
|
||||
environment also has a separate stack.
|
||||
|
||||
The transition libraries are:
|
||||
|
||||
a) librm
|
||||
|
||||
librm handles transitions between an external 16-bit real-mode
|
||||
environment and an internal 32-bit protected-mode environment with
|
||||
virtual addresses.
|
||||
|
||||
b) libkir
|
||||
|
||||
libkir handles transitions between an external 16-bit real-mode (or
|
||||
16:16 or 16:32 protected-mode) environment and an internal 16-bit
|
||||
real-mode (or 16:16 protected-mode) environment.
|
||||
|
||||
c) libpm
|
||||
|
||||
libpm handles transitions between an external 32-bit protected-mode
|
||||
environment with flat physical addresses and an internal 32-bit
|
||||
protected-mode environment with virtual addresses.
|
||||
|
||||
The transition libraries handle the transitions required when
|
||||
Etherboot is started up for the first time, the transitions required
|
||||
to execute any external code, and the transitions required when
|
||||
Etherboot exits (if it exits). When Etherboot provides a PXE API,
|
||||
they also handle the transitions required when a PXE client makes a
|
||||
PXE API call to Etherboot.
|
||||
|
||||
Etherboot may use multiple transition libraries. For example, an
|
||||
Etherboot ELF image does not require librm for its initial transitions
|
||||
from prefix to runtime, but may require librm for calling external
|
||||
real-mode functions.
|
||||
|
||||
3. Setup and initialisation
|
||||
|
||||
Etherboot is conceptually divided into the prefix, the decompressor,
|
||||
and the runtime image. (For non-compressed images, the decompressor
|
||||
is a no-op.) The complete image comprises all three parts and is
|
||||
distinct from the runtime image, which exclude the prefix and the
|
||||
decompressor.
|
||||
|
||||
The prefix does several tasks:
|
||||
|
||||
Load the complete image into memory. (For example, the floppy
|
||||
prefix issues BIOS calls to load the remainder of the complete image
|
||||
from the floppy disk into RAM, and the ISA ROM prefix copies the ROM
|
||||
contents into RAM for faster access.)
|
||||
|
||||
Call the decompressor, if the runtime image is compressed. This
|
||||
decompresses the runtime image.
|
||||
|
||||
Call the runtime image's setup() routine. This is a routine
|
||||
implemented in assembly code which sets up the internal environment
|
||||
so that C code can execute.
|
||||
|
||||
Call the runtime image's arch_initialise() routine. This is a
|
||||
routine implemented in C which does some basic startup tasks, such
|
||||
as initialising the console device, obtaining a memory map and
|
||||
relocating the runtime image to high memory.
|
||||
|
||||
Call the runtime image's arch_main() routine. This records the exit
|
||||
mechanism requested by the prefix and calls main(). (The prefix
|
||||
needs to register an exit mechanism because by the time main()
|
||||
returns, the memory occupied by the prefix has most likely been
|
||||
overwritten.)
|
||||
|
||||
When acting as a PXE ROM, the ROM prefix contains an UNDI loader
|
||||
routine in addition to its usual code. The UNDI loader performs a
|
||||
similar sequence of steps:
|
||||
|
||||
Load the complete image into memory.
|
||||
|
||||
Call the decompressor.
|
||||
|
||||
Call the runtime image's setup() routine.
|
||||
|
||||
Call the runtime image's arch_initialise() routine.
|
||||
|
||||
Call the runtime image's install_pxe_stack() routine.
|
||||
|
||||
Return to caller.
|
||||
|
||||
The runtime image's setup() routine will perform the following steps:
|
||||
|
||||
Switch to the internal environment using an appropriate transition
|
||||
library. This will record the parameters of the external
|
||||
environment.
|
||||
|
||||
Set up the internal environment: load a stack, and set up a GDT for
|
||||
virtual addressing if virtual addressing is to be used.
|
||||
|
||||
Switch back to the external environment using the transition
|
||||
library. This will record the parameters of the internal
|
||||
environment.
|
||||
|
||||
Once the setup() routine has returned, the internal environment has been
|
||||
set up ready for C code to run. The prefix can call C routines using
|
||||
a function from the transition library.
|
||||
|
||||
The runtime image's arch_initialise() routine will perform the
|
||||
following steps:
|
||||
|
||||
Zero the bss
|
||||
|
||||
Initialise the console device(s) and print a welcome message.
|
||||
|
||||
Obtain a memory map via the INT 15,E820 BIOS call or suitable
|
||||
fallback mechanism. [not done if libkir is being used]
|
||||
|
||||
Relocate the runtime image to the top of high memory. [not done if
|
||||
libkir is being used]
|
||||
|
||||
Install librm to base memory. [done only if librm is being used]
|
||||
|
||||
Call initialise().
|
||||
|
||||
Return to the prefix, setting registers to indicate to the prefix
|
||||
the new location of the transition library, if applicable. Which
|
||||
registers these are is specific to the transition library being
|
||||
used.
|
||||
|
||||
Once the arch_initialise() routine has returned, the prefix will
|
||||
probably call arch_main().
|
144
ipxe/src/arch/i386/core/aout_loader.c
Normal file
144
ipxe/src/arch/i386/core/aout_loader.c
Normal file
@@ -0,0 +1,144 @@
|
||||
/* 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;
|
||||
}
|
32
ipxe/src/arch/i386/core/basemem_packet.c
Normal file
32
ipxe/src/arch/i386/core/basemem_packet.c
Normal file
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* 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] );
|
73
ipxe/src/arch/i386/core/cpu.c
Normal file
73
ipxe/src/arch/i386/core/cpu.c
Normal file
@@ -0,0 +1,73 @@
|
||||
#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 );
|
||||
}
|
||||
}
|
||||
}
|
23
ipxe/src/arch/i386/core/dumpregs.c
Normal file
23
ipxe/src/arch/i386/core/dumpregs.c
Normal file
@@ -0,0 +1,23 @@
|
||||
#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 );
|
||||
}
|
377
ipxe/src/arch/i386/core/freebsd_loader.c
Normal file
377
ipxe/src/arch/i386/core/freebsd_loader.c
Normal file
@@ -0,0 +1,377 @@
|
||||
/* 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
|
215
ipxe/src/arch/i386/core/gdbidt.S
Normal file
215
ipxe/src/arch/i386/core/gdbidt.S
Normal file
@@ -0,0 +1,215 @@
|
||||
/*
|
||||
* Interrupt Descriptor Table (IDT) setup and 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
|
||||
****************************************************************************
|
||||
*/
|
||||
.section ".text", "ax", @progbits
|
||||
.code32
|
||||
|
||||
/* 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:
|
||||
pushl $SIGFPE
|
||||
jmp do_interrupt
|
||||
|
||||
int_debug_trap:
|
||||
int_breakpoint:
|
||||
pushl $SIGTRAP
|
||||
jmp do_interrupt
|
||||
|
||||
int_overflow:
|
||||
int_bound_range_exceeded:
|
||||
pushl $SIGSTKFLT
|
||||
jmp do_interrupt
|
||||
|
||||
int_invalid_opcode:
|
||||
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
|
||||
|
||||
/* When invoked, the stack contains: eflags, cs, eip, signo. */
|
||||
#define IH_OFFSET_GDB_REGS ( 0 )
|
||||
#define IH_OFFSET_GDB_EIP ( IH_OFFSET_GDB_REGS + SIZEOF_I386_REGS )
|
||||
#define IH_OFFSET_GDB_EFLAGS ( IH_OFFSET_GDB_EIP + 4 )
|
||||
#define IH_OFFSET_GDB_SEG_REGS ( IH_OFFSET_GDB_EFLAGS + SIZEOF_I386_FLAGS )
|
||||
#define IH_OFFSET_GDB_END ( IH_OFFSET_GDB_SEG_REGS + 6 * 4 )
|
||||
#define IH_OFFSET_SIGNO ( IH_OFFSET_GDB_END )
|
||||
#define IH_OFFSET_OLD_EIP ( IH_OFFSET_SIGNO + 4 )
|
||||
#define IH_OFFSET_OLD_CS ( IH_OFFSET_OLD_EIP + 4 )
|
||||
#define IH_OFFSET_OLD_EFLAGS ( IH_OFFSET_OLD_CS + 4 )
|
||||
#define IH_OFFSET_END ( IH_OFFSET_OLD_EFLAGS + 4 )
|
||||
|
||||
/* We also access the stack whilst still storing or restoring
|
||||
* the register snapshot. Since ESP is in flux, we need
|
||||
* special offsets.
|
||||
*/
|
||||
#define IH_OFFSET_FLUX_OLD_CS ( IH_OFFSET_OLD_CS - 44 )
|
||||
#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:
|
||||
/* Store CPU state in GDB register snapshot */
|
||||
pushw $0
|
||||
pushw %gs
|
||||
pushw $0
|
||||
pushw %fs
|
||||
pushw $0
|
||||
pushw %es
|
||||
pushw $0
|
||||
pushw %ds
|
||||
pushw $0
|
||||
pushw %ss
|
||||
pushw $0
|
||||
pushw IH_OFFSET_FLUX_OLD_CS + 2(%esp)
|
||||
pushl IH_OFFSET_FLUX_OLD_EFLAGS(%esp)
|
||||
pushl IH_OFFSET_FLUX_OLD_EIP(%esp)
|
||||
pushl %edi
|
||||
pushl %esi
|
||||
pushl %ebp
|
||||
leal IH_OFFSET_FLUX_END(%esp), %edi
|
||||
pushl %edi /* old ESP */
|
||||
pushl %ebx
|
||||
pushl %edx
|
||||
pushl %ecx
|
||||
pushl %eax
|
||||
|
||||
/* Call GDB stub exception handler */
|
||||
pushl %esp
|
||||
pushl (IH_OFFSET_SIGNO + 4)(%esp)
|
||||
call gdbmach_handler
|
||||
addl $8, %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
|
||||
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
|
||||
popl %es
|
||||
popl %fs
|
||||
popl %gs
|
||||
|
||||
addl $4, %esp /* drop signo */
|
||||
iret
|
149
ipxe/src/arch/i386/core/gdbmach.c
Normal file
149
ipxe/src/arch/i386/core/gdbmach.c
Normal file
@@ -0,0 +1,149 @@
|
||||
/*
|
||||
* 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();
|
||||
}
|
45
ipxe/src/arch/i386/core/linux/linux_syscall.S
Normal file
45
ipxe/src/arch/i386/core/linux/linux_syscall.S
Normal file
@@ -0,0 +1,45 @@
|
||||
|
||||
.section ".data"
|
||||
.globl linux_errno
|
||||
|
||||
linux_errno: .int 0
|
||||
|
||||
.section ".text"
|
||||
.code32
|
||||
.globl linux_syscall
|
||||
.type linux_syscall, @function
|
||||
|
||||
linux_syscall:
|
||||
/* Save registers */
|
||||
pushl %ebx
|
||||
pushl %esi
|
||||
pushl %edi
|
||||
pushl %ebp
|
||||
|
||||
movl 20(%esp), %eax // C arg1 -> syscall number
|
||||
movl 24(%esp), %ebx // C arg2 -> syscall arg1
|
||||
movl 28(%esp), %ecx // C arg3 -> syscall arg2
|
||||
movl 32(%esp), %edx // C arg4 -> syscall arg3
|
||||
movl 36(%esp), %esi // C arg5 -> syscall arg4
|
||||
movl 40(%esp), %edi // C arg6 -> syscall arg5
|
||||
movl 44(%esp), %ebp // C arg7 -> syscall arg6
|
||||
|
||||
int $0x80
|
||||
|
||||
/* Restore registers */
|
||||
popl %ebp
|
||||
popl %edi
|
||||
popl %esi
|
||||
popl %ebx
|
||||
|
||||
cmpl $-4095, %eax
|
||||
jae 1f
|
||||
ret
|
||||
|
||||
1:
|
||||
negl %eax
|
||||
movl %eax, linux_errno
|
||||
movl $-1, %eax
|
||||
ret
|
||||
|
||||
.size linux_syscall, . - linux_syscall
|
51
ipxe/src/arch/i386/core/nulltrap.c
Normal file
51
ipxe/src/arch/i386/core/nulltrap.c
Normal file
@@ -0,0 +1,51 @@
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
__attribute__ (( noreturn, section ( ".text.null_trap" ) ))
|
||||
void null_function_trap ( void ) {
|
||||
void *stack;
|
||||
|
||||
/* 128 bytes of NOPs; the idea of this is that if something
|
||||
* dereferences a NULL pointer and overwrites us, we at least
|
||||
* have some chance of still getting to execute the printf()
|
||||
* statement.
|
||||
*/
|
||||
__asm__ __volatile__ ( "nop ; nop ; nop ; nop" );
|
||||
__asm__ __volatile__ ( "nop ; nop ; nop ; nop" );
|
||||
__asm__ __volatile__ ( "nop ; nop ; nop ; nop" );
|
||||
__asm__ __volatile__ ( "nop ; nop ; nop ; nop" );
|
||||
__asm__ __volatile__ ( "nop ; nop ; nop ; nop" );
|
||||
__asm__ __volatile__ ( "nop ; nop ; nop ; nop" );
|
||||
__asm__ __volatile__ ( "nop ; nop ; nop ; nop" );
|
||||
__asm__ __volatile__ ( "nop ; nop ; nop ; nop" );
|
||||
__asm__ __volatile__ ( "nop ; nop ; nop ; nop" );
|
||||
__asm__ __volatile__ ( "nop ; nop ; nop ; nop" );
|
||||
__asm__ __volatile__ ( "nop ; nop ; nop ; nop" );
|
||||
__asm__ __volatile__ ( "nop ; nop ; nop ; nop" );
|
||||
__asm__ __volatile__ ( "nop ; nop ; nop ; nop" );
|
||||
__asm__ __volatile__ ( "nop ; nop ; nop ; nop" );
|
||||
__asm__ __volatile__ ( "nop ; nop ; nop ; nop" );
|
||||
__asm__ __volatile__ ( "nop ; nop ; nop ; nop" );
|
||||
__asm__ __volatile__ ( "nop ; nop ; nop ; nop" );
|
||||
__asm__ __volatile__ ( "nop ; nop ; nop ; nop" );
|
||||
__asm__ __volatile__ ( "nop ; nop ; nop ; nop" );
|
||||
__asm__ __volatile__ ( "nop ; nop ; nop ; nop" );
|
||||
__asm__ __volatile__ ( "nop ; nop ; nop ; nop" );
|
||||
__asm__ __volatile__ ( "nop ; nop ; nop ; nop" );
|
||||
__asm__ __volatile__ ( "nop ; nop ; nop ; nop" );
|
||||
__asm__ __volatile__ ( "nop ; nop ; nop ; nop" );
|
||||
__asm__ __volatile__ ( "nop ; nop ; nop ; nop" );
|
||||
__asm__ __volatile__ ( "nop ; nop ; nop ; nop" );
|
||||
__asm__ __volatile__ ( "nop ; nop ; nop ; nop" );
|
||||
__asm__ __volatile__ ( "nop ; nop ; nop ; nop" );
|
||||
__asm__ __volatile__ ( "nop ; nop ; nop ; nop" );
|
||||
__asm__ __volatile__ ( "nop ; nop ; nop ; nop" );
|
||||
__asm__ __volatile__ ( "nop ; nop ; nop ; nop" );
|
||||
__asm__ __volatile__ ( "nop ; nop ; nop ; nop" );
|
||||
|
||||
__asm__ __volatile__ ( "movl %%esp, %0" : "=r" ( stack ) );
|
||||
printf ( "NULL method called from %p (stack %p)\n",
|
||||
__builtin_return_address ( 0 ), stack );
|
||||
DBG_HD ( stack, 256 );
|
||||
while ( 1 ) {}
|
||||
}
|
38
ipxe/src/arch/i386/core/patch_cf.S
Normal file
38
ipxe/src/arch/i386/core/patch_cf.S
Normal file
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* 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
|
66
ipxe/src/arch/i386/core/pic8259.c
Normal file
66
ipxe/src/arch/i386/core/pic8259.c
Normal file
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* 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 );
|
||||
}
|
89
ipxe/src/arch/i386/core/rdtsc_timer.c
Normal file
89
ipxe/src/arch/i386/core/rdtsc_timer.c
Normal file
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* 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 );
|
129
ipxe/src/arch/i386/core/relocate.c
Normal file
129
ipxe/src/arch/i386/core/relocate.c
Normal file
@@ -0,0 +1,129 @@
|
||||
#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;
|
||||
}
|
42
ipxe/src/arch/i386/core/setjmp.S
Normal file
42
ipxe/src/arch/i386/core/setjmp.S
Normal file
@@ -0,0 +1,42 @@
|
||||
/* setjmp and longjmp. Use of these functions is deprecated. */
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER )
|
||||
|
||||
.text
|
||||
.arch i386
|
||||
.code32
|
||||
|
||||
/**************************************************************************
|
||||
SETJMP - 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
|
||||
ret
|
||||
|
||||
/**************************************************************************
|
||||
LONGJMP - 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)
|
||||
ret
|
15
ipxe/src/arch/i386/core/stack.S
Normal file
15
ipxe/src/arch/i386/core/stack.S
Normal file
@@ -0,0 +1,15 @@
|
||||
FILE_LICENCE ( GPL2_OR_LATER )
|
||||
|
||||
.arch i386
|
||||
|
||||
/****************************************************************************
|
||||
* Internal stack
|
||||
****************************************************************************
|
||||
*/
|
||||
.section ".stack", "aw", @nobits
|
||||
.align 8
|
||||
.globl _stack
|
||||
_stack:
|
||||
.space 4096
|
||||
.globl _estack
|
||||
_estack:
|
15
ipxe/src/arch/i386/core/stack16.S
Normal file
15
ipxe/src/arch/i386/core/stack16.S
Normal file
@@ -0,0 +1,15 @@
|
||||
FILE_LICENCE ( GPL2_OR_LATER )
|
||||
|
||||
.arch i386
|
||||
|
||||
/****************************************************************************
|
||||
* Internal stack
|
||||
****************************************************************************
|
||||
*/
|
||||
.section ".stack16", "aw", @nobits
|
||||
.align 8
|
||||
.globl _stack16
|
||||
_stack16:
|
||||
.space 4096
|
||||
.globl _estack16
|
||||
_estack16:
|
87
ipxe/src/arch/i386/core/timer2.c
Normal file
87
ipxe/src/arch/i386/core/timer2.c
Normal file
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* 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 */
|
||||
}
|
||||
}
|
104
ipxe/src/arch/i386/core/video_subr.c
Normal file
104
ipxe/src/arch/i386/core/video_subr.c
Normal file
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
*
|
||||
* 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,
|
||||
};
|
103
ipxe/src/arch/i386/core/virtaddr.S
Normal file
103
ipxe/src/arch/i386/core/virtaddr.S
Normal file
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
* 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
|
273
ipxe/src/arch/i386/core/wince_loader.c
Normal file
273
ipxe/src/arch/i386/core/wince_loader.c
Normal file
@@ -0,0 +1,273 @@
|
||||
#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);
|
||||
}
|
96
ipxe/src/arch/i386/core/x86_io.c
Normal file
96
ipxe/src/arch/i386/core/x86_io.c
Normal file
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* 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 );
|
148
ipxe/src/arch/i386/drivers/net/undi.c
Normal file
148
ipxe/src/arch/i386/drivers/net/undi.c
Normal file
@@ -0,0 +1,148 @@
|
||||
/*
|
||||
* 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,
|
||||
};
|
87
ipxe/src/arch/i386/drivers/net/undiisr.S
Normal file
87
ipxe/src/arch/i386/drivers/net/undiisr.S
Normal file
@@ -0,0 +1,87 @@
|
||||
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
|
173
ipxe/src/arch/i386/drivers/net/undiload.c
Normal file
173
ipxe/src/arch/i386/drivers/net/undiload.c
Normal file
@@ -0,0 +1,173 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
}
|
631
ipxe/src/arch/i386/drivers/net/undinet.c
Normal file
631
ipxe/src/arch/i386/drivers/net/undinet.c
Normal file
@@ -0,0 +1,631 @@
|
||||
/*
|
||||
* 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 );
|
||||
}
|
129
ipxe/src/arch/i386/drivers/net/undionly.c
Normal file
129
ipxe/src/arch/i386/drivers/net/undionly.c
Normal file
@@ -0,0 +1,129 @@
|
||||
/*
|
||||
* 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,
|
||||
};
|
37
ipxe/src/arch/i386/drivers/net/undipreload.c
Normal file
37
ipxe/src/arch/i386/drivers/net/undipreload.c
Normal file
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* 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 );
|
234
ipxe/src/arch/i386/drivers/net/undirom.c
Normal file
234
ipxe/src/arch/i386/drivers/net/undirom.c
Normal file
@@ -0,0 +1,234 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
46
ipxe/src/arch/i386/firmware/pcbios/basemem.c
Normal file
46
ipxe/src/arch/i386/firmware/pcbios/basemem.c
Normal file
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* 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();
|
||||
}
|
298
ipxe/src/arch/i386/firmware/pcbios/bios_console.c
Normal file
298
ipxe/src/arch/i386/firmware/pcbios/bios_console.c
Normal file
@@ -0,0 +1,298 @@
|
||||
/*
|
||||
* 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,
|
||||
};
|
584
ipxe/src/arch/i386/firmware/pcbios/e820mangler.S
Normal file
584
ipxe/src/arch/i386/firmware/pcbios/e820mangler.S
Normal file
@@ -0,0 +1,584 @@
|
||||
/*
|
||||
* 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
|
93
ipxe/src/arch/i386/firmware/pcbios/fakee820.c
Normal file
93
ipxe/src/arch/i386/firmware/pcbios/fakee820.c
Normal file
@@ -0,0 +1,93 @@
|
||||
/* 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 );
|
||||
}
|
220
ipxe/src/arch/i386/firmware/pcbios/hidemem.c
Normal file
220
ipxe/src/arch/i386/firmware/pcbios/hidemem.c
Normal file
@@ -0,0 +1,220 @@
|
||||
/* 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,
|
||||
};
|
314
ipxe/src/arch/i386/firmware/pcbios/memmap.c
Normal file
314
ipxe/src/arch/i386/firmware/pcbios/memmap.c
Normal file
@@ -0,0 +1,314 @@
|
||||
/*
|
||||
* 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 );
|
109
ipxe/src/arch/i386/firmware/pcbios/pnpbios.c
Normal file
109
ipxe/src/arch/i386/firmware/pcbios/pnpbios.c
Normal file
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
33
ipxe/src/arch/i386/hci/commands/pxe_cmd.c
Normal file
33
ipxe/src/arch/i386/hci/commands/pxe_cmd.c
Normal file
@@ -0,0 +1,33 @@
|
||||
#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,
|
||||
},
|
||||
};
|
114
ipxe/src/arch/i386/image/bootsector.c
Normal file
114
ipxe/src/arch/i386/image/bootsector.c
Normal file
@@ -0,0 +1,114 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user