mirror of
https://github.com/xcat2/xNBA.git
synced 2025-08-29 06:18:16 +00:00
Init ipxe source code cloned fron ipxe.org at Oct 29th 2020
This commit is contained in:
57
.travis.yml
Normal file
57
.travis.yml
Normal file
@@ -0,0 +1,57 @@
|
||||
dist: trusty
|
||||
|
||||
sudo: false
|
||||
|
||||
git:
|
||||
depth: false
|
||||
|
||||
language: c
|
||||
|
||||
cache: ccache
|
||||
|
||||
compiler:
|
||||
- gcc
|
||||
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- binutils-dev
|
||||
- liblzma-dev
|
||||
- syslinux
|
||||
- genisoimage
|
||||
coverity_scan:
|
||||
project:
|
||||
name: "ipxe/ipxe"
|
||||
version: $TRAVIS_COMMIT
|
||||
build_command_prepend: "make -C src bin/deps"
|
||||
build_command: "make -C src bin/blib.a"
|
||||
branch_pattern: coverity_scan
|
||||
|
||||
env:
|
||||
global:
|
||||
- MAKEFLAGS="-j 4"
|
||||
|
||||
script:
|
||||
- make -C src bin/blib.a
|
||||
- make -C src bin/ipxe.pxe
|
||||
- make -C src bin/ipxe.usb
|
||||
- make -C src bin/ipxe.iso
|
||||
- make -C src bin/8086100e.mrom
|
||||
- make -C src bin-x86_64-pcbios/blib.a
|
||||
- make -C src bin-x86_64-pcbios/ipxe.pxe
|
||||
- make -C src bin-x86_64-pcbios/ipxe.usb
|
||||
- make -C src bin-x86_64-pcbios/ipxe.iso
|
||||
- make -C src bin-x86_64-pcbios/8086100e.mrom
|
||||
- make -C src bin-x86_64-efi/blib.a
|
||||
- make -C src bin-x86_64-efi/ipxe.efi
|
||||
- make -C src bin-x86_64-efi/intel.efidrv
|
||||
- make -C src bin-x86_64-efi/intel.efirom
|
||||
- make -C src bin-i386-efi/blib.a
|
||||
- make -C src bin-i386-efi/ipxe.efi
|
||||
- make -C src bin-i386-efi/intel.efidrv
|
||||
- make -C src bin-i386-efi/intel.efirom
|
||||
- make -C src bin-x86_64-linux/blib.a
|
||||
- make -C src bin-x86_64-linux/tap.linux
|
||||
- make -C src bin-x86_64-linux/af_packet.linux
|
||||
- make -C src bin-x86_64-linux/tests.linux
|
||||
- ./src/bin-x86_64-linux/tests.linux
|
339
COPYING.GPLv2
Normal file
339
COPYING.GPLv2
Normal file
@@ -0,0 +1,339 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Lesser General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) year name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License.
|
59
COPYING.UBDL
Normal file
59
COPYING.UBDL
Normal file
@@ -0,0 +1,59 @@
|
||||
UNMODIFIED BINARY DISTRIBUTION LICENCE
|
||||
|
||||
|
||||
PREAMBLE
|
||||
|
||||
The GNU General Public License provides a legal guarantee that
|
||||
software covered by it remains free (in the sense of freedom, not
|
||||
price). It achieves this guarantee by imposing obligations on anyone
|
||||
who chooses to distribute the software.
|
||||
|
||||
Some of these obligations may be seen as unnecessarily burdensome. In
|
||||
particular, when the source code for the software is already publicly
|
||||
and freely available, there is minimal value in imposing upon each
|
||||
distributor the obligation to provide the complete source code (or an
|
||||
equivalent written offer to provide the complete source code).
|
||||
|
||||
This Licence allows for the distribution of unmodified binaries built
|
||||
from publicly available source code, without imposing the obligations
|
||||
of the GNU General Public License upon anyone who chooses to
|
||||
distribute only the unmodified binaries built from that source code.
|
||||
|
||||
The extra permissions granted by this Licence apply only to unmodified
|
||||
binaries built from source code which has already been made available
|
||||
to the public in accordance with the terms of the GNU General Public
|
||||
Licence. Nothing in this Licence allows for the creation of
|
||||
closed-source modified versions of the Program. Any modified versions
|
||||
of the Program are subject to the usual terms and conditions of the
|
||||
GNU General Public License.
|
||||
|
||||
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
This Licence 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 Unmodified Binary Distribution Licence. All
|
||||
terms used in the text of this Licence are to be interpreted as they
|
||||
are used in version 2 of the GNU General Public License as published
|
||||
by the Free Software Foundation.
|
||||
|
||||
If you have made this Program available to the public in both source
|
||||
code and executable form in accordance with 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, then you are hereby granted an additional permission to use,
|
||||
copy, and distribute the unmodified executable form of this Program
|
||||
(the "Unmodified Binary") without restriction, including the right to
|
||||
permit persons to whom the Unmodified Binary is furnished to do
|
||||
likewise, subject to the following conditions:
|
||||
|
||||
- when started running, the Program must display an announcement which
|
||||
includes the details of your existing publication of the Program
|
||||
made in accordance with the terms of the GNU General Public License.
|
||||
For example, the Program could display the URL of the publicly
|
||||
available source code from which the Unmodified Binary was built.
|
||||
|
||||
- when exercising your right to grant permissions under this Licence,
|
||||
you do not need to refer directly to the text of this Licence, but
|
||||
you may not grant permissions beyond those granted to you by this
|
||||
Licence.
|
29
contrib/coverity/model.c
Normal file
29
contrib/coverity/model.c
Normal file
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Coverity modelling file
|
||||
*
|
||||
*/
|
||||
|
||||
typedef long off_t;
|
||||
typedef void * userptr_t;
|
||||
typedef long long time_t;
|
||||
struct tm;
|
||||
typedef unsigned short wchar_t;
|
||||
typedef void mbstate_t;
|
||||
struct digest_algorithm;
|
||||
|
||||
/* Inhibit use of built-in models for functions where Coverity's
|
||||
* assumptions about the modelled function are incorrect for iPXE.
|
||||
*/
|
||||
char * strerror ( int errno ) {
|
||||
}
|
||||
void copy_from_user ( void *dest, userptr_t src, off_t src_off, size_t len ) {
|
||||
}
|
||||
time_t mktime ( struct tm *tm ) {
|
||||
}
|
||||
int getchar ( void ) {
|
||||
}
|
||||
size_t wcrtomb ( char *buf, wchar_t wc, mbstate_t *ps ) {
|
||||
}
|
||||
void hmac_init ( struct digest_algorithm *digest, void *digest_ctx,
|
||||
void *key, size_t *key_len ) {
|
||||
}
|
54
src/Makefile.efi
Normal file
54
src/Makefile.efi
Normal file
@@ -0,0 +1,54 @@
|
||||
# -*- makefile -*- : Force emacs to use Makefile mode
|
||||
|
||||
# Enable stack protection if available
|
||||
#
|
||||
SPG_TEST = $(CC) -fstack-protector-strong -mstack-protector-guard=global \
|
||||
-x c -c /dev/null -o /dev/null >/dev/null 2>&1
|
||||
SPG_FLAGS := $(shell $(SPG_TEST) && $(ECHO) '-fstack-protector-strong ' \
|
||||
'-mstack-protector-guard=global')
|
||||
CFLAGS += $(SPG_FLAGS)
|
||||
|
||||
# The EFI linker script
|
||||
#
|
||||
LDSCRIPT = scripts/efi.lds
|
||||
|
||||
# Retain relocation information for elf2efi
|
||||
#
|
||||
LDFLAGS += -q -S
|
||||
|
||||
# Media types.
|
||||
#
|
||||
NON_AUTO_MEDIA += efi
|
||||
NON_AUTO_MEDIA += efidrv
|
||||
NON_AUTO_MEDIA += drv.efi
|
||||
NON_AUTO_MEDIA += efirom
|
||||
|
||||
# Include SNP driver in the all-drivers build
|
||||
#
|
||||
DRIVERS_net += snp
|
||||
|
||||
# Rules for building EFI files
|
||||
#
|
||||
$(BIN)/%.efi : $(BIN)/%.efi.tmp $(ELF2EFI)
|
||||
$(QM)$(ECHO) " [FINISH] $@"
|
||||
$(Q)$(ELF2EFI) --subsystem=10 $< $@
|
||||
|
||||
$(BIN)/%.efidrv : $(BIN)/%.efidrv.tmp $(ELF2EFI)
|
||||
$(QM)$(ECHO) " [FINISH] $@"
|
||||
$(Q)$(ELF2EFI) --subsystem=11 $< $@
|
||||
|
||||
$(BIN)/%.drv.efi : $(BIN)/%.efidrv
|
||||
$(QM)$(ECHO) " [FINISH] $@"
|
||||
$(Q)$(CP) $< $@
|
||||
|
||||
$(BIN)/%.efirom : $(BIN)/%.efidrv $(EFIROM)
|
||||
$(QM)$(ECHO) " [FINISH] $@"
|
||||
$(Q)$(EFIROM) -v $(TGT_PCI_VENDOR) -d $(TGT_PCI_DEVICE) $< $@
|
||||
|
||||
$(BIN)/efidrv.cab : $(BIN)/alldrv.efis # $(ALL_drv.efi) is not yet defined
|
||||
$(QM)$(ECHO) " [CAB] $@"
|
||||
$(Q)$(LCAB) -n -q $(ALL_drv.efi) $@
|
||||
|
||||
$(BIN)/%.usb : $(BIN)/%.efi
|
||||
$(QM)$(ECHO) " [GENEFIDSK] $@"
|
||||
$(Q)bash util/genefidsk -o $@ -b $(EFI_BOOT_FILE) $<
|
12
src/arch/arm/Makefile
Normal file
12
src/arch/arm/Makefile
Normal file
@@ -0,0 +1,12 @@
|
||||
# Assembler section type character
|
||||
#
|
||||
ASM_TCHAR := %
|
||||
ASM_TCHAR_OPS := %%
|
||||
|
||||
# Include common ARM headers
|
||||
#
|
||||
INCDIRS += arch/arm/include
|
||||
|
||||
# ARM-specific directories containing source files
|
||||
#
|
||||
SRCDIRS += arch/arm/interface/efi
|
6
src/arch/arm/Makefile.efi
Normal file
6
src/arch/arm/Makefile.efi
Normal file
@@ -0,0 +1,6 @@
|
||||
# -*- makefile -*- : Force emacs to use Makefile mode
|
||||
|
||||
# Include generic EFI Makefile
|
||||
#
|
||||
MAKEDEPS += Makefile.efi
|
||||
include Makefile.efi
|
93
src/arch/arm/core/arm_io.c
Normal file
93
src/arch/arm/core/arm_io.c
Normal file
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* Copyright (C) 2016 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., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA.
|
||||
*
|
||||
* You can also choose to distribute this program under the terms of
|
||||
* the Unmodified Binary Distribution Licence (as given in the file
|
||||
* COPYING.UBDL), provided that you have satisfied its requirements.
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
#include <ipxe/io.h>
|
||||
#include <ipxe/arm_io.h>
|
||||
|
||||
/** @file
|
||||
*
|
||||
* iPXE I/O API for ARM
|
||||
*
|
||||
*/
|
||||
|
||||
/** An ARM I/O qword */
|
||||
union arm32_io_qword {
|
||||
uint64_t qword;
|
||||
uint32_t dword[2];
|
||||
};
|
||||
|
||||
/**
|
||||
* Read 64-bit qword from memory-mapped device
|
||||
*
|
||||
* @v io_addr I/O address
|
||||
* @ret data Value read
|
||||
*
|
||||
* This is not atomic for ARM32.
|
||||
*/
|
||||
static uint64_t arm32_readq ( volatile uint64_t *io_addr ) {
|
||||
volatile union arm32_io_qword *ptr =
|
||||
container_of ( io_addr, union arm32_io_qword, qword );
|
||||
union arm32_io_qword tmp;
|
||||
|
||||
tmp.dword[0] = readl ( &ptr->dword[0] );
|
||||
tmp.dword[1] = readl ( &ptr->dword[1] );
|
||||
return tmp.qword;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write 64-bit qword to memory-mapped device
|
||||
*
|
||||
* @v data Value to write
|
||||
* @v io_addr I/O address
|
||||
*
|
||||
* This is not atomic for ARM32.
|
||||
*/
|
||||
static void arm32_writeq ( uint64_t data, volatile uint64_t *io_addr ) {
|
||||
volatile union arm32_io_qword *ptr =
|
||||
container_of ( io_addr, union arm32_io_qword, qword );
|
||||
union arm32_io_qword tmp;
|
||||
|
||||
tmp.qword = data;
|
||||
writel ( tmp.dword[0], &ptr->dword[0] );
|
||||
writel ( tmp.dword[1], &ptr->dword[1] );
|
||||
}
|
||||
|
||||
PROVIDE_IOAPI_INLINE ( arm, phys_to_bus );
|
||||
PROVIDE_IOAPI_INLINE ( arm, bus_to_phys );
|
||||
PROVIDE_IOAPI_INLINE ( arm, readb );
|
||||
PROVIDE_IOAPI_INLINE ( arm, readw );
|
||||
PROVIDE_IOAPI_INLINE ( arm, readl );
|
||||
PROVIDE_IOAPI_INLINE ( arm, writeb );
|
||||
PROVIDE_IOAPI_INLINE ( arm, writew );
|
||||
PROVIDE_IOAPI_INLINE ( arm, writel );
|
||||
PROVIDE_IOAPI_INLINE ( arm, iodelay );
|
||||
PROVIDE_IOAPI_INLINE ( arm, mb );
|
||||
#ifdef __aarch64__
|
||||
PROVIDE_IOAPI_INLINE ( arm, readq );
|
||||
PROVIDE_IOAPI_INLINE ( arm, writeq );
|
||||
#else
|
||||
PROVIDE_IOAPI ( arm, readq, arm32_readq );
|
||||
PROVIDE_IOAPI ( arm, writeq, arm32_writeq );
|
||||
#endif
|
12
src/arch/arm/include/bits/acpi.h
Normal file
12
src/arch/arm/include/bits/acpi.h
Normal file
@@ -0,0 +1,12 @@
|
||||
#ifndef _BITS_ACPI_H
|
||||
#define _BITS_ACPI_H
|
||||
|
||||
/** @file
|
||||
*
|
||||
* ARM-specific ACPI API implementations
|
||||
*
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
#endif /* _BITS_ACPI_H */
|
13
src/arch/arm/include/bits/endian.h
Normal file
13
src/arch/arm/include/bits/endian.h
Normal file
@@ -0,0 +1,13 @@
|
||||
#ifndef _BITS_ENDIAN_H
|
||||
#define _BITS_ENDIAN_H
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
/* ARM may be either little-endian or big-endian */
|
||||
#ifdef __ARM_BIG_ENDIAN
|
||||
#define __BYTE_ORDER __BIG_ENDIAN
|
||||
#else
|
||||
#define __BYTE_ORDER __LITTLE_ENDIAN
|
||||
#endif
|
||||
|
||||
#endif /* _BITS_ENDIAN_H */
|
12
src/arch/arm/include/bits/entropy.h
Normal file
12
src/arch/arm/include/bits/entropy.h
Normal file
@@ -0,0 +1,12 @@
|
||||
#ifndef _BITS_ENTROPY_H
|
||||
#define _BITS_ENTROPY_H
|
||||
|
||||
/** @file
|
||||
*
|
||||
* ARM-specific entropy API implementations
|
||||
*
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
#endif /* _BITS_ENTROPY_H */
|
19
src/arch/arm/include/bits/errfile.h
Normal file
19
src/arch/arm/include/bits/errfile.h
Normal file
@@ -0,0 +1,19 @@
|
||||
#ifndef _BITS_ERRFILE_H
|
||||
#define _BITS_ERRFILE_H
|
||||
|
||||
/** @file
|
||||
*
|
||||
* ARM-specific error file identifiers
|
||||
*
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
/**
|
||||
* @addtogroup errfile Error file identifiers
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** @} */
|
||||
|
||||
#endif /* _BITS_ERRFILE_H */
|
12
src/arch/arm/include/bits/hyperv.h
Normal file
12
src/arch/arm/include/bits/hyperv.h
Normal file
@@ -0,0 +1,12 @@
|
||||
#ifndef _BITS_HYPERV_H
|
||||
#define _BITS_HYPERV_H
|
||||
|
||||
/** @file
|
||||
*
|
||||
* Hyper-V interface
|
||||
*
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
#endif /* _BITS_HYPERV_H */
|
14
src/arch/arm/include/bits/io.h
Normal file
14
src/arch/arm/include/bits/io.h
Normal file
@@ -0,0 +1,14 @@
|
||||
#ifndef _BITS_IO_H
|
||||
#define _BITS_IO_H
|
||||
|
||||
/** @file
|
||||
*
|
||||
* ARM-specific I/O API implementations
|
||||
*
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
#include <ipxe/arm_io.h>
|
||||
|
||||
#endif /* _BITS_IO_H */
|
12
src/arch/arm/include/bits/iomap.h
Normal file
12
src/arch/arm/include/bits/iomap.h
Normal file
@@ -0,0 +1,12 @@
|
||||
#ifndef _BITS_IOMAP_H
|
||||
#define _BITS_IOMAP_H
|
||||
|
||||
/** @file
|
||||
*
|
||||
* ARM-specific I/O mapping API implementations
|
||||
*
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
#endif /* _BITS_IOMAP_H */
|
14
src/arch/arm/include/bits/nap.h
Normal file
14
src/arch/arm/include/bits/nap.h
Normal file
@@ -0,0 +1,14 @@
|
||||
#ifndef _BITS_NAP_H
|
||||
#define _BITS_NAP_H
|
||||
|
||||
/** @file
|
||||
*
|
||||
* ARM-specific CPU sleeping API implementations
|
||||
*
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
#include <ipxe/efi/efiarm_nap.h>
|
||||
|
||||
#endif /* _BITS_MAP_H */
|
14
src/arch/arm/include/bits/pci_io.h
Normal file
14
src/arch/arm/include/bits/pci_io.h
Normal file
@@ -0,0 +1,14 @@
|
||||
#ifndef _BITS_PCI_IO_H
|
||||
#define _BITS_PCI_IO_H
|
||||
|
||||
/** @file
|
||||
*
|
||||
* ARM PCI I/O API implementations
|
||||
*
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
#include <ipxe/io.h>
|
||||
|
||||
#endif /* _BITS_PCI_IO_H */
|
12
src/arch/arm/include/bits/reboot.h
Normal file
12
src/arch/arm/include/bits/reboot.h
Normal file
@@ -0,0 +1,12 @@
|
||||
#ifndef _BITS_REBOOT_H
|
||||
#define _BITS_REBOOT_H
|
||||
|
||||
/** @file
|
||||
*
|
||||
* ARM-specific reboot API implementations
|
||||
*
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
#endif /* _BITS_REBOOT_H */
|
12
src/arch/arm/include/bits/sanboot.h
Normal file
12
src/arch/arm/include/bits/sanboot.h
Normal file
@@ -0,0 +1,12 @@
|
||||
#ifndef _BITS_SANBOOT_H
|
||||
#define _BITS_SANBOOT_H
|
||||
|
||||
/** @file
|
||||
*
|
||||
* ARM-specific sanboot API implementations
|
||||
*
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
#endif /* _BITS_SANBOOT_H */
|
12
src/arch/arm/include/bits/smbios.h
Normal file
12
src/arch/arm/include/bits/smbios.h
Normal file
@@ -0,0 +1,12 @@
|
||||
#ifndef _BITS_SMBIOS_H
|
||||
#define _BITS_SMBIOS_H
|
||||
|
||||
/** @file
|
||||
*
|
||||
* ARM-specific SMBIOS API implementations
|
||||
*
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
#endif /* _BITS_SMBIOS_H */
|
12
src/arch/arm/include/bits/time.h
Normal file
12
src/arch/arm/include/bits/time.h
Normal file
@@ -0,0 +1,12 @@
|
||||
#ifndef _BITS_TIME_H
|
||||
#define _BITS_TIME_H
|
||||
|
||||
/** @file
|
||||
*
|
||||
* ARM-specific time API implementations
|
||||
*
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
#endif /* _BITS_TIME_H */
|
12
src/arch/arm/include/bits/uaccess.h
Normal file
12
src/arch/arm/include/bits/uaccess.h
Normal file
@@ -0,0 +1,12 @@
|
||||
#ifndef _BITS_UACCESS_H
|
||||
#define _BITS_UACCESS_H
|
||||
|
||||
/** @file
|
||||
*
|
||||
* ARM-specific user access API implementations
|
||||
*
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
#endif /* _BITS_UACCESS_H */
|
12
src/arch/arm/include/bits/uart.h
Normal file
12
src/arch/arm/include/bits/uart.h
Normal file
@@ -0,0 +1,12 @@
|
||||
#ifndef _BITS_UART_H
|
||||
#define _BITS_UART_H
|
||||
|
||||
/** @file
|
||||
*
|
||||
* 16550-compatible UART
|
||||
*
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
#endif /* _BITS_UART_H */
|
12
src/arch/arm/include/bits/umalloc.h
Normal file
12
src/arch/arm/include/bits/umalloc.h
Normal file
@@ -0,0 +1,12 @@
|
||||
#ifndef _BITS_UMALLOC_H
|
||||
#define _BITS_UMALLOC_H
|
||||
|
||||
/** @file
|
||||
*
|
||||
* ARM-specific user memory allocation API implementations
|
||||
*
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
#endif /* _BITS_UMALLOC_H */
|
158
src/arch/arm/include/bits/xen.h
Normal file
158
src/arch/arm/include/bits/xen.h
Normal file
@@ -0,0 +1,158 @@
|
||||
#ifndef _BITS_XEN_H
|
||||
#define _BITS_XEN_H
|
||||
|
||||
/** @file
|
||||
*
|
||||
* Xen interface
|
||||
*
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
/* Hypercall registers */
|
||||
#ifdef __aarch64__
|
||||
#define XEN_HC "x16"
|
||||
#define XEN_REG1 "x0"
|
||||
#define XEN_REG2 "x1"
|
||||
#define XEN_REG3 "x2"
|
||||
#define XEN_REG4 "x3"
|
||||
#define XEN_REG5 "x4"
|
||||
#else
|
||||
#define XEN_HC "r12"
|
||||
#define XEN_REG1 "r0"
|
||||
#define XEN_REG2 "r1"
|
||||
#define XEN_REG3 "r2"
|
||||
#define XEN_REG4 "r3"
|
||||
#define XEN_REG5 "r4"
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Issue hypercall with one argument
|
||||
*
|
||||
* @v xen Xen hypervisor
|
||||
* @v hypercall Hypercall number
|
||||
* @v arg1 First argument
|
||||
* @ret retval Return value
|
||||
*/
|
||||
static inline __attribute__ (( always_inline )) unsigned long
|
||||
xen_hypercall_1 ( struct xen_hypervisor *xen __unused, unsigned int hypercall,
|
||||
unsigned long arg1 ) {
|
||||
register unsigned long hc asm ( XEN_HC ) = hypercall;
|
||||
register unsigned long reg1 asm ( XEN_REG1 ) = arg1;
|
||||
|
||||
__asm__ __volatile__ ( "hvc %1"
|
||||
: "+r" ( reg1 )
|
||||
: "i" ( XEN_HYPERCALL_TAG ), "r" ( hc )
|
||||
: "memory", "cc" );
|
||||
return reg1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Issue hypercall with two arguments
|
||||
*
|
||||
* @v xen Xen hypervisor
|
||||
* @v hypercall Hypercall number
|
||||
* @v arg1 First argument
|
||||
* @v arg2 Second argument
|
||||
* @ret retval Return value
|
||||
*/
|
||||
static inline __attribute__ (( always_inline )) unsigned long
|
||||
xen_hypercall_2 ( struct xen_hypervisor *xen __unused, unsigned int hypercall,
|
||||
unsigned long arg1, unsigned long arg2 ) {
|
||||
register unsigned long hc asm ( XEN_HC ) = hypercall;
|
||||
register unsigned long reg1 asm ( XEN_REG1 ) = arg1;
|
||||
register unsigned long reg2 asm ( XEN_REG2 ) = arg2;
|
||||
|
||||
__asm__ __volatile__ ( "hvc %2"
|
||||
: "+r" ( reg1 ), "+r" ( reg2 )
|
||||
: "i" ( XEN_HYPERCALL_TAG ), "r" ( hc )
|
||||
: "memory", "cc" );
|
||||
return reg1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Issue hypercall with three arguments
|
||||
*
|
||||
* @v xen Xen hypervisor
|
||||
* @v hypercall Hypercall number
|
||||
* @v arg1 First argument
|
||||
* @v arg2 Second argument
|
||||
* @v arg3 Third argument
|
||||
* @ret retval Return value
|
||||
*/
|
||||
static inline __attribute__ (( always_inline )) unsigned long
|
||||
xen_hypercall_3 ( struct xen_hypervisor *xen __unused, unsigned int hypercall,
|
||||
unsigned long arg1, unsigned long arg2, unsigned long arg3 ) {
|
||||
register unsigned long hc asm ( XEN_HC ) = hypercall;
|
||||
register unsigned long reg1 asm ( XEN_REG1 ) = arg1;
|
||||
register unsigned long reg2 asm ( XEN_REG2 ) = arg2;
|
||||
register unsigned long reg3 asm ( XEN_REG3 ) = arg3;
|
||||
|
||||
__asm__ __volatile__ ( "hvc %3"
|
||||
: "+r" ( reg1 ), "+r" ( reg2 ), "+r" ( reg3 )
|
||||
: "i" ( XEN_HYPERCALL_TAG ), "r" ( hc )
|
||||
: "memory", "cc" );
|
||||
return reg1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Issue hypercall with four arguments
|
||||
*
|
||||
* @v xen Xen hypervisor
|
||||
* @v hypercall Hypercall number
|
||||
* @v arg1 First argument
|
||||
* @v arg2 Second argument
|
||||
* @v arg3 Third argument
|
||||
* @v arg4 Fourth argument
|
||||
* @ret retval Return value
|
||||
*/
|
||||
static inline __attribute__ (( always_inline )) unsigned long
|
||||
xen_hypercall_4 ( struct xen_hypervisor *xen __unused, unsigned int hypercall,
|
||||
unsigned long arg1, unsigned long arg2, unsigned long arg3,
|
||||
unsigned long arg4 ) {
|
||||
register unsigned long hc asm ( XEN_HC ) = hypercall;
|
||||
register unsigned long reg1 asm ( XEN_REG1 ) = arg1;
|
||||
register unsigned long reg2 asm ( XEN_REG2 ) = arg2;
|
||||
register unsigned long reg3 asm ( XEN_REG3 ) = arg3;
|
||||
register unsigned long reg4 asm ( XEN_REG4 ) = arg4;
|
||||
|
||||
__asm__ __volatile__ ( "hvc %4"
|
||||
: "+r" ( reg1 ), "+r" ( reg2 ), "+r" ( reg3 ),
|
||||
"+r" ( reg4 )
|
||||
: "i" ( XEN_HYPERCALL_TAG ), "r" ( hc )
|
||||
: "memory", "cc" );
|
||||
return reg1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Issue hypercall with five arguments
|
||||
*
|
||||
* @v xen Xen hypervisor
|
||||
* @v hypercall Hypercall number
|
||||
* @v arg1 First argument
|
||||
* @v arg2 Second argument
|
||||
* @v arg3 Third argument
|
||||
* @v arg4 Fourth argument
|
||||
* @v arg5 Fifth argument
|
||||
* @ret retval Return value
|
||||
*/
|
||||
static inline __attribute__ (( always_inline )) unsigned long
|
||||
xen_hypercall_5 ( struct xen_hypervisor *xen __unused, unsigned int hypercall,
|
||||
unsigned long arg1, unsigned long arg2, unsigned long arg3,
|
||||
unsigned long arg4, unsigned long arg5 ) {
|
||||
register unsigned long hc asm ( XEN_HC ) = hypercall;
|
||||
register unsigned long reg1 asm ( XEN_REG1 ) = arg1;
|
||||
register unsigned long reg2 asm ( XEN_REG2 ) = arg2;
|
||||
register unsigned long reg3 asm ( XEN_REG3 ) = arg3;
|
||||
register unsigned long reg4 asm ( XEN_REG4 ) = arg4;
|
||||
register unsigned long reg5 asm ( XEN_REG5 ) = arg5;
|
||||
|
||||
__asm__ __volatile__ ( "hvc %5"
|
||||
: "+r" ( reg1 ), "+r" ( reg2 ), "+r" ( reg3 ),
|
||||
"+r" ( reg4 ), "+r" ( reg5 )
|
||||
: "i" ( XEN_HYPERCALL_TAG ), "r" ( hc )
|
||||
: "memory", "cc" );
|
||||
return reg1;
|
||||
}
|
||||
|
||||
#endif /* _BITS_XEN_H */
|
146
src/arch/arm/include/ipxe/arm_io.h
Normal file
146
src/arch/arm/include/ipxe/arm_io.h
Normal file
@@ -0,0 +1,146 @@
|
||||
#ifndef _IPXE_ARM_IO_H
|
||||
#define _IPXE_ARM_IO_H
|
||||
|
||||
/** @file
|
||||
*
|
||||
* iPXE I/O API for ARM
|
||||
*
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
#ifdef IOAPI_ARM
|
||||
#define IOAPI_PREFIX_arm
|
||||
#else
|
||||
#define IOAPI_PREFIX_arm __arm_
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Memory space mappings
|
||||
*
|
||||
*/
|
||||
|
||||
/** Page shift */
|
||||
#define PAGE_SHIFT 12
|
||||
|
||||
/*
|
||||
* Physical<->Bus address mappings
|
||||
*
|
||||
*/
|
||||
|
||||
static inline __always_inline unsigned long
|
||||
IOAPI_INLINE ( arm, phys_to_bus ) ( unsigned long phys_addr ) {
|
||||
return phys_addr;
|
||||
}
|
||||
|
||||
static inline __always_inline unsigned long
|
||||
IOAPI_INLINE ( arm, bus_to_phys ) ( unsigned long bus_addr ) {
|
||||
return bus_addr;
|
||||
}
|
||||
|
||||
/*
|
||||
* MMIO reads and writes up to native word size
|
||||
*
|
||||
*/
|
||||
|
||||
#define ARM_READX( _suffix, _type, _insn_suffix, _reg_prefix ) \
|
||||
static inline __always_inline _type \
|
||||
IOAPI_INLINE ( arm, read ## _suffix ) ( volatile _type *io_addr ) { \
|
||||
_type data; \
|
||||
__asm__ __volatile__ ( "ldr" _insn_suffix " %" _reg_prefix "0, %1" \
|
||||
: "=r" ( data ) : "Qo" ( *io_addr ) ); \
|
||||
return data; \
|
||||
}
|
||||
#ifdef __aarch64__
|
||||
ARM_READX ( b, uint8_t, "b", "w" );
|
||||
ARM_READX ( w, uint16_t, "h", "w" );
|
||||
ARM_READX ( l, uint32_t, "", "w" );
|
||||
ARM_READX ( q, uint64_t, "", "" );
|
||||
#else
|
||||
ARM_READX ( b, uint8_t, "b", "" );
|
||||
ARM_READX ( w, uint16_t, "h", "" );
|
||||
ARM_READX ( l, uint32_t, "", "" );
|
||||
#endif
|
||||
|
||||
#define ARM_WRITEX( _suffix, _type, _insn_suffix, _reg_prefix ) \
|
||||
static inline __always_inline void \
|
||||
IOAPI_INLINE ( arm, write ## _suffix ) ( _type data, \
|
||||
volatile _type *io_addr ) { \
|
||||
__asm__ __volatile__ ( "str" _insn_suffix " %" _reg_prefix "0, %1" \
|
||||
: : "r" ( data ), "Qo" ( *io_addr ) ); \
|
||||
}
|
||||
#ifdef __aarch64__
|
||||
ARM_WRITEX ( b, uint8_t, "b", "w" );
|
||||
ARM_WRITEX ( w, uint16_t, "h", "w" );
|
||||
ARM_WRITEX ( l, uint32_t, "", "w" );
|
||||
ARM_WRITEX ( q, uint64_t, "", "" );
|
||||
#else
|
||||
ARM_WRITEX ( b, uint8_t, "b", "" );
|
||||
ARM_WRITEX ( w, uint16_t, "h", "" );
|
||||
ARM_WRITEX ( l, uint32_t, "", "" );
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Dummy PIO reads and writes up to 32 bits
|
||||
*
|
||||
* There is no common standard for I/O-space access for ARM, and
|
||||
* non-MMIO peripherals are vanishingly rare. Provide dummy
|
||||
* implementations that will allow code to link and should cause
|
||||
* drivers to simply fail to detect hardware at runtime.
|
||||
*
|
||||
*/
|
||||
|
||||
#define ARM_INX( _suffix, _type ) \
|
||||
static inline __always_inline _type \
|
||||
IOAPI_INLINE ( arm, in ## _suffix ) ( volatile _type *io_addr __unused) { \
|
||||
return ~( (_type) 0 ); \
|
||||
} \
|
||||
static inline __always_inline void \
|
||||
IOAPI_INLINE ( arm, ins ## _suffix ) ( volatile _type *io_addr __unused, \
|
||||
_type *data, unsigned int count ) { \
|
||||
memset ( data, 0xff, count * sizeof ( *data ) ); \
|
||||
}
|
||||
ARM_INX ( b, uint8_t );
|
||||
ARM_INX ( w, uint16_t );
|
||||
ARM_INX ( l, uint32_t );
|
||||
|
||||
#define ARM_OUTX( _suffix, _type ) \
|
||||
static inline __always_inline void \
|
||||
IOAPI_INLINE ( arm, out ## _suffix ) ( _type data __unused, \
|
||||
volatile _type *io_addr __unused ) { \
|
||||
/* Do nothing */ \
|
||||
} \
|
||||
static inline __always_inline void \
|
||||
IOAPI_INLINE ( arm, outs ## _suffix ) ( volatile _type *io_addr __unused, \
|
||||
const _type *data __unused, \
|
||||
unsigned int count __unused ) { \
|
||||
/* Do nothing */ \
|
||||
}
|
||||
ARM_OUTX ( b, uint8_t );
|
||||
ARM_OUTX ( w, uint16_t );
|
||||
ARM_OUTX ( l, uint32_t );
|
||||
|
||||
/*
|
||||
* Slow down I/O
|
||||
*
|
||||
*/
|
||||
static inline __always_inline void
|
||||
IOAPI_INLINE ( arm, iodelay ) ( void ) {
|
||||
/* Nothing to do */
|
||||
}
|
||||
|
||||
/*
|
||||
* Memory barrier
|
||||
*
|
||||
*/
|
||||
static inline __always_inline void
|
||||
IOAPI_INLINE ( arm, mb ) ( void ) {
|
||||
|
||||
#ifdef __aarch64__
|
||||
__asm__ __volatile__ ( "dmb sy" );
|
||||
#else
|
||||
__asm__ __volatile__ ( "dmb" );
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif /* _IPXE_ARM_IO_H */
|
18
src/arch/arm/include/ipxe/efi/efiarm_nap.h
Normal file
18
src/arch/arm/include/ipxe/efi/efiarm_nap.h
Normal file
@@ -0,0 +1,18 @@
|
||||
#ifndef _IPXE_EFIARM_NAP_H
|
||||
#define _IPXE_EFIARM_NAP_H
|
||||
|
||||
/** @file
|
||||
*
|
||||
* EFI CPU sleeping
|
||||
*
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
#ifdef NAP_EFIARM
|
||||
#define NAP_PREFIX_efiarm
|
||||
#else
|
||||
#define NAP_PREFIX_efiarm __efiarm_
|
||||
#endif
|
||||
|
||||
#endif /* _IPXE_EFIARM_NAP_H */
|
53
src/arch/arm/interface/efi/efiarm_nap.c
Normal file
53
src/arch/arm/interface/efi/efiarm_nap.c
Normal file
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright (C) 2016 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., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA.
|
||||
*
|
||||
* You can also choose to distribute this program under the terms of
|
||||
* the Unmodified Binary Distribution Licence (as given in the file
|
||||
* COPYING.UBDL), provided that you have satisfied its requirements.
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
#include <ipxe/nap.h>
|
||||
#include <ipxe/efi/efi.h>
|
||||
|
||||
/** @file
|
||||
*
|
||||
* iPXE CPU sleeping API for EFI
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Sleep until next interrupt
|
||||
*
|
||||
*/
|
||||
static void efiarm_cpu_nap ( void ) {
|
||||
/*
|
||||
* I can't find any EFI API that allows us to put the CPU to
|
||||
* sleep. The CpuSleep() function is defined in CpuLib.h, but
|
||||
* isn't part of any exposed protocol so we have no way to
|
||||
* call it.
|
||||
*
|
||||
* The EFI shell doesn't seem to bother sleeping the CPU; it
|
||||
* just sits there idly burning power.
|
||||
*
|
||||
*/
|
||||
__asm__ __volatile__ ( "wfi" );
|
||||
}
|
||||
|
||||
PROVIDE_NAP ( efiarm, cpu_nap, efiarm_cpu_nap );
|
23
src/arch/arm32/Makefile
Normal file
23
src/arch/arm32/Makefile
Normal file
@@ -0,0 +1,23 @@
|
||||
# ARM32-specific directories containing source files
|
||||
#
|
||||
SRCDIRS += arch/arm32/core
|
||||
SRCDIRS += arch/arm32/libgcc
|
||||
|
||||
# ARM32-specific flags
|
||||
#
|
||||
CFLAGS += -mthumb -mcpu=cortex-a15 -mabi=aapcs -mfloat-abi=soft
|
||||
CFLAGS += -mword-relocations
|
||||
ASFLAGS += -mthumb -mcpu=cortex-a15
|
||||
|
||||
# EFI requires -fshort-wchar, and nothing else currently uses wchar_t
|
||||
#
|
||||
CFLAGS += -fshort-wchar
|
||||
|
||||
# Include common ARM Makefile
|
||||
MAKEDEPS += arch/arm/Makefile
|
||||
include arch/arm/Makefile
|
||||
|
||||
# Include platform-specific Makefile
|
||||
#
|
||||
MAKEDEPS += arch/arm32/Makefile.$(PLATFORM)
|
||||
include arch/arm32/Makefile.$(PLATFORM)
|
18
src/arch/arm32/Makefile.efi
Normal file
18
src/arch/arm32/Makefile.efi
Normal file
@@ -0,0 +1,18 @@
|
||||
# -*- makefile -*- : Force emacs to use Makefile mode
|
||||
|
||||
# UEFI requires that enums are always 32 bits
|
||||
#
|
||||
CFLAGS += -fno-short-enums
|
||||
|
||||
# Specify EFI image builder
|
||||
#
|
||||
ELF2EFI = $(ELF2EFI32)
|
||||
|
||||
# Specify EFI boot file
|
||||
#
|
||||
EFI_BOOT_FILE = bootarm.efi
|
||||
|
||||
# Include generic EFI Makefile
|
||||
#
|
||||
MAKEDEPS += arch/arm/Makefile.efi
|
||||
include arch/arm/Makefile.efi
|
102
src/arch/arm32/core/arm32_bigint.c
Normal file
102
src/arch/arm32/core/arm32_bigint.c
Normal file
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Copyright (C) 2016 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., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA.
|
||||
*
|
||||
* You can also choose to distribute this program under the terms of
|
||||
* the Unmodified Binary Distribution Licence (as given in the file
|
||||
* COPYING.UBDL), provided that you have satisfied its requirements.
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <ipxe/bigint.h>
|
||||
|
||||
/** @file
|
||||
*
|
||||
* Big integer support
|
||||
*/
|
||||
|
||||
/**
|
||||
* Multiply big integers
|
||||
*
|
||||
* @v multiplicand0 Element 0 of big integer to be multiplied
|
||||
* @v multiplier0 Element 0 of big integer to be multiplied
|
||||
* @v result0 Element 0 of big integer to hold result
|
||||
* @v size Number of elements
|
||||
*/
|
||||
void bigint_multiply_raw ( const uint32_t *multiplicand0,
|
||||
const uint32_t *multiplier0,
|
||||
uint32_t *result0, unsigned int size ) {
|
||||
const bigint_t ( size ) __attribute__ (( may_alias )) *multiplicand =
|
||||
( ( const void * ) multiplicand0 );
|
||||
const bigint_t ( size ) __attribute__ (( may_alias )) *multiplier =
|
||||
( ( const void * ) multiplier0 );
|
||||
bigint_t ( size * 2 ) __attribute__ (( may_alias )) *result =
|
||||
( ( void * ) result0 );
|
||||
unsigned int i;
|
||||
unsigned int j;
|
||||
uint32_t multiplicand_element;
|
||||
uint32_t multiplier_element;
|
||||
uint32_t *result_elements;
|
||||
uint32_t discard_low;
|
||||
uint32_t discard_high;
|
||||
uint32_t discard_temp;
|
||||
|
||||
/* Zero result */
|
||||
memset ( result, 0, sizeof ( *result ) );
|
||||
|
||||
/* Multiply integers one element at a time */
|
||||
for ( i = 0 ; i < size ; i++ ) {
|
||||
multiplicand_element = multiplicand->element[i];
|
||||
for ( j = 0 ; j < size ; j++ ) {
|
||||
multiplier_element = multiplier->element[j];
|
||||
result_elements = &result->element[ i + j ];
|
||||
/* Perform a single multiply, and add the
|
||||
* resulting double-element into the result,
|
||||
* carrying as necessary. The carry can
|
||||
* never overflow beyond the end of the
|
||||
* result, since:
|
||||
*
|
||||
* a < 2^{n}, b < 2^{n} => ab < 2^{2n}
|
||||
*/
|
||||
__asm__ __volatile__ ( "umull %1, %2, %5, %6\n\t"
|
||||
"ldr %3, [%0]\n\t"
|
||||
"adds %3, %1\n\t"
|
||||
"stmia %0!, {%3}\n\t"
|
||||
"ldr %3, [%0]\n\t"
|
||||
"adcs %3, %2\n\t"
|
||||
"stmia %0!, {%3}\n\t"
|
||||
"bcc 2f\n\t"
|
||||
"\n1:\n\t"
|
||||
"ldr %3, [%0]\n\t"
|
||||
"adcs %3, #0\n\t"
|
||||
"stmia %0!, {%3}\n\t"
|
||||
"bcs 1b\n\t"
|
||||
"\n2:\n\t"
|
||||
: "+l" ( result_elements ),
|
||||
"=l" ( discard_low ),
|
||||
"=l" ( discard_high ),
|
||||
"=l" ( discard_temp ),
|
||||
"+m" ( *result )
|
||||
: "l" ( multiplicand_element ),
|
||||
"l" ( multiplier_element )
|
||||
: "cc" );
|
||||
}
|
||||
}
|
||||
}
|
32
src/arch/arm32/core/setjmp.S
Normal file
32
src/arch/arm32/core/setjmp.S
Normal file
@@ -0,0 +1,32 @@
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
|
||||
|
||||
.text
|
||||
.arm
|
||||
|
||||
/*
|
||||
* Save stack context for non-local goto
|
||||
*/
|
||||
.globl setjmp
|
||||
.type setjmp, %function
|
||||
setjmp:
|
||||
/* Store registers */
|
||||
stmia r0, { r4, r5, r6, r7, r8, r9, r10, fp, sp, lr }
|
||||
/* Return 0 when returning as setjmp() */
|
||||
mov r0, #0
|
||||
bx lr
|
||||
.size setjmp, . - setjmp
|
||||
|
||||
/*
|
||||
* Non-local jump to a saved stack context
|
||||
*/
|
||||
.globl longjmp
|
||||
.type longjmp, %function
|
||||
longjmp:
|
||||
/* Restore registers */
|
||||
ldmia r0, { r4, r5, r6, r7, r8, r9, r10, fp, sp, lr }
|
||||
/* Force result to non-zero */
|
||||
movs r0, r1
|
||||
moveq r0, #1
|
||||
/* Return to setjmp() caller */
|
||||
bx lr
|
||||
.size longjmp, . - longjmp
|
316
src/arch/arm32/include/bits/bigint.h
Normal file
316
src/arch/arm32/include/bits/bigint.h
Normal file
@@ -0,0 +1,316 @@
|
||||
#ifndef _BITS_BIGINT_H
|
||||
#define _BITS_BIGINT_H
|
||||
|
||||
/** @file
|
||||
*
|
||||
* Big integer support
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
|
||||
/** Element of a big integer */
|
||||
typedef uint32_t bigint_element_t;
|
||||
|
||||
/**
|
||||
* Initialise big integer
|
||||
*
|
||||
* @v value0 Element 0 of big integer to initialise
|
||||
* @v size Number of elements
|
||||
* @v data Raw data
|
||||
* @v len Length of raw data
|
||||
*/
|
||||
static inline __attribute__ (( always_inline )) void
|
||||
bigint_init_raw ( uint32_t *value0, unsigned int size,
|
||||
const void *data, size_t len ) {
|
||||
size_t pad_len = ( sizeof ( bigint_t ( size ) ) - len );
|
||||
uint8_t *value_byte = ( ( void * ) value0 );
|
||||
const uint8_t *data_byte = ( data + len );
|
||||
|
||||
/* Copy raw data in reverse order, padding with zeros */
|
||||
while ( len-- )
|
||||
*(value_byte++) = *(--data_byte);
|
||||
while ( pad_len-- )
|
||||
*(value_byte++) = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add big integers
|
||||
*
|
||||
* @v addend0 Element 0 of big integer to add
|
||||
* @v value0 Element 0 of big integer to be added to
|
||||
* @v size Number of elements
|
||||
*/
|
||||
static inline __attribute__ (( always_inline )) void
|
||||
bigint_add_raw ( const uint32_t *addend0, uint32_t *value0,
|
||||
unsigned int size ) {
|
||||
bigint_t ( size ) __attribute__ (( may_alias )) *value =
|
||||
( ( void * ) value0 );
|
||||
uint32_t *discard_addend;
|
||||
uint32_t *discard_value;
|
||||
uint32_t *discard_end;
|
||||
uint32_t discard_addend_i;
|
||||
uint32_t discard_value_i;
|
||||
|
||||
__asm__ __volatile__ ( "adds %2, %0, %8, lsl #2\n\t" /* clear CF */
|
||||
"\n1:\n\t"
|
||||
"ldmia %0!, {%3}\n\t"
|
||||
"ldr %4, [%1]\n\t"
|
||||
"adcs %4, %3\n\t"
|
||||
"stmia %1!, {%4}\n\t"
|
||||
"teq %0, %2\n\t"
|
||||
"bne 1b\n\t"
|
||||
: "=l" ( discard_addend ),
|
||||
"=l" ( discard_value ),
|
||||
"=l" ( discard_end ),
|
||||
"=l" ( discard_addend_i ),
|
||||
"=l" ( discard_value_i ),
|
||||
"+m" ( *value )
|
||||
: "0" ( addend0 ), "1" ( value0 ), "l" ( size )
|
||||
: "cc" );
|
||||
}
|
||||
|
||||
/**
|
||||
* Subtract big integers
|
||||
*
|
||||
* @v subtrahend0 Element 0 of big integer to subtract
|
||||
* @v value0 Element 0 of big integer to be subtracted from
|
||||
* @v size Number of elements
|
||||
*/
|
||||
static inline __attribute__ (( always_inline )) void
|
||||
bigint_subtract_raw ( const uint32_t *subtrahend0, uint32_t *value0,
|
||||
unsigned int size ) {
|
||||
bigint_t ( size ) __attribute__ (( may_alias )) *value =
|
||||
( ( void * ) value0 );
|
||||
uint32_t *discard_subtrahend;
|
||||
uint32_t *discard_value;
|
||||
uint32_t *discard_end;
|
||||
uint32_t discard_subtrahend_i;
|
||||
uint32_t discard_value_i;
|
||||
|
||||
__asm__ __volatile__ ( "add %2, %0, %8, lsl #2\n\t"
|
||||
"cmp %2, %0\n\t" /* set CF */
|
||||
"\n1:\n\t"
|
||||
"ldmia %0!, {%3}\n\t"
|
||||
"ldr %4, [%1]\n\t"
|
||||
"sbcs %4, %3\n\t"
|
||||
"stmia %1!, {%4}\n\t"
|
||||
"teq %0, %2\n\t"
|
||||
"bne 1b\n\t"
|
||||
: "=l" ( discard_subtrahend ),
|
||||
"=l" ( discard_value ),
|
||||
"=l" ( discard_end ),
|
||||
"=l" ( discard_subtrahend_i ),
|
||||
"=l" ( discard_value_i ),
|
||||
"+m" ( *value )
|
||||
: "0" ( subtrahend0 ), "1" ( value0 ),
|
||||
"l" ( size )
|
||||
: "cc" );
|
||||
}
|
||||
|
||||
/**
|
||||
* Rotate big integer left
|
||||
*
|
||||
* @v value0 Element 0 of big integer
|
||||
* @v size Number of elements
|
||||
*/
|
||||
static inline __attribute__ (( always_inline )) void
|
||||
bigint_rol_raw ( uint32_t *value0, unsigned int size ) {
|
||||
bigint_t ( size ) __attribute__ (( may_alias )) *value =
|
||||
( ( void * ) value0 );
|
||||
uint32_t *discard_value;
|
||||
uint32_t *discard_end;
|
||||
uint32_t discard_value_i;
|
||||
|
||||
__asm__ __volatile__ ( "adds %1, %0, %5, lsl #2\n\t" /* clear CF */
|
||||
"\n1:\n\t"
|
||||
"ldr %2, [%0]\n\t"
|
||||
"adcs %2, %2\n\t"
|
||||
"stmia %0!, {%2}\n\t"
|
||||
"teq %0, %1\n\t"
|
||||
"bne 1b\n\t"
|
||||
: "=l" ( discard_value ),
|
||||
"=l" ( discard_end ),
|
||||
"=l" ( discard_value_i ),
|
||||
"+m" ( *value )
|
||||
: "0" ( value0 ), "1" ( size )
|
||||
: "cc" );
|
||||
}
|
||||
|
||||
/**
|
||||
* Rotate big integer right
|
||||
*
|
||||
* @v value0 Element 0 of big integer
|
||||
* @v size Number of elements
|
||||
*/
|
||||
static inline __attribute__ (( always_inline )) void
|
||||
bigint_ror_raw ( uint32_t *value0, unsigned int size ) {
|
||||
bigint_t ( size ) __attribute__ (( may_alias )) *value =
|
||||
( ( void * ) value0 );
|
||||
uint32_t *discard_value;
|
||||
uint32_t *discard_end;
|
||||
uint32_t discard_value_i;
|
||||
|
||||
__asm__ __volatile__ ( "adds %1, %0, %5, lsl #2\n\t" /* clear CF */
|
||||
"\n1:\n\t"
|
||||
"ldmdb %1!, {%2}\n\t"
|
||||
"rrxs %2, %2\n\t"
|
||||
"str %2, [%1]\n\t"
|
||||
"teq %0, %1\n\t"
|
||||
"bne 1b\n\t"
|
||||
: "=l" ( discard_value ),
|
||||
"=l" ( discard_end ),
|
||||
"=l" ( discard_value_i ),
|
||||
"+m" ( *value )
|
||||
: "0" ( value0 ), "1" ( size )
|
||||
: "cc" );
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if big integer is equal to zero
|
||||
*
|
||||
* @v value0 Element 0 of big integer
|
||||
* @v size Number of elements
|
||||
* @ret is_zero Big integer is equal to zero
|
||||
*/
|
||||
static inline __attribute__ (( always_inline, pure )) int
|
||||
bigint_is_zero_raw ( const uint32_t *value0, unsigned int size ) {
|
||||
const uint32_t *value = value0;
|
||||
uint32_t value_i;
|
||||
|
||||
do {
|
||||
value_i = *(value++);
|
||||
if ( value_i )
|
||||
break;
|
||||
} while ( --size );
|
||||
|
||||
return ( value_i == 0 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare big integers
|
||||
*
|
||||
* @v value0 Element 0 of big integer
|
||||
* @v reference0 Element 0 of reference big integer
|
||||
* @v size Number of elements
|
||||
* @ret geq Big integer is greater than or equal to the reference
|
||||
*/
|
||||
static inline __attribute__ (( always_inline, pure )) int
|
||||
bigint_is_geq_raw ( const uint32_t *value0, const uint32_t *reference0,
|
||||
unsigned int size ) {
|
||||
const uint32_t *value = ( value0 + size );
|
||||
const uint32_t *reference = ( reference0 + size );
|
||||
uint32_t value_i;
|
||||
uint32_t reference_i;
|
||||
|
||||
do {
|
||||
value_i = *(--value);
|
||||
reference_i = *(--reference);
|
||||
if ( value_i != reference_i )
|
||||
break;
|
||||
} while ( --size );
|
||||
|
||||
return ( value_i >= reference_i );
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if bit is set in big integer
|
||||
*
|
||||
* @v value0 Element 0 of big integer
|
||||
* @v size Number of elements
|
||||
* @v bit Bit to test
|
||||
* @ret is_set Bit is set
|
||||
*/
|
||||
static inline __attribute__ (( always_inline )) int
|
||||
bigint_bit_is_set_raw ( const uint32_t *value0, unsigned int size,
|
||||
unsigned int bit ) {
|
||||
const bigint_t ( size ) __attribute__ (( may_alias )) *value =
|
||||
( ( const void * ) value0 );
|
||||
unsigned int index = ( bit / ( 8 * sizeof ( value->element[0] ) ) );
|
||||
unsigned int subindex = ( bit % ( 8 * sizeof ( value->element[0] ) ) );
|
||||
|
||||
return ( value->element[index] & ( 1 << subindex ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Find highest bit set in big integer
|
||||
*
|
||||
* @v value0 Element 0 of big integer
|
||||
* @v size Number of elements
|
||||
* @ret max_bit Highest bit set + 1 (or 0 if no bits set)
|
||||
*/
|
||||
static inline __attribute__ (( always_inline )) int
|
||||
bigint_max_set_bit_raw ( const uint32_t *value0, unsigned int size ) {
|
||||
const uint32_t *value = ( value0 + size );
|
||||
int max_bit = ( 8 * sizeof ( bigint_t ( size ) ) );
|
||||
uint32_t value_i;
|
||||
|
||||
do {
|
||||
value_i = *(--value);
|
||||
max_bit -= ( 32 - fls ( value_i ) );
|
||||
if ( value_i )
|
||||
break;
|
||||
} while ( --size );
|
||||
|
||||
return max_bit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Grow big integer
|
||||
*
|
||||
* @v source0 Element 0 of source big integer
|
||||
* @v source_size Number of elements in source big integer
|
||||
* @v dest0 Element 0 of destination big integer
|
||||
* @v dest_size Number of elements in destination big integer
|
||||
*/
|
||||
static inline __attribute__ (( always_inline )) void
|
||||
bigint_grow_raw ( const uint32_t *source0, unsigned int source_size,
|
||||
uint32_t *dest0, unsigned int dest_size ) {
|
||||
unsigned int pad_size = ( dest_size - source_size );
|
||||
|
||||
memcpy ( dest0, source0, sizeof ( bigint_t ( source_size ) ) );
|
||||
memset ( ( dest0 + source_size ), 0, sizeof ( bigint_t ( pad_size ) ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Shrink big integer
|
||||
*
|
||||
* @v source0 Element 0 of source big integer
|
||||
* @v source_size Number of elements in source big integer
|
||||
* @v dest0 Element 0 of destination big integer
|
||||
* @v dest_size Number of elements in destination big integer
|
||||
*/
|
||||
static inline __attribute__ (( always_inline )) void
|
||||
bigint_shrink_raw ( const uint32_t *source0, unsigned int source_size __unused,
|
||||
uint32_t *dest0, unsigned int dest_size ) {
|
||||
|
||||
memcpy ( dest0, source0, sizeof ( bigint_t ( dest_size ) ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Finalise big integer
|
||||
*
|
||||
* @v value0 Element 0 of big integer to finalise
|
||||
* @v size Number of elements
|
||||
* @v out Output buffer
|
||||
* @v len Length of output buffer
|
||||
*/
|
||||
static inline __attribute__ (( always_inline )) void
|
||||
bigint_done_raw ( const uint32_t *value0, unsigned int size __unused,
|
||||
void *out, size_t len ) {
|
||||
const uint8_t *value_byte = ( ( const void * ) value0 );
|
||||
uint8_t *out_byte = ( out + len );
|
||||
|
||||
/* Copy raw data in reverse order */
|
||||
while ( len-- )
|
||||
*(--out_byte) = *(value_byte++);
|
||||
}
|
||||
|
||||
extern void bigint_multiply_raw ( const uint32_t *multiplicand0,
|
||||
const uint32_t *multiplier0,
|
||||
uint32_t *value0, unsigned int size );
|
||||
|
||||
#endif /* _BITS_BIGINT_H */
|
100
src/arch/arm32/include/bits/bitops.h
Normal file
100
src/arch/arm32/include/bits/bitops.h
Normal file
@@ -0,0 +1,100 @@
|
||||
#ifndef _BITS_BITOPS_H
|
||||
#define _BITS_BITOPS_H
|
||||
|
||||
/** @file
|
||||
*
|
||||
* ARM bit operations
|
||||
*
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/**
|
||||
* Test and set bit atomically
|
||||
*
|
||||
* @v bit Bit to set
|
||||
* @v bits Bit field
|
||||
* @ret old Old value of bit (zero or non-zero)
|
||||
*/
|
||||
static inline __attribute__ (( always_inline )) int
|
||||
test_and_set_bit ( unsigned int bit, volatile void *bits ) {
|
||||
unsigned int index = ( bit / 32 );
|
||||
unsigned int offset = ( bit % 32 );
|
||||
volatile uint32_t *dword = ( ( ( volatile uint32_t * ) bits ) + index );
|
||||
uint32_t mask = ( 1UL << offset );
|
||||
uint32_t old;
|
||||
uint32_t new;
|
||||
uint32_t flag;
|
||||
|
||||
__asm__ __volatile__ ( "\n1:\n\t"
|
||||
"ldrex %0, %3\n\t"
|
||||
"orr %1, %0, %4\n\t"
|
||||
"strex %2, %1, %3\n\t"
|
||||
"tst %2, %2\n\t"
|
||||
"bne 1b\n\t"
|
||||
: "=&r" ( old ), "=&r" ( new ), "=&l" ( flag ),
|
||||
"+Q" ( *dword )
|
||||
: "r" ( mask )
|
||||
: "cc" );
|
||||
|
||||
return ( old & mask );
|
||||
}
|
||||
|
||||
/**
|
||||
* Test and clear bit atomically
|
||||
*
|
||||
* @v bit Bit to set
|
||||
* @v bits Bit field
|
||||
* @ret old Old value of bit (zero or non-zero)
|
||||
*/
|
||||
static inline __attribute__ (( always_inline )) int
|
||||
test_and_clear_bit ( unsigned int bit, volatile void *bits ) {
|
||||
unsigned int index = ( bit / 32 );
|
||||
unsigned int offset = ( bit % 32 );
|
||||
volatile uint32_t *dword = ( ( ( volatile uint32_t * ) bits ) + index );
|
||||
uint32_t mask = ( 1UL << offset );
|
||||
uint32_t old;
|
||||
uint32_t new;
|
||||
uint32_t flag;
|
||||
|
||||
__asm__ __volatile__ ( "\n1:\n\t"
|
||||
"ldrex %0, %3\n\t"
|
||||
"bic %1, %0, %4\n\t"
|
||||
"strex %2, %1, %3\n\t"
|
||||
"tst %2, %2\n\t"
|
||||
"bne 1b\n\t"
|
||||
: "=&r" ( old ), "=&r" ( new ), "=&l" ( flag ),
|
||||
"+Q" ( *dword )
|
||||
: "r" ( mask )
|
||||
: "cc" );
|
||||
|
||||
return ( old & mask );
|
||||
}
|
||||
|
||||
/**
|
||||
* Set bit atomically
|
||||
*
|
||||
* @v bit Bit to set
|
||||
* @v bits Bit field
|
||||
*/
|
||||
static inline __attribute__ (( always_inline )) void
|
||||
set_bit ( unsigned int bit, volatile void *bits ) {
|
||||
|
||||
test_and_set_bit ( bit, bits );
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear bit atomically
|
||||
*
|
||||
* @v bit Bit to set
|
||||
* @v bits Bit field
|
||||
*/
|
||||
static inline __attribute__ (( always_inline )) void
|
||||
clear_bit ( unsigned int bit, volatile void *bits ) {
|
||||
|
||||
test_and_clear_bit ( bit, bits );
|
||||
}
|
||||
|
||||
#endif /* _BITS_BITOPS_H */
|
52
src/arch/arm32/include/bits/byteswap.h
Normal file
52
src/arch/arm32/include/bits/byteswap.h
Normal file
@@ -0,0 +1,52 @@
|
||||
#ifndef _BITS_BYTESWAP_H
|
||||
#define _BITS_BYTESWAP_H
|
||||
|
||||
/** @file
|
||||
*
|
||||
* Byte-order swapping functions
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
static inline __attribute__ (( always_inline, const )) uint16_t
|
||||
__bswap_variable_16 ( uint16_t x ) {
|
||||
__asm__ ( "rev16 %0, %1" : "=l" ( x ) : "l" ( x ) );
|
||||
return x;
|
||||
}
|
||||
|
||||
static inline __attribute__ (( always_inline )) void
|
||||
__bswap_16s ( uint16_t *x ) {
|
||||
*x = __bswap_variable_16 ( *x );
|
||||
}
|
||||
|
||||
static inline __attribute__ (( always_inline, const )) uint32_t
|
||||
__bswap_variable_32 ( uint32_t x ) {
|
||||
__asm__ ( "rev %0, %1" : "=l" ( x ) : "l" ( x ) );
|
||||
return x;
|
||||
}
|
||||
|
||||
static inline __attribute__ (( always_inline )) void
|
||||
__bswap_32s ( uint32_t *x ) {
|
||||
*x = __bswap_variable_32 ( *x );
|
||||
}
|
||||
|
||||
static inline __attribute__ (( always_inline, const )) uint64_t
|
||||
__bswap_variable_64 ( uint64_t x ) {
|
||||
uint32_t in_high = ( x >> 32 );
|
||||
uint32_t in_low = ( x & 0xffffffffUL );
|
||||
uint32_t out_high = __bswap_variable_32 ( in_low );
|
||||
uint32_t out_low = __bswap_variable_32 ( in_high );
|
||||
|
||||
return ( ( ( ( uint64_t ) out_high ) << 32 ) |
|
||||
( ( uint64_t ) out_low ) );
|
||||
}
|
||||
|
||||
static inline __attribute__ (( always_inline )) void
|
||||
__bswap_64s ( uint64_t *x ) {
|
||||
*x = __bswap_variable_64 ( *x );
|
||||
}
|
||||
|
||||
#endif
|
16
src/arch/arm32/include/bits/compiler.h
Normal file
16
src/arch/arm32/include/bits/compiler.h
Normal file
@@ -0,0 +1,16 @@
|
||||
#ifndef _BITS_COMPILER_H
|
||||
#define _BITS_COMPILER_H
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
/** Dummy relocation type */
|
||||
#define RELOC_TYPE_NONE R_ARM_NONE
|
||||
|
||||
#ifndef ASSEMBLY
|
||||
|
||||
#define __asmcall
|
||||
#define __libgcc
|
||||
|
||||
#endif /* ASSEMBLY */
|
||||
|
||||
#endif /*_BITS_COMPILER_H */
|
30
src/arch/arm32/include/bits/profile.h
Normal file
30
src/arch/arm32/include/bits/profile.h
Normal file
@@ -0,0 +1,30 @@
|
||||
#ifndef _BITS_PROFILE_H
|
||||
#define _BITS_PROFILE_H
|
||||
|
||||
/** @file
|
||||
*
|
||||
* Profiling
|
||||
*
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/**
|
||||
* Get profiling timestamp
|
||||
*
|
||||
* @ret timestamp Timestamp
|
||||
*/
|
||||
static inline __attribute__ (( always_inline )) uint64_t
|
||||
profile_timestamp ( void ) {
|
||||
uint32_t cycles;
|
||||
|
||||
/* Read cycle counter */
|
||||
__asm__ __volatile__ ( "mcr p15, 0, %1, c9, c12, 0\n\t"
|
||||
"mrc p15, 0, %0, c9, c13, 0\n\t"
|
||||
: "=r" ( cycles ) : "r" ( 1 ) );
|
||||
return cycles;
|
||||
}
|
||||
|
||||
#endif /* _BITS_PROFILE_H */
|
23
src/arch/arm32/include/bits/stdint.h
Normal file
23
src/arch/arm32/include/bits/stdint.h
Normal file
@@ -0,0 +1,23 @@
|
||||
#ifndef _BITS_STDINT_H
|
||||
#define _BITS_STDINT_H
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
typedef __SIZE_TYPE__ size_t;
|
||||
typedef signed long ssize_t;
|
||||
typedef signed long off_t;
|
||||
|
||||
typedef unsigned char uint8_t;
|
||||
typedef unsigned short uint16_t;
|
||||
typedef unsigned int uint32_t;
|
||||
typedef unsigned long long uint64_t;
|
||||
|
||||
typedef signed char int8_t;
|
||||
typedef signed short int16_t;
|
||||
typedef signed int int32_t;
|
||||
typedef signed long long int64_t;
|
||||
|
||||
typedef unsigned long physaddr_t;
|
||||
typedef unsigned long intptr_t;
|
||||
|
||||
#endif /* _BITS_STDINT_H */
|
60
src/arch/arm32/include/bits/string.h
Normal file
60
src/arch/arm32/include/bits/string.h
Normal file
@@ -0,0 +1,60 @@
|
||||
#ifndef BITS_STRING_H
|
||||
#define BITS_STRING_H
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
/** @file
|
||||
*
|
||||
* String functions
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Fill memory region
|
||||
*
|
||||
* @v dest Destination region
|
||||
* @v character Fill character
|
||||
* @v len Length
|
||||
* @ret dest Destination region
|
||||
*/
|
||||
static inline __attribute__ (( always_inline )) void *
|
||||
memset ( void *dest, int character, size_t len ) {
|
||||
|
||||
/* Not yet optimised */
|
||||
generic_memset ( dest, character, len );
|
||||
return dest;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy memory region
|
||||
*
|
||||
* @v dest Destination region
|
||||
* @v src Source region
|
||||
* @v len Length
|
||||
* @ret dest Destination region
|
||||
*/
|
||||
static inline __attribute__ (( always_inline )) void *
|
||||
memcpy ( void *dest, const void *src, size_t len ) {
|
||||
|
||||
/* Not yet optimised */
|
||||
generic_memcpy ( dest, src, len );
|
||||
return dest;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy (possibly overlapping) memory region
|
||||
*
|
||||
* @v dest Destination region
|
||||
* @v src Source region
|
||||
* @v len Length
|
||||
* @ret dest Destination region
|
||||
*/
|
||||
static inline __attribute__ (( always_inline )) void *
|
||||
memmove ( void *dest, const void *src, size_t len ) {
|
||||
|
||||
/* Not yet optimised */
|
||||
generic_memmove ( dest, src, len );
|
||||
return dest;
|
||||
}
|
||||
|
||||
#endif /* BITS_STRING_H */
|
85
src/arch/arm32/include/bits/strings.h
Normal file
85
src/arch/arm32/include/bits/strings.h
Normal file
@@ -0,0 +1,85 @@
|
||||
#ifndef _BITS_STRINGS_H
|
||||
#define _BITS_STRINGS_H
|
||||
|
||||
/** @file
|
||||
*
|
||||
* String functions
|
||||
*
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
/**
|
||||
* Find first (i.e. least significant) set bit
|
||||
*
|
||||
* @v value Value
|
||||
* @ret lsb Least significant bit set in value (LSB=1), or zero
|
||||
*/
|
||||
static inline __attribute__ (( always_inline )) int __ffsl ( long value ) {
|
||||
unsigned long bits = value;
|
||||
unsigned long lsb;
|
||||
unsigned int lz;
|
||||
|
||||
/* Extract least significant set bit */
|
||||
lsb = ( bits & -bits );
|
||||
|
||||
/* Count number of leading zeroes before LSB */
|
||||
__asm__ ( "clz %0, %1" : "=r" ( lz ) : "r" ( lsb ) );
|
||||
|
||||
return ( 32 - lz );
|
||||
}
|
||||
|
||||
/**
|
||||
* Find first (i.e. least significant) set bit
|
||||
*
|
||||
* @v value Value
|
||||
* @ret lsb Least significant bit set in value (LSB=1), or zero
|
||||
*/
|
||||
static inline __attribute__ (( always_inline )) int __ffsll ( long long value ){
|
||||
unsigned long high = ( value >> 32 );
|
||||
unsigned long low = ( value >> 0 );
|
||||
|
||||
if ( low ) {
|
||||
return ( __ffsl ( low ) );
|
||||
} else if ( high ) {
|
||||
return ( 32 + __ffsl ( high ) );
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find last (i.e. most significant) set bit
|
||||
*
|
||||
* @v value Value
|
||||
* @ret msb Most significant bit set in value (LSB=1), or zero
|
||||
*/
|
||||
static inline __attribute__ (( always_inline )) int __flsl ( long value ) {
|
||||
unsigned int lz;
|
||||
|
||||
/* Count number of leading zeroes */
|
||||
__asm__ ( "clz %0, %1" : "=r" ( lz ) : "r" ( value ) );
|
||||
|
||||
return ( 32 - lz );
|
||||
}
|
||||
|
||||
/**
|
||||
* Find last (i.e. most significant) set bit
|
||||
*
|
||||
* @v value Value
|
||||
* @ret msb Most significant bit set in value (LSB=1), or zero
|
||||
*/
|
||||
static inline __attribute__ (( always_inline )) int __flsll ( long long value ){
|
||||
unsigned long high = ( value >> 32 );
|
||||
unsigned long low = ( value >> 0 );
|
||||
|
||||
if ( high ) {
|
||||
return ( 32 + __flsl ( high ) );
|
||||
} else if ( low ) {
|
||||
return ( __flsl ( low ) );
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* _BITS_STRINGS_H */
|
19
src/arch/arm32/include/bits/tcpip.h
Normal file
19
src/arch/arm32/include/bits/tcpip.h
Normal file
@@ -0,0 +1,19 @@
|
||||
#ifndef _BITS_TCPIP_H
|
||||
#define _BITS_TCPIP_H
|
||||
|
||||
/** @file
|
||||
*
|
||||
* Transport-network layer interface
|
||||
*
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
static inline __attribute__ (( always_inline )) uint16_t
|
||||
tcpip_continue_chksum ( uint16_t partial, const void *data, size_t len ) {
|
||||
|
||||
/* Not yet optimised */
|
||||
return generic_tcpip_continue_chksum ( partial, data, len );
|
||||
}
|
||||
|
||||
#endif /* _BITS_TCPIP_H */
|
40
src/arch/arm32/include/efi/ipxe/dhcp_arch.h
Normal file
40
src/arch/arm32/include/efi/ipxe/dhcp_arch.h
Normal file
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright (C) 2015 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 (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.
|
||||
*
|
||||
* You can also choose to distribute this program under the terms of
|
||||
* the Unmodified Binary Distribution Licence (as given in the file
|
||||
* COPYING.UBDL), provided that you have satisfied its requirements.
|
||||
*/
|
||||
|
||||
#ifndef _DHCP_ARCH_H
|
||||
#define _DHCP_ARCH_H
|
||||
|
||||
/** @file
|
||||
*
|
||||
* Architecture-specific DHCP options
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
#include <ipxe/dhcp.h>
|
||||
|
||||
#define DHCP_ARCH_CLIENT_ARCHITECTURE DHCP_CLIENT_ARCHITECTURE_ARM32
|
||||
|
||||
#define DHCP_ARCH_CLIENT_NDI 1 /* UNDI */ , 3, 10 /* v3.10 */
|
||||
|
||||
#endif
|
45
src/arch/arm32/include/gdbmach.h
Normal file
45
src/arch/arm32/include/gdbmach.h
Normal file
@@ -0,0 +1,45 @@
|
||||
#ifndef GDBMACH_H
|
||||
#define GDBMACH_H
|
||||
|
||||
/** @file
|
||||
*
|
||||
* GDB architecture specifics
|
||||
*
|
||||
* This file declares functions for manipulating the machine state and
|
||||
* debugging context.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
typedef unsigned long gdbreg_t;
|
||||
|
||||
/* Register snapshot */
|
||||
enum {
|
||||
/* Not yet implemented */
|
||||
GDBMACH_NREGS,
|
||||
};
|
||||
|
||||
#define GDBMACH_SIZEOF_REGS ( GDBMACH_NREGS * sizeof ( gdbreg_t ) )
|
||||
|
||||
static inline void gdbmach_set_pc ( gdbreg_t *regs, gdbreg_t pc ) {
|
||||
/* Not yet implemented */
|
||||
( void ) regs;
|
||||
( void ) pc;
|
||||
}
|
||||
|
||||
static inline void gdbmach_set_single_step ( gdbreg_t *regs, int step ) {
|
||||
/* Not yet implemented */
|
||||
( void ) regs;
|
||||
( void ) step;
|
||||
}
|
||||
|
||||
static inline void gdbmach_breakpoint ( void ) {
|
||||
/* Not yet implemented */
|
||||
}
|
||||
|
||||
extern int gdbmach_set_breakpoint ( int type, unsigned long addr, size_t len,
|
||||
int enable );
|
||||
extern void gdbmach_init ( void );
|
||||
|
||||
#endif /* GDBMACH_H */
|
61
src/arch/arm32/include/limits.h
Normal file
61
src/arch/arm32/include/limits.h
Normal file
@@ -0,0 +1,61 @@
|
||||
#ifndef LIMITS_H
|
||||
#define LIMITS_H 1
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
/* Number of bits in a `char' */
|
||||
#define CHAR_BIT 8
|
||||
|
||||
/* Minimum and maximum values a `signed char' can hold */
|
||||
#define SCHAR_MIN (-128)
|
||||
#define SCHAR_MAX 127
|
||||
|
||||
/* Maximum value an `unsigned char' can hold. (Minimum is 0.) */
|
||||
#define UCHAR_MAX 255
|
||||
|
||||
/* Minimum and maximum values a `char' can hold */
|
||||
#define CHAR_MIN SCHAR_MIN
|
||||
#define CHAR_MAX SCHAR_MAX
|
||||
|
||||
/* Minimum and maximum values a `signed short int' can hold */
|
||||
#define SHRT_MIN (-32768)
|
||||
#define SHRT_MAX 32767
|
||||
|
||||
/* Maximum value an `unsigned short' can hold. (Minimum is 0.) */
|
||||
#define USHRT_MAX 65535
|
||||
|
||||
|
||||
/* Minimum and maximum values a `signed int' can hold */
|
||||
#define INT_MIN (-INT_MAX - 1)
|
||||
#define INT_MAX 2147483647
|
||||
|
||||
/* Maximum value an `unsigned int' can hold. (Minimum is 0.) */
|
||||
#define UINT_MAX 4294967295U
|
||||
|
||||
|
||||
/* Minimum and maximum values a `signed int' can hold */
|
||||
#define INT_MAX 2147483647
|
||||
#define INT_MIN (-INT_MAX - 1)
|
||||
|
||||
|
||||
/* Maximum value an `unsigned int' can hold. (Minimum is 0.) */
|
||||
#define UINT_MAX 4294967295U
|
||||
|
||||
|
||||
/* Minimum and maximum values a `signed long' can hold */
|
||||
#define LONG_MAX 2147483647
|
||||
#define LONG_MIN (-LONG_MAX - 1L)
|
||||
|
||||
/* Maximum value an `unsigned long' can hold. (Minimum is 0.) */
|
||||
#define ULONG_MAX 4294967295UL
|
||||
|
||||
/* Minimum and maximum values a `signed long long' can hold */
|
||||
#define LLONG_MAX 9223372036854775807LL
|
||||
#define LLONG_MIN (-LONG_MAX - 1LL)
|
||||
|
||||
|
||||
/* Maximum value an `unsigned long long' can hold. (Minimum is 0.) */
|
||||
#define ULLONG_MAX 18446744073709551615ULL
|
||||
|
||||
|
||||
#endif /* LIMITS_H */
|
38
src/arch/arm32/include/setjmp.h
Normal file
38
src/arch/arm32/include/setjmp.h
Normal file
@@ -0,0 +1,38 @@
|
||||
#ifndef _SETJMP_H
|
||||
#define _SETJMP_H
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/** A jump buffer */
|
||||
typedef struct {
|
||||
/** Saved r4 */
|
||||
uint32_t r4;
|
||||
/** Saved r5 */
|
||||
uint32_t r5;
|
||||
/** Saved r6 */
|
||||
uint32_t r6;
|
||||
/** Saved r7 */
|
||||
uint32_t r7;
|
||||
/** Saved r8 */
|
||||
uint32_t r8;
|
||||
/** Saved r9 */
|
||||
uint32_t r9;
|
||||
/** Saved r10 */
|
||||
uint32_t r10;
|
||||
/** Saved frame pointer (r11) */
|
||||
uint32_t fp;
|
||||
/** Saved stack pointer (r13) */
|
||||
uint32_t sp;
|
||||
/** Saved link register (r14) */
|
||||
uint32_t lr;
|
||||
} jmp_buf[1];
|
||||
|
||||
extern int __asmcall __attribute__ (( returns_twice ))
|
||||
setjmp ( jmp_buf env );
|
||||
|
||||
extern void __asmcall __attribute__ (( noreturn ))
|
||||
longjmp ( jmp_buf env, int val );
|
||||
|
||||
#endif /* _SETJMP_H */
|
50
src/arch/arm32/libgcc/lldivmod.S
Normal file
50
src/arch/arm32/libgcc/lldivmod.S
Normal file
@@ -0,0 +1,50 @@
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
|
||||
|
||||
.text
|
||||
.thumb
|
||||
|
||||
/**
|
||||
* Unsigned long long division
|
||||
*
|
||||
* @v r1:r0 Dividend
|
||||
* @v r3:r2 Divisor
|
||||
* @ret r1:r0 Quotient
|
||||
* @ret r3:r2 Remainder
|
||||
*/
|
||||
.section ".text.__aeabi_uldivmod", "ax", %progbits
|
||||
.globl __aeabi_uldivmod
|
||||
.type __aeabi_uldivmod, %function
|
||||
__aeabi_uldivmod:
|
||||
/* Allocate stack space for remainder and pointer to remainder */
|
||||
push {r0, r1, r2, r3, r4, lr}
|
||||
/* Call __udivmoddi4() */
|
||||
add r4, sp, #8
|
||||
str r4, [sp]
|
||||
bl __udivmoddi4
|
||||
/* Retrieve remainder and return */
|
||||
add sp, sp, #8
|
||||
pop {r2, r3, r4, pc}
|
||||
.size __aeabi_uldivmod, . - __aeabi_uldivmod
|
||||
|
||||
/**
|
||||
* Signed long long division
|
||||
*
|
||||
* @v r1:r0 Dividend
|
||||
* @v r3:r2 Divisor
|
||||
* @ret r1:r0 Quotient
|
||||
* @ret r3:r2 Remainder
|
||||
*/
|
||||
.section ".text.__aeabi_ldivmod", "ax", %progbits
|
||||
.globl __aeabi_ldivmod
|
||||
.type __aeabi_ldivmod, %function
|
||||
__aeabi_ldivmod:
|
||||
/* Allocate stack space for remainder and pointer to remainder */
|
||||
push {r0, r1, r2, r3, r4, lr}
|
||||
/* Call __divmoddi4() */
|
||||
add r4, sp, #8
|
||||
str r4, [sp]
|
||||
bl __divmoddi4
|
||||
/* Retrieve remainder and return */
|
||||
add sp, sp, #8
|
||||
pop {r2, r3, r4, pc}
|
||||
.size __aeabi_ldivmod, . - __aeabi_ldivmod
|
88
src/arch/arm32/libgcc/llshift.S
Normal file
88
src/arch/arm32/libgcc/llshift.S
Normal file
@@ -0,0 +1,88 @@
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
|
||||
|
||||
.text
|
||||
.arm
|
||||
|
||||
/**
|
||||
* Logical shift left
|
||||
*
|
||||
* @v r1:r0 Value to shift
|
||||
* @v r2 Shift amount
|
||||
* @ret r1:r0 Shifted value
|
||||
*/
|
||||
.section ".text.__aeabi_llsl", "ax", %progbits
|
||||
.globl __aeabi_llsl
|
||||
.type __aeabi_llsl, %function
|
||||
__aeabi_llsl:
|
||||
/* r3 = ( shift - 32 ) */
|
||||
subs r3, r2, #32
|
||||
/* If shift >= 32, then
|
||||
* high = ( low << ( shift - 32 ) )
|
||||
*/
|
||||
movpl r1, r0, lsl r3
|
||||
/* If shift < 32, then
|
||||
* high = ( ( high << shift ) | ( low >> ( 32 - shift ) ) )
|
||||
*/
|
||||
movmi r1, r1, lsl r2
|
||||
rsbmi r3, r2, #32
|
||||
orrmi r1, r1, r0, lsr r3
|
||||
/* low = ( low << shift ) */
|
||||
mov r0, r0, lsl r2
|
||||
bx lr
|
||||
.size __aeabi_llsl, . - __aeabi_llsl
|
||||
|
||||
/**
|
||||
* Logical shift right
|
||||
*
|
||||
* @v r1:r0 Value to shift
|
||||
* @v r2 Shift amount
|
||||
* @ret r1:r0 Shifted value
|
||||
*/
|
||||
.section ".text.__aeabi_llsr", "ax", %progbits
|
||||
.globl __aeabi_llsr
|
||||
.type __aeabi_llsr, %function
|
||||
__aeabi_llsr:
|
||||
/* r3 = ( shift - 32 ) */
|
||||
subs r3, r2, #32
|
||||
/* If shift >= 32, then
|
||||
* low = ( high >> ( shift - 32 ) )
|
||||
*/
|
||||
movpl r0, r1, lsr r3
|
||||
/* If shift < 32, then
|
||||
* low = ( ( low >> shift ) | ( high << ( 32 - shift ) ) )
|
||||
*/
|
||||
movmi r0, r0, lsr r2
|
||||
rsbmi r3, r2, #32
|
||||
orrmi r0, r0, r1, lsl r3
|
||||
/* high = ( high >> shift ) */
|
||||
mov r1, r1, lsr r2
|
||||
bx lr
|
||||
.size __aeabi_llsr, . - __aeabi_llsr
|
||||
|
||||
/**
|
||||
* Arithmetic shift right
|
||||
*
|
||||
* @v r1:r0 Value to shift
|
||||
* @v r2 Shift amount
|
||||
* @ret r1:r0 Shifted value
|
||||
*/
|
||||
.section ".text.__aeabi_lasr", "ax", %progbits
|
||||
.globl __aeabi_lasr
|
||||
.type __aeabi_lasr, %function
|
||||
__aeabi_lasr:
|
||||
/* r3 = ( shift - 32 ) */
|
||||
subs r3, r2, #32
|
||||
/* If shift >= 32, then
|
||||
* low = ( high >> ( shift - 32 ) )
|
||||
*/
|
||||
movpl r0, r1, asr r3
|
||||
/* If shift < 32, then
|
||||
* low = ( ( low >> shift ) | ( high << ( 32 - shift ) ) )
|
||||
*/
|
||||
movmi r0, r0, lsr r2
|
||||
rsbmi r3, r2, #32
|
||||
orrmi r0, r0, r1, lsl r3
|
||||
/* high = ( high >> shift ) */
|
||||
mov r1, r1, asr r2
|
||||
bx lr
|
||||
.size __aeabi_lasr, . - __aeabi_lasr
|
33
src/arch/arm64/Makefile
Normal file
33
src/arch/arm64/Makefile
Normal file
@@ -0,0 +1,33 @@
|
||||
# ARM64-specific directories containing source files
|
||||
#
|
||||
SRCDIRS += arch/arm64/core
|
||||
|
||||
# ARM64-specific flags
|
||||
#
|
||||
CFLAGS += -mlittle-endian -mcmodel=small
|
||||
CFLAGS += -fomit-frame-pointer
|
||||
ASFLAGS += -mabi=lp64 -EL
|
||||
|
||||
# We want to specify the LP64 model. There is an explicit -mabi=lp64
|
||||
# on GCC 4.9 and later, and no guarantee as to which is the default
|
||||
# model. In earlier versions of GCC, there is no -mabi option and the
|
||||
# default appears to be LP64 anyway.
|
||||
#
|
||||
ifeq ($(CCTYPE),gcc)
|
||||
LP64_TEST = $(CC) -mabi=lp64 -x c -c /dev/null -o /dev/null >/dev/null 2>&1
|
||||
LP64_FLAGS := $(shell $(LP64_TEST) && $(ECHO) '-mabi=lp64')
|
||||
WORKAROUND_CFLAGS += $(LP64_FLAGS)
|
||||
endif
|
||||
|
||||
# EFI requires -fshort-wchar, and nothing else currently uses wchar_t
|
||||
#
|
||||
CFLAGS += -fshort-wchar
|
||||
|
||||
# Include common ARM Makefile
|
||||
MAKEDEPS += arch/arm/Makefile
|
||||
include arch/arm/Makefile
|
||||
|
||||
# Include platform-specific Makefile
|
||||
#
|
||||
MAKEDEPS += arch/arm64/Makefile.$(PLATFORM)
|
||||
include arch/arm64/Makefile.$(PLATFORM)
|
18
src/arch/arm64/Makefile.efi
Normal file
18
src/arch/arm64/Makefile.efi
Normal file
@@ -0,0 +1,18 @@
|
||||
# -*- makefile -*- : Force emacs to use Makefile mode
|
||||
|
||||
# Avoid untranslatable relocations
|
||||
#
|
||||
CFLAGS += -fno-pic
|
||||
|
||||
# Specify EFI image builder
|
||||
#
|
||||
ELF2EFI = $(ELF2EFI64)
|
||||
|
||||
# Specify EFI boot file
|
||||
#
|
||||
EFI_BOOT_FILE = bootaa64.efi
|
||||
|
||||
# Include generic EFI Makefile
|
||||
#
|
||||
MAKEDEPS += arch/arm/Makefile.efi
|
||||
include arch/arm/Makefile.efi
|
103
src/arch/arm64/core/arm64_bigint.c
Normal file
103
src/arch/arm64/core/arm64_bigint.c
Normal file
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
* Copyright (C) 2016 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., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA.
|
||||
*
|
||||
* You can also choose to distribute this program under the terms of
|
||||
* the Unmodified Binary Distribution Licence (as given in the file
|
||||
* COPYING.UBDL), provided that you have satisfied its requirements.
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <ipxe/bigint.h>
|
||||
|
||||
/** @file
|
||||
*
|
||||
* Big integer support
|
||||
*/
|
||||
|
||||
/**
|
||||
* Multiply big integers
|
||||
*
|
||||
* @v multiplicand0 Element 0 of big integer to be multiplied
|
||||
* @v multiplier0 Element 0 of big integer to be multiplied
|
||||
* @v result0 Element 0 of big integer to hold result
|
||||
* @v size Number of elements
|
||||
*/
|
||||
void bigint_multiply_raw ( const uint64_t *multiplicand0,
|
||||
const uint64_t *multiplier0,
|
||||
uint64_t *result0, unsigned int size ) {
|
||||
const bigint_t ( size ) __attribute__ (( may_alias )) *multiplicand =
|
||||
( ( const void * ) multiplicand0 );
|
||||
const bigint_t ( size ) __attribute__ (( may_alias )) *multiplier =
|
||||
( ( const void * ) multiplier0 );
|
||||
bigint_t ( size * 2 ) __attribute__ (( may_alias )) *result =
|
||||
( ( void * ) result0 );
|
||||
unsigned int i;
|
||||
unsigned int j;
|
||||
uint64_t multiplicand_element;
|
||||
uint64_t multiplier_element;
|
||||
uint64_t *result_elements;
|
||||
uint64_t discard_low;
|
||||
uint64_t discard_high;
|
||||
uint64_t discard_temp_low;
|
||||
uint64_t discard_temp_high;
|
||||
|
||||
/* Zero result */
|
||||
memset ( result, 0, sizeof ( *result ) );
|
||||
|
||||
/* Multiply integers one element at a time */
|
||||
for ( i = 0 ; i < size ; i++ ) {
|
||||
multiplicand_element = multiplicand->element[i];
|
||||
for ( j = 0 ; j < size ; j++ ) {
|
||||
multiplier_element = multiplier->element[j];
|
||||
result_elements = &result->element[ i + j ];
|
||||
/* Perform a single multiply, and add the
|
||||
* resulting double-element into the result,
|
||||
* carrying as necessary. The carry can
|
||||
* never overflow beyond the end of the
|
||||
* result, since:
|
||||
*
|
||||
* a < 2^{n}, b < 2^{n} => ab < 2^{2n}
|
||||
*/
|
||||
__asm__ __volatile__ ( "mul %1, %6, %7\n\t"
|
||||
"umulh %2, %6, %7\n\t"
|
||||
"ldp %3, %4, [%0]\n\t"
|
||||
"adds %3, %3, %1\n\t"
|
||||
"adcs %4, %4, %2\n\t"
|
||||
"stp %3, %4, [%0], #16\n\t"
|
||||
"bcc 2f\n\t"
|
||||
"\n1:\n\t"
|
||||
"ldr %3, [%0]\n\t"
|
||||
"adcs %3, %3, xzr\n\t"
|
||||
"str %3, [%0], #8\n\t"
|
||||
"bcs 1b\n\t"
|
||||
"\n2:\n\t"
|
||||
: "+r" ( result_elements ),
|
||||
"=&r" ( discard_low ),
|
||||
"=&r" ( discard_high ),
|
||||
"=r" ( discard_temp_low ),
|
||||
"=r" ( discard_temp_high ),
|
||||
"+m" ( *result )
|
||||
: "r" ( multiplicand_element ),
|
||||
"r" ( multiplier_element )
|
||||
: "cc" );
|
||||
}
|
||||
}
|
||||
}
|
249
src/arch/arm64/core/arm64_string.c
Normal file
249
src/arch/arm64/core/arm64_string.c
Normal file
@@ -0,0 +1,249 @@
|
||||
/*
|
||||
* Copyright (C) 2016 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., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA.
|
||||
*
|
||||
* You can also choose to distribute this program under the terms of
|
||||
* the Unmodified Binary Distribution Licence (as given in the file
|
||||
* COPYING.UBDL), provided that you have satisfied its requirements.
|
||||
*/
|
||||
|
||||
/** @file
|
||||
*
|
||||
* Optimised string operations
|
||||
*
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
#include <string.h>
|
||||
|
||||
/**
|
||||
* Copy memory area
|
||||
*
|
||||
* @v dest Destination address
|
||||
* @v src Source address
|
||||
* @v len Length
|
||||
* @ret dest Destination address
|
||||
*/
|
||||
void arm64_memcpy ( void *dest, const void *src, size_t len ) {
|
||||
void *discard_dest;
|
||||
void *discard_end;
|
||||
const void *discard_src;
|
||||
size_t discard_offset;
|
||||
unsigned long discard_data;
|
||||
unsigned long discard_low;
|
||||
unsigned long discard_high;
|
||||
|
||||
/* If length is too short for an "ldp"/"stp" instruction pair,
|
||||
* then just copy individual bytes.
|
||||
*/
|
||||
if ( len < 16 ) {
|
||||
__asm__ __volatile__ ( "cbz %0, 2f\n\t"
|
||||
"\n1:\n\t"
|
||||
"sub %0, %0, #1\n\t"
|
||||
"ldrb %w1, [%3, %0]\n\t"
|
||||
"strb %w1, [%2, %0]\n\t"
|
||||
"cbnz %0, 1b\n\t"
|
||||
"\n2:\n\t"
|
||||
: "=&r" ( discard_offset ),
|
||||
"=&r" ( discard_data )
|
||||
: "r" ( dest ), "r" ( src ), "0" ( len )
|
||||
: "memory" );
|
||||
return;
|
||||
}
|
||||
|
||||
/* Use "ldp"/"stp" to copy 16 bytes at a time: one initial
|
||||
* potentially unaligned access, multiple destination-aligned
|
||||
* accesses, one final potentially unaligned access.
|
||||
*/
|
||||
__asm__ __volatile__ ( "ldp %3, %4, [%1], #16\n\t"
|
||||
"stp %3, %4, [%0], #16\n\t"
|
||||
"and %3, %0, #15\n\t"
|
||||
"sub %0, %0, %3\n\t"
|
||||
"sub %1, %1, %3\n\t"
|
||||
"bic %2, %5, #15\n\t"
|
||||
"b 2f\n\t"
|
||||
"\n1:\n\t"
|
||||
"ldp %3, %4, [%1], #16\n\t"
|
||||
"stp %3, %4, [%0], #16\n\t"
|
||||
"\n2:\n\t"
|
||||
"cmp %0, %2\n\t"
|
||||
"bne 1b\n\t"
|
||||
"ldp %3, %4, [%6, #-16]\n\t"
|
||||
"stp %3, %4, [%5, #-16]\n\t"
|
||||
: "=&r" ( discard_dest ),
|
||||
"=&r" ( discard_src ),
|
||||
"=&r" ( discard_end ),
|
||||
"=&r" ( discard_low ),
|
||||
"=&r" ( discard_high )
|
||||
: "r" ( dest + len ), "r" ( src + len ),
|
||||
"0" ( dest ), "1" ( src )
|
||||
: "memory", "cc" );
|
||||
}
|
||||
|
||||
/**
|
||||
* Zero memory region
|
||||
*
|
||||
* @v dest Destination region
|
||||
* @v len Length
|
||||
*/
|
||||
void arm64_bzero ( void *dest, size_t len ) {
|
||||
size_t discard_offset;
|
||||
void *discard_dest;
|
||||
void *discard_end;
|
||||
|
||||
/* If length is too short for an "stp" instruction, then just
|
||||
* zero individual bytes.
|
||||
*/
|
||||
if ( len < 16 ) {
|
||||
__asm__ __volatile__ ( "cbz %0, 2f\n\t"
|
||||
"\n1:\n\t"
|
||||
"sub %0, %0, #1\n\t"
|
||||
"strb wzr, [%1, %0]\n\t"
|
||||
"cbnz %0, 1b\n\t"
|
||||
"\n2:\n\t"
|
||||
: "=&r" ( discard_offset )
|
||||
: "r" ( dest ), "0" ( len )
|
||||
: "memory" );
|
||||
return;
|
||||
}
|
||||
|
||||
/* Use "stp" to zero 16 bytes at a time: one initial
|
||||
* potentially unaligned access, multiple aligned accesses,
|
||||
* one final potentially unaligned access.
|
||||
*/
|
||||
__asm__ __volatile__ ( "stp xzr, xzr, [%0], #16\n\t"
|
||||
"bic %0, %0, #15\n\t"
|
||||
"bic %1, %2, #15\n\t"
|
||||
"b 2f\n\t"
|
||||
"\n1:\n\t"
|
||||
"stp xzr, xzr, [%0], #16\n\t"
|
||||
"\n2:\n\t"
|
||||
"cmp %0, %1\n\t"
|
||||
"bne 1b\n\t"
|
||||
"stp xzr, xzr, [%2, #-16]\n\t"
|
||||
: "=&r" ( discard_dest ),
|
||||
"=&r" ( discard_end )
|
||||
: "r" ( dest + len ), "0" ( dest )
|
||||
: "memory", "cc" );
|
||||
}
|
||||
|
||||
/**
|
||||
* Fill memory region
|
||||
*
|
||||
* @v dest Destination region
|
||||
* @v len Length
|
||||
* @v character Fill character
|
||||
*
|
||||
* The unusual parameter order is to allow for more efficient
|
||||
* tail-calling to arm64_memset() when zeroing a region.
|
||||
*/
|
||||
void arm64_memset ( void *dest, size_t len, int character ) {
|
||||
size_t discard_offset;
|
||||
|
||||
/* Use optimised zeroing code if applicable */
|
||||
if ( character == 0 ) {
|
||||
arm64_bzero ( dest, len );
|
||||
return;
|
||||
}
|
||||
|
||||
/* Fill one byte at a time. Calling memset() with a non-zero
|
||||
* value is relatively rare and unlikely to be
|
||||
* performance-critical.
|
||||
*/
|
||||
__asm__ __volatile__ ( "cbz %0, 2f\n\t"
|
||||
"\n1:\n\t"
|
||||
"sub %0, %0, #1\n\t"
|
||||
"strb %w2, [%1, %0]\n\t"
|
||||
"cbnz %0, 1b\n\t"
|
||||
"\n2:\n\t"
|
||||
: "=&r" ( discard_offset )
|
||||
: "r" ( dest ), "r" ( character ), "0" ( len )
|
||||
: "memory" );
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy (possibly overlapping) memory region forwards
|
||||
*
|
||||
* @v dest Destination region
|
||||
* @v src Source region
|
||||
* @v len Length
|
||||
*/
|
||||
void arm64_memmove_forwards ( void *dest, const void *src, size_t len ) {
|
||||
void *discard_dest;
|
||||
const void *discard_src;
|
||||
unsigned long discard_data;
|
||||
|
||||
/* Assume memmove() is not performance-critical, and perform a
|
||||
* bytewise copy for simplicity.
|
||||
*/
|
||||
__asm__ __volatile__ ( "b 2f\n\t"
|
||||
"\n1:\n\t"
|
||||
"ldrb %w2, [%1], #1\n\t"
|
||||
"strb %w2, [%0], #1\n\t"
|
||||
"\n2:\n\t"
|
||||
"cmp %0, %3\n\t"
|
||||
"bne 1b\n\t"
|
||||
: "=&r" ( discard_dest ),
|
||||
"=&r" ( discard_src ),
|
||||
"=&r" ( discard_data )
|
||||
: "r" ( dest + len ), "0" ( dest ), "1" ( src )
|
||||
: "memory" );
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy (possibly overlapping) memory region backwards
|
||||
*
|
||||
* @v dest Destination region
|
||||
* @v src Source region
|
||||
* @v len Length
|
||||
*/
|
||||
void arm64_memmove_backwards ( void *dest, const void *src, size_t len ) {
|
||||
size_t discard_offset;
|
||||
unsigned long discard_data;
|
||||
|
||||
/* Assume memmove() is not performance-critical, and perform a
|
||||
* bytewise copy for simplicity.
|
||||
*/
|
||||
__asm__ __volatile__ ( "cbz %0, 2f\n\t"
|
||||
"\n1:\n\t"
|
||||
"sub %0, %0, #1\n\t"
|
||||
"ldrb %w1, [%3, %0]\n\t"
|
||||
"strb %w1, [%2, %0]\n\t"
|
||||
"cbnz %0, 1b\n\t"
|
||||
"\n2:\n\t"
|
||||
: "=&r" ( discard_offset ),
|
||||
"=&r" ( discard_data )
|
||||
: "r" ( dest ), "r" ( src ), "0" ( len )
|
||||
: "memory" );
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy (possibly overlapping) memory region
|
||||
*
|
||||
* @v dest Destination region
|
||||
* @v src Source region
|
||||
* @v len Length
|
||||
*/
|
||||
void arm64_memmove ( void *dest, const void *src, size_t len ) {
|
||||
|
||||
if ( dest <= src ) {
|
||||
arm64_memmove_forwards ( dest, src, len );
|
||||
} else {
|
||||
arm64_memmove_backwards ( dest, src, len );
|
||||
}
|
||||
}
|
175
src/arch/arm64/core/arm64_tcpip.c
Normal file
175
src/arch/arm64/core/arm64_tcpip.c
Normal file
@@ -0,0 +1,175 @@
|
||||
/*
|
||||
* Copyright (C) 2016 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 (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.
|
||||
*
|
||||
* You can also choose to distribute this program under the terms of
|
||||
* the Unmodified Binary Distribution Licence (as given in the file
|
||||
* COPYING.UBDL), provided that you have satisfied its requirements.
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
/** @file
|
||||
*
|
||||
* TCP/IP checksum
|
||||
*
|
||||
*/
|
||||
|
||||
#include <strings.h>
|
||||
#include <ipxe/tcpip.h>
|
||||
|
||||
/** Alignment used by main checksumming loop */
|
||||
#define TCPIP_CHKSUM_ALIGN 16
|
||||
|
||||
/** Number of steps in each iteration of the unrolled main checksumming loop */
|
||||
#define TCPIP_CHKSUM_UNROLL 4
|
||||
|
||||
/**
|
||||
* Calculate continued TCP/IP checkum
|
||||
*
|
||||
* @v sum Checksum of already-summed data, in network byte order
|
||||
* @v data Data buffer
|
||||
* @v len Length of data buffer
|
||||
* @ret sum Updated checksum, in network byte order
|
||||
*/
|
||||
uint16_t tcpip_continue_chksum ( uint16_t sum, const void *data,
|
||||
size_t len ) {
|
||||
intptr_t start;
|
||||
intptr_t end;
|
||||
intptr_t mid;
|
||||
unsigned int pre;
|
||||
unsigned int post;
|
||||
unsigned int first;
|
||||
uint64_t discard_low;
|
||||
uint64_t discard_high;
|
||||
|
||||
/* Avoid potentially undefined shift operation */
|
||||
if ( len == 0 )
|
||||
return sum;
|
||||
|
||||
/* Find maximally-aligned midpoint. For short blocks of data,
|
||||
* this may be aligned to fewer than 16 bytes.
|
||||
*/
|
||||
start = ( ( intptr_t ) data );
|
||||
end = ( start + len );
|
||||
mid = ( end &
|
||||
~( ( ~( 1UL << 63 ) ) >> ( 64 - flsl ( start ^ end ) ) ) );
|
||||
|
||||
/* Calculate pre- and post-alignment lengths */
|
||||
pre = ( ( mid - start ) & ( TCPIP_CHKSUM_ALIGN - 1 ) );
|
||||
post = ( ( end - mid ) & ( TCPIP_CHKSUM_ALIGN - 1 ) );
|
||||
|
||||
/* Calculate number of steps in first iteration of unrolled loop */
|
||||
first = ( ( ( len - pre - post ) / TCPIP_CHKSUM_ALIGN ) &
|
||||
( TCPIP_CHKSUM_UNROLL - 1 ) );
|
||||
|
||||
/* Calculate checksum */
|
||||
__asm__ ( /* Invert sum */
|
||||
"eor %w0, %w0, #0xffff\n\t"
|
||||
/* Clear carry flag */
|
||||
"cmn xzr, xzr\n\t"
|
||||
/* Byteswap and sum pre-alignment byte, if applicable */
|
||||
"tbz %w4, #0, 1f\n\t"
|
||||
"ldrb %w2, [%1], #1\n\t"
|
||||
"rev16 %w0, %w0\n\t"
|
||||
"rev16 %w2, %w2\n\t"
|
||||
"adcs %0, %0, %2\n\t"
|
||||
"\n1:\n\t"
|
||||
/* Sum pre-alignment halfword, if applicable */
|
||||
"tbz %w4, #1, 1f\n\t"
|
||||
"ldrh %w2, [%1], #2\n\t"
|
||||
"adcs %0, %0, %2\n\t"
|
||||
"\n1:\n\t"
|
||||
/* Sum pre-alignment word, if applicable */
|
||||
"tbz %w4, #2, 1f\n\t"
|
||||
"ldr %w2, [%1], #4\n\t"
|
||||
"adcs %0, %0, %2\n\t"
|
||||
"\n1:\n\t"
|
||||
/* Sum pre-alignment doubleword, if applicable */
|
||||
"tbz %w4, #3, 1f\n\t"
|
||||
"ldr %2, [%1], #8\n\t"
|
||||
"adcs %0, %0, %2\n\t"
|
||||
"\n1:\n\t"
|
||||
/* Jump into unrolled (x4) main loop */
|
||||
"adr %2, 2f\n\t"
|
||||
"sub %2, %2, %5, lsl #3\n\t"
|
||||
"sub %2, %2, %5, lsl #2\n\t"
|
||||
"br %2\n\t"
|
||||
"\n1:\n\t"
|
||||
"ldp %2, %3, [%1], #16\n\t"
|
||||
"adcs %0, %0, %2\n\t"
|
||||
"adcs %0, %0, %3\n\t"
|
||||
"ldp %2, %3, [%1], #16\n\t"
|
||||
"adcs %0, %0, %2\n\t"
|
||||
"adcs %0, %0, %3\n\t"
|
||||
"ldp %2, %3, [%1], #16\n\t"
|
||||
"adcs %0, %0, %2\n\t"
|
||||
"adcs %0, %0, %3\n\t"
|
||||
"ldp %2, %3, [%1], #16\n\t"
|
||||
"adcs %0, %0, %2\n\t"
|
||||
"adcs %0, %0, %3\n\t"
|
||||
"\n2:\n\t"
|
||||
"sub %2, %1, %6\n\t"
|
||||
"cbnz %2, 1b\n\t"
|
||||
/* Sum post-alignment doubleword, if applicable */
|
||||
"tbz %w7, #3, 1f\n\t"
|
||||
"ldr %2, [%1], #8\n\t"
|
||||
"adcs %0, %0, %2\n\t"
|
||||
"\n1:\n\t"
|
||||
/* Sum post-alignment word, if applicable */
|
||||
"tbz %w7, #2, 1f\n\t"
|
||||
"ldr %w2, [%1], #4\n\t"
|
||||
"adcs %0, %0, %2\n\t"
|
||||
"\n1:\n\t"
|
||||
/* Sum post-alignment halfword, if applicable */
|
||||
"tbz %w7, #1, 1f\n\t"
|
||||
"ldrh %w2, [%1], #2\n\t"
|
||||
"adcs %0, %0, %2\n\t"
|
||||
"\n1:\n\t"
|
||||
/* Sum post-alignment byte, if applicable */
|
||||
"tbz %w7, #0, 1f\n\t"
|
||||
"ldrb %w2, [%1], #1\n\t"
|
||||
"adcs %0, %0, %2\n\t"
|
||||
"\n1:\n\t"
|
||||
/* Fold down to a uint32_t plus carry flag */
|
||||
"lsr %2, %0, #32\n\t"
|
||||
"adcs %w0, %w0, %w2\n\t"
|
||||
/* Fold down to a uint16_t plus carry in bit 16 */
|
||||
"ubfm %2, %0, #0, #15\n\t"
|
||||
"ubfm %3, %0, #16, #31\n\t"
|
||||
"adc %w0, %w2, %w3\n\t"
|
||||
/* Fold down to a uint16_t */
|
||||
"tbz %w0, #16, 1f\n\t"
|
||||
"mov %w2, #0xffff\n\t"
|
||||
"sub %w0, %w0, %w2\n\t"
|
||||
"tbz %w0, #16, 1f\n\t"
|
||||
"sub %w0, %w0, %w2\n\t"
|
||||
"\n1:\n\t"
|
||||
/* Byteswap back, if applicable */
|
||||
"tbz %w4, #0, 1f\n\t"
|
||||
"rev16 %w0, %w0\n\t"
|
||||
"\n1:\n\t"
|
||||
/* Invert sum */
|
||||
"eor %w0, %w0, #0xffff\n\t"
|
||||
: "+r" ( sum ), "+r" ( data ), "=&r" ( discard_low ),
|
||||
"=&r" ( discard_high )
|
||||
: "r" ( pre ), "r" ( first ), "r" ( end - post ),
|
||||
"r" ( post )
|
||||
: "cc" );
|
||||
|
||||
return sum;
|
||||
}
|
56
src/arch/arm64/core/setjmp.S
Normal file
56
src/arch/arm64/core/setjmp.S
Normal file
@@ -0,0 +1,56 @@
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
|
||||
|
||||
.text
|
||||
|
||||
/* Must match jmp_buf structure layout */
|
||||
.struct 0
|
||||
env_x19_x20: .quad 0, 0
|
||||
env_x21_x22: .quad 0, 0
|
||||
env_x23_x24: .quad 0, 0
|
||||
env_x25_x26: .quad 0, 0
|
||||
env_x27_x28: .quad 0, 0
|
||||
env_x29_x30: .quad 0, 0
|
||||
env_sp: .quad 0
|
||||
.previous
|
||||
|
||||
/*
|
||||
* Save stack context for non-local goto
|
||||
*/
|
||||
.globl setjmp
|
||||
.type setjmp, %function
|
||||
setjmp:
|
||||
/* Store registers */
|
||||
stp x19, x20, [x0, #env_x19_x20]
|
||||
stp x21, x22, [x0, #env_x21_x22]
|
||||
stp x23, x24, [x0, #env_x23_x24]
|
||||
stp x25, x26, [x0, #env_x25_x26]
|
||||
stp x27, x28, [x0, #env_x27_x28]
|
||||
stp x29, x30, [x0, #env_x29_x30]
|
||||
mov x16, sp
|
||||
str x16, [x0, #env_sp]
|
||||
/* Return 0 when returning as setjmp() */
|
||||
mov x0, #0
|
||||
ret
|
||||
.size setjmp, . - setjmp
|
||||
|
||||
/*
|
||||
* Non-local jump to a saved stack context
|
||||
*/
|
||||
.globl longjmp
|
||||
.type longjmp, %function
|
||||
longjmp:
|
||||
/* Restore registers */
|
||||
ldp x19, x20, [x0, #env_x19_x20]
|
||||
ldp x21, x22, [x0, #env_x21_x22]
|
||||
ldp x23, x24, [x0, #env_x23_x24]
|
||||
ldp x25, x26, [x0, #env_x25_x26]
|
||||
ldp x27, x28, [x0, #env_x27_x28]
|
||||
ldp x29, x30, [x0, #env_x29_x30]
|
||||
ldr x16, [x0, #env_sp]
|
||||
mov sp, x16
|
||||
/* Force result to non-zero */
|
||||
cmp w1, #0
|
||||
csinc w0, w1, w1, ne
|
||||
/* Return to setjmp() caller */
|
||||
br x30
|
||||
.size longjmp, . - longjmp
|
317
src/arch/arm64/include/bits/bigint.h
Normal file
317
src/arch/arm64/include/bits/bigint.h
Normal file
@@ -0,0 +1,317 @@
|
||||
#ifndef _BITS_BIGINT_H
|
||||
#define _BITS_BIGINT_H
|
||||
|
||||
/** @file
|
||||
*
|
||||
* Big integer support
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
|
||||
/** Element of a big integer */
|
||||
typedef uint64_t bigint_element_t;
|
||||
|
||||
/**
|
||||
* Initialise big integer
|
||||
*
|
||||
* @v value0 Element 0 of big integer to initialise
|
||||
* @v size Number of elements
|
||||
* @v data Raw data
|
||||
* @v len Length of raw data
|
||||
*/
|
||||
static inline __attribute__ (( always_inline )) void
|
||||
bigint_init_raw ( uint64_t *value0, unsigned int size,
|
||||
const void *data, size_t len ) {
|
||||
size_t pad_len = ( sizeof ( bigint_t ( size ) ) - len );
|
||||
uint8_t *value_byte = ( ( void * ) value0 );
|
||||
const uint8_t *data_byte = ( data + len );
|
||||
|
||||
/* Copy raw data in reverse order, padding with zeros */
|
||||
while ( len-- )
|
||||
*(value_byte++) = *(--data_byte);
|
||||
while ( pad_len-- )
|
||||
*(value_byte++) = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add big integers
|
||||
*
|
||||
* @v addend0 Element 0 of big integer to add
|
||||
* @v value0 Element 0 of big integer to be added to
|
||||
* @v size Number of elements
|
||||
*/
|
||||
static inline __attribute__ (( always_inline )) void
|
||||
bigint_add_raw ( const uint64_t *addend0, uint64_t *value0,
|
||||
unsigned int size ) {
|
||||
bigint_t ( size ) __attribute__ (( may_alias )) *value =
|
||||
( ( void * ) value0 );
|
||||
uint64_t *discard_addend;
|
||||
uint64_t *discard_value;
|
||||
uint64_t discard_addend_i;
|
||||
uint64_t discard_value_i;
|
||||
unsigned int discard_size;
|
||||
|
||||
__asm__ __volatile__ ( "cmn xzr, xzr\n\t" /* clear CF */
|
||||
"\n1:\n\t"
|
||||
"ldr %3, [%0], #8\n\t"
|
||||
"ldr %4, [%1]\n\t"
|
||||
"adcs %4, %4, %3\n\t"
|
||||
"str %4, [%1], #8\n\t"
|
||||
"sub %w2, %w2, #1\n\t"
|
||||
"cbnz %w2, 1b\n\t"
|
||||
: "=r" ( discard_addend ),
|
||||
"=r" ( discard_value ),
|
||||
"=r" ( discard_size ),
|
||||
"=r" ( discard_addend_i ),
|
||||
"=r" ( discard_value_i ),
|
||||
"+m" ( *value )
|
||||
: "0" ( addend0 ), "1" ( value0 ), "2" ( size )
|
||||
: "cc" );
|
||||
}
|
||||
|
||||
/**
|
||||
* Subtract big integers
|
||||
*
|
||||
* @v subtrahend0 Element 0 of big integer to subtract
|
||||
* @v value0 Element 0 of big integer to be subtracted from
|
||||
* @v size Number of elements
|
||||
*/
|
||||
static inline __attribute__ (( always_inline )) void
|
||||
bigint_subtract_raw ( const uint64_t *subtrahend0, uint64_t *value0,
|
||||
unsigned int size ) {
|
||||
bigint_t ( size ) __attribute__ (( may_alias )) *value =
|
||||
( ( void * ) value0 );
|
||||
uint64_t *discard_subtrahend;
|
||||
uint64_t *discard_value;
|
||||
uint64_t discard_subtrahend_i;
|
||||
uint64_t discard_value_i;
|
||||
unsigned int discard_size;
|
||||
|
||||
__asm__ __volatile__ ( "cmp xzr, xzr\n\t" /* set CF */
|
||||
"\n1:\n\t"
|
||||
"ldr %3, [%0], #8\n\t"
|
||||
"ldr %4, [%1]\n\t"
|
||||
"sbcs %4, %4, %3\n\t"
|
||||
"str %4, [%1], #8\n\t"
|
||||
"sub %w2, %w2, #1\n\t"
|
||||
"cbnz %w2, 1b\n\t"
|
||||
: "=r" ( discard_subtrahend ),
|
||||
"=r" ( discard_value ),
|
||||
"=r" ( discard_size ),
|
||||
"=r" ( discard_subtrahend_i ),
|
||||
"=r" ( discard_value_i ),
|
||||
"+m" ( *value )
|
||||
: "0" ( subtrahend0 ), "1" ( value0 ),
|
||||
"2" ( size )
|
||||
: "cc" );
|
||||
}
|
||||
|
||||
/**
|
||||
* Rotate big integer left
|
||||
*
|
||||
* @v value0 Element 0 of big integer
|
||||
* @v size Number of elements
|
||||
*/
|
||||
static inline __attribute__ (( always_inline )) void
|
||||
bigint_rol_raw ( uint64_t *value0, unsigned int size ) {
|
||||
bigint_t ( size ) __attribute__ (( may_alias )) *value =
|
||||
( ( void * ) value0 );
|
||||
uint64_t *discard_value;
|
||||
uint64_t discard_value_i;
|
||||
unsigned int discard_size;
|
||||
|
||||
__asm__ __volatile__ ( "cmn xzr, xzr\n\t" /* clear CF */
|
||||
"\n1:\n\t"
|
||||
"ldr %2, [%0]\n\t"
|
||||
"adcs %2, %2, %2\n\t"
|
||||
"str %2, [%0], #8\n\t"
|
||||
"sub %w1, %w1, #1\n\t"
|
||||
"cbnz %w1, 1b\n\t"
|
||||
: "=r" ( discard_value ),
|
||||
"=r" ( discard_size ),
|
||||
"=r" ( discard_value_i ),
|
||||
"+m" ( *value )
|
||||
: "0" ( value0 ), "1" ( size )
|
||||
: "cc" );
|
||||
}
|
||||
|
||||
/**
|
||||
* Rotate big integer right
|
||||
*
|
||||
* @v value0 Element 0 of big integer
|
||||
* @v size Number of elements
|
||||
*/
|
||||
static inline __attribute__ (( always_inline )) void
|
||||
bigint_ror_raw ( uint64_t *value0, unsigned int size ) {
|
||||
bigint_t ( size ) __attribute__ (( may_alias )) *value =
|
||||
( ( void * ) value0 );
|
||||
uint64_t *discard_value;
|
||||
uint64_t discard_value_i;
|
||||
uint64_t discard_value_j;
|
||||
unsigned int discard_size;
|
||||
|
||||
__asm__ __volatile__ ( "mov %3, #0\n\t"
|
||||
"\n1:\n\t"
|
||||
"sub %w1, %w1, #1\n\t"
|
||||
"ldr %2, [%0, %1, lsl #3]\n\t"
|
||||
"extr %3, %3, %2, #1\n\t"
|
||||
"str %3, [%0, %1, lsl #3]\n\t"
|
||||
"mov %3, %2\n\t"
|
||||
"cbnz %w1, 1b\n\t"
|
||||
: "=r" ( discard_value ),
|
||||
"=r" ( discard_size ),
|
||||
"=r" ( discard_value_i ),
|
||||
"=r" ( discard_value_j ),
|
||||
"+m" ( *value )
|
||||
: "0" ( value0 ), "1" ( size ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if big integer is equal to zero
|
||||
*
|
||||
* @v value0 Element 0 of big integer
|
||||
* @v size Number of elements
|
||||
* @ret is_zero Big integer is equal to zero
|
||||
*/
|
||||
static inline __attribute__ (( always_inline, pure )) int
|
||||
bigint_is_zero_raw ( const uint64_t *value0, unsigned int size ) {
|
||||
const uint64_t *value = value0;
|
||||
uint64_t value_i;
|
||||
|
||||
do {
|
||||
value_i = *(value++);
|
||||
if ( value_i )
|
||||
break;
|
||||
} while ( --size );
|
||||
|
||||
return ( value_i == 0 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare big integers
|
||||
*
|
||||
* @v value0 Element 0 of big integer
|
||||
* @v reference0 Element 0 of reference big integer
|
||||
* @v size Number of elements
|
||||
* @ret geq Big integer is greater than or equal to the reference
|
||||
*/
|
||||
static inline __attribute__ (( always_inline, pure )) int
|
||||
bigint_is_geq_raw ( const uint64_t *value0, const uint64_t *reference0,
|
||||
unsigned int size ) {
|
||||
const uint64_t *value = ( value0 + size );
|
||||
const uint64_t *reference = ( reference0 + size );
|
||||
uint64_t value_i;
|
||||
uint64_t reference_i;
|
||||
|
||||
do {
|
||||
value_i = *(--value);
|
||||
reference_i = *(--reference);
|
||||
if ( value_i != reference_i )
|
||||
break;
|
||||
} while ( --size );
|
||||
|
||||
return ( value_i >= reference_i );
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if bit is set in big integer
|
||||
*
|
||||
* @v value0 Element 0 of big integer
|
||||
* @v size Number of elements
|
||||
* @v bit Bit to test
|
||||
* @ret is_set Bit is set
|
||||
*/
|
||||
static inline __attribute__ (( always_inline )) int
|
||||
bigint_bit_is_set_raw ( const uint64_t *value0, unsigned int size,
|
||||
unsigned int bit ) {
|
||||
const bigint_t ( size ) __attribute__ (( may_alias )) *value =
|
||||
( ( const void * ) value0 );
|
||||
unsigned int index = ( bit / ( 8 * sizeof ( value->element[0] ) ) );
|
||||
unsigned int subindex = ( bit % ( 8 * sizeof ( value->element[0] ) ) );
|
||||
|
||||
return ( !! ( value->element[index] & ( 1UL << subindex ) ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Find highest bit set in big integer
|
||||
*
|
||||
* @v value0 Element 0 of big integer
|
||||
* @v size Number of elements
|
||||
* @ret max_bit Highest bit set + 1 (or 0 if no bits set)
|
||||
*/
|
||||
static inline __attribute__ (( always_inline )) int
|
||||
bigint_max_set_bit_raw ( const uint64_t *value0, unsigned int size ) {
|
||||
const uint64_t *value = ( value0 + size );
|
||||
int max_bit = ( 8 * sizeof ( bigint_t ( size ) ) );
|
||||
uint64_t value_i;
|
||||
|
||||
do {
|
||||
value_i = *(--value);
|
||||
max_bit -= ( 64 - fls ( value_i ) );
|
||||
if ( value_i )
|
||||
break;
|
||||
} while ( --size );
|
||||
|
||||
return max_bit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Grow big integer
|
||||
*
|
||||
* @v source0 Element 0 of source big integer
|
||||
* @v source_size Number of elements in source big integer
|
||||
* @v dest0 Element 0 of destination big integer
|
||||
* @v dest_size Number of elements in destination big integer
|
||||
*/
|
||||
static inline __attribute__ (( always_inline )) void
|
||||
bigint_grow_raw ( const uint64_t *source0, unsigned int source_size,
|
||||
uint64_t *dest0, unsigned int dest_size ) {
|
||||
unsigned int pad_size = ( dest_size - source_size );
|
||||
|
||||
memcpy ( dest0, source0, sizeof ( bigint_t ( source_size ) ) );
|
||||
memset ( ( dest0 + source_size ), 0, sizeof ( bigint_t ( pad_size ) ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Shrink big integer
|
||||
*
|
||||
* @v source0 Element 0 of source big integer
|
||||
* @v source_size Number of elements in source big integer
|
||||
* @v dest0 Element 0 of destination big integer
|
||||
* @v dest_size Number of elements in destination big integer
|
||||
*/
|
||||
static inline __attribute__ (( always_inline )) void
|
||||
bigint_shrink_raw ( const uint64_t *source0, unsigned int source_size __unused,
|
||||
uint64_t *dest0, unsigned int dest_size ) {
|
||||
|
||||
memcpy ( dest0, source0, sizeof ( bigint_t ( dest_size ) ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Finalise big integer
|
||||
*
|
||||
* @v value0 Element 0 of big integer to finalise
|
||||
* @v size Number of elements
|
||||
* @v out Output buffer
|
||||
* @v len Length of output buffer
|
||||
*/
|
||||
static inline __attribute__ (( always_inline )) void
|
||||
bigint_done_raw ( const uint64_t *value0, unsigned int size __unused,
|
||||
void *out, size_t len ) {
|
||||
const uint8_t *value_byte = ( ( const void * ) value0 );
|
||||
uint8_t *out_byte = ( out + len );
|
||||
|
||||
/* Copy raw data in reverse order */
|
||||
while ( len-- )
|
||||
*(--out_byte) = *(value_byte++);
|
||||
}
|
||||
|
||||
extern void bigint_multiply_raw ( const uint64_t *multiplicand0,
|
||||
const uint64_t *multiplier0,
|
||||
uint64_t *value0, unsigned int size );
|
||||
|
||||
#endif /* _BITS_BIGINT_H */
|
100
src/arch/arm64/include/bits/bitops.h
Normal file
100
src/arch/arm64/include/bits/bitops.h
Normal file
@@ -0,0 +1,100 @@
|
||||
#ifndef _BITS_BITOPS_H
|
||||
#define _BITS_BITOPS_H
|
||||
|
||||
/** @file
|
||||
*
|
||||
* ARM bit operations
|
||||
*
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/**
|
||||
* Test and set bit atomically
|
||||
*
|
||||
* @v bit Bit to set
|
||||
* @v bits Bit field
|
||||
* @ret old Old value of bit (zero or non-zero)
|
||||
*/
|
||||
static inline __attribute__ (( always_inline )) int
|
||||
test_and_set_bit ( unsigned int bit, volatile void *bits ) {
|
||||
unsigned int index = ( bit / 64 );
|
||||
unsigned int offset = ( bit % 64 );
|
||||
volatile uint64_t *qword = ( ( ( volatile uint64_t * ) bits ) + index );
|
||||
uint64_t mask = ( 1UL << offset );
|
||||
uint64_t old;
|
||||
uint64_t new;
|
||||
uint32_t flag;
|
||||
|
||||
__asm__ __volatile__ ( "\n1:\n\t"
|
||||
"ldxr %0, %3\n\t"
|
||||
"orr %1, %0, %4\n\t"
|
||||
"stxr %w2, %1, %3\n\t"
|
||||
"tst %w2, %w2\n\t"
|
||||
"bne 1b\n\t"
|
||||
: "=&r" ( old ), "=&r" ( new ), "=&r" ( flag ),
|
||||
"+Q" ( *qword )
|
||||
: "r" ( mask )
|
||||
: "cc" );
|
||||
|
||||
return ( !! ( old & mask ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Test and clear bit atomically
|
||||
*
|
||||
* @v bit Bit to set
|
||||
* @v bits Bit field
|
||||
* @ret old Old value of bit (zero or non-zero)
|
||||
*/
|
||||
static inline __attribute__ (( always_inline )) int
|
||||
test_and_clear_bit ( unsigned int bit, volatile void *bits ) {
|
||||
unsigned int index = ( bit / 64 );
|
||||
unsigned int offset = ( bit % 64 );
|
||||
volatile uint64_t *qword = ( ( ( volatile uint64_t * ) bits ) + index );
|
||||
uint64_t mask = ( 1UL << offset );
|
||||
uint64_t old;
|
||||
uint64_t new;
|
||||
uint32_t flag;
|
||||
|
||||
__asm__ __volatile__ ( "\n1:\n\t"
|
||||
"ldxr %0, %3\n\t"
|
||||
"bic %1, %0, %4\n\t"
|
||||
"stxr %w2, %1, %3\n\t"
|
||||
"tst %w2, %w2\n\t"
|
||||
"bne 1b\n\t"
|
||||
: "=&r" ( old ), "=&r" ( new ), "=&r" ( flag ),
|
||||
"+Q" ( *qword )
|
||||
: "r" ( mask )
|
||||
: "cc" );
|
||||
|
||||
return ( !! ( old & mask ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Set bit atomically
|
||||
*
|
||||
* @v bit Bit to set
|
||||
* @v bits Bit field
|
||||
*/
|
||||
static inline __attribute__ (( always_inline )) void
|
||||
set_bit ( unsigned int bit, volatile void *bits ) {
|
||||
|
||||
test_and_set_bit ( bit, bits );
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear bit atomically
|
||||
*
|
||||
* @v bit Bit to set
|
||||
* @v bits Bit field
|
||||
*/
|
||||
static inline __attribute__ (( always_inline )) void
|
||||
clear_bit ( unsigned int bit, volatile void *bits ) {
|
||||
|
||||
test_and_clear_bit ( bit, bits );
|
||||
}
|
||||
|
||||
#endif /* _BITS_BITOPS_H */
|
47
src/arch/arm64/include/bits/byteswap.h
Normal file
47
src/arch/arm64/include/bits/byteswap.h
Normal file
@@ -0,0 +1,47 @@
|
||||
#ifndef _BITS_BYTESWAP_H
|
||||
#define _BITS_BYTESWAP_H
|
||||
|
||||
/** @file
|
||||
*
|
||||
* Byte-order swapping functions
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
static inline __attribute__ (( always_inline, const )) uint16_t
|
||||
__bswap_variable_16 ( uint16_t x ) {
|
||||
__asm__ ( "rev16 %0, %1" : "=r" ( x ) : "r" ( x ) );
|
||||
return x;
|
||||
}
|
||||
|
||||
static inline __attribute__ (( always_inline )) void
|
||||
__bswap_16s ( uint16_t *x ) {
|
||||
*x = __bswap_variable_16 ( *x );
|
||||
}
|
||||
|
||||
static inline __attribute__ (( always_inline, const )) uint32_t
|
||||
__bswap_variable_32 ( uint32_t x ) {
|
||||
__asm__ ( "rev32 %0, %1" : "=r" ( x ) : "r" ( x ) );
|
||||
return x;
|
||||
}
|
||||
|
||||
static inline __attribute__ (( always_inline )) void
|
||||
__bswap_32s ( uint32_t *x ) {
|
||||
*x = __bswap_variable_32 ( *x );
|
||||
}
|
||||
|
||||
static inline __attribute__ (( always_inline, const )) uint64_t
|
||||
__bswap_variable_64 ( uint64_t x ) {
|
||||
__asm__ ( "rev %0, %1" : "=r" ( x ) : "r" ( x ) );
|
||||
return x;
|
||||
}
|
||||
|
||||
static inline __attribute__ (( always_inline )) void
|
||||
__bswap_64s ( uint64_t *x ) {
|
||||
*x = __bswap_variable_64 ( *x );
|
||||
}
|
||||
|
||||
#endif
|
16
src/arch/arm64/include/bits/compiler.h
Normal file
16
src/arch/arm64/include/bits/compiler.h
Normal file
@@ -0,0 +1,16 @@
|
||||
#ifndef _BITS_COMPILER_H
|
||||
#define _BITS_COMPILER_H
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
/** Dummy relocation type */
|
||||
#define RELOC_TYPE_NONE R_AARCH64_NULL
|
||||
|
||||
#ifndef ASSEMBLY
|
||||
|
||||
#define __asmcall
|
||||
#define __libgcc
|
||||
|
||||
#endif /* ASSEMBLY */
|
||||
|
||||
#endif /*_BITS_COMPILER_H */
|
28
src/arch/arm64/include/bits/profile.h
Normal file
28
src/arch/arm64/include/bits/profile.h
Normal file
@@ -0,0 +1,28 @@
|
||||
#ifndef _BITS_PROFILE_H
|
||||
#define _BITS_PROFILE_H
|
||||
|
||||
/** @file
|
||||
*
|
||||
* Profiling
|
||||
*
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/**
|
||||
* Get profiling timestamp
|
||||
*
|
||||
* @ret timestamp Timestamp
|
||||
*/
|
||||
static inline __attribute__ (( always_inline )) uint64_t
|
||||
profile_timestamp ( void ) {
|
||||
uint64_t cycles;
|
||||
|
||||
/* Read cycle counter */
|
||||
__asm__ __volatile__ ( "mrs %0, CNTVCT_EL0\n\t" : "=r" ( cycles ) );
|
||||
return cycles;
|
||||
}
|
||||
|
||||
#endif /* _BITS_PROFILE_H */
|
21
src/arch/arm64/include/bits/stdint.h
Normal file
21
src/arch/arm64/include/bits/stdint.h
Normal file
@@ -0,0 +1,21 @@
|
||||
#ifndef _BITS_STDINT_H
|
||||
#define _BITS_STDINT_H
|
||||
|
||||
typedef __SIZE_TYPE__ size_t;
|
||||
typedef signed long ssize_t;
|
||||
typedef signed long off_t;
|
||||
|
||||
typedef unsigned char uint8_t;
|
||||
typedef unsigned short uint16_t;
|
||||
typedef unsigned int uint32_t;
|
||||
typedef unsigned long long uint64_t;
|
||||
|
||||
typedef signed char int8_t;
|
||||
typedef signed short int16_t;
|
||||
typedef signed int int32_t;
|
||||
typedef signed long long int64_t;
|
||||
|
||||
typedef unsigned long physaddr_t;
|
||||
typedef unsigned long intptr_t;
|
||||
|
||||
#endif /* _BITS_STDINT_H */
|
106
src/arch/arm64/include/bits/string.h
Normal file
106
src/arch/arm64/include/bits/string.h
Normal file
@@ -0,0 +1,106 @@
|
||||
#ifndef BITS_STRING_H
|
||||
#define BITS_STRING_H
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
/** @file
|
||||
*
|
||||
* String functions
|
||||
*
|
||||
*/
|
||||
|
||||
extern void arm64_bzero ( void *dest, size_t len );
|
||||
extern void arm64_memset ( void *dest, size_t len, int character );
|
||||
extern void arm64_memcpy ( void *dest, const void *src, size_t len );
|
||||
extern void arm64_memmove_forwards ( void *dest, const void *src, size_t len );
|
||||
extern void arm64_memmove_backwards ( void *dest, const void *src, size_t len );
|
||||
extern void arm64_memmove ( void *dest, const void *src, size_t len );
|
||||
|
||||
/**
|
||||
* Fill memory region
|
||||
*
|
||||
* @v dest Destination region
|
||||
* @v character Fill character
|
||||
* @v len Length
|
||||
* @ret dest Destination region
|
||||
*/
|
||||
static inline __attribute__ (( always_inline )) void *
|
||||
memset ( void *dest, int character, size_t len ) {
|
||||
|
||||
/* Allow gcc to generate inline "stX xzr" instructions for
|
||||
* small, constant lengths.
|
||||
*/
|
||||
if ( __builtin_constant_p ( character ) && ( character == 0 ) &&
|
||||
__builtin_constant_p ( len ) && ( len <= 64 ) ) {
|
||||
__builtin_memset ( dest, 0, len );
|
||||
return dest;
|
||||
}
|
||||
|
||||
/* For zeroing larger or non-constant lengths, use the
|
||||
* optimised variable-length zeroing code.
|
||||
*/
|
||||
if ( __builtin_constant_p ( character ) && ( character == 0 ) ) {
|
||||
arm64_bzero ( dest, len );
|
||||
return dest;
|
||||
}
|
||||
|
||||
/* Not necessarily zeroing: use basic variable-length code */
|
||||
arm64_memset ( dest, len, character );
|
||||
return dest;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy memory region
|
||||
*
|
||||
* @v dest Destination region
|
||||
* @v src Source region
|
||||
* @v len Length
|
||||
* @ret dest Destination region
|
||||
*/
|
||||
static inline __attribute__ (( always_inline )) void *
|
||||
memcpy ( void *dest, const void *src, size_t len ) {
|
||||
|
||||
/* Allow gcc to generate inline "ldX"/"stX" instructions for
|
||||
* small, constant lengths.
|
||||
*/
|
||||
if ( __builtin_constant_p ( len ) && ( len <= 64 ) ) {
|
||||
__builtin_memcpy ( dest, src, len );
|
||||
return dest;
|
||||
}
|
||||
|
||||
/* Otherwise, use variable-length code */
|
||||
arm64_memcpy ( dest, src, len );
|
||||
return dest;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy (possibly overlapping) memory region
|
||||
*
|
||||
* @v dest Destination region
|
||||
* @v src Source region
|
||||
* @v len Length
|
||||
* @ret dest Destination region
|
||||
*/
|
||||
static inline __attribute__ (( always_inline )) void *
|
||||
memmove ( void *dest, const void *src, size_t len ) {
|
||||
ssize_t offset = ( dest - src );
|
||||
|
||||
/* If required direction of copy is known at build time, then
|
||||
* use the appropriate forwards/backwards copy directly.
|
||||
*/
|
||||
if ( __builtin_constant_p ( offset ) ) {
|
||||
if ( offset <= 0 ) {
|
||||
arm64_memmove_forwards ( dest, src, len );
|
||||
return dest;
|
||||
} else {
|
||||
arm64_memmove_backwards ( dest, src, len );
|
||||
return dest;
|
||||
}
|
||||
}
|
||||
|
||||
/* Otherwise, use ambidirectional copy */
|
||||
arm64_memmove ( dest, src, len );
|
||||
return dest;
|
||||
}
|
||||
|
||||
#endif /* BITS_STRING_H */
|
69
src/arch/arm64/include/bits/strings.h
Normal file
69
src/arch/arm64/include/bits/strings.h
Normal file
@@ -0,0 +1,69 @@
|
||||
#ifndef _BITS_STRINGS_H
|
||||
#define _BITS_STRINGS_H
|
||||
|
||||
/** @file
|
||||
*
|
||||
* String functions
|
||||
*
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
/**
|
||||
* Find first (i.e. least significant) set bit
|
||||
*
|
||||
* @v value Value
|
||||
* @ret lsb Least significant bit set in value (LSB=1), or zero
|
||||
*/
|
||||
static inline __attribute__ (( always_inline )) int __ffsll ( long long value ){
|
||||
unsigned long long bits = value;
|
||||
unsigned long long lsb;
|
||||
unsigned int lz;
|
||||
|
||||
/* Extract least significant set bit */
|
||||
lsb = ( bits & -bits );
|
||||
|
||||
/* Count number of leading zeroes before LSB */
|
||||
__asm__ ( "clz %0, %1" : "=r" ( lz ) : "r" ( lsb ) );
|
||||
|
||||
return ( 64 - lz );
|
||||
}
|
||||
|
||||
/**
|
||||
* Find first (i.e. least significant) set bit
|
||||
*
|
||||
* @v value Value
|
||||
* @ret lsb Least significant bit set in value (LSB=1), or zero
|
||||
*/
|
||||
static inline __attribute__ (( always_inline )) int __ffsl ( long value ) {
|
||||
|
||||
return __ffsll ( value );
|
||||
}
|
||||
|
||||
/**
|
||||
* Find last (i.e. most significant) set bit
|
||||
*
|
||||
* @v value Value
|
||||
* @ret msb Most significant bit set in value (LSB=1), or zero
|
||||
*/
|
||||
static inline __attribute__ (( always_inline )) int __flsll ( long long value ){
|
||||
unsigned int lz;
|
||||
|
||||
/* Count number of leading zeroes */
|
||||
__asm__ ( "clz %0, %1" : "=r" ( lz ) : "r" ( value ) );
|
||||
|
||||
return ( 64 - lz );
|
||||
}
|
||||
|
||||
/**
|
||||
* Find last (i.e. most significant) set bit
|
||||
*
|
||||
* @v value Value
|
||||
* @ret msb Most significant bit set in value (LSB=1), or zero
|
||||
*/
|
||||
static inline __attribute__ (( always_inline )) int __flsl ( long value ) {
|
||||
|
||||
return __flsll ( value );
|
||||
}
|
||||
|
||||
#endif /* _BITS_STRINGS_H */
|
15
src/arch/arm64/include/bits/tcpip.h
Normal file
15
src/arch/arm64/include/bits/tcpip.h
Normal file
@@ -0,0 +1,15 @@
|
||||
#ifndef _BITS_TCPIP_H
|
||||
#define _BITS_TCPIP_H
|
||||
|
||||
/** @file
|
||||
*
|
||||
* Transport-network layer interface
|
||||
*
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
extern uint16_t tcpip_continue_chksum ( uint16_t sum, const void *data,
|
||||
size_t len );
|
||||
|
||||
#endif /* _BITS_TCPIP_H */
|
40
src/arch/arm64/include/efi/ipxe/dhcp_arch.h
Normal file
40
src/arch/arm64/include/efi/ipxe/dhcp_arch.h
Normal file
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright (C) 2015 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 (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.
|
||||
*
|
||||
* You can also choose to distribute this program under the terms of
|
||||
* the Unmodified Binary Distribution Licence (as given in the file
|
||||
* COPYING.UBDL), provided that you have satisfied its requirements.
|
||||
*/
|
||||
|
||||
#ifndef _DHCP_ARCH_H
|
||||
#define _DHCP_ARCH_H
|
||||
|
||||
/** @file
|
||||
*
|
||||
* Architecture-specific DHCP options
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
#include <ipxe/dhcp.h>
|
||||
|
||||
#define DHCP_ARCH_CLIENT_ARCHITECTURE DHCP_CLIENT_ARCHITECTURE_ARM64
|
||||
|
||||
#define DHCP_ARCH_CLIENT_NDI 1 /* UNDI */ , 3, 10 /* v3.10 */
|
||||
|
||||
#endif
|
45
src/arch/arm64/include/gdbmach.h
Normal file
45
src/arch/arm64/include/gdbmach.h
Normal file
@@ -0,0 +1,45 @@
|
||||
#ifndef GDBMACH_H
|
||||
#define GDBMACH_H
|
||||
|
||||
/** @file
|
||||
*
|
||||
* GDB architecture specifics
|
||||
*
|
||||
* This file declares functions for manipulating the machine state and
|
||||
* debugging context.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
typedef unsigned long gdbreg_t;
|
||||
|
||||
/* Register snapshot */
|
||||
enum {
|
||||
/* Not yet implemented */
|
||||
GDBMACH_NREGS,
|
||||
};
|
||||
|
||||
#define GDBMACH_SIZEOF_REGS ( GDBMACH_NREGS * sizeof ( gdbreg_t ) )
|
||||
|
||||
static inline void gdbmach_set_pc ( gdbreg_t *regs, gdbreg_t pc ) {
|
||||
/* Not yet implemented */
|
||||
( void ) regs;
|
||||
( void ) pc;
|
||||
}
|
||||
|
||||
static inline void gdbmach_set_single_step ( gdbreg_t *regs, int step ) {
|
||||
/* Not yet implemented */
|
||||
( void ) regs;
|
||||
( void ) step;
|
||||
}
|
||||
|
||||
static inline void gdbmach_breakpoint ( void ) {
|
||||
/* Not yet implemented */
|
||||
}
|
||||
|
||||
extern int gdbmach_set_breakpoint ( int type, unsigned long addr, size_t len,
|
||||
int enable );
|
||||
extern void gdbmach_init ( void );
|
||||
|
||||
#endif /* GDBMACH_H */
|
59
src/arch/arm64/include/limits.h
Normal file
59
src/arch/arm64/include/limits.h
Normal file
@@ -0,0 +1,59 @@
|
||||
#ifndef LIMITS_H
|
||||
#define LIMITS_H 1
|
||||
|
||||
/* Number of bits in a `char' */
|
||||
#define CHAR_BIT 8
|
||||
|
||||
/* Minimum and maximum values a `signed char' can hold */
|
||||
#define SCHAR_MIN (-128)
|
||||
#define SCHAR_MAX 127
|
||||
|
||||
/* Maximum value an `unsigned char' can hold. (Minimum is 0.) */
|
||||
#define UCHAR_MAX 255
|
||||
|
||||
/* Minimum and maximum values a `char' can hold */
|
||||
#define CHAR_MIN SCHAR_MIN
|
||||
#define CHAR_MAX SCHAR_MAX
|
||||
|
||||
/* Minimum and maximum values a `signed short int' can hold */
|
||||
#define SHRT_MIN (-32768)
|
||||
#define SHRT_MAX 32767
|
||||
|
||||
/* Maximum value an `unsigned short' can hold. (Minimum is 0.) */
|
||||
#define USHRT_MAX 65535
|
||||
|
||||
|
||||
/* Minimum and maximum values a `signed int' can hold */
|
||||
#define INT_MIN (-INT_MAX - 1)
|
||||
#define INT_MAX 2147483647
|
||||
|
||||
/* Maximum value an `unsigned int' can hold. (Minimum is 0.) */
|
||||
#define UINT_MAX 4294967295U
|
||||
|
||||
|
||||
/* Minimum and maximum values a `signed int' can hold */
|
||||
#define INT_MAX 2147483647
|
||||
#define INT_MIN (-INT_MAX - 1)
|
||||
|
||||
|
||||
/* Maximum value an `unsigned int' can hold. (Minimum is 0.) */
|
||||
#define UINT_MAX 4294967295U
|
||||
|
||||
|
||||
/* Minimum and maximum values a `signed long' can hold */
|
||||
#define LONG_MAX 9223372036854775807L
|
||||
#define LONG_MIN (-LONG_MAX - 1L)
|
||||
|
||||
/* Maximum value an `unsigned long' can hold. (Minimum is 0.) */
|
||||
#define ULONG_MAX 18446744073709551615UL
|
||||
|
||||
/* Minimum and maximum values a `signed long long' can hold */
|
||||
#define LLONG_MAX 9223372036854775807LL
|
||||
#define LLONG_MIN (-LONG_MAX - 1LL)
|
||||
|
||||
|
||||
/* Maximum value an `unsigned long long' can hold. (Minimum is 0.) */
|
||||
#define ULLONG_MAX 18446744073709551615ULL
|
||||
|
||||
|
||||
#endif /* LIMITS_H */
|
44
src/arch/arm64/include/setjmp.h
Normal file
44
src/arch/arm64/include/setjmp.h
Normal file
@@ -0,0 +1,44 @@
|
||||
#ifndef _SETJMP_H
|
||||
#define _SETJMP_H
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/** A jump buffer */
|
||||
typedef struct {
|
||||
/** Saved x19 */
|
||||
uint64_t x19;
|
||||
/** Saved x20 */
|
||||
uint64_t x20;
|
||||
/** Saved x21 */
|
||||
uint64_t x21;
|
||||
/** Saved x22 */
|
||||
uint64_t x22;
|
||||
/** Saved x23 */
|
||||
uint64_t x23;
|
||||
/** Saved x24 */
|
||||
uint64_t x24;
|
||||
/** Saved x25 */
|
||||
uint64_t x25;
|
||||
/** Saved x26 */
|
||||
uint64_t x26;
|
||||
/** Saved x27 */
|
||||
uint64_t x27;
|
||||
/** Saved x28 */
|
||||
uint64_t x28;
|
||||
/** Saved frame pointer (x29) */
|
||||
uint64_t x29;
|
||||
/** Saved link register (x30) */
|
||||
uint64_t x30;
|
||||
/** Saved stack pointer (x31) */
|
||||
uint64_t sp;
|
||||
} jmp_buf[1];
|
||||
|
||||
extern int __asmcall __attribute__ (( returns_twice ))
|
||||
setjmp ( jmp_buf env );
|
||||
|
||||
extern void __asmcall __attribute__ (( noreturn ))
|
||||
longjmp ( jmp_buf env, int val );
|
||||
|
||||
#endif /* _SETJMP_H */
|
49
src/arch/i386/include/bits/hyperv.h
Normal file
49
src/arch/i386/include/bits/hyperv.h
Normal file
@@ -0,0 +1,49 @@
|
||||
#ifndef _BITS_HYPERV_H
|
||||
#define _BITS_HYPERV_H
|
||||
|
||||
/** @file
|
||||
*
|
||||
* Hyper-V interface
|
||||
*
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <ipxe/io.h>
|
||||
|
||||
/**
|
||||
* Issue hypercall
|
||||
*
|
||||
* @v hv Hyper-V hypervisor
|
||||
* @v code Call code
|
||||
* @v in Input parameters
|
||||
* @v out Output parameters
|
||||
* @ret status Status code
|
||||
*/
|
||||
static inline __attribute__ (( always_inline )) int
|
||||
hv_call ( struct hv_hypervisor *hv, unsigned int code, const void *in,
|
||||
void *out ) {
|
||||
void *hypercall = hv->hypercall;
|
||||
uint32_t in_phys;
|
||||
uint32_t out_phys;
|
||||
uint32_t discard_ecx;
|
||||
uint32_t discard_edx;
|
||||
uint16_t result;
|
||||
|
||||
in_phys = ( ( __builtin_constant_p ( in ) && ( in == NULL ) )
|
||||
? 0 : virt_to_phys ( in ) );
|
||||
out_phys = ( ( __builtin_constant_p ( out ) && ( out == NULL ) )
|
||||
? 0 : virt_to_phys ( out ) );
|
||||
__asm__ __volatile__ ( "call *%9"
|
||||
: "=a" ( result ), "=c" ( discard_ecx ),
|
||||
"=d" ( discard_edx )
|
||||
: "d" ( 0 ), "a" ( code ),
|
||||
"b" ( 0 ), "c" ( in_phys ),
|
||||
"D" ( 0 ), "S" ( out_phys ),
|
||||
"m" ( hypercall ) );
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif /* _BITS_HYPERV_H */
|
38
src/arch/i386/include/ipxe/msr.h
Normal file
38
src/arch/i386/include/ipxe/msr.h
Normal file
@@ -0,0 +1,38 @@
|
||||
#ifndef _IPXE_MSR_H
|
||||
#define _IPXE_MSR_H
|
||||
|
||||
/** @file
|
||||
*
|
||||
* Model-specific registers
|
||||
*
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
/**
|
||||
* Read model-specific register
|
||||
*
|
||||
* @v msr Model-specific register
|
||||
* @ret value Value
|
||||
*/
|
||||
static inline __attribute__ (( always_inline )) uint64_t
|
||||
rdmsr ( unsigned int msr ) {
|
||||
uint64_t value;
|
||||
|
||||
__asm__ __volatile__ ( "rdmsr" : "=A" ( value ) : "c" ( msr ) );
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write model-specific register
|
||||
*
|
||||
* @v msr Model-specific register
|
||||
* @v value Value
|
||||
*/
|
||||
static inline __attribute__ (( always_inline )) void
|
||||
wrmsr ( unsigned int msr, uint64_t value ) {
|
||||
|
||||
__asm__ __volatile__ ( "wrmsr" : : "c" ( msr ), "A" ( value ) );
|
||||
}
|
||||
|
||||
#endif /* _IPXE_MSR_H */
|
54
src/arch/i386/tests/gdbstub_test.S
Normal file
54
src/arch/i386/tests/gdbstub_test.S
Normal file
@@ -0,0 +1,54 @@
|
||||
.arch i386
|
||||
|
||||
.section ".data", "aw", @progbits
|
||||
watch_me:
|
||||
.long 0xfeedbeef
|
||||
|
||||
.section ".text", "ax", @progbits
|
||||
.code32
|
||||
gdbstub_test:
|
||||
/* 1. Read registers test */
|
||||
movl $0xea010203, %eax
|
||||
movl $0xeb040506, %ebx
|
||||
movl $0xec070809, %ecx
|
||||
movl $0xed0a0b0c, %edx
|
||||
movl $0x510d0e0f, %esi
|
||||
movl $0xd1102030, %edi
|
||||
int $3
|
||||
|
||||
/* 2. Write registers test */
|
||||
int $3
|
||||
|
||||
/* 3. Read memory test */
|
||||
subl $8, %esp
|
||||
movl $0x11223344, 4(%esp)
|
||||
movw $0x5566, 2(%esp)
|
||||
movb $0x77, (%esp)
|
||||
int $3
|
||||
|
||||
/* 4. Write memory test */
|
||||
int $3
|
||||
addl $8, %esp
|
||||
|
||||
/* 5. Step test */
|
||||
int $3
|
||||
nop
|
||||
|
||||
/* 6. Access watch test */
|
||||
movl $0x600d0000, %ecx
|
||||
movl watch_me, %eax
|
||||
movl $0xbad00000, %ecx
|
||||
int $3
|
||||
movl $0x600d0001, %ecx
|
||||
movl %eax, watch_me
|
||||
movl $0xbad00001, %ecx
|
||||
int $3
|
||||
|
||||
/* 7. Write watch test */
|
||||
movl $0x600d0002, %ecx
|
||||
movl %eax, watch_me
|
||||
movl $0xbad00002, %ecx
|
||||
int $3
|
||||
|
||||
1:
|
||||
jmp 1b
|
116
src/arch/i386/tests/gdbstub_test.gdb
Executable file
116
src/arch/i386/tests/gdbstub_test.gdb
Executable file
@@ -0,0 +1,116 @@
|
||||
#!/usr/bin/gdb -x
|
||||
# Test suite for GDB remote debugging
|
||||
# Run:
|
||||
# make bin/ipxe.hd.tmp
|
||||
# make
|
||||
# gdb
|
||||
# (gdb) target remote :TCPPORT
|
||||
# OR
|
||||
# (gdb) target remote udp:IP:UDPPORT
|
||||
# (gdb) source tests/gdbstub_test.gdb
|
||||
|
||||
define ipxe_load_symbols
|
||||
file bin/ipxe.hd.tmp
|
||||
end
|
||||
|
||||
define ipxe_assert
|
||||
if $arg0 != $arg1
|
||||
echo FAIL $arg2\n
|
||||
else
|
||||
echo PASS $arg2\n
|
||||
end
|
||||
end
|
||||
|
||||
define ipxe_start_tests
|
||||
jump gdbstub_test
|
||||
end
|
||||
|
||||
define ipxe_test_regs_read
|
||||
ipxe_assert $eax 0xea010203 "ipxe_test_regs_read eax"
|
||||
ipxe_assert $ebx 0xeb040506 "ipxe_test_regs_read ebx"
|
||||
ipxe_assert $ecx 0xec070809 "ipxe_test_regs_read ecx"
|
||||
ipxe_assert $edx 0xed0a0b0c "ipxe_test_regs_read edx"
|
||||
ipxe_assert $esi 0x510d0e0f "ipxe_test_regs_read esi"
|
||||
ipxe_assert $edi 0xd1102030 "ipxe_test_regs_read edi"
|
||||
end
|
||||
|
||||
define ipxe_test_regs_write
|
||||
set $eax = 0xea112233
|
||||
set $ebx = 0xeb445566
|
||||
set $ecx = 0xec778899
|
||||
set $edx = 0xedaabbcc
|
||||
set $esi = 0x51ddeeff
|
||||
set $edi = 0xd1010203
|
||||
c
|
||||
ipxe_assert $eax 0xea112233 "ipxe_test_regs_write eax"
|
||||
ipxe_assert $ebx 0xeb445566 "ipxe_test_regs_write ebx"
|
||||
ipxe_assert $ecx 0xec778899 "ipxe_test_regs_write ecx"
|
||||
ipxe_assert $edx 0xedaabbcc "ipxe_test_regs_write edx"
|
||||
ipxe_assert $esi 0x51ddeeff "ipxe_test_regs_write esi"
|
||||
ipxe_assert $edi 0xd1010203 "ipxe_test_regs_write edi"
|
||||
|
||||
# This assumes segment selectors are always 0x10 or 0x8 (for code).
|
||||
ipxe_assert $cs 0x08 "ipxe_test_regs_write cs"
|
||||
ipxe_assert $ds 0x10 "ipxe_test_regs_write ds"
|
||||
end
|
||||
|
||||
define ipxe_test_mem_read
|
||||
c
|
||||
ipxe_assert ({int}($esp+4)) 0x11223344 "ipxe_test_mem_read int"
|
||||
ipxe_assert ({short}($esp+2)) 0x5566 "ipxe_test_mem_read short"
|
||||
ipxe_assert ({char}($esp)) 0x77 "ipxe_test_mem_read char"
|
||||
end
|
||||
|
||||
define ipxe_test_mem_write
|
||||
set ({int}($esp+4)) = 0xaabbccdd
|
||||
set ({short}($esp+2)) = 0xeeff
|
||||
set ({char}($esp)) = 0x99
|
||||
c
|
||||
ipxe_assert ({int}($esp+4)) 0xaabbccdd "ipxe_test_mem_write int"
|
||||
ipxe_assert ({short}($esp+2)) (short)0xeeff "ipxe_test_mem_write short"
|
||||
ipxe_assert ({char}($esp)) (char)0x99 "ipxe_test_mem_write char"
|
||||
end
|
||||
|
||||
define ipxe_test_step
|
||||
c
|
||||
si
|
||||
ipxe_assert ({char}($eip-1)) (char)0x90 "ipxe_test_step" # nop = 0x90
|
||||
end
|
||||
|
||||
define ipxe_test_awatch
|
||||
awatch watch_me
|
||||
|
||||
c
|
||||
ipxe_assert $ecx 0x600d0000 "ipxe_test_awatch read"
|
||||
if $ecx == 0x600d0000
|
||||
c
|
||||
end
|
||||
|
||||
c
|
||||
ipxe_assert $ecx 0x600d0001 "ipxe_test_awatch write"
|
||||
if $ecx == 0x600d0001
|
||||
c
|
||||
end
|
||||
|
||||
delete
|
||||
end
|
||||
|
||||
define ipxe_test_watch
|
||||
watch watch_me
|
||||
c
|
||||
ipxe_assert $ecx 0x600d0002 "ipxe_test_watch"
|
||||
if $ecx == 0x600d0002
|
||||
c
|
||||
end
|
||||
delete
|
||||
end
|
||||
|
||||
ipxe_load_symbols
|
||||
ipxe_start_tests
|
||||
ipxe_test_regs_read
|
||||
ipxe_test_regs_write
|
||||
ipxe_test_mem_read
|
||||
ipxe_test_mem_write
|
||||
ipxe_test_step
|
||||
ipxe_test_awatch
|
||||
ipxe_test_watch
|
132
src/arch/x86/Makefile.pcbios
Normal file
132
src/arch/x86/Makefile.pcbios
Normal file
@@ -0,0 +1,132 @@
|
||||
# -*- makefile -*- : Force emacs to use Makefile mode
|
||||
|
||||
# BIOS-specific directories containing source files
|
||||
#
|
||||
SRCDIRS += arch/x86/drivers/net
|
||||
|
||||
# The i386 linker script
|
||||
#
|
||||
LDSCRIPT = arch/x86/scripts/pcbios.lds
|
||||
|
||||
# Stop ld from complaining about our customised linker script
|
||||
#
|
||||
LDFLAGS += -N --no-check-sections
|
||||
|
||||
# Prefix always starts at address zero
|
||||
#
|
||||
LDFLAGS += --section-start=.prefix=0
|
||||
|
||||
# Media types.
|
||||
#
|
||||
MEDIA += rom
|
||||
MEDIA += mrom
|
||||
MEDIA += pcirom
|
||||
MEDIA += isarom
|
||||
MEDIA += pxe
|
||||
MEDIA += kpxe
|
||||
MEDIA += kkpxe
|
||||
MEDIA += kkkpxe
|
||||
MEDIA += lkrn
|
||||
MEDIA += dsk
|
||||
MEDIA += nbi
|
||||
MEDIA += hd
|
||||
MEDIA += raw
|
||||
MEDIA += exe
|
||||
|
||||
# Padding rules
|
||||
#
|
||||
PAD_rom = $(PERL) $(PADIMG) --blksize=512 --byte=0xff
|
||||
PAD_mrom = $(PAD_rom)
|
||||
PAD_pcirom = $(PAD_rom)
|
||||
PAD_isarom = $(PAD_rom)
|
||||
PAD_dsk = $(PERL) $(PADIMG) --blksize=512
|
||||
PAD_hd = $(PERL) $(PADIMG) --blksize=32768
|
||||
PAD_exe = $(PERL) $(PADIMG) --blksize=512
|
||||
|
||||
# Finalisation rules
|
||||
#
|
||||
FINALISE_rom = $(PERL) $(FIXROM)
|
||||
FINALISE_mrom = $(FINALISE_rom)
|
||||
FINALISE_pcirom = $(FINALISE_rom)
|
||||
FINALISE_isarom = $(FINALISE_rom)
|
||||
|
||||
# Use $(ROMS) rather than $(DRIVERS) for "allroms", "allmroms", etc.
|
||||
#
|
||||
LIST_NAME_rom := ROMS
|
||||
LIST_NAME_mrom := ROMS
|
||||
LIST_NAME_pcirom := ROMS
|
||||
LIST_NAME_isarom := ROMS
|
||||
|
||||
# Locations of isolinux files
|
||||
#
|
||||
SYSLINUX_DIR_LIST := \
|
||||
/usr/lib/syslinux \
|
||||
/usr/lib/syslinux/bios \
|
||||
/usr/lib/syslinux/modules/bios \
|
||||
/usr/share/syslinux \
|
||||
/usr/share/syslinux/bios \
|
||||
/usr/share/syslinux/modules/bios \
|
||||
/usr/local/share/syslinux \
|
||||
/usr/local/share/syslinux/bios \
|
||||
/usr/local/share/syslinux/modules/bios \
|
||||
/usr/lib/ISOLINUX
|
||||
ISOLINUX_BIN_LIST := \
|
||||
$(ISOLINUX_BIN) \
|
||||
$(patsubst %,%/isolinux.bin,$(SYSLINUX_DIR_LIST))
|
||||
LDLINUX_C32_LIST := \
|
||||
$(LDLINUX_C32) \
|
||||
$(patsubst %,%/ldlinux.c32,$(SYSLINUX_DIR_LIST))
|
||||
ISOLINUX_BIN = $(firstword $(wildcard $(ISOLINUX_BIN_LIST)))
|
||||
LDLINUX_C32 = $(firstword $(wildcard $(LDLINUX_C32_LIST)))
|
||||
|
||||
# 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) LDLINUX_C32=$(LDLINUX_C32) \
|
||||
VERSION="$(VERSION)" bash util/geniso -o $@ $<
|
||||
|
||||
# rule to make a floppy emulation ISO boot image
|
||||
NON_AUTO_MEDIA += liso
|
||||
%liso: %lkrn util/geniso
|
||||
$(QM)$(ECHO) " [GENISO] $@"
|
||||
$(Q)VERSION="$(VERSION)" bash util/geniso -l -o $@ $<
|
||||
|
||||
# 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.tmp : $(BIN)/mbr.o
|
||||
$(QM)$(ECHO) " [LD] $@"
|
||||
$(Q)$(LD) $(LDFLAGS) -o $@ -e mbr $<
|
||||
|
||||
# rule to make a USB disk image
|
||||
$(BIN)/usbdisk.tmp : $(BIN)/usbdisk.o
|
||||
$(QM)$(ECHO) " [LD] $@"
|
||||
$(Q)$(LD) $(LDFLAGS) -o $@ -e mbr $<
|
||||
|
||||
NON_AUTO_MEDIA += usb
|
||||
%usb: $(BIN)/usbdisk.bin %hd
|
||||
$(QM)$(ECHO) " [FINISH] $@"
|
||||
$(Q)cat $^ > $@
|
||||
|
||||
NON_AUTO_MEDIA += vhd
|
||||
%vhd: %usb
|
||||
$(QM)$(ECHO) " [FINISH] $@"
|
||||
$(Q)$(QEMUIMG) convert -f raw -O vpc $< $@
|
||||
|
||||
# Padded floppy image (e.g. for iLO)
|
||||
NON_AUTO_MEDIA += pdsk
|
||||
%pdsk : %dsk
|
||||
$(Q)cp $< $@
|
||||
$(Q)$(PADIMG) --blksize=1474560 $@
|
37
src/arch/x86/core/basemem_packet.c
Normal file
37
src/arch/x86/core/basemem_packet.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., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA.
|
||||
*
|
||||
* You can also choose to distribute this program under the terms of
|
||||
* the Unmodified Binary Distribution Licence (as given in the file
|
||||
* COPYING.UBDL), provided that you have satisfied its requirements.
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
/**
|
||||
* @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] );
|
179
src/arch/x86/core/cachedhcp.c
Normal file
179
src/arch/x86/core/cachedhcp.c
Normal file
@@ -0,0 +1,179 @@
|
||||
/*
|
||||
* Copyright (C) 2013 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., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA.
|
||||
*
|
||||
* You can also choose to distribute this program under the terms of
|
||||
* the Unmodified Binary Distribution Licence (as given in the file
|
||||
* COPYING.UBDL), provided that you have satisfied its requirements.
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <ipxe/dhcppkt.h>
|
||||
#include <ipxe/init.h>
|
||||
#include <ipxe/netdevice.h>
|
||||
#include <realmode.h>
|
||||
#include <pxe_api.h>
|
||||
|
||||
/** @file
|
||||
*
|
||||
* Cached DHCP packet
|
||||
*
|
||||
*/
|
||||
|
||||
/** Cached DHCPACK physical address
|
||||
*
|
||||
* This can be set by the prefix.
|
||||
*/
|
||||
uint32_t __bss16 ( cached_dhcpack_phys );
|
||||
#define cached_dhcpack_phys __use_data16 ( cached_dhcpack_phys )
|
||||
|
||||
/** Colour for debug messages */
|
||||
#define colour &cached_dhcpack_phys
|
||||
|
||||
/** Cached DHCPACK */
|
||||
static struct dhcp_packet *cached_dhcpack;
|
||||
|
||||
/**
|
||||
* Cached DHCPACK startup function
|
||||
*
|
||||
*/
|
||||
static void cachedhcp_init ( void ) {
|
||||
struct dhcp_packet *dhcppkt;
|
||||
struct dhcp_packet *tmp;
|
||||
struct dhcphdr *dhcphdr;
|
||||
size_t max_len;
|
||||
size_t len;
|
||||
|
||||
/* Do nothing if no cached DHCPACK is present */
|
||||
if ( ! cached_dhcpack_phys ) {
|
||||
DBGC ( colour, "CACHEDHCP found no cached DHCPACK\n" );
|
||||
return;
|
||||
}
|
||||
|
||||
/* No reliable way to determine length before parsing packet;
|
||||
* start by assuming maximum length permitted by PXE.
|
||||
*/
|
||||
max_len = sizeof ( BOOTPLAYER_t );
|
||||
|
||||
/* Allocate and populate DHCP packet */
|
||||
dhcppkt = zalloc ( sizeof ( *dhcppkt ) + max_len );
|
||||
if ( ! dhcppkt ) {
|
||||
DBGC ( colour, "CACHEDHCP could not allocate copy\n" );
|
||||
return;
|
||||
}
|
||||
dhcphdr = ( ( ( void * ) dhcppkt ) + sizeof ( *dhcppkt ) );
|
||||
copy_from_user ( dhcphdr, phys_to_user ( cached_dhcpack_phys ), 0,
|
||||
max_len );
|
||||
dhcppkt_init ( dhcppkt, dhcphdr, max_len );
|
||||
|
||||
/* Shrink packet to required length. If reallocation fails,
|
||||
* just continue to use the original packet and waste the
|
||||
* unused space.
|
||||
*/
|
||||
len = dhcppkt_len ( dhcppkt );
|
||||
assert ( len <= max_len );
|
||||
tmp = realloc ( dhcppkt, ( sizeof ( *dhcppkt ) + len ) );
|
||||
if ( tmp )
|
||||
dhcppkt = tmp;
|
||||
|
||||
/* Reinitialise packet at new address */
|
||||
dhcphdr = ( ( ( void * ) dhcppkt ) + sizeof ( *dhcppkt ) );
|
||||
dhcppkt_init ( dhcppkt, dhcphdr, len );
|
||||
|
||||
/* Store as cached DHCPACK, and mark original copy as consumed */
|
||||
DBGC ( colour, "CACHEDHCP found cached DHCPACK at %08x+%zx\n",
|
||||
cached_dhcpack_phys, len );
|
||||
cached_dhcpack = dhcppkt;
|
||||
cached_dhcpack_phys = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cached DHCPACK startup function
|
||||
*
|
||||
*/
|
||||
static void cachedhcp_startup ( void ) {
|
||||
|
||||
/* If cached DHCP packet was not claimed by any network device
|
||||
* during startup, then free it.
|
||||
*/
|
||||
if ( cached_dhcpack ) {
|
||||
DBGC ( colour, "CACHEDHCP freeing unclaimed cached DHCPACK\n" );
|
||||
dhcppkt_put ( cached_dhcpack );
|
||||
cached_dhcpack = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/** Cached DHCPACK initialisation function */
|
||||
struct init_fn cachedhcp_init_fn __init_fn ( INIT_NORMAL ) = {
|
||||
.initialise = cachedhcp_init,
|
||||
};
|
||||
|
||||
/** Cached DHCPACK startup function */
|
||||
struct startup_fn cachedhcp_startup_fn __startup_fn ( STARTUP_LATE ) = {
|
||||
.name = "cachedhcp",
|
||||
.startup = cachedhcp_startup,
|
||||
};
|
||||
|
||||
/**
|
||||
* Apply cached DHCPACK to network device, if applicable
|
||||
*
|
||||
* @v netdev Network device
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int cachedhcp_probe ( struct net_device *netdev ) {
|
||||
struct ll_protocol *ll_protocol = netdev->ll_protocol;
|
||||
int rc;
|
||||
|
||||
/* Do nothing unless we have a cached DHCPACK */
|
||||
if ( ! cached_dhcpack )
|
||||
return 0;
|
||||
|
||||
/* Do nothing unless cached DHCPACK's MAC address matches this
|
||||
* network device.
|
||||
*/
|
||||
if ( memcmp ( netdev->ll_addr, cached_dhcpack->dhcphdr->chaddr,
|
||||
ll_protocol->ll_addr_len ) != 0 ) {
|
||||
DBGC ( colour, "CACHEDHCP cached DHCPACK does not match %s\n",
|
||||
netdev->name );
|
||||
return 0;
|
||||
}
|
||||
DBGC ( colour, "CACHEDHCP cached DHCPACK is for %s\n", netdev->name );
|
||||
|
||||
/* Register as DHCP settings for this network device */
|
||||
if ( ( rc = register_settings ( &cached_dhcpack->settings,
|
||||
netdev_settings ( netdev ),
|
||||
DHCP_SETTINGS_NAME ) ) != 0 ) {
|
||||
DBGC ( colour, "CACHEDHCP could not register settings: %s\n",
|
||||
strerror ( rc ) );
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Claim cached DHCPACK */
|
||||
dhcppkt_put ( cached_dhcpack );
|
||||
cached_dhcpack = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Cached DHCP packet network device driver */
|
||||
struct net_driver cachedhcp_driver __net_driver = {
|
||||
.name = "cachedhcp",
|
||||
.probe = cachedhcp_probe,
|
||||
};
|
20
src/arch/x86/core/dumpregs.c
Normal file
20
src/arch/x86/core/dumpregs.c
Normal file
@@ -0,0 +1,20 @@
|
||||
#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"
|
||||
VIRT_CALL ( _dump_regs )
|
||||
"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 );
|
||||
}
|
251
src/arch/x86/core/gdbmach.c
Normal file
251
src/arch/x86/core/gdbmach.c
Normal file
@@ -0,0 +1,251 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Stefan Hajnoczi <stefanha@gmail.com>.
|
||||
* Copyright (C) 2016 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., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA.
|
||||
*
|
||||
* You can also choose to distribute this program under the terms of
|
||||
* the Unmodified Binary Distribution Licence (as given in the file
|
||||
* COPYING.UBDL), provided that you have satisfied its requirements.
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
#include <ipxe/uaccess.h>
|
||||
#include <ipxe/gdbstub.h>
|
||||
#include <librm.h>
|
||||
#include <gdbmach.h>
|
||||
|
||||
/** @file
|
||||
*
|
||||
* GDB architecture-specific bits for x86
|
||||
*
|
||||
*/
|
||||
|
||||
/** Number of hardware breakpoints */
|
||||
#define NUM_HWBP 4
|
||||
|
||||
/** Debug register 7: Global breakpoint enable */
|
||||
#define DR7_G( bp ) ( 2 << ( 2 * (bp) ) )
|
||||
|
||||
/** Debug register 7: Global exact breakpoint enable */
|
||||
#define DR7_GE ( 1 << 9 )
|
||||
|
||||
/** Debug register 7: Break on data writes */
|
||||
#define DR7_RWLEN_WRITE 0x11110000
|
||||
|
||||
/** Debug register 7: Break on data access */
|
||||
#define DR7_RWLEN_ACCESS 0x33330000
|
||||
|
||||
/** Debug register 7: One-byte length */
|
||||
#define DR7_RWLEN_1 0x00000000
|
||||
|
||||
/** Debug register 7: Two-byte length */
|
||||
#define DR7_RWLEN_2 0x44440000
|
||||
|
||||
/** Debug register 7: Four-byte length */
|
||||
#define DR7_RWLEN_4 0xcccc0000
|
||||
|
||||
/** Debug register 7: Eight-byte length */
|
||||
#define DR7_RWLEN_8 0x88880000
|
||||
|
||||
/** Debug register 7: Breakpoint R/W and length mask */
|
||||
#define DR7_RWLEN_MASK( bp ) ( 0xf0000 << ( 4 * (bp) ) )
|
||||
|
||||
/** Hardware breakpoint addresses (debug registers 0-3) */
|
||||
static unsigned long dr[NUM_HWBP];
|
||||
|
||||
/** Active value of debug register 7 */
|
||||
static unsigned long dr7 = DR7_GE;
|
||||
|
||||
/**
|
||||
* Update debug registers
|
||||
*
|
||||
*/
|
||||
static void gdbmach_update ( void ) {
|
||||
|
||||
/* Set debug registers */
|
||||
__asm__ __volatile__ ( "mov %0, %%dr0" : : "r" ( dr[0] ) );
|
||||
__asm__ __volatile__ ( "mov %0, %%dr1" : : "r" ( dr[1] ) );
|
||||
__asm__ __volatile__ ( "mov %0, %%dr2" : : "r" ( dr[2] ) );
|
||||
__asm__ __volatile__ ( "mov %0, %%dr3" : : "r" ( dr[3] ) );
|
||||
__asm__ __volatile__ ( "mov %0, %%dr7" : : "r" ( dr7 ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Find reusable or available hardware breakpoint
|
||||
*
|
||||
* @v addr Linear address
|
||||
* @v rwlen Control bits
|
||||
* @ret bp Hardware breakpoint, or negative error
|
||||
*/
|
||||
static int gdbmach_find ( unsigned long addr, unsigned int rwlen ) {
|
||||
unsigned int i;
|
||||
int bp = -ENOENT;
|
||||
|
||||
/* Look for a reusable or available breakpoint */
|
||||
for ( i = 0 ; i < NUM_HWBP ; i++ ) {
|
||||
|
||||
/* If breakpoint is not enabled, then it is available */
|
||||
if ( ! ( dr7 & DR7_G ( i ) ) ) {
|
||||
bp = i;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* If breakpoint is enabled and has the same address
|
||||
* and control bits, then reuse it.
|
||||
*/
|
||||
if ( ( dr[i] == addr ) &&
|
||||
( ( ( dr7 ^ rwlen ) & DR7_RWLEN_MASK ( i ) ) == 0 ) ) {
|
||||
bp = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return bp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set hardware breakpoint
|
||||
*
|
||||
* @v type GDB breakpoint type
|
||||
* @v addr Virtual address
|
||||
* @v len Length
|
||||
* @v enable Enable (not disable) breakpoint
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
int gdbmach_set_breakpoint ( int type, unsigned long addr, size_t len,
|
||||
int enable ) {
|
||||
unsigned int rwlen;
|
||||
unsigned long mask;
|
||||
int bp;
|
||||
|
||||
/* Parse breakpoint type */
|
||||
switch ( type ) {
|
||||
case GDBMACH_WATCH:
|
||||
rwlen = DR7_RWLEN_WRITE;
|
||||
break;
|
||||
case GDBMACH_AWATCH:
|
||||
rwlen = DR7_RWLEN_ACCESS;
|
||||
break;
|
||||
default:
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
/* Parse breakpoint length */
|
||||
switch ( len ) {
|
||||
case 1:
|
||||
rwlen |= DR7_RWLEN_1;
|
||||
break;
|
||||
case 2:
|
||||
rwlen |= DR7_RWLEN_2;
|
||||
break;
|
||||
case 4:
|
||||
rwlen |= DR7_RWLEN_4;
|
||||
break;
|
||||
case 8:
|
||||
rwlen |= DR7_RWLEN_8;
|
||||
break;
|
||||
default:
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
/* Convert to linear address */
|
||||
if ( sizeof ( physaddr_t ) <= sizeof ( uint32_t ) )
|
||||
addr = virt_to_phys ( ( void * ) addr );
|
||||
|
||||
/* Find reusable or available hardware breakpoint */
|
||||
bp = gdbmach_find ( addr, rwlen );
|
||||
if ( bp < 0 )
|
||||
return ( enable ? -ENOBUFS : 0 );
|
||||
|
||||
/* Configure this breakpoint */
|
||||
DBGC ( &dr[0], "GDB bp %d at %p+%zx type %d (%sabled)\n",
|
||||
bp, ( ( void * ) addr ), len, type, ( enable ? "en" : "dis" ) );
|
||||
dr[bp] = addr;
|
||||
mask = DR7_RWLEN_MASK ( bp );
|
||||
dr7 = ( ( dr7 & ~mask ) | ( rwlen & mask ) );
|
||||
mask = DR7_G ( bp );
|
||||
dr7 &= ~mask;
|
||||
if ( enable )
|
||||
dr7 |= mask;
|
||||
|
||||
/* Update debug registers */
|
||||
gdbmach_update();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle exception
|
||||
*
|
||||
* @v signo GDB signal number
|
||||
* @v regs Register dump
|
||||
*/
|
||||
__asmcall void gdbmach_handler ( int signo, gdbreg_t *regs ) {
|
||||
unsigned long dr7_disabled = DR7_GE;
|
||||
unsigned long dr6_clear = 0;
|
||||
|
||||
/* Temporarily disable breakpoints */
|
||||
__asm__ __volatile__ ( "mov %0, %%dr7\n" : : "r" ( dr7_disabled ) );
|
||||
|
||||
/* Handle exception */
|
||||
DBGC ( &dr[0], "GDB signal %d\n", signo );
|
||||
DBGC2_HDA ( &dr[0], 0, regs, ( GDBMACH_NREGS * sizeof ( *regs ) ) );
|
||||
gdbstub_handler ( signo, regs );
|
||||
DBGC ( &dr[0], "GDB signal %d returning\n", signo );
|
||||
DBGC2_HDA ( &dr[0], 0, regs, ( GDBMACH_NREGS * sizeof ( *regs ) ) );
|
||||
|
||||
/* Clear breakpoint status register */
|
||||
__asm__ __volatile__ ( "mov %0, %%dr6\n" : : "r" ( dr6_clear ) );
|
||||
|
||||
/* Re-enable breakpoints */
|
||||
__asm__ __volatile__ ( "mov %0, %%dr7\n" : : "r" ( dr7 ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* CPU exception vectors
|
||||
*
|
||||
* Note that we cannot intercept anything from INT8 (double fault)
|
||||
* upwards, since these overlap by default with IRQ0-7.
|
||||
*/
|
||||
static void * gdbmach_vectors[] = {
|
||||
gdbmach_sigfpe, /* Divide by zero */
|
||||
gdbmach_sigtrap, /* Debug trap */
|
||||
NULL, /* Non-maskable interrupt */
|
||||
gdbmach_sigtrap, /* Breakpoint */
|
||||
gdbmach_sigstkflt, /* Overflow */
|
||||
gdbmach_sigstkflt, /* Bound range exceeded */
|
||||
gdbmach_sigill, /* Invalid opcode */
|
||||
};
|
||||
|
||||
/**
|
||||
* Initialise GDB
|
||||
*/
|
||||
void gdbmach_init ( void ) {
|
||||
unsigned int i;
|
||||
|
||||
/* Hook CPU exception vectors */
|
||||
for ( i = 0 ; i < ( sizeof ( gdbmach_vectors ) /
|
||||
sizeof ( gdbmach_vectors[0] ) ) ; i++ ) {
|
||||
if ( gdbmach_vectors[i] )
|
||||
set_interrupt_vector ( i, gdbmach_vectors[i] );
|
||||
}
|
||||
}
|
42
src/arch/x86/core/patch_cf.S
Normal file
42
src/arch/x86/core/patch_cf.S
Normal file
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
* You can also choose to distribute this program under the terms of
|
||||
* the Unmodified Binary Distribution Licence (as given in the file
|
||||
* COPYING.UBDL), provided that you have satisfied its requirements.
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
|
||||
|
||||
.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
|
48
src/arch/x86/core/pci_autoboot.c
Normal file
48
src/arch/x86/core/pci_autoboot.c
Normal file
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Red Hat Inc.
|
||||
* Alex Williamson <alex.williamson@redhat.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., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA.
|
||||
*
|
||||
* You can also choose to distribute this program under the terms of
|
||||
* the Unmodified Binary Distribution Licence (as given in the file
|
||||
* COPYING.UBDL), provided that you have satisfied its requirements.
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
#include <stdint.h>
|
||||
#include <ipxe/device.h>
|
||||
#include <ipxe/init.h>
|
||||
#include <realmode.h>
|
||||
#include <usr/autoboot.h>
|
||||
|
||||
uint16_t __bss16 ( autoboot_busdevfn );
|
||||
#define autoboot_busdevfn __use_data16 ( autoboot_busdevfn )
|
||||
|
||||
/**
|
||||
* Initialise PCI autoboot device
|
||||
*/
|
||||
static void pci_autoboot_init ( void ) {
|
||||
|
||||
if ( autoboot_busdevfn )
|
||||
set_autoboot_busloc ( BUS_TYPE_PCI, autoboot_busdevfn );
|
||||
}
|
||||
|
||||
/** PCI autoboot device initialisation function */
|
||||
struct init_fn pci_autoboot_init_fn __init_fn ( INIT_NORMAL ) = {
|
||||
.initialise = pci_autoboot_init,
|
||||
};
|
67
src/arch/x86/core/pic8259.c
Normal file
67
src/arch/x86/core/pic8259.c
Normal file
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* 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., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, 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 );
|
||||
}
|
70
src/arch/x86/core/pit8254.c
Normal file
70
src/arch/x86/core/pit8254.c
Normal file
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright (C) 2015 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 (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.
|
||||
*
|
||||
* You can also choose to distribute this program under the terms of
|
||||
* the Unmodified Binary Distribution Licence (as given in the file
|
||||
* COPYING.UBDL), provided that you have satisfied its requirements.
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
#include <assert.h>
|
||||
#include <ipxe/io.h>
|
||||
#include <ipxe/pit8254.h>
|
||||
|
||||
/** @file
|
||||
*
|
||||
* 8254 Programmable Interval Timer
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Delay for a fixed number of timer ticks using the speaker channel
|
||||
*
|
||||
* @v ticks Number of timer ticks for which to delay
|
||||
*/
|
||||
void pit8254_speaker_delay ( unsigned int ticks ) {
|
||||
uint8_t spkr;
|
||||
uint8_t cmd;
|
||||
uint8_t low;
|
||||
uint8_t high;
|
||||
|
||||
/* Sanity check */
|
||||
assert ( ticks <= 0xffff );
|
||||
|
||||
/* Disable speaker, set speaker channel gate input high */
|
||||
spkr = inb ( PIT8254_SPKR );
|
||||
spkr &= ~PIT8254_SPKR_ENABLE;
|
||||
spkr |= PIT8254_SPKR_GATE;
|
||||
outb ( spkr, PIT8254_SPKR );
|
||||
|
||||
/* Program speaker channel to "interrupt" on terminal count */
|
||||
cmd = ( PIT8254_CMD_CHANNEL ( PIT8254_CH_SPKR ) |
|
||||
PIT8254_CMD_ACCESS_LOHI | PIT8254_CMD_OP_TERMINAL |
|
||||
PIT8254_CMD_BINARY );
|
||||
low = ( ( ticks >> 0 ) & 0xff );
|
||||
high = ( ( ticks >> 8 ) & 0xff );
|
||||
outb ( cmd, PIT8254_CMD );
|
||||
outb ( low, PIT8254_DATA ( PIT8254_CH_SPKR ) );
|
||||
outb ( high, PIT8254_DATA ( PIT8254_CH_SPKR ) );
|
||||
|
||||
/* Wait for channel to "interrupt" */
|
||||
do {
|
||||
spkr = inb ( PIT8254_SPKR );
|
||||
} while ( ! ( spkr & PIT8254_SPKR_OUT ) );
|
||||
}
|
177
src/arch/x86/core/rdtsc_timer.c
Normal file
177
src/arch/x86/core/rdtsc_timer.c
Normal file
@@ -0,0 +1,177 @@
|
||||
/*
|
||||
* 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., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA.
|
||||
*
|
||||
* You can also choose to distribute this program under the terms of
|
||||
* the Unmodified Binary Distribution Licence (as given in the file
|
||||
* COPYING.UBDL), provided that you have satisfied its requirements.
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
/** @file
|
||||
*
|
||||
* RDTSC timer
|
||||
*
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <ipxe/timer.h>
|
||||
#include <ipxe/cpuid.h>
|
||||
#include <ipxe/pit8254.h>
|
||||
|
||||
/** Number of microseconds to use for TSC calibration */
|
||||
#define TSC_CALIBRATE_US 1024
|
||||
|
||||
/** TSC increment per microsecond */
|
||||
static unsigned long tsc_per_us;
|
||||
|
||||
/** Minimum resolution for scaled TSC timer */
|
||||
#define TSC_SCALED_HZ 32
|
||||
|
||||
/** TSC scale (expressed as a bit shift)
|
||||
*
|
||||
* We use this to avoid the need for 64-bit divsion on 32-bit systems.
|
||||
*/
|
||||
static unsigned int tsc_scale;
|
||||
|
||||
/** Number of timer ticks per scaled TSC increment */
|
||||
static unsigned long ticks_per_scaled_tsc;
|
||||
|
||||
/** Colour for debug messages */
|
||||
#define colour &tsc_per_us
|
||||
|
||||
/**
|
||||
* Get raw TSC value
|
||||
*
|
||||
* @ret tsc Raw TSC value
|
||||
*/
|
||||
static inline __always_inline unsigned long rdtsc_raw ( void ) {
|
||||
unsigned long raw;
|
||||
|
||||
__asm__ __volatile__ ( "rdtsc\n\t" : "=a" ( raw ) : : "edx" );
|
||||
return raw;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get TSC value, shifted to avoid rollover within a realistic timescale
|
||||
*
|
||||
* @ret tsc Scaled TSC value
|
||||
*/
|
||||
static inline __always_inline unsigned long rdtsc_scaled ( void ) {
|
||||
unsigned long scaled;
|
||||
|
||||
__asm__ __volatile__ ( "rdtsc\n\t"
|
||||
"shrdl %b1, %%edx, %%eax\n\t"
|
||||
: "=a" ( scaled ) : "c" ( tsc_scale ) : "edx" );
|
||||
return scaled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get current system time in ticks
|
||||
*
|
||||
* @ret ticks Current time, in ticks
|
||||
*/
|
||||
static unsigned long rdtsc_currticks ( void ) {
|
||||
unsigned long scaled;
|
||||
|
||||
scaled = rdtsc_scaled();
|
||||
return ( scaled * ticks_per_scaled_tsc );
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
unsigned long threshold;
|
||||
|
||||
start = rdtsc_raw();
|
||||
threshold = ( usecs * tsc_per_us );
|
||||
do {
|
||||
elapsed = ( rdtsc_raw() - start );
|
||||
} while ( elapsed < threshold );
|
||||
}
|
||||
|
||||
/**
|
||||
* Probe RDTSC timer
|
||||
*
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int rdtsc_probe ( void ) {
|
||||
unsigned long before;
|
||||
unsigned long after;
|
||||
unsigned long elapsed;
|
||||
uint32_t apm;
|
||||
uint32_t discard_a;
|
||||
uint32_t discard_b;
|
||||
uint32_t discard_c;
|
||||
int rc;
|
||||
|
||||
/* Check that TSC is invariant */
|
||||
if ( ( rc = cpuid_supported ( CPUID_APM ) ) != 0 ) {
|
||||
DBGC ( colour, "RDTSC cannot determine APM features: %s\n",
|
||||
strerror ( rc ) );
|
||||
return rc;
|
||||
}
|
||||
cpuid ( CPUID_APM, 0, &discard_a, &discard_b, &discard_c, &apm );
|
||||
if ( ! ( apm & CPUID_APM_EDX_TSC_INVARIANT ) ) {
|
||||
DBGC ( colour, "RDTSC has non-invariant TSC (%#08x)\n",
|
||||
apm );
|
||||
return -ENOTTY;
|
||||
}
|
||||
|
||||
/* Calibrate udelay() timer via 8254 PIT */
|
||||
before = rdtsc_raw();
|
||||
pit8254_udelay ( TSC_CALIBRATE_US );
|
||||
after = rdtsc_raw();
|
||||
elapsed = ( after - before );
|
||||
tsc_per_us = ( elapsed / TSC_CALIBRATE_US );
|
||||
if ( ! tsc_per_us ) {
|
||||
DBGC ( colour, "RDTSC has zero TSC per microsecond\n" );
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
/* Calibrate currticks() scaling factor */
|
||||
tsc_scale = 31;
|
||||
ticks_per_scaled_tsc = ( ( 1UL << tsc_scale ) /
|
||||
( tsc_per_us * ( 1000000 / TICKS_PER_SEC ) ) );
|
||||
while ( ticks_per_scaled_tsc > ( TICKS_PER_SEC / TSC_SCALED_HZ ) ) {
|
||||
tsc_scale--;
|
||||
ticks_per_scaled_tsc >>= 1;
|
||||
}
|
||||
DBGC ( colour, "RDTSC has %ld tsc per us, %ld ticks per 2^%d tsc\n",
|
||||
tsc_per_us, ticks_per_scaled_tsc, tsc_scale );
|
||||
if ( ! ticks_per_scaled_tsc ) {
|
||||
DBGC ( colour, "RDTSC has zero ticks per TSC\n" );
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** RDTSC timer */
|
||||
struct timer rdtsc_timer __timer ( TIMER_PREFERRED ) = {
|
||||
.name = "rdtsc",
|
||||
.probe = rdtsc_probe,
|
||||
.currticks = rdtsc_currticks,
|
||||
.udelay = rdtsc_udelay,
|
||||
};
|
136
src/arch/x86/core/relocate.c
Normal file
136
src/arch/x86/core/relocate.c
Normal file
@@ -0,0 +1,136 @@
|
||||
#include <ipxe/io.h>
|
||||
#include <registers.h>
|
||||
|
||||
/*
|
||||
* Originally by Eric Biederman
|
||||
*
|
||||
* Heavily modified by Michael Brown
|
||||
*
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
/* 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)
|
||||
|
||||
/* Preserve alignment to a 4kB page
|
||||
*
|
||||
* Required for x86_64, and doesn't hurt for i386.
|
||||
*/
|
||||
#define ALIGN 4096
|
||||
|
||||
/**
|
||||
* Relocate iPXE
|
||||
*
|
||||
* @v ebp Maximum address to use for relocation
|
||||
* @ret esi Current physical address
|
||||
* @ret edi New physical address
|
||||
* @ret ecx Length to copy
|
||||
*
|
||||
* 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;
|
||||
uint32_t start, end, size, padded_size, max;
|
||||
uint32_t 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 + ALIGN - 1 );
|
||||
|
||||
DBG ( "Relocate: currently at [%x,%x)\n"
|
||||
"...need %x bytes for %d-byte alignment\n",
|
||||
start, end, padded_size, ALIGN );
|
||||
|
||||
/* Determine maximum usable address */
|
||||
max = MAX_ADDR;
|
||||
if ( ix86->regs.ebp < max ) {
|
||||
max = ix86->regs.ebp;
|
||||
DBG ( "Limiting relocation to [0,%x)\n", max );
|
||||
}
|
||||
|
||||
/* 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];
|
||||
uint32_t r_start, r_end;
|
||||
|
||||
DBG ( "Considering [%llx,%llx)\n", region->start, region->end);
|
||||
|
||||
/* Truncate block to maximum address. 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 ) {
|
||||
DBG ( "...starts after max=%x\n", max );
|
||||
continue;
|
||||
}
|
||||
r_start = region->start;
|
||||
if ( region->end > max ) {
|
||||
DBG ( "...end truncated to max=%x\n", max );
|
||||
r_end = max;
|
||||
} else {
|
||||
r_end = region->end;
|
||||
}
|
||||
DBG ( "...usable portion is [%x,%x)\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 %x 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 ) & ( ALIGN - 1 ) );
|
||||
new_end = new_start + size;
|
||||
|
||||
DBG ( "Relocating from [%x,%x) to [%x,%x)\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;
|
||||
}
|
270
src/arch/x86/core/runtime.c
Normal file
270
src/arch/x86/core/runtime.c
Normal file
@@ -0,0 +1,270 @@
|
||||
/*
|
||||
* Copyright (C) 2011 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., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA.
|
||||
*
|
||||
* You can also choose to distribute this program under the terms of
|
||||
* the Unmodified Binary Distribution Licence (as given in the file
|
||||
* COPYING.UBDL), provided that you have satisfied its requirements.
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
/** @file
|
||||
*
|
||||
* Command line and initrd passed to iPXE at runtime
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
#include <ipxe/init.h>
|
||||
#include <ipxe/image.h>
|
||||
#include <ipxe/script.h>
|
||||
#include <ipxe/umalloc.h>
|
||||
#include <realmode.h>
|
||||
|
||||
/** Command line physical address
|
||||
*
|
||||
* This can be set by the prefix.
|
||||
*/
|
||||
uint32_t __bss16 ( cmdline_phys );
|
||||
#define cmdline_phys __use_data16 ( cmdline_phys )
|
||||
|
||||
/** initrd physical address
|
||||
*
|
||||
* This can be set by the prefix.
|
||||
*/
|
||||
uint32_t __bss16 ( initrd_phys );
|
||||
#define initrd_phys __use_data16 ( initrd_phys )
|
||||
|
||||
/** initrd length
|
||||
*
|
||||
* This can be set by the prefix.
|
||||
*/
|
||||
uint32_t __bss16 ( initrd_len );
|
||||
#define initrd_len __use_data16 ( initrd_len )
|
||||
|
||||
/** Internal copy of the command line */
|
||||
static char *cmdline_copy;
|
||||
|
||||
/** Free command line image */
|
||||
static void cmdline_image_free ( struct refcnt *refcnt ) {
|
||||
struct image *image = container_of ( refcnt, struct image, refcnt );
|
||||
|
||||
DBGC ( image, "RUNTIME freeing command line\n" );
|
||||
free ( cmdline_copy );
|
||||
}
|
||||
|
||||
/** Embedded script representing the command line */
|
||||
static struct image cmdline_image = {
|
||||
.refcnt = REF_INIT ( cmdline_image_free ),
|
||||
.name = "<CMDLINE>",
|
||||
.type = &script_image_type,
|
||||
};
|
||||
|
||||
/** Colour for debug messages */
|
||||
#define colour &cmdline_image
|
||||
|
||||
/**
|
||||
* Strip unwanted cruft from command line
|
||||
*
|
||||
* @v cmdline Command line
|
||||
* @v cruft Initial substring of cruft to strip
|
||||
*/
|
||||
static void cmdline_strip ( char *cmdline, const char *cruft ) {
|
||||
char *strip;
|
||||
char *strip_end;
|
||||
|
||||
/* Find unwanted cruft, if present */
|
||||
if ( ! ( strip = strstr ( cmdline, cruft ) ) )
|
||||
return;
|
||||
|
||||
/* Strip unwanted cruft */
|
||||
strip_end = strchr ( strip, ' ' );
|
||||
if ( strip_end ) {
|
||||
*strip_end = '\0';
|
||||
DBGC ( colour, "RUNTIME stripping \"%s\"\n", strip );
|
||||
strcpy ( strip, ( strip_end + 1 ) );
|
||||
} else {
|
||||
DBGC ( colour, "RUNTIME stripping \"%s\"\n", strip );
|
||||
*strip = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialise command line
|
||||
*
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int cmdline_init ( void ) {
|
||||
userptr_t cmdline_user;
|
||||
char *cmdline;
|
||||
size_t len;
|
||||
int rc;
|
||||
|
||||
/* Do nothing if no command line was specified */
|
||||
if ( ! cmdline_phys ) {
|
||||
DBGC ( colour, "RUNTIME found no command line\n" );
|
||||
return 0;
|
||||
}
|
||||
cmdline_user = phys_to_user ( cmdline_phys );
|
||||
len = ( strlen_user ( cmdline_user, 0 ) + 1 /* NUL */ );
|
||||
|
||||
/* Allocate and copy command line */
|
||||
cmdline_copy = malloc ( len );
|
||||
if ( ! cmdline_copy ) {
|
||||
DBGC ( colour, "RUNTIME could not allocate %zd bytes for "
|
||||
"command line\n", len );
|
||||
rc = -ENOMEM;
|
||||
goto err_alloc_cmdline_copy;
|
||||
}
|
||||
cmdline = cmdline_copy;
|
||||
copy_from_user ( cmdline, cmdline_user, 0, len );
|
||||
DBGC ( colour, "RUNTIME found command line \"%s\" at %08x\n",
|
||||
cmdline, cmdline_phys );
|
||||
|
||||
/* Mark command line as consumed */
|
||||
cmdline_phys = 0;
|
||||
|
||||
/* Strip unwanted cruft from the command line */
|
||||
cmdline_strip ( cmdline, "BOOT_IMAGE=" );
|
||||
cmdline_strip ( cmdline, "initrd=" );
|
||||
while ( isspace ( *cmdline ) )
|
||||
cmdline++;
|
||||
DBGC ( colour, "RUNTIME using command line \"%s\"\n", cmdline );
|
||||
|
||||
/* Prepare and register image */
|
||||
cmdline_image.data = virt_to_user ( cmdline );
|
||||
cmdline_image.len = strlen ( cmdline );
|
||||
if ( cmdline_image.len ) {
|
||||
if ( ( rc = register_image ( &cmdline_image ) ) != 0 ) {
|
||||
DBGC ( colour, "RUNTIME could not register command "
|
||||
"line: %s\n", strerror ( rc ) );
|
||||
goto err_register_image;
|
||||
}
|
||||
}
|
||||
|
||||
/* Drop our reference to the image */
|
||||
image_put ( &cmdline_image );
|
||||
|
||||
return 0;
|
||||
|
||||
err_register_image:
|
||||
image_put ( &cmdline_image );
|
||||
err_alloc_cmdline_copy:
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialise initrd
|
||||
*
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int initrd_init ( void ) {
|
||||
struct image *image;
|
||||
int rc;
|
||||
|
||||
/* Do nothing if no initrd was specified */
|
||||
if ( ! initrd_phys ) {
|
||||
DBGC ( colour, "RUNTIME found no initrd\n" );
|
||||
return 0;
|
||||
}
|
||||
if ( ! initrd_len ) {
|
||||
DBGC ( colour, "RUNTIME found empty initrd\n" );
|
||||
return 0;
|
||||
}
|
||||
DBGC ( colour, "RUNTIME found initrd at [%x,%x)\n",
|
||||
initrd_phys, ( initrd_phys + initrd_len ) );
|
||||
|
||||
/* Allocate image */
|
||||
image = alloc_image ( NULL );
|
||||
if ( ! image ) {
|
||||
DBGC ( colour, "RUNTIME could not allocate image for "
|
||||
"initrd\n" );
|
||||
rc = -ENOMEM;
|
||||
goto err_alloc_image;
|
||||
}
|
||||
if ( ( rc = image_set_name ( image, "<INITRD>" ) ) != 0 ) {
|
||||
DBGC ( colour, "RUNTIME could not set image name: %s\n",
|
||||
strerror ( rc ) );
|
||||
goto err_set_name;
|
||||
}
|
||||
|
||||
/* Allocate and copy initrd content */
|
||||
image->data = umalloc ( initrd_len );
|
||||
if ( ! image->data ) {
|
||||
DBGC ( colour, "RUNTIME could not allocate %d bytes for "
|
||||
"initrd\n", initrd_len );
|
||||
rc = -ENOMEM;
|
||||
goto err_umalloc;
|
||||
}
|
||||
image->len = initrd_len;
|
||||
memcpy_user ( image->data, 0, phys_to_user ( initrd_phys ), 0,
|
||||
initrd_len );
|
||||
|
||||
/* Mark initrd as consumed */
|
||||
initrd_phys = 0;
|
||||
|
||||
/* Register image */
|
||||
if ( ( rc = register_image ( image ) ) != 0 ) {
|
||||
DBGC ( colour, "RUNTIME could not register initrd: %s\n",
|
||||
strerror ( rc ) );
|
||||
goto err_register_image;
|
||||
}
|
||||
|
||||
/* Drop our reference to the image */
|
||||
image_put ( image );
|
||||
|
||||
return 0;
|
||||
|
||||
err_register_image:
|
||||
err_umalloc:
|
||||
err_set_name:
|
||||
image_put ( image );
|
||||
err_alloc_image:
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialise command line and initrd
|
||||
*
|
||||
*/
|
||||
static void runtime_init ( void ) {
|
||||
int rc;
|
||||
|
||||
/* Initialise command line */
|
||||
if ( ( rc = cmdline_init() ) != 0 ) {
|
||||
/* No way to report failure */
|
||||
return;
|
||||
}
|
||||
|
||||
/* Initialise initrd */
|
||||
if ( ( rc = initrd_init() ) != 0 ) {
|
||||
/* No way to report failure */
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/** Command line and initrd initialisation function */
|
||||
struct startup_fn runtime_startup_fn __startup_fn ( STARTUP_NORMAL ) = {
|
||||
.name = "runtime",
|
||||
.startup = runtime_init,
|
||||
};
|
21
src/arch/x86/core/stack.S
Normal file
21
src/arch/x86/core/stack.S
Normal file
@@ -0,0 +1,21 @@
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
|
||||
|
||||
.arch i386
|
||||
|
||||
#ifdef __x86_64__
|
||||
#define STACK_SIZE 8192
|
||||
#else
|
||||
#define STACK_SIZE 4096
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Internal stack
|
||||
****************************************************************************
|
||||
*/
|
||||
.section ".stack", "aw", @nobits
|
||||
.align 8
|
||||
.globl _stack
|
||||
_stack:
|
||||
.space STACK_SIZE
|
||||
.globl _estack
|
||||
_estack:
|
15
src/arch/x86/core/stack16.S
Normal file
15
src/arch/x86/core/stack16.S
Normal file
@@ -0,0 +1,15 @@
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
|
||||
|
||||
.arch i386
|
||||
|
||||
/****************************************************************************
|
||||
* Internal stack
|
||||
****************************************************************************
|
||||
*/
|
||||
.section ".stack16", "aw", @nobits
|
||||
.align 8
|
||||
.globl _stack16
|
||||
_stack16:
|
||||
.space 4096
|
||||
.globl _estack16
|
||||
_estack16:
|
113
src/arch/x86/core/video_subr.c
Normal file
113
src/arch/x86/core/video_subr.c
Normal file
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
*
|
||||
* modified from linuxbios code
|
||||
* by Cai Qiang <rimy2000@hotmail.com>
|
||||
*
|
||||
*/
|
||||
|
||||
#include "stddef.h"
|
||||
#include "string.h"
|
||||
#include <ipxe/io.h>
|
||||
#include <ipxe/console.h>
|
||||
#include <ipxe/init.h>
|
||||
#include "vga.h"
|
||||
#include <config/console.h>
|
||||
|
||||
/* Set default console usage if applicable */
|
||||
#if ! ( defined ( CONSOLE_DIRECT_VGA ) && \
|
||||
CONSOLE_EXPLICIT ( CONSOLE_DIRECT_VGA ) )
|
||||
#undef CONSOLE_DIRECT_VGA
|
||||
#define CONSOLE_DIRECT_VGA ( CONSOLE_USAGE_ALL & ~CONSOLE_USAGE_LOG )
|
||||
#endif
|
||||
|
||||
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;
|
||||
|
||||
memmove(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 = CONSOLE_DISABLED,
|
||||
.usage = CONSOLE_DIRECT_VGA,
|
||||
};
|
||||
|
||||
struct init_fn video_init_fn __init_fn ( INIT_EARLY ) = {
|
||||
.initialise = video_init,
|
||||
};
|
72
src/arch/x86/core/vram_settings.c
Normal file
72
src/arch/x86/core/vram_settings.c
Normal file
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright (C) 2015 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., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA.
|
||||
*
|
||||
* You can also choose to distribute this program under the terms of
|
||||
* the Unmodified Binary Distribution Licence (as given in the file
|
||||
* COPYING.UBDL), provided that you have satisfied its requirements.
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
#include <ipxe/uaccess.h>
|
||||
#include <ipxe/settings.h>
|
||||
|
||||
/** @file
|
||||
*
|
||||
* Video RAM dump
|
||||
*
|
||||
*/
|
||||
|
||||
/** Video RAM base address */
|
||||
#define VRAM_BASE 0xb8000
|
||||
|
||||
/** Video RAM length */
|
||||
#define VRAM_LEN \
|
||||
( 80 /* columns */ * 25 /* rows */ * 2 /* bytes per character */ )
|
||||
|
||||
/**
|
||||
* Fetch video RAM setting
|
||||
*
|
||||
* @v data Buffer to fill with setting data
|
||||
* @v len Length of buffer
|
||||
* @ret len Length of setting data, or negative error
|
||||
*/
|
||||
static int vram_fetch ( void *data, size_t len ) {
|
||||
userptr_t vram = phys_to_user ( VRAM_BASE );
|
||||
|
||||
/* Copy video RAM */
|
||||
if ( len > VRAM_LEN )
|
||||
len = VRAM_LEN;
|
||||
copy_from_user ( data, vram, 0, len );
|
||||
|
||||
return VRAM_LEN;
|
||||
}
|
||||
|
||||
/** Video RAM setting */
|
||||
const struct setting vram_setting __setting ( SETTING_MISC, vram ) = {
|
||||
.name = "vram",
|
||||
.description = "Video RAM",
|
||||
.type = &setting_type_base64,
|
||||
.scope = &builtin_scope,
|
||||
};
|
||||
|
||||
/** Video RAM built-in setting */
|
||||
struct builtin_setting vram_builtin_setting __builtin_setting = {
|
||||
.setting = &vram_setting,
|
||||
.fetch = vram_fetch,
|
||||
};
|
69
src/arch/x86/core/x86_uart.c
Normal file
69
src/arch/x86/core/x86_uart.c
Normal file
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright (C) 2014 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., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA.
|
||||
*
|
||||
* You can also choose to distribute this program under the terms of
|
||||
* the Unmodified Binary Distribution Licence (as given in the file
|
||||
* COPYING.UBDL), provided that you have satisfied its requirements.
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
/** @file
|
||||
*
|
||||
* 16550-compatible UART
|
||||
*
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <ipxe/uart.h>
|
||||
|
||||
/** UART port bases */
|
||||
static uint16_t uart_base[] = {
|
||||
[COM1] = 0x3f8,
|
||||
[COM2] = 0x2f8,
|
||||
[COM3] = 0x3e8,
|
||||
[COM4] = 0x2e8,
|
||||
};
|
||||
|
||||
/**
|
||||
* Select UART port
|
||||
*
|
||||
* @v uart UART
|
||||
* @v port Port number, or 0 to disable
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
int uart_select ( struct uart *uart, unsigned int port ) {
|
||||
int rc;
|
||||
|
||||
/* Set new UART base */
|
||||
if ( port >= ( sizeof ( uart_base ) / sizeof ( uart_base[0] ) ) ) {
|
||||
rc = -ENODEV;
|
||||
goto err;
|
||||
}
|
||||
uart->base = ( ( void * ) ( intptr_t ) uart_base[port] );
|
||||
|
||||
/* Check that UART exists */
|
||||
if ( ( rc = uart_exists ( uart ) ) != 0 )
|
||||
goto err;
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
uart->base = NULL;
|
||||
return rc;
|
||||
}
|
820
src/arch/x86/drivers/hyperv/hyperv.c
Normal file
820
src/arch/x86/drivers/hyperv/hyperv.c
Normal file
@@ -0,0 +1,820 @@
|
||||
/*
|
||||
* Copyright (C) 2014 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 (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.
|
||||
*
|
||||
* You can also choose to distribute this program under the terms of
|
||||
* the Unmodified Binary Distribution Licence (as given in the file
|
||||
* COPYING.UBDL), provided that you have satisfied its requirements.
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
/** @file
|
||||
*
|
||||
* Hyper-V driver
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <byteswap.h>
|
||||
#include <pic8259.h>
|
||||
#include <ipxe/malloc.h>
|
||||
#include <ipxe/device.h>
|
||||
#include <ipxe/timer.h>
|
||||
#include <ipxe/quiesce.h>
|
||||
#include <ipxe/cpuid.h>
|
||||
#include <ipxe/msr.h>
|
||||
#include <ipxe/hyperv.h>
|
||||
#include <ipxe/vmbus.h>
|
||||
#include "hyperv.h"
|
||||
|
||||
/** Maximum time to wait for a message response
|
||||
*
|
||||
* This is a policy decision.
|
||||
*/
|
||||
#define HV_MESSAGE_MAX_WAIT_MS 1000
|
||||
|
||||
/** Hyper-V timer frequency (fixed 10Mhz) */
|
||||
#define HV_TIMER_HZ 10000000
|
||||
|
||||
/** Hyper-V timer scale factor (used to avoid 64-bit division) */
|
||||
#define HV_TIMER_SHIFT 18
|
||||
|
||||
/**
|
||||
* Convert a Hyper-V status code to an iPXE status code
|
||||
*
|
||||
* @v status Hyper-V status code
|
||||
* @ret rc iPXE status code (before negation)
|
||||
*/
|
||||
#define EHV( status ) EPLATFORM ( EINFO_EPLATFORM, (status) )
|
||||
|
||||
/**
|
||||
* Allocate zeroed pages
|
||||
*
|
||||
* @v hv Hyper-V hypervisor
|
||||
* @v ... Page addresses to fill in, terminated by NULL
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
__attribute__ (( sentinel )) int
|
||||
hv_alloc_pages ( struct hv_hypervisor *hv, ... ) {
|
||||
va_list args;
|
||||
void **page;
|
||||
int i;
|
||||
|
||||
/* Allocate and zero pages */
|
||||
va_start ( args, hv );
|
||||
for ( i = 0 ; ( ( page = va_arg ( args, void ** ) ) != NULL ); i++ ) {
|
||||
*page = malloc_dma ( PAGE_SIZE, PAGE_SIZE );
|
||||
if ( ! *page )
|
||||
goto err_alloc;
|
||||
memset ( *page, 0, PAGE_SIZE );
|
||||
}
|
||||
va_end ( args );
|
||||
|
||||
return 0;
|
||||
|
||||
err_alloc:
|
||||
va_end ( args );
|
||||
va_start ( args, hv );
|
||||
for ( ; i >= 0 ; i-- ) {
|
||||
page = va_arg ( args, void ** );
|
||||
free_dma ( *page, PAGE_SIZE );
|
||||
}
|
||||
va_end ( args );
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/**
|
||||
* Free pages
|
||||
*
|
||||
* @v hv Hyper-V hypervisor
|
||||
* @v ... Page addresses, terminated by NULL
|
||||
*/
|
||||
__attribute__ (( sentinel )) void
|
||||
hv_free_pages ( struct hv_hypervisor *hv, ... ) {
|
||||
va_list args;
|
||||
void *page;
|
||||
|
||||
va_start ( args, hv );
|
||||
while ( ( page = va_arg ( args, void * ) ) != NULL )
|
||||
free_dma ( page, PAGE_SIZE );
|
||||
va_end ( args );
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocate message buffer
|
||||
*
|
||||
* @v hv Hyper-V hypervisor
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int hv_alloc_message ( struct hv_hypervisor *hv ) {
|
||||
|
||||
/* Allocate buffer. Must be aligned to at least 8 bytes and
|
||||
* must not cross a page boundary, so align on its own size.
|
||||
*/
|
||||
hv->message = malloc_dma ( sizeof ( *hv->message ),
|
||||
sizeof ( *hv->message ) );
|
||||
if ( ! hv->message )
|
||||
return -ENOMEM;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Free message buffer
|
||||
*
|
||||
* @v hv Hyper-V hypervisor
|
||||
*/
|
||||
static void hv_free_message ( struct hv_hypervisor *hv ) {
|
||||
|
||||
/* Free buffer */
|
||||
free_dma ( hv->message, sizeof ( *hv->message ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether or not we are running in Hyper-V
|
||||
*
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int hv_check_hv ( void ) {
|
||||
struct x86_features features;
|
||||
uint32_t interface_id;
|
||||
uint32_t discard_ebx;
|
||||
uint32_t discard_ecx;
|
||||
uint32_t discard_edx;
|
||||
|
||||
/* Check for presence of a hypervisor (not necessarily Hyper-V) */
|
||||
x86_features ( &features );
|
||||
if ( ! ( features.intel.ecx & CPUID_FEATURES_INTEL_ECX_HYPERVISOR ) ) {
|
||||
DBGC ( HV_INTERFACE_ID, "HV not running in a hypervisor\n" );
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/* Check that hypervisor is Hyper-V */
|
||||
cpuid ( HV_CPUID_INTERFACE_ID, 0, &interface_id, &discard_ebx,
|
||||
&discard_ecx, &discard_edx );
|
||||
if ( interface_id != HV_INTERFACE_ID ) {
|
||||
DBGC ( HV_INTERFACE_ID, "HV not running in Hyper-V (interface "
|
||||
"ID %#08x)\n", interface_id );
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check required features
|
||||
*
|
||||
* @v hv Hyper-V hypervisor
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int hv_check_features ( struct hv_hypervisor *hv ) {
|
||||
uint32_t available;
|
||||
uint32_t permissions;
|
||||
uint32_t discard_ecx;
|
||||
uint32_t discard_edx;
|
||||
|
||||
/* Check that required features and privileges are available */
|
||||
cpuid ( HV_CPUID_FEATURES, 0, &available, &permissions, &discard_ecx,
|
||||
&discard_edx );
|
||||
if ( ! ( available & HV_FEATURES_AVAIL_HYPERCALL_MSR ) ) {
|
||||
DBGC ( hv, "HV %p has no hypercall MSRs (features %08x:%08x)\n",
|
||||
hv, available, permissions );
|
||||
return -ENODEV;
|
||||
}
|
||||
if ( ! ( available & HV_FEATURES_AVAIL_SYNIC_MSR ) ) {
|
||||
DBGC ( hv, "HV %p has no SynIC MSRs (features %08x:%08x)\n",
|
||||
hv, available, permissions );
|
||||
return -ENODEV;
|
||||
}
|
||||
if ( ! ( permissions & HV_FEATURES_PERM_POST_MESSAGES ) ) {
|
||||
DBGC ( hv, "HV %p cannot post messages (features %08x:%08x)\n",
|
||||
hv, available, permissions );
|
||||
return -EACCES;
|
||||
}
|
||||
if ( ! ( permissions & HV_FEATURES_PERM_SIGNAL_EVENTS ) ) {
|
||||
DBGC ( hv, "HV %p cannot signal events (features %08x:%08x)",
|
||||
hv, available, permissions );
|
||||
return -EACCES;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check that Gen 2 UEFI firmware is not running
|
||||
*
|
||||
* @v hv Hyper-V hypervisor
|
||||
* @ret rc Return status code
|
||||
*
|
||||
* We must not steal ownership from the Gen 2 UEFI firmware, since
|
||||
* doing so will cause an immediate crash. Avoid this by checking for
|
||||
* the guest OS identity known to be used by the Gen 2 UEFI firmware.
|
||||
*/
|
||||
static int hv_check_uefi ( struct hv_hypervisor *hv ) {
|
||||
uint64_t guest_os_id;
|
||||
|
||||
/* Check for UEFI firmware's guest OS identity */
|
||||
guest_os_id = rdmsr ( HV_X64_MSR_GUEST_OS_ID );
|
||||
if ( guest_os_id == HV_GUEST_OS_ID_UEFI ) {
|
||||
DBGC ( hv, "HV %p is owned by UEFI firmware\n", hv );
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Map hypercall page
|
||||
*
|
||||
* @v hv Hyper-V hypervisor
|
||||
*/
|
||||
static void hv_map_hypercall ( struct hv_hypervisor *hv ) {
|
||||
union {
|
||||
struct {
|
||||
uint32_t ebx;
|
||||
uint32_t ecx;
|
||||
uint32_t edx;
|
||||
} __attribute__ (( packed ));
|
||||
char text[ 13 /* "bbbbccccdddd" + NUL */ ];
|
||||
} vendor_id;
|
||||
uint32_t build;
|
||||
uint32_t version;
|
||||
uint32_t discard_eax;
|
||||
uint32_t discard_ecx;
|
||||
uint32_t discard_edx;
|
||||
uint64_t guest_os_id;
|
||||
uint64_t hypercall;
|
||||
|
||||
/* Report guest OS identity */
|
||||
guest_os_id = rdmsr ( HV_X64_MSR_GUEST_OS_ID );
|
||||
if ( guest_os_id != 0 ) {
|
||||
DBGC ( hv, "HV %p guest OS ID MSR was %#08llx\n",
|
||||
hv, guest_os_id );
|
||||
}
|
||||
guest_os_id = HV_GUEST_OS_ID_IPXE;
|
||||
DBGC2 ( hv, "HV %p guest OS ID MSR is %#08llx\n", hv, guest_os_id );
|
||||
wrmsr ( HV_X64_MSR_GUEST_OS_ID, guest_os_id );
|
||||
|
||||
/* Get hypervisor system identity (for debugging) */
|
||||
cpuid ( HV_CPUID_VENDOR_ID, 0, &discard_eax, &vendor_id.ebx,
|
||||
&vendor_id.ecx, &vendor_id.edx );
|
||||
vendor_id.text[ sizeof ( vendor_id.text ) - 1 ] = '\0';
|
||||
cpuid ( HV_CPUID_HYPERVISOR_ID, 0, &build, &version, &discard_ecx,
|
||||
&discard_edx );
|
||||
DBGC ( hv, "HV %p detected \"%s\" version %d.%d build %d\n", hv,
|
||||
vendor_id.text, ( version >> 16 ), ( version & 0xffff ), build );
|
||||
|
||||
/* Map hypercall page */
|
||||
hypercall = rdmsr ( HV_X64_MSR_HYPERCALL );
|
||||
hypercall &= ( PAGE_SIZE - 1 );
|
||||
hypercall |= ( virt_to_phys ( hv->hypercall ) | HV_HYPERCALL_ENABLE );
|
||||
DBGC2 ( hv, "HV %p hypercall MSR is %#08llx\n", hv, hypercall );
|
||||
wrmsr ( HV_X64_MSR_HYPERCALL, hypercall );
|
||||
}
|
||||
|
||||
/**
|
||||
* Unmap hypercall page
|
||||
*
|
||||
* @v hv Hyper-V hypervisor
|
||||
*/
|
||||
static void hv_unmap_hypercall ( struct hv_hypervisor *hv ) {
|
||||
uint64_t hypercall;
|
||||
uint64_t guest_os_id;
|
||||
|
||||
/* Unmap the hypercall page */
|
||||
hypercall = rdmsr ( HV_X64_MSR_HYPERCALL );
|
||||
hypercall &= ( ( PAGE_SIZE - 1 ) & ~HV_HYPERCALL_ENABLE );
|
||||
DBGC2 ( hv, "HV %p hypercall MSR is %#08llx\n", hv, hypercall );
|
||||
wrmsr ( HV_X64_MSR_HYPERCALL, hypercall );
|
||||
|
||||
/* Reset the guest OS identity */
|
||||
guest_os_id = 0;
|
||||
DBGC2 ( hv, "HV %p guest OS ID MSR is %#08llx\n", hv, guest_os_id );
|
||||
wrmsr ( HV_X64_MSR_GUEST_OS_ID, guest_os_id );
|
||||
}
|
||||
|
||||
/**
|
||||
* Map synthetic interrupt controller
|
||||
*
|
||||
* @v hv Hyper-V hypervisor
|
||||
*/
|
||||
static void hv_map_synic ( struct hv_hypervisor *hv ) {
|
||||
uint64_t simp;
|
||||
uint64_t siefp;
|
||||
uint64_t scontrol;
|
||||
|
||||
/* Zero SynIC message and event pages */
|
||||
memset ( hv->synic.message, 0, PAGE_SIZE );
|
||||
memset ( hv->synic.event, 0, PAGE_SIZE );
|
||||
|
||||
/* Map SynIC message page */
|
||||
simp = rdmsr ( HV_X64_MSR_SIMP );
|
||||
simp &= ( PAGE_SIZE - 1 );
|
||||
simp |= ( virt_to_phys ( hv->synic.message ) | HV_SIMP_ENABLE );
|
||||
DBGC2 ( hv, "HV %p SIMP MSR is %#08llx\n", hv, simp );
|
||||
wrmsr ( HV_X64_MSR_SIMP, simp );
|
||||
|
||||
/* Map SynIC event page */
|
||||
siefp = rdmsr ( HV_X64_MSR_SIEFP );
|
||||
siefp &= ( PAGE_SIZE - 1 );
|
||||
siefp |= ( virt_to_phys ( hv->synic.event ) | HV_SIEFP_ENABLE );
|
||||
DBGC2 ( hv, "HV %p SIEFP MSR is %#08llx\n", hv, siefp );
|
||||
wrmsr ( HV_X64_MSR_SIEFP, siefp );
|
||||
|
||||
/* Enable SynIC */
|
||||
scontrol = rdmsr ( HV_X64_MSR_SCONTROL );
|
||||
scontrol |= HV_SCONTROL_ENABLE;
|
||||
DBGC2 ( hv, "HV %p SCONTROL MSR is %#08llx\n", hv, scontrol );
|
||||
wrmsr ( HV_X64_MSR_SCONTROL, scontrol );
|
||||
}
|
||||
|
||||
/**
|
||||
* Unmap synthetic interrupt controller, leaving SCONTROL untouched
|
||||
*
|
||||
* @v hv Hyper-V hypervisor
|
||||
*/
|
||||
static void hv_unmap_synic_no_scontrol ( struct hv_hypervisor *hv ) {
|
||||
uint64_t siefp;
|
||||
uint64_t simp;
|
||||
|
||||
/* Unmap SynIC event page */
|
||||
siefp = rdmsr ( HV_X64_MSR_SIEFP );
|
||||
siefp &= ( ( PAGE_SIZE - 1 ) & ~HV_SIEFP_ENABLE );
|
||||
DBGC2 ( hv, "HV %p SIEFP MSR is %#08llx\n", hv, siefp );
|
||||
wrmsr ( HV_X64_MSR_SIEFP, siefp );
|
||||
|
||||
/* Unmap SynIC message page */
|
||||
simp = rdmsr ( HV_X64_MSR_SIMP );
|
||||
simp &= ( ( PAGE_SIZE - 1 ) & ~HV_SIMP_ENABLE );
|
||||
DBGC2 ( hv, "HV %p SIMP MSR is %#08llx\n", hv, simp );
|
||||
wrmsr ( HV_X64_MSR_SIMP, simp );
|
||||
}
|
||||
|
||||
/**
|
||||
* Unmap synthetic interrupt controller
|
||||
*
|
||||
* @v hv Hyper-V hypervisor
|
||||
*/
|
||||
static void hv_unmap_synic ( struct hv_hypervisor *hv ) {
|
||||
uint64_t scontrol;
|
||||
|
||||
/* Disable SynIC */
|
||||
scontrol = rdmsr ( HV_X64_MSR_SCONTROL );
|
||||
scontrol &= ~HV_SCONTROL_ENABLE;
|
||||
DBGC2 ( hv, "HV %p SCONTROL MSR is %#08llx\n", hv, scontrol );
|
||||
wrmsr ( HV_X64_MSR_SCONTROL, scontrol );
|
||||
|
||||
/* Unmap SynIC event and message pages */
|
||||
hv_unmap_synic_no_scontrol ( hv );
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable synthetic interrupt
|
||||
*
|
||||
* @v hv Hyper-V hypervisor
|
||||
* @v sintx Synthetic interrupt number
|
||||
*/
|
||||
void hv_enable_sint ( struct hv_hypervisor *hv, unsigned int sintx ) {
|
||||
unsigned long msr = HV_X64_MSR_SINT ( sintx );
|
||||
uint64_t sint;
|
||||
|
||||
/* Enable synthetic interrupt
|
||||
*
|
||||
* We have to enable the interrupt, otherwise messages will
|
||||
* not be delivered (even though the documentation implies
|
||||
* that polling for messages is possible). We enable AutoEOI
|
||||
* and hook the interrupt to the obsolete IRQ13 (FPU
|
||||
* exception) vector, which will be implemented as a no-op.
|
||||
*/
|
||||
sint = rdmsr ( msr );
|
||||
sint &= ~( HV_SINT_MASKED | HV_SINT_VECTOR_MASK );
|
||||
sint |= ( HV_SINT_AUTO_EOI |
|
||||
HV_SINT_VECTOR ( IRQ_INT ( 13 /* See comment above */ ) ) );
|
||||
DBGC2 ( hv, "HV %p SINT%d MSR is %#08llx\n", hv, sintx, sint );
|
||||
wrmsr ( msr, sint );
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable synthetic interrupt
|
||||
*
|
||||
* @v hv Hyper-V hypervisor
|
||||
* @v sintx Synthetic interrupt number
|
||||
*/
|
||||
void hv_disable_sint ( struct hv_hypervisor *hv, unsigned int sintx ) {
|
||||
unsigned long msr = HV_X64_MSR_SINT ( sintx );
|
||||
uint64_t sint;
|
||||
|
||||
/* Do nothing if interrupt is already disabled */
|
||||
sint = rdmsr ( msr );
|
||||
if ( sint & HV_SINT_MASKED )
|
||||
return;
|
||||
|
||||
/* Disable synthetic interrupt */
|
||||
sint &= ~HV_SINT_AUTO_EOI;
|
||||
sint |= HV_SINT_MASKED;
|
||||
DBGC2 ( hv, "HV %p SINT%d MSR is %#08llx\n", hv, sintx, sint );
|
||||
wrmsr ( msr, sint );
|
||||
}
|
||||
|
||||
/**
|
||||
* Post message
|
||||
*
|
||||
* @v hv Hyper-V hypervisor
|
||||
* @v id Connection ID
|
||||
* @v type Message type
|
||||
* @v data Message
|
||||
* @v len Length of message
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
int hv_post_message ( struct hv_hypervisor *hv, unsigned int id,
|
||||
unsigned int type, const void *data, size_t len ) {
|
||||
struct hv_post_message *msg = &hv->message->posted;
|
||||
int status;
|
||||
int rc;
|
||||
|
||||
/* Sanity check */
|
||||
assert ( len <= sizeof ( msg->data ) );
|
||||
|
||||
/* Construct message */
|
||||
memset ( msg, 0, sizeof ( *msg ) );
|
||||
msg->id = cpu_to_le32 ( id );
|
||||
msg->type = cpu_to_le32 ( type );
|
||||
msg->len = cpu_to_le32 ( len );
|
||||
memcpy ( msg->data, data, len );
|
||||
DBGC2 ( hv, "HV %p connection %d posting message type %#08x:\n",
|
||||
hv, id, type );
|
||||
DBGC2_HDA ( hv, 0, msg->data, len );
|
||||
|
||||
/* Post message */
|
||||
if ( ( status = hv_call ( hv, HV_POST_MESSAGE, msg, NULL ) ) != 0 ) {
|
||||
rc = -EHV ( status );
|
||||
DBGC ( hv, "HV %p could not post message to %#08x: %s\n",
|
||||
hv, id, strerror ( rc ) );
|
||||
return rc;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait for received message
|
||||
*
|
||||
* @v hv Hyper-V hypervisor
|
||||
* @v sintx Synthetic interrupt number
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
int hv_wait_for_message ( struct hv_hypervisor *hv, unsigned int sintx ) {
|
||||
struct hv_message *msg = &hv->message->received;
|
||||
struct hv_message *src = &hv->synic.message[sintx];
|
||||
unsigned int retries;
|
||||
size_t len;
|
||||
|
||||
/* Wait for message to arrive */
|
||||
for ( retries = 0 ; retries < HV_MESSAGE_MAX_WAIT_MS ; retries++ ) {
|
||||
|
||||
/* Check for message */
|
||||
if ( src->type ) {
|
||||
|
||||
/* Copy message */
|
||||
memset ( msg, 0, sizeof ( *msg ) );
|
||||
len = src->len;
|
||||
assert ( len <= sizeof ( *msg ) );
|
||||
memcpy ( msg, src,
|
||||
( offsetof ( typeof ( *msg ), data ) + len ) );
|
||||
DBGC2 ( hv, "HV %p SINT%d received message type "
|
||||
"%#08x:\n", hv, sintx,
|
||||
le32_to_cpu ( msg->type ) );
|
||||
DBGC2_HDA ( hv, 0, msg->data, len );
|
||||
|
||||
/* Consume message */
|
||||
src->type = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Trigger message delivery */
|
||||
wrmsr ( HV_X64_MSR_EOM, 0 );
|
||||
|
||||
/* Delay */
|
||||
mdelay ( 1 );
|
||||
}
|
||||
|
||||
DBGC ( hv, "HV %p SINT%d timed out waiting for message\n",
|
||||
hv, sintx );
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Signal event
|
||||
*
|
||||
* @v hv Hyper-V hypervisor
|
||||
* @v id Connection ID
|
||||
* @v flag Flag number
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
int hv_signal_event ( struct hv_hypervisor *hv, unsigned int id,
|
||||
unsigned int flag ) {
|
||||
struct hv_signal_event *event = &hv->message->signalled;
|
||||
int status;
|
||||
int rc;
|
||||
|
||||
/* Construct event */
|
||||
memset ( event, 0, sizeof ( *event ) );
|
||||
event->id = cpu_to_le32 ( id );
|
||||
event->flag = cpu_to_le16 ( flag );
|
||||
|
||||
/* Signal event */
|
||||
if ( ( status = hv_call ( hv, HV_SIGNAL_EVENT, event, NULL ) ) != 0 ) {
|
||||
rc = -EHV ( status );
|
||||
DBGC ( hv, "HV %p could not signal event to %#08x: %s\n",
|
||||
hv, id, strerror ( rc ) );
|
||||
return rc;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Probe root device
|
||||
*
|
||||
* @v rootdev Root device
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int hv_probe ( struct root_device *rootdev ) {
|
||||
struct hv_hypervisor *hv;
|
||||
int rc;
|
||||
|
||||
/* Check we are running in Hyper-V */
|
||||
if ( ( rc = hv_check_hv() ) != 0 )
|
||||
goto err_check_hv;
|
||||
|
||||
/* Allocate and initialise structure */
|
||||
hv = zalloc ( sizeof ( *hv ) );
|
||||
if ( ! hv ) {
|
||||
rc = -ENOMEM;
|
||||
goto err_alloc;
|
||||
}
|
||||
|
||||
/* Check features */
|
||||
if ( ( rc = hv_check_features ( hv ) ) != 0 )
|
||||
goto err_check_features;
|
||||
|
||||
/* Check that Gen 2 UEFI firmware is not running */
|
||||
if ( ( rc = hv_check_uefi ( hv ) ) != 0 )
|
||||
goto err_check_uefi;
|
||||
|
||||
/* Allocate pages */
|
||||
if ( ( rc = hv_alloc_pages ( hv, &hv->hypercall, &hv->synic.message,
|
||||
&hv->synic.event, NULL ) ) != 0 )
|
||||
goto err_alloc_pages;
|
||||
|
||||
/* Allocate message buffer */
|
||||
if ( ( rc = hv_alloc_message ( hv ) ) != 0 )
|
||||
goto err_alloc_message;
|
||||
|
||||
/* Map hypercall page */
|
||||
hv_map_hypercall ( hv );
|
||||
|
||||
/* Map synthetic interrupt controller */
|
||||
hv_map_synic ( hv );
|
||||
|
||||
/* Probe Hyper-V devices */
|
||||
if ( ( rc = vmbus_probe ( hv, &rootdev->dev ) ) != 0 )
|
||||
goto err_vmbus_probe;
|
||||
|
||||
rootdev_set_drvdata ( rootdev, hv );
|
||||
return 0;
|
||||
|
||||
vmbus_remove ( hv, &rootdev->dev );
|
||||
err_vmbus_probe:
|
||||
hv_unmap_synic ( hv );
|
||||
hv_unmap_hypercall ( hv );
|
||||
hv_free_message ( hv );
|
||||
err_alloc_message:
|
||||
hv_free_pages ( hv, hv->hypercall, hv->synic.message, hv->synic.event,
|
||||
NULL );
|
||||
err_alloc_pages:
|
||||
err_check_uefi:
|
||||
err_check_features:
|
||||
free ( hv );
|
||||
err_alloc:
|
||||
err_check_hv:
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove root device
|
||||
*
|
||||
* @v rootdev Root device
|
||||
*/
|
||||
static void hv_remove ( struct root_device *rootdev ) {
|
||||
struct hv_hypervisor *hv = rootdev_get_drvdata ( rootdev );
|
||||
|
||||
vmbus_remove ( hv, &rootdev->dev );
|
||||
hv_unmap_synic ( hv );
|
||||
hv_unmap_hypercall ( hv );
|
||||
hv_free_message ( hv );
|
||||
hv_free_pages ( hv, hv->hypercall, hv->synic.message, hv->synic.event,
|
||||
NULL );
|
||||
free ( hv );
|
||||
rootdev_set_drvdata ( rootdev, NULL );
|
||||
}
|
||||
|
||||
/** Hyper-V root device driver */
|
||||
static struct root_driver hv_root_driver = {
|
||||
.probe = hv_probe,
|
||||
.remove = hv_remove,
|
||||
};
|
||||
|
||||
/** Hyper-V root device */
|
||||
struct root_device hv_root_device __root_device = {
|
||||
.dev = { .name = "Hyper-V" },
|
||||
.driver = &hv_root_driver,
|
||||
};
|
||||
|
||||
/**
|
||||
* Quiesce system
|
||||
*
|
||||
*/
|
||||
static void hv_quiesce ( void ) {
|
||||
struct hv_hypervisor *hv = rootdev_get_drvdata ( &hv_root_device );
|
||||
unsigned int i;
|
||||
|
||||
/* Do nothing if we are not running in Hyper-V */
|
||||
if ( ! hv )
|
||||
return;
|
||||
|
||||
/* The "enlightened" portions of the Windows Server 2016 boot
|
||||
* process will not cleanly take ownership of an active
|
||||
* Hyper-V connection. Experimentation shows that the minimum
|
||||
* requirement is that we disable the SynIC message page
|
||||
* (i.e. zero the SIMP MSR).
|
||||
*
|
||||
* We cannot perform a full shutdown of the Hyper-V
|
||||
* connection. Experimentation shows that if we disable the
|
||||
* SynIC (i.e. zero the SCONTROL MSR) then Windows Server 2016
|
||||
* will enter an indefinite wait loop.
|
||||
*
|
||||
* Attempt to create a safe handover environment by resetting
|
||||
* all MSRs except for SCONTROL.
|
||||
*
|
||||
* Note that we do not shut down our VMBus devices, since we
|
||||
* may need to unquiesce the system and continue operation.
|
||||
*/
|
||||
|
||||
/* Disable all synthetic interrupts */
|
||||
for ( i = 0 ; i <= HV_SINT_MAX ; i++ )
|
||||
hv_disable_sint ( hv, i );
|
||||
|
||||
/* Unmap synthetic interrupt controller, leaving SCONTROL
|
||||
* enabled (see above).
|
||||
*/
|
||||
hv_unmap_synic_no_scontrol ( hv );
|
||||
|
||||
/* Unmap hypercall page */
|
||||
hv_unmap_hypercall ( hv );
|
||||
|
||||
DBGC ( hv, "HV %p quiesced\n", hv );
|
||||
}
|
||||
|
||||
/**
|
||||
* Unquiesce system
|
||||
*
|
||||
*/
|
||||
static void hv_unquiesce ( void ) {
|
||||
struct hv_hypervisor *hv = rootdev_get_drvdata ( &hv_root_device );
|
||||
uint64_t simp;
|
||||
int rc;
|
||||
|
||||
/* Do nothing if we are not running in Hyper-V */
|
||||
if ( ! hv )
|
||||
return;
|
||||
|
||||
/* Experimentation shows that the "enlightened" portions of
|
||||
* Windows Server 2016 will break our Hyper-V connection at
|
||||
* some point during a SAN boot. Surprisingly it does not
|
||||
* change the guest OS ID MSR, but it does leave the SynIC
|
||||
* message page disabled.
|
||||
*
|
||||
* Our own explicit quiescing procedure will also disable the
|
||||
* SynIC message page. We can therefore use the SynIC message
|
||||
* page enable bit as a heuristic to determine when we need to
|
||||
* reestablish our Hyper-V connection.
|
||||
*/
|
||||
simp = rdmsr ( HV_X64_MSR_SIMP );
|
||||
if ( simp & HV_SIMP_ENABLE )
|
||||
return;
|
||||
|
||||
/* Remap hypercall page */
|
||||
hv_map_hypercall ( hv );
|
||||
|
||||
/* Remap synthetic interrupt controller */
|
||||
hv_map_synic ( hv );
|
||||
|
||||
/* Reset Hyper-V devices */
|
||||
if ( ( rc = vmbus_reset ( hv, &hv_root_device.dev ) ) != 0 ) {
|
||||
DBGC ( hv, "HV %p could not unquiesce: %s\n",
|
||||
hv, strerror ( rc ) );
|
||||
/* Nothing we can do */
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/** Hyper-V quiescer */
|
||||
struct quiescer hv_quiescer __quiescer = {
|
||||
.quiesce = hv_quiesce,
|
||||
.unquiesce = hv_unquiesce,
|
||||
};
|
||||
|
||||
/**
|
||||
* Probe timer
|
||||
*
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int hv_timer_probe ( void ) {
|
||||
uint32_t available;
|
||||
uint32_t discard_ebx;
|
||||
uint32_t discard_ecx;
|
||||
uint32_t discard_edx;
|
||||
int rc;
|
||||
|
||||
/* Check we are running in Hyper-V */
|
||||
if ( ( rc = hv_check_hv() ) != 0 )
|
||||
return rc;
|
||||
|
||||
/* Check for available reference counter */
|
||||
cpuid ( HV_CPUID_FEATURES, 0, &available, &discard_ebx, &discard_ecx,
|
||||
&discard_edx );
|
||||
if ( ! ( available & HV_FEATURES_AVAIL_TIME_REF_COUNT_MSR ) ) {
|
||||
DBGC ( HV_INTERFACE_ID, "HV has no time reference counter\n" );
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get current system time in ticks
|
||||
*
|
||||
* @ret ticks Current time, in ticks
|
||||
*/
|
||||
static unsigned long hv_currticks ( void ) {
|
||||
|
||||
/* Calculate time using a combination of bit shifts and
|
||||
* multiplication (to avoid a 64-bit division).
|
||||
*/
|
||||
return ( ( rdmsr ( HV_X64_MSR_TIME_REF_COUNT ) >> HV_TIMER_SHIFT ) *
|
||||
( TICKS_PER_SEC / ( HV_TIMER_HZ >> HV_TIMER_SHIFT ) ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Delay for a fixed number of microseconds
|
||||
*
|
||||
* @v usecs Number of microseconds for which to delay
|
||||
*/
|
||||
static void hv_udelay ( unsigned long usecs ) {
|
||||
uint32_t start;
|
||||
uint32_t elapsed;
|
||||
uint32_t threshold;
|
||||
|
||||
/* Spin until specified number of 10MHz ticks have elapsed */
|
||||
start = rdmsr ( HV_X64_MSR_TIME_REF_COUNT );
|
||||
threshold = ( usecs * ( HV_TIMER_HZ / 1000000 ) );
|
||||
do {
|
||||
elapsed = ( rdmsr ( HV_X64_MSR_TIME_REF_COUNT ) - start );
|
||||
} while ( elapsed < threshold );
|
||||
}
|
||||
|
||||
/** Hyper-V timer */
|
||||
struct timer hv_timer __timer ( TIMER_PREFERRED ) = {
|
||||
.name = "Hyper-V",
|
||||
.probe = hv_timer_probe,
|
||||
.currticks = hv_currticks,
|
||||
.udelay = hv_udelay,
|
||||
};
|
||||
|
||||
/* Drag in objects via hv_root_device */
|
||||
REQUIRING_SYMBOL ( hv_root_device );
|
||||
|
||||
/* Drag in netvsc driver */
|
||||
REQUIRE_OBJECT ( netvsc );
|
63
src/arch/x86/drivers/hyperv/hyperv.h
Normal file
63
src/arch/x86/drivers/hyperv/hyperv.h
Normal file
@@ -0,0 +1,63 @@
|
||||
#ifndef _HYPERV_H
|
||||
#define _HYPERV_H
|
||||
|
||||
/** @file
|
||||
*
|
||||
* Hyper-V driver
|
||||
*
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
/** Get vendor identification */
|
||||
#define HV_CPUID_VENDOR_ID 0x40000000UL
|
||||
|
||||
/** Get interface identification */
|
||||
#define HV_CPUID_INTERFACE_ID 0x40000001UL
|
||||
|
||||
/** Get hypervisor identification */
|
||||
#define HV_CPUID_HYPERVISOR_ID 0x40000002UL
|
||||
|
||||
/** Get hypervisor features */
|
||||
#define HV_CPUID_FEATURES 0x40000003UL
|
||||
|
||||
/** Time reference counter MSR is available */
|
||||
#define HV_FEATURES_AVAIL_TIME_REF_COUNT_MSR 0x00000002UL
|
||||
|
||||
/** SynIC MSRs are available */
|
||||
#define HV_FEATURES_AVAIL_SYNIC_MSR 0x00000004UL
|
||||
|
||||
/** Hypercall MSRs are available */
|
||||
#define HV_FEATURES_AVAIL_HYPERCALL_MSR 0x00000020UL
|
||||
|
||||
/** Guest may post messages */
|
||||
#define HV_FEATURES_PERM_POST_MESSAGES 0x00000010UL
|
||||
|
||||
/** Guest may signal events */
|
||||
#define HV_FEATURES_PERM_SIGNAL_EVENTS 0x00000020UL
|
||||
|
||||
/** Guest OS identity MSR */
|
||||
#define HV_X64_MSR_GUEST_OS_ID 0x40000000UL
|
||||
|
||||
/** Hypercall page MSR */
|
||||
#define HV_X64_MSR_HYPERCALL 0x40000001UL
|
||||
|
||||
/** Time reference MSR */
|
||||
#define HV_X64_MSR_TIME_REF_COUNT 0x40000020UL
|
||||
|
||||
/** SynIC control MSR */
|
||||
#define HV_X64_MSR_SCONTROL 0x40000080UL
|
||||
|
||||
/** SynIC event flags page MSR */
|
||||
#define HV_X64_MSR_SIEFP 0x40000082UL
|
||||
|
||||
/** SynIC message page MSR */
|
||||
#define HV_X64_MSR_SIMP 0x40000083UL
|
||||
|
||||
/** SynIC end of message MSR */
|
||||
#define HV_X64_MSR_EOM 0x40000084UL
|
||||
|
||||
/** SynIC interrupt source MSRs */
|
||||
#define HV_X64_MSR_SINT(x) ( 0x40000090UL + (x) )
|
||||
|
||||
#endif /* _HYPERV_H */
|
136
src/arch/x86/drivers/net/undi.c
Normal file
136
src/arch/x86/drivers/net/undi.c
Normal file
@@ -0,0 +1,136 @@
|
||||
/*
|
||||
* 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., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, 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 ) {
|
||||
struct undi_device *undi;
|
||||
struct undi_rom *undirom;
|
||||
int rc;
|
||||
|
||||
/* 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 == pci->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,
|
||||
pci->busdevfn ) ) != 0 ) {
|
||||
goto err_load_pci;
|
||||
}
|
||||
}
|
||||
|
||||
/* Create network device */
|
||||
if ( ( rc = undinet_probe ( undi, &pci->dev ) ) != 0 )
|
||||
goto err_undinet_probe;
|
||||
|
||||
return 0;
|
||||
|
||||
err_undinet_probe:
|
||||
undi_unload ( undi );
|
||||
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 );
|
||||
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_fallback = {
|
||||
.ids = undipci_nics,
|
||||
.id_count = ( sizeof ( undipci_nics ) / sizeof ( undipci_nics[0] ) ),
|
||||
.class = PCI_CLASS_ID ( PCI_CLASS_NETWORK, PCI_ANY_ID, PCI_ANY_ID ),
|
||||
.probe = undipci_probe,
|
||||
.remove = undipci_remove,
|
||||
};
|
87
src/arch/x86/drivers/net/undiisr.S
Normal file
87
src/arch/x86/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, undinet_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 *undinet_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
|
186
src/arch/x86/drivers/net/undiload.c
Normal file
186
src/arch/x86/drivers/net/undiload.c
Normal file
@@ -0,0 +1,186 @@
|
||||
/*
|
||||
* 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., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA.
|
||||
*
|
||||
* You can also choose to distribute this program under the terms of
|
||||
* the Unmodified Binary Distribution Licence (as given in the file
|
||||
* COPYING.UBDL), provided that you have satisfied its requirements.
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
#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
|
||||
*
|
||||
*/
|
||||
|
||||
/* Disambiguate the various error causes */
|
||||
#define EINFO_EUNDILOAD \
|
||||
__einfo_uniqify ( EINFO_EPLATFORM, 0x01, \
|
||||
"UNDI loader error" )
|
||||
#define EUNDILOAD( status ) EPLATFORM ( EINFO_EUNDILOAD, status )
|
||||
|
||||
/** 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 );
|
||||
rc = -EBUSY;
|
||||
goto err_multiple;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
undi->fbms = ( fbms_seg >> 6 );
|
||||
set_fbms ( undi->fbms );
|
||||
DBGC ( undi, "UNDI %p allocated [%d,%d) kB of base memory\n",
|
||||
undi, undi->fbms, undi->restore_fbms );
|
||||
|
||||
/* Debug info */
|
||||
DBGC ( undi, "UNDI %p loading ROM %p to CS %04x:%04zx DS %04x:%04zx "
|
||||
"for ", undi, undirom, undi_loader.UNDI_CS, undirom->code_size,
|
||||
undi_loader.UNDI_DS, undirom->data_size );
|
||||
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 ( "pushl %%ebp\n\t" /* gcc bug */
|
||||
"pushw %%ds\n\t"
|
||||
"pushw %%ax\n\t"
|
||||
"lcall *undi_loader_entry\n\t"
|
||||
"popl %%ebp\n\t" /* discard */
|
||||
"popl %%ebp\n\t" /* gcc bug */ )
|
||||
: "=a" ( exit )
|
||||
: "a" ( __from_data16 ( &undi_loader ) )
|
||||
: "ebx", "ecx", "edx", "esi", "edi" );
|
||||
if ( exit != PXENV_EXIT_SUCCESS ) {
|
||||
rc = -EUNDILOAD ( undi_loader.Status );
|
||||
DBGC ( undi, "UNDI %p loader failed: %s\n",
|
||||
undi, strerror ( rc ) );
|
||||
goto err_loader;
|
||||
}
|
||||
|
||||
/* 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 );
|
||||
|
||||
return 0;
|
||||
|
||||
err_loader:
|
||||
set_fbms ( undi->restore_fbms );
|
||||
memset ( &undi_loader_entry, 0, sizeof ( undi_loader_entry ) );
|
||||
err_multiple:
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
}
|
1074
src/arch/x86/drivers/net/undinet.c
Normal file
1074
src/arch/x86/drivers/net/undinet.c
Normal file
File diff suppressed because it is too large
Load Diff
146
src/arch/x86/drivers/net/undionly.c
Normal file
146
src/arch/x86/drivers/net/undionly.c
Normal file
@@ -0,0 +1,146 @@
|
||||
/*
|
||||
* 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., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA.
|
||||
*
|
||||
* You can also choose to distribute this program under the terms of
|
||||
* the Unmodified Binary Distribution Licence (as given in the file
|
||||
* COPYING.UBDL), provided that you have satisfied its requirements.
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <ipxe/device.h>
|
||||
#include <ipxe/init.h>
|
||||
#include <ipxe/pci.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".
|
||||
*/
|
||||
|
||||
/** UNDI root bus device */
|
||||
static struct device undibus_dev;
|
||||
|
||||
/**
|
||||
* 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;
|
||||
struct device *dev = &undibus_dev;
|
||||
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 */
|
||||
dev->driver_name = "undionly";
|
||||
if ( undi->pci_busdevfn != UNDI_NO_PCI_BUSDEVFN ) {
|
||||
dev->desc.bus_type = BUS_TYPE_PCI;
|
||||
dev->desc.location = undi->pci_busdevfn;
|
||||
dev->desc.vendor = undi->pci_vendor;
|
||||
dev->desc.device = undi->pci_device;
|
||||
snprintf ( dev->name, sizeof ( dev->name ),
|
||||
"0000:%02x:%02x.%x", PCI_BUS ( undi->pci_busdevfn ),
|
||||
PCI_SLOT ( undi->pci_busdevfn ),
|
||||
PCI_FUNC ( undi->pci_busdevfn ) );
|
||||
} else if ( undi->isapnp_csn != UNDI_NO_ISAPNP_CSN ) {
|
||||
dev->desc.bus_type = BUS_TYPE_ISAPNP;
|
||||
snprintf ( dev->name, sizeof ( dev->name ), "ISAPNP" );
|
||||
}
|
||||
dev->parent = &rootdev->dev;
|
||||
list_add ( &dev->siblings, &rootdev->dev.children);
|
||||
INIT_LIST_HEAD ( &dev->children );
|
||||
|
||||
/* Create network device */
|
||||
if ( ( rc = undinet_probe ( undi, dev ) ) != 0 )
|
||||
goto err;
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
list_del ( &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;
|
||||
struct device *dev = &undibus_dev;
|
||||
|
||||
undinet_remove ( undi );
|
||||
list_del ( &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 booting System is shutting down for OS boot
|
||||
*/
|
||||
static void undionly_shutdown ( int booting ) {
|
||||
/* If we are shutting down to boot an OS, clear the "keep PXE
|
||||
* stack" flag.
|
||||
*/
|
||||
if ( booting )
|
||||
preloaded_undi.flags &= ~UNDI_FL_KEEP_ALL;
|
||||
}
|
||||
|
||||
struct startup_fn startup_undionly __startup_fn ( STARTUP_LATE ) = {
|
||||
.name = "undionly",
|
||||
.shutdown = undionly_shutdown,
|
||||
};
|
42
src/arch/x86/drivers/net/undipreload.c
Normal file
42
src/arch/x86/drivers/net/undipreload.c
Normal file
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* 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., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA.
|
||||
*
|
||||
* You can also choose to distribute this program under the terms of
|
||||
* the Unmodified Binary Distribution Licence (as given in the file
|
||||
* COPYING.UBDL), provided that you have satisfied its requirements.
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
#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 );
|
235
src/arch/x86/drivers/net/undirom.c
Normal file
235
src/arch/x86/drivers/net/undirom.c
Normal file
@@ -0,0 +1,235 @@
|
||||
/*
|
||||
* 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., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, 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_tail ( &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;
|
||||
}
|
505
src/arch/x86/drivers/xen/hvm.c
Normal file
505
src/arch/x86/drivers/xen/hvm.c
Normal file
@@ -0,0 +1,505 @@
|
||||
/*
|
||||
* Copyright (C) 2014 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 (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.
|
||||
*
|
||||
* You can also choose to distribute this program under the terms of
|
||||
* the Unmodified Binary Distribution Licence (as given in the file
|
||||
* COPYING.UBDL), provided that you have satisfied its requirements.
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <ipxe/malloc.h>
|
||||
#include <ipxe/pci.h>
|
||||
#include <ipxe/cpuid.h>
|
||||
#include <ipxe/msr.h>
|
||||
#include <ipxe/xen.h>
|
||||
#include <ipxe/xenver.h>
|
||||
#include <ipxe/xenmem.h>
|
||||
#include <ipxe/xenstore.h>
|
||||
#include <ipxe/xenbus.h>
|
||||
#include <ipxe/xengrant.h>
|
||||
#include "hvm.h"
|
||||
|
||||
/** @file
|
||||
*
|
||||
* Xen HVM driver
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Get CPUID base
|
||||
*
|
||||
* @v hvm HVM device
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int hvm_cpuid_base ( struct hvm_device *hvm ) {
|
||||
struct {
|
||||
uint32_t ebx;
|
||||
uint32_t ecx;
|
||||
uint32_t edx;
|
||||
} __attribute__ (( packed )) signature;
|
||||
uint32_t base;
|
||||
uint32_t version;
|
||||
uint32_t discard_eax;
|
||||
uint32_t discard_ebx;
|
||||
uint32_t discard_ecx;
|
||||
uint32_t discard_edx;
|
||||
|
||||
/* Scan for magic signature */
|
||||
for ( base = HVM_CPUID_MIN ; base <= HVM_CPUID_MAX ;
|
||||
base += HVM_CPUID_STEP ) {
|
||||
cpuid ( base, 0, &discard_eax, &signature.ebx, &signature.ecx,
|
||||
&signature.edx );
|
||||
if ( memcmp ( &signature, HVM_CPUID_MAGIC,
|
||||
sizeof ( signature ) ) == 0 ) {
|
||||
hvm->cpuid_base = base;
|
||||
cpuid ( ( base + HVM_CPUID_VERSION ), 0, &version,
|
||||
&discard_ebx, &discard_ecx, &discard_edx );
|
||||
DBGC2 ( hvm, "HVM using CPUID base %#08x (v%d.%d)\n",
|
||||
base, ( version >> 16 ), ( version & 0xffff ) );
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
DBGC ( hvm, "HVM could not find hypervisor\n" );
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/**
|
||||
* Map hypercall page(s)
|
||||
*
|
||||
* @v hvm HVM device
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int hvm_map_hypercall ( struct hvm_device *hvm ) {
|
||||
uint32_t pages;
|
||||
uint32_t msr;
|
||||
uint32_t discard_ecx;
|
||||
uint32_t discard_edx;
|
||||
physaddr_t hypercall_phys;
|
||||
uint32_t version;
|
||||
static xen_extraversion_t extraversion;
|
||||
int xenrc;
|
||||
int rc;
|
||||
|
||||
/* Get number of hypercall pages and MSR to use */
|
||||
cpuid ( ( hvm->cpuid_base + HVM_CPUID_PAGES ), 0, &pages, &msr,
|
||||
&discard_ecx, &discard_edx );
|
||||
|
||||
/* Allocate pages */
|
||||
hvm->hypercall_len = ( pages * PAGE_SIZE );
|
||||
hvm->xen.hypercall = malloc_dma ( hvm->hypercall_len, PAGE_SIZE );
|
||||
if ( ! hvm->xen.hypercall ) {
|
||||
DBGC ( hvm, "HVM could not allocate %d hypercall page(s)\n",
|
||||
pages );
|
||||
return -ENOMEM;
|
||||
}
|
||||
hypercall_phys = virt_to_phys ( hvm->xen.hypercall );
|
||||
DBGC2 ( hvm, "HVM hypercall page(s) at [%#08lx,%#08lx) via MSR %#08x\n",
|
||||
hypercall_phys, ( hypercall_phys + hvm->hypercall_len ), msr );
|
||||
|
||||
/* Write to MSR */
|
||||
wrmsr ( msr, hypercall_phys );
|
||||
|
||||
/* Check that hypercall mechanism is working */
|
||||
version = xenver_version ( &hvm->xen );
|
||||
if ( ( xenrc = xenver_extraversion ( &hvm->xen, &extraversion ) ) != 0){
|
||||
rc = -EXEN ( xenrc );
|
||||
DBGC ( hvm, "HVM could not get extraversion: %s\n",
|
||||
strerror ( rc ) );
|
||||
return rc;
|
||||
}
|
||||
DBGC2 ( hvm, "HVM found Xen version %d.%d%s\n",
|
||||
( version >> 16 ), ( version & 0xffff ) , extraversion );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unmap hypercall page(s)
|
||||
*
|
||||
* @v hvm HVM device
|
||||
*/
|
||||
static void hvm_unmap_hypercall ( struct hvm_device *hvm ) {
|
||||
|
||||
/* Free pages */
|
||||
free_dma ( hvm->xen.hypercall, hvm->hypercall_len );
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocate and map MMIO space
|
||||
*
|
||||
* @v hvm HVM device
|
||||
* @v space Source mapping space
|
||||
* @v len Length (must be a multiple of PAGE_SIZE)
|
||||
* @ret mmio MMIO space address, or NULL on error
|
||||
*/
|
||||
static void * hvm_ioremap ( struct hvm_device *hvm, unsigned int space,
|
||||
size_t len ) {
|
||||
struct xen_add_to_physmap add;
|
||||
struct xen_remove_from_physmap remove;
|
||||
unsigned int pages = ( len / PAGE_SIZE );
|
||||
physaddr_t mmio_phys;
|
||||
unsigned int i;
|
||||
void *mmio;
|
||||
int xenrc;
|
||||
int rc;
|
||||
|
||||
/* Sanity check */
|
||||
assert ( ( len % PAGE_SIZE ) == 0 );
|
||||
|
||||
/* Check for available space */
|
||||
if ( ( hvm->mmio_offset + len ) > hvm->mmio_len ) {
|
||||
DBGC ( hvm, "HVM could not allocate %zd bytes of MMIO space "
|
||||
"(%zd of %zd remaining)\n", len,
|
||||
( hvm->mmio_len - hvm->mmio_offset ), hvm->mmio_len );
|
||||
goto err_no_space;
|
||||
}
|
||||
|
||||
/* Map this space */
|
||||
mmio = pci_ioremap ( hvm->pci, ( hvm->mmio + hvm->mmio_offset ), len );
|
||||
if ( ! mmio ) {
|
||||
DBGC ( hvm, "HVM could not map MMIO space [%08lx,%08lx)\n",
|
||||
( hvm->mmio + hvm->mmio_offset ),
|
||||
( hvm->mmio + hvm->mmio_offset + len ) );
|
||||
goto err_ioremap;
|
||||
}
|
||||
mmio_phys = virt_to_phys ( mmio );
|
||||
|
||||
/* Add to physical address space */
|
||||
for ( i = 0 ; i < pages ; i++ ) {
|
||||
add.domid = DOMID_SELF;
|
||||
add.idx = i;
|
||||
add.space = space;
|
||||
add.gpfn = ( ( mmio_phys / PAGE_SIZE ) + i );
|
||||
if ( ( xenrc = xenmem_add_to_physmap ( &hvm->xen, &add ) ) !=0){
|
||||
rc = -EXEN ( xenrc );
|
||||
DBGC ( hvm, "HVM could not add space %d idx %d at "
|
||||
"[%08lx,%08lx): %s\n", space, i,
|
||||
( mmio_phys + ( i * PAGE_SIZE ) ),
|
||||
( mmio_phys + ( ( i + 1 ) * PAGE_SIZE ) ),
|
||||
strerror ( rc ) );
|
||||
goto err_add_to_physmap;
|
||||
}
|
||||
}
|
||||
|
||||
/* Update offset */
|
||||
hvm->mmio_offset += len;
|
||||
|
||||
return mmio;
|
||||
|
||||
i = pages;
|
||||
err_add_to_physmap:
|
||||
for ( i-- ; ( signed int ) i >= 0 ; i-- ) {
|
||||
remove.domid = DOMID_SELF;
|
||||
add.gpfn = ( ( mmio_phys / PAGE_SIZE ) + i );
|
||||
xenmem_remove_from_physmap ( &hvm->xen, &remove );
|
||||
}
|
||||
iounmap ( mmio );
|
||||
err_ioremap:
|
||||
err_no_space:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unmap MMIO space
|
||||
*
|
||||
* @v hvm HVM device
|
||||
* @v mmio MMIO space address
|
||||
* @v len Length (must be a multiple of PAGE_SIZE)
|
||||
*/
|
||||
static void hvm_iounmap ( struct hvm_device *hvm, void *mmio, size_t len ) {
|
||||
struct xen_remove_from_physmap remove;
|
||||
physaddr_t mmio_phys = virt_to_phys ( mmio );
|
||||
unsigned int pages = ( len / PAGE_SIZE );
|
||||
unsigned int i;
|
||||
int xenrc;
|
||||
int rc;
|
||||
|
||||
/* Unmap this space */
|
||||
iounmap ( mmio );
|
||||
|
||||
/* Remove from physical address space */
|
||||
for ( i = 0 ; i < pages ; i++ ) {
|
||||
remove.domid = DOMID_SELF;
|
||||
remove.gpfn = ( ( mmio_phys / PAGE_SIZE ) + i );
|
||||
if ( ( xenrc = xenmem_remove_from_physmap ( &hvm->xen,
|
||||
&remove ) ) != 0 ) {
|
||||
rc = -EXEN ( xenrc );
|
||||
DBGC ( hvm, "HVM could not remove space [%08lx,%08lx): "
|
||||
"%s\n", ( mmio_phys + ( i * PAGE_SIZE ) ),
|
||||
( mmio_phys + ( ( i + 1 ) * PAGE_SIZE ) ),
|
||||
strerror ( rc ) );
|
||||
/* Nothing we can do about this */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Map shared info page
|
||||
*
|
||||
* @v hvm HVM device
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int hvm_map_shared_info ( struct hvm_device *hvm ) {
|
||||
physaddr_t shared_info_phys;
|
||||
int rc;
|
||||
|
||||
/* Map shared info page */
|
||||
hvm->xen.shared = hvm_ioremap ( hvm, XENMAPSPACE_shared_info,
|
||||
PAGE_SIZE );
|
||||
if ( ! hvm->xen.shared ) {
|
||||
rc = -ENOMEM;
|
||||
goto err_alloc;
|
||||
}
|
||||
shared_info_phys = virt_to_phys ( hvm->xen.shared );
|
||||
DBGC2 ( hvm, "HVM shared info page at [%#08lx,%#08lx)\n",
|
||||
shared_info_phys, ( shared_info_phys + PAGE_SIZE ) );
|
||||
|
||||
/* Sanity check */
|
||||
DBGC2 ( hvm, "HVM wallclock time is %d\n",
|
||||
readl ( &hvm->xen.shared->wc_sec ) );
|
||||
|
||||
return 0;
|
||||
|
||||
hvm_iounmap ( hvm, hvm->xen.shared, PAGE_SIZE );
|
||||
err_alloc:
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unmap shared info page
|
||||
*
|
||||
* @v hvm HVM device
|
||||
*/
|
||||
static void hvm_unmap_shared_info ( struct hvm_device *hvm ) {
|
||||
|
||||
/* Unmap shared info page */
|
||||
hvm_iounmap ( hvm, hvm->xen.shared, PAGE_SIZE );
|
||||
}
|
||||
|
||||
/**
|
||||
* Map grant table
|
||||
*
|
||||
* @v hvm HVM device
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int hvm_map_grant ( struct hvm_device *hvm ) {
|
||||
physaddr_t grant_phys;
|
||||
int rc;
|
||||
|
||||
/* Initialise grant table */
|
||||
if ( ( rc = xengrant_init ( &hvm->xen ) ) != 0 ) {
|
||||
DBGC ( hvm, "HVM could not initialise grant table: %s\n",
|
||||
strerror ( rc ) );
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Map grant table */
|
||||
hvm->xen.grant.table = hvm_ioremap ( hvm, XENMAPSPACE_grant_table,
|
||||
hvm->xen.grant.len );
|
||||
if ( ! hvm->xen.grant.table )
|
||||
return -ENODEV;
|
||||
|
||||
grant_phys = virt_to_phys ( hvm->xen.grant.table );
|
||||
DBGC2 ( hvm, "HVM mapped grant table at [%08lx,%08lx)\n",
|
||||
grant_phys, ( grant_phys + hvm->xen.grant.len ) );
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unmap grant table
|
||||
*
|
||||
* @v hvm HVM device
|
||||
*/
|
||||
static void hvm_unmap_grant ( struct hvm_device *hvm ) {
|
||||
|
||||
/* Unmap grant table */
|
||||
hvm_iounmap ( hvm, hvm->xen.grant.table, hvm->xen.grant.len );
|
||||
}
|
||||
|
||||
/**
|
||||
* Map XenStore
|
||||
*
|
||||
* @v hvm HVM device
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int hvm_map_xenstore ( struct hvm_device *hvm ) {
|
||||
uint64_t xenstore_evtchn;
|
||||
uint64_t xenstore_pfn;
|
||||
physaddr_t xenstore_phys;
|
||||
char *name;
|
||||
int xenrc;
|
||||
int rc;
|
||||
|
||||
/* Get XenStore event channel */
|
||||
if ( ( xenrc = xen_hvm_get_param ( &hvm->xen, HVM_PARAM_STORE_EVTCHN,
|
||||
&xenstore_evtchn ) ) != 0 ) {
|
||||
rc = -EXEN ( xenrc );
|
||||
DBGC ( hvm, "HVM could not get XenStore event channel: %s\n",
|
||||
strerror ( rc ) );
|
||||
return rc;
|
||||
}
|
||||
hvm->xen.store.port = xenstore_evtchn;
|
||||
|
||||
/* Get XenStore PFN */
|
||||
if ( ( xenrc = xen_hvm_get_param ( &hvm->xen, HVM_PARAM_STORE_PFN,
|
||||
&xenstore_pfn ) ) != 0 ) {
|
||||
rc = -EXEN ( xenrc );
|
||||
DBGC ( hvm, "HVM could not get XenStore PFN: %s\n",
|
||||
strerror ( rc ) );
|
||||
return rc;
|
||||
}
|
||||
xenstore_phys = ( xenstore_pfn * PAGE_SIZE );
|
||||
|
||||
/* Map XenStore */
|
||||
hvm->xen.store.intf = pci_ioremap ( hvm->pci, xenstore_phys,
|
||||
PAGE_SIZE );
|
||||
if ( ! hvm->xen.store.intf ) {
|
||||
DBGC ( hvm, "HVM could not map XenStore at [%08lx,%08lx)\n",
|
||||
xenstore_phys, ( xenstore_phys + PAGE_SIZE ) );
|
||||
return -ENODEV;
|
||||
}
|
||||
DBGC2 ( hvm, "HVM mapped XenStore at [%08lx,%08lx) with event port "
|
||||
"%d\n", xenstore_phys, ( xenstore_phys + PAGE_SIZE ),
|
||||
hvm->xen.store.port );
|
||||
|
||||
/* Check that XenStore is working */
|
||||
if ( ( rc = xenstore_read ( &hvm->xen, &name, "name", NULL ) ) != 0 ) {
|
||||
DBGC ( hvm, "HVM could not read domain name: %s\n",
|
||||
strerror ( rc ) );
|
||||
return rc;
|
||||
}
|
||||
DBGC2 ( hvm, "HVM running in domain \"%s\"\n", name );
|
||||
free ( name );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unmap XenStore
|
||||
*
|
||||
* @v hvm HVM device
|
||||
*/
|
||||
static void hvm_unmap_xenstore ( struct hvm_device *hvm ) {
|
||||
|
||||
/* Unmap XenStore */
|
||||
iounmap ( hvm->xen.store.intf );
|
||||
}
|
||||
|
||||
/**
|
||||
* Probe PCI device
|
||||
*
|
||||
* @v pci PCI device
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int hvm_probe ( struct pci_device *pci ) {
|
||||
struct hvm_device *hvm;
|
||||
int rc;
|
||||
|
||||
/* Allocate and initialise structure */
|
||||
hvm = zalloc ( sizeof ( *hvm ) );
|
||||
if ( ! hvm ) {
|
||||
rc = -ENOMEM;
|
||||
goto err_alloc;
|
||||
}
|
||||
hvm->pci = pci;
|
||||
hvm->mmio = pci_bar_start ( pci, HVM_MMIO_BAR );
|
||||
hvm->mmio_len = pci_bar_size ( pci, HVM_MMIO_BAR );
|
||||
DBGC2 ( hvm, "HVM has MMIO space [%08lx,%08lx)\n",
|
||||
hvm->mmio, ( hvm->mmio + hvm->mmio_len ) );
|
||||
|
||||
/* Fix up PCI device */
|
||||
adjust_pci_device ( pci );
|
||||
|
||||
/* Attach to hypervisor */
|
||||
if ( ( rc = hvm_cpuid_base ( hvm ) ) != 0 )
|
||||
goto err_cpuid_base;
|
||||
if ( ( rc = hvm_map_hypercall ( hvm ) ) != 0 )
|
||||
goto err_map_hypercall;
|
||||
if ( ( rc = hvm_map_shared_info ( hvm ) ) != 0 )
|
||||
goto err_map_shared_info;
|
||||
if ( ( rc = hvm_map_grant ( hvm ) ) != 0 )
|
||||
goto err_map_grant;
|
||||
if ( ( rc = hvm_map_xenstore ( hvm ) ) != 0 )
|
||||
goto err_map_xenstore;
|
||||
|
||||
/* Probe Xen devices */
|
||||
if ( ( rc = xenbus_probe ( &hvm->xen, &pci->dev ) ) != 0 ) {
|
||||
DBGC ( hvm, "HVM could not probe Xen bus: %s\n",
|
||||
strerror ( rc ) );
|
||||
goto err_xenbus_probe;
|
||||
}
|
||||
|
||||
pci_set_drvdata ( pci, hvm );
|
||||
return 0;
|
||||
|
||||
xenbus_remove ( &hvm->xen, &pci->dev );
|
||||
err_xenbus_probe:
|
||||
hvm_unmap_xenstore ( hvm );
|
||||
err_map_xenstore:
|
||||
hvm_unmap_grant ( hvm );
|
||||
err_map_grant:
|
||||
hvm_unmap_shared_info ( hvm );
|
||||
err_map_shared_info:
|
||||
hvm_unmap_hypercall ( hvm );
|
||||
err_map_hypercall:
|
||||
err_cpuid_base:
|
||||
free ( hvm );
|
||||
err_alloc:
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove PCI device
|
||||
*
|
||||
* @v pci PCI device
|
||||
*/
|
||||
static void hvm_remove ( struct pci_device *pci ) {
|
||||
struct hvm_device *hvm = pci_get_drvdata ( pci );
|
||||
|
||||
xenbus_remove ( &hvm->xen, &pci->dev );
|
||||
hvm_unmap_xenstore ( hvm );
|
||||
hvm_unmap_grant ( hvm );
|
||||
hvm_unmap_shared_info ( hvm );
|
||||
hvm_unmap_hypercall ( hvm );
|
||||
free ( hvm );
|
||||
}
|
||||
|
||||
/** PCI device IDs */
|
||||
static struct pci_device_id hvm_ids[] = {
|
||||
PCI_ROM ( 0x5853, 0x0001, "hvm", "hvm", 0 ),
|
||||
PCI_ROM ( 0x5853, 0x0002, "hvm2", "hvm2", 0 ),
|
||||
};
|
||||
|
||||
/** PCI driver */
|
||||
struct pci_driver hvm_driver __pci_driver = {
|
||||
.ids = hvm_ids,
|
||||
.id_count = ( sizeof ( hvm_ids ) / sizeof ( hvm_ids[0] ) ),
|
||||
.probe = hvm_probe,
|
||||
.remove = hvm_remove,
|
||||
};
|
||||
|
||||
/* Drag in objects via hvm_driver */
|
||||
REQUIRING_SYMBOL ( hvm_driver );
|
||||
|
||||
/* Drag in netfront driver */
|
||||
REQUIRE_OBJECT ( netfront );
|
77
src/arch/x86/drivers/xen/hvm.h
Normal file
77
src/arch/x86/drivers/xen/hvm.h
Normal file
@@ -0,0 +1,77 @@
|
||||
#ifndef _HVM_H
|
||||
#define _HVM_H
|
||||
|
||||
/** @file
|
||||
*
|
||||
* Xen HVM driver
|
||||
*
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
#include <stdint.h>
|
||||
#include <ipxe/xen.h>
|
||||
#include <xen/hvm/hvm_op.h>
|
||||
#include <xen/hvm/params.h>
|
||||
|
||||
/** Minimum CPUID base */
|
||||
#define HVM_CPUID_MIN 0x40000000UL
|
||||
|
||||
/** Maximum CPUID base */
|
||||
#define HVM_CPUID_MAX 0x4000ff00UL
|
||||
|
||||
/** Increment between CPUID bases */
|
||||
#define HVM_CPUID_STEP 0x00000100UL
|
||||
|
||||
/** Magic signature */
|
||||
#define HVM_CPUID_MAGIC "XenVMMXenVMM"
|
||||
|
||||
/** Get Xen version */
|
||||
#define HVM_CPUID_VERSION 1
|
||||
|
||||
/** Get number of hypercall pages */
|
||||
#define HVM_CPUID_PAGES 2
|
||||
|
||||
/** PCI MMIO BAR */
|
||||
#define HVM_MMIO_BAR PCI_BASE_ADDRESS_1
|
||||
|
||||
/** A Xen HVM device */
|
||||
struct hvm_device {
|
||||
/** Xen hypervisor */
|
||||
struct xen_hypervisor xen;
|
||||
/** PCI device */
|
||||
struct pci_device *pci;
|
||||
/** CPUID base */
|
||||
uint32_t cpuid_base;
|
||||
/** Length of hypercall table */
|
||||
size_t hypercall_len;
|
||||
/** MMIO base address */
|
||||
unsigned long mmio;
|
||||
/** Current offset within MMIO address space */
|
||||
size_t mmio_offset;
|
||||
/** Length of MMIO address space */
|
||||
size_t mmio_len;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get HVM parameter value
|
||||
*
|
||||
* @v xen Xen hypervisor
|
||||
* @v index Parameter index
|
||||
* @v value Value to fill in
|
||||
* @ret xenrc Xen status code
|
||||
*/
|
||||
static inline int xen_hvm_get_param ( struct xen_hypervisor *xen,
|
||||
unsigned int index, uint64_t *value ) {
|
||||
struct xen_hvm_param param;
|
||||
int xenrc;
|
||||
|
||||
param.domid = DOMID_SELF;
|
||||
param.index = index;
|
||||
xenrc = xen_hypercall_2 ( xen, __HYPERVISOR_hvm_op, HVMOP_get_param,
|
||||
virt_to_phys ( ¶m ) );
|
||||
*value = param.value;
|
||||
return xenrc;
|
||||
}
|
||||
|
||||
#endif /* _HVM_H */
|
117
src/arch/x86/hci/commands/pxe_cmd.c
Normal file
117
src/arch/x86/hci/commands/pxe_cmd.c
Normal file
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
* Copyright (C) 2010 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., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA.
|
||||
*
|
||||
* You can also choose to distribute this program under the terms of
|
||||
* the Unmodified Binary Distribution Licence (as given in the file
|
||||
* COPYING.UBDL), provided that you have satisfied its requirements.
|
||||
*/
|
||||
|
||||
#include <ipxe/netdevice.h>
|
||||
#include <ipxe/command.h>
|
||||
#include <ipxe/parseopt.h>
|
||||
#include <hci/ifmgmt_cmd.h>
|
||||
#include <pxe_call.h>
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
/** @file
|
||||
*
|
||||
* PXE commands
|
||||
*
|
||||
*/
|
||||
|
||||
/** "startpxe" options */
|
||||
struct startpxe_options {};
|
||||
|
||||
/** "startpxe" option list */
|
||||
static struct option_descriptor startpxe_opts[] = {};
|
||||
|
||||
/**
|
||||
* "startpxe" payload
|
||||
*
|
||||
* @v netdev Network device
|
||||
* @v opts Command options
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int startpxe_payload ( struct net_device *netdev,
|
||||
struct startpxe_options *opts __unused ) {
|
||||
|
||||
if ( netdev_is_open ( netdev ) )
|
||||
pxe_activate ( netdev );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** "startpxe" command descriptor */
|
||||
static struct ifcommon_command_descriptor startpxe_cmd =
|
||||
IFCOMMON_COMMAND_DESC ( struct startpxe_options, startpxe_opts,
|
||||
0, MAX_ARGUMENTS, "[<interface>]",
|
||||
startpxe_payload, 0 );
|
||||
|
||||
/**
|
||||
* The "startpxe" command
|
||||
*
|
||||
* @v argc Argument count
|
||||
* @v argv Argument list
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int startpxe_exec ( int argc, char **argv ) {
|
||||
return ifcommon_exec ( argc, argv, &startpxe_cmd );
|
||||
}
|
||||
|
||||
/** "stoppxe" options */
|
||||
struct stoppxe_options {};
|
||||
|
||||
/** "stoppxe" option list */
|
||||
static struct option_descriptor stoppxe_opts[] = {};
|
||||
|
||||
/** "stoppxe" command descriptor */
|
||||
static struct command_descriptor stoppxe_cmd =
|
||||
COMMAND_DESC ( struct stoppxe_options, stoppxe_opts, 0, 0, NULL );
|
||||
|
||||
/**
|
||||
* The "stoppxe" command
|
||||
*
|
||||
* @v argc Argument count
|
||||
* @v argv Argument list
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int stoppxe_exec ( int argc __unused, char **argv __unused ) {
|
||||
struct stoppxe_options opts;
|
||||
int rc;
|
||||
|
||||
/* Parse options */
|
||||
if ( ( rc = parse_options ( argc, argv, &stoppxe_cmd, &opts ) ) != 0 )
|
||||
return rc;
|
||||
|
||||
pxe_deactivate();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** PXE commands */
|
||||
struct command pxe_commands[] __command = {
|
||||
{
|
||||
.name = "startpxe",
|
||||
.exec = startpxe_exec,
|
||||
},
|
||||
{
|
||||
.name = "stoppxe",
|
||||
.exec = stoppxe_exec,
|
||||
},
|
||||
};
|
141
src/arch/x86/image/bootsector.c
Normal file
141
src/arch/x86/image/bootsector.c
Normal file
@@ -0,0 +1,141 @@
|
||||
/*
|
||||
* 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., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA.
|
||||
*
|
||||
* You can also choose to distribute this program under the terms of
|
||||
* the Unmodified Binary Distribution Licence (as given in the file
|
||||
* COPYING.UBDL), provided that you have satisfied its requirements.
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
* x86 bootsector image format
|
||||
*
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <realmode.h>
|
||||
#include <biosint.h>
|
||||
#include <bootsector.h>
|
||||
#include <ipxe/console.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;
|
||||
|
||||
/* Reset console, since boot sector will probably use it */
|
||||
console_reset();
|
||||
|
||||
DBG ( "Booting from boot sector at %04x:%04x\n", segment, offset );
|
||||
|
||||
/* Hook INTs 18 and 19 to capture failure paths */
|
||||
hook_bios_interrupt ( 0x18, ( intptr_t ) bootsector_exec_fail,
|
||||
&int18_vector );
|
||||
hook_bios_interrupt ( 0x19, ( intptr_t ) 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"
|
||||
/* Save frame pointer (gcc bug) */
|
||||
"movl %%ebp, %%cs:saved_ebp\n\t"
|
||||
/* Prepare jump to boot sector */
|
||||
"pushw %%bx\n\t"
|
||||
"pushw %%di\n\t"
|
||||
/* Clear all registers */
|
||||
"xorl %%eax, %%eax\n\t"
|
||||
"xorl %%ebx, %%ebx\n\t"
|
||||
"xorl %%ecx, %%ecx\n\t"
|
||||
/* %edx contains drive number */
|
||||
"xorl %%esi, %%esi\n\t"
|
||||
"xorl %%edi, %%edi\n\t"
|
||||
"xorl %%ebp, %%ebp\n\t"
|
||||
"movw %%ax, %%ds\n\t"
|
||||
"movw %%ax, %%es\n\t"
|
||||
"movw %%ax, %%fs\n\t"
|
||||
"movw %%ax, %%gs\n\t"
|
||||
/* Jump to boot sector */
|
||||
"sti\n\t"
|
||||
"lret\n\t"
|
||||
/* Preserved variables */
|
||||
"\nsaved_ebp: .long 0\n\t"
|
||||
"\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 frame pointer (gcc bug) */
|
||||
"movl %%cs:saved_ebp, %%ebp\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" );
|
||||
|
||||
DBG ( "Booted disk returned via INT 18 or 19\n" );
|
||||
|
||||
/* Unhook INTs 18 and 19 */
|
||||
unhook_bios_interrupt ( 0x18, ( intptr_t ) bootsector_exec_fail,
|
||||
&int18_vector );
|
||||
unhook_bios_interrupt ( 0x19, ( intptr_t ) 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