Initial checkin.
This commit is contained in:
commit
f076a3eeb9
|
@ -0,0 +1,674 @@
|
|||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The GNU General Public License is a free, copyleft license for
|
||||
software and other kinds of works.
|
||||
|
||||
The licenses for most software and other practical works are designed
|
||||
to take away your freedom to share and change the works. By contrast,
|
||||
the GNU General Public License is intended to guarantee your freedom to
|
||||
share and change all versions of a program--to make sure it remains free
|
||||
software for all its users. We, the Free Software Foundation, use the
|
||||
GNU General Public License for most of our software; it applies also to
|
||||
any other work released this way by its authors. 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
|
||||
them 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 prevent others from denying you
|
||||
these rights or asking you to surrender the rights. Therefore, you have
|
||||
certain responsibilities if you distribute copies of the software, or if
|
||||
you modify it: responsibilities to respect the freedom of others.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must pass on to the recipients the same
|
||||
freedoms that you received. 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.
|
||||
|
||||
Developers that use the GNU GPL protect your rights with two steps:
|
||||
(1) assert copyright on the software, and (2) offer you this License
|
||||
giving you legal permission to copy, distribute and/or modify it.
|
||||
|
||||
For the developers' and authors' protection, the GPL clearly explains
|
||||
that there is no warranty for this free software. For both users' and
|
||||
authors' sake, the GPL requires that modified versions be marked as
|
||||
changed, so that their problems will not be attributed erroneously to
|
||||
authors of previous versions.
|
||||
|
||||
Some devices are designed to deny users access to install or run
|
||||
modified versions of the software inside them, although the manufacturer
|
||||
can do so. This is fundamentally incompatible with the aim of
|
||||
protecting users' freedom to change the software. The systematic
|
||||
pattern of such abuse occurs in the area of products for individuals to
|
||||
use, which is precisely where it is most unacceptable. Therefore, we
|
||||
have designed this version of the GPL to prohibit the practice for those
|
||||
products. If such problems arise substantially in other domains, we
|
||||
stand ready to extend this provision to those domains in future versions
|
||||
of the GPL, as needed to protect the freedom of users.
|
||||
|
||||
Finally, every program is threatened constantly by software patents.
|
||||
States should not allow patents to restrict development and use of
|
||||
software on general-purpose computers, but in those that do, we wish to
|
||||
avoid the special danger that patents applied to a free program could
|
||||
make it effectively proprietary. To prevent this, the GPL assures that
|
||||
patents cannot be used to render the program non-free.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
TERMS AND CONDITIONS
|
||||
|
||||
0. Definitions.
|
||||
|
||||
"This License" refers to version 3 of the GNU General Public License.
|
||||
|
||||
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||
works, such as semiconductor masks.
|
||||
|
||||
"The Program" refers to any copyrightable work licensed under this
|
||||
License. Each licensee is addressed as "you". "Licensees" and
|
||||
"recipients" may be individuals or organizations.
|
||||
|
||||
To "modify" a work means to copy from or adapt all or part of the work
|
||||
in a fashion requiring copyright permission, other than the making of an
|
||||
exact copy. The resulting work is called a "modified version" of the
|
||||
earlier work or a work "based on" the earlier work.
|
||||
|
||||
A "covered work" means either the unmodified Program or a work based
|
||||
on the Program.
|
||||
|
||||
To "propagate" a work means to do anything with it that, without
|
||||
permission, would make you directly or secondarily liable for
|
||||
infringement under applicable copyright law, except executing it on a
|
||||
computer or modifying a private copy. Propagation includes copying,
|
||||
distribution (with or without modification), making available to the
|
||||
public, and in some countries other activities as well.
|
||||
|
||||
To "convey" a work means any kind of propagation that enables other
|
||||
parties to make or receive copies. Mere interaction with a user through
|
||||
a computer network, with no transfer of a copy, is not conveying.
|
||||
|
||||
An interactive user interface displays "Appropriate Legal Notices"
|
||||
to the extent that it includes a convenient and prominently visible
|
||||
feature that (1) displays an appropriate copyright notice, and (2)
|
||||
tells the user that there is no warranty for the work (except to the
|
||||
extent that warranties are provided), that licensees may convey the
|
||||
work under this License, and how to view a copy of this License. If
|
||||
the interface presents a list of user commands or options, such as a
|
||||
menu, a prominent item in the list meets this criterion.
|
||||
|
||||
1. Source Code.
|
||||
|
||||
The "source code" for a work means the preferred form of the work
|
||||
for making modifications to it. "Object code" means any non-source
|
||||
form of a work.
|
||||
|
||||
A "Standard Interface" means an interface that either is an official
|
||||
standard defined by a recognized standards body, or, in the case of
|
||||
interfaces specified for a particular programming language, one that
|
||||
is widely used among developers working in that language.
|
||||
|
||||
The "System Libraries" of an executable work include anything, other
|
||||
than the work as a whole, that (a) is included in the normal form of
|
||||
packaging a Major Component, but which is not part of that Major
|
||||
Component, and (b) serves only to enable use of the work with that
|
||||
Major Component, or to implement a Standard Interface for which an
|
||||
implementation is available to the public in source code form. A
|
||||
"Major Component", in this context, means a major essential component
|
||||
(kernel, window system, and so on) of the specific operating system
|
||||
(if any) on which the executable work runs, or a compiler used to
|
||||
produce the work, or an object code interpreter used to run it.
|
||||
|
||||
The "Corresponding Source" for a work in object code form means all
|
||||
the source code needed to generate, install, and (for an executable
|
||||
work) run the object code and to modify the work, including scripts to
|
||||
control those activities. However, it does not include the work's
|
||||
System Libraries, or general-purpose tools or generally available free
|
||||
programs which are used unmodified in performing those activities but
|
||||
which are not part of the work. For example, Corresponding Source
|
||||
includes interface definition files associated with source files for
|
||||
the work, and the source code for shared libraries and dynamically
|
||||
linked subprograms that the work is specifically designed to require,
|
||||
such as by intimate data communication or control flow between those
|
||||
subprograms and other parts of the work.
|
||||
|
||||
The Corresponding Source need not include anything that users
|
||||
can regenerate automatically from other parts of the Corresponding
|
||||
Source.
|
||||
|
||||
The Corresponding Source for a work in source code form is that
|
||||
same work.
|
||||
|
||||
2. Basic Permissions.
|
||||
|
||||
All rights granted under this License are granted for the term of
|
||||
copyright on the Program, and are irrevocable provided the stated
|
||||
conditions are met. This License explicitly affirms your unlimited
|
||||
permission to run the unmodified Program. The output from running a
|
||||
covered work is covered by this License only if the output, given its
|
||||
content, constitutes a covered work. This License acknowledges your
|
||||
rights of fair use or other equivalent, as provided by copyright law.
|
||||
|
||||
You may make, run and propagate covered works that you do not
|
||||
convey, without conditions so long as your license otherwise remains
|
||||
in force. You may convey covered works to others for the sole purpose
|
||||
of having them make modifications exclusively for you, or provide you
|
||||
with facilities for running those works, provided that you comply with
|
||||
the terms of this License in conveying all material for which you do
|
||||
not control copyright. Those thus making or running the covered works
|
||||
for you must do so exclusively on your behalf, under your direction
|
||||
and control, on terms that prohibit them from making any copies of
|
||||
your copyrighted material outside their relationship with you.
|
||||
|
||||
Conveying under any other circumstances is permitted solely under
|
||||
the conditions stated below. Sublicensing is not allowed; section 10
|
||||
makes it unnecessary.
|
||||
|
||||
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||
|
||||
No covered work shall be deemed part of an effective technological
|
||||
measure under any applicable law fulfilling obligations under article
|
||||
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||
similar laws prohibiting or restricting circumvention of such
|
||||
measures.
|
||||
|
||||
When you convey a covered work, you waive any legal power to forbid
|
||||
circumvention of technological measures to the extent such circumvention
|
||||
is effected by exercising rights under this License with respect to
|
||||
the covered work, and you disclaim any intention to limit operation or
|
||||
modification of the work as a means of enforcing, against the work's
|
||||
users, your or third parties' legal rights to forbid circumvention of
|
||||
technological measures.
|
||||
|
||||
4. Conveying Verbatim Copies.
|
||||
|
||||
You may convey 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;
|
||||
keep intact all notices stating that this License and any
|
||||
non-permissive terms added in accord with section 7 apply to the code;
|
||||
keep intact all notices of the absence of any warranty; and give all
|
||||
recipients a copy of this License along with the Program.
|
||||
|
||||
You may charge any price or no price for each copy that you convey,
|
||||
and you may offer support or warranty protection for a fee.
|
||||
|
||||
5. Conveying Modified Source Versions.
|
||||
|
||||
You may convey a work based on the Program, or the modifications to
|
||||
produce it from the Program, in the form of source code under the
|
||||
terms of section 4, provided that you also meet all of these conditions:
|
||||
|
||||
a) The work must carry prominent notices stating that you modified
|
||||
it, and giving a relevant date.
|
||||
|
||||
b) The work must carry prominent notices stating that it is
|
||||
released under this License and any conditions added under section
|
||||
7. This requirement modifies the requirement in section 4 to
|
||||
"keep intact all notices".
|
||||
|
||||
c) You must license the entire work, as a whole, under this
|
||||
License to anyone who comes into possession of a copy. This
|
||||
License will therefore apply, along with any applicable section 7
|
||||
additional terms, to the whole of the work, and all its parts,
|
||||
regardless of how they are packaged. This License gives no
|
||||
permission to license the work in any other way, but it does not
|
||||
invalidate such permission if you have separately received it.
|
||||
|
||||
d) If the work has interactive user interfaces, each must display
|
||||
Appropriate Legal Notices; however, if the Program has interactive
|
||||
interfaces that do not display Appropriate Legal Notices, your
|
||||
work need not make them do so.
|
||||
|
||||
A compilation of a covered work with other separate and independent
|
||||
works, which are not by their nature extensions of the covered work,
|
||||
and which are not combined with it such as to form a larger program,
|
||||
in or on a volume of a storage or distribution medium, is called an
|
||||
"aggregate" if the compilation and its resulting copyright are not
|
||||
used to limit the access or legal rights of the compilation's users
|
||||
beyond what the individual works permit. Inclusion of a covered work
|
||||
in an aggregate does not cause this License to apply to the other
|
||||
parts of the aggregate.
|
||||
|
||||
6. Conveying Non-Source Forms.
|
||||
|
||||
You may convey a covered work in object code form under the terms
|
||||
of sections 4 and 5, provided that you also convey the
|
||||
machine-readable Corresponding Source under the terms of this License,
|
||||
in one of these ways:
|
||||
|
||||
a) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by the
|
||||
Corresponding Source fixed on a durable physical medium
|
||||
customarily used for software interchange.
|
||||
|
||||
b) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by a
|
||||
written offer, valid for at least three years and valid for as
|
||||
long as you offer spare parts or customer support for that product
|
||||
model, to give anyone who possesses the object code either (1) a
|
||||
copy of the Corresponding Source for all the software in the
|
||||
product that is covered by this License, on a durable physical
|
||||
medium customarily used for software interchange, for a price no
|
||||
more than your reasonable cost of physically performing this
|
||||
conveying of source, or (2) access to copy the
|
||||
Corresponding Source from a network server at no charge.
|
||||
|
||||
c) Convey individual copies of the object code with a copy of the
|
||||
written offer to provide the Corresponding Source. This
|
||||
alternative is allowed only occasionally and noncommercially, and
|
||||
only if you received the object code with such an offer, in accord
|
||||
with subsection 6b.
|
||||
|
||||
d) Convey the object code by offering access from a designated
|
||||
place (gratis or for a charge), and offer equivalent access to the
|
||||
Corresponding Source in the same way through the same place at no
|
||||
further charge. You need not require recipients to copy the
|
||||
Corresponding Source along with the object code. If the place to
|
||||
copy the object code is a network server, the Corresponding Source
|
||||
may be on a different server (operated by you or a third party)
|
||||
that supports equivalent copying facilities, provided you maintain
|
||||
clear directions next to the object code saying where to find the
|
||||
Corresponding Source. Regardless of what server hosts the
|
||||
Corresponding Source, you remain obligated to ensure that it is
|
||||
available for as long as needed to satisfy these requirements.
|
||||
|
||||
e) Convey the object code using peer-to-peer transmission, provided
|
||||
you inform other peers where the object code and Corresponding
|
||||
Source of the work are being offered to the general public at no
|
||||
charge under subsection 6d.
|
||||
|
||||
A separable portion of the object code, whose source code is excluded
|
||||
from the Corresponding Source as a System Library, need not be
|
||||
included in conveying the object code work.
|
||||
|
||||
A "User Product" is either (1) a "consumer product", which means any
|
||||
tangible personal property which is normally used for personal, family,
|
||||
or household purposes, or (2) anything designed or sold for incorporation
|
||||
into a dwelling. In determining whether a product is a consumer product,
|
||||
doubtful cases shall be resolved in favor of coverage. For a particular
|
||||
product received by a particular user, "normally used" refers to a
|
||||
typical or common use of that class of product, regardless of the status
|
||||
of the particular user or of the way in which the particular user
|
||||
actually uses, or expects or is expected to use, the product. A product
|
||||
is a consumer product regardless of whether the product has substantial
|
||||
commercial, industrial or non-consumer uses, unless such uses represent
|
||||
the only significant mode of use of the product.
|
||||
|
||||
"Installation Information" for a User Product means any methods,
|
||||
procedures, authorization keys, or other information required to install
|
||||
and execute modified versions of a covered work in that User Product from
|
||||
a modified version of its Corresponding Source. The information must
|
||||
suffice to ensure that the continued functioning of the modified object
|
||||
code is in no case prevented or interfered with solely because
|
||||
modification has been made.
|
||||
|
||||
If you convey an object code work under this section in, or with, or
|
||||
specifically for use in, a User Product, and the conveying occurs as
|
||||
part of a transaction in which the right of possession and use of the
|
||||
User Product is transferred to the recipient in perpetuity or for a
|
||||
fixed term (regardless of how the transaction is characterized), the
|
||||
Corresponding Source conveyed under this section must be accompanied
|
||||
by the Installation Information. But this requirement does not apply
|
||||
if neither you nor any third party retains the ability to install
|
||||
modified object code on the User Product (for example, the work has
|
||||
been installed in ROM).
|
||||
|
||||
The requirement to provide Installation Information does not include a
|
||||
requirement to continue to provide support service, warranty, or updates
|
||||
for a work that has been modified or installed by the recipient, or for
|
||||
the User Product in which it has been modified or installed. Access to a
|
||||
network may be denied when the modification itself materially and
|
||||
adversely affects the operation of the network or violates the rules and
|
||||
protocols for communication across the network.
|
||||
|
||||
Corresponding Source conveyed, and Installation Information provided,
|
||||
in accord with this section must be in a format that is publicly
|
||||
documented (and with an implementation available to the public in
|
||||
source code form), and must require no special password or key for
|
||||
unpacking, reading or copying.
|
||||
|
||||
7. Additional Terms.
|
||||
|
||||
"Additional permissions" are terms that supplement the terms of this
|
||||
License by making exceptions from one or more of its conditions.
|
||||
Additional permissions that are applicable to the entire Program shall
|
||||
be treated as though they were included in this License, to the extent
|
||||
that they are valid under applicable law. If additional permissions
|
||||
apply only to part of the Program, that part may be used separately
|
||||
under those permissions, but the entire Program remains governed by
|
||||
this License without regard to the additional permissions.
|
||||
|
||||
When you convey a copy of a covered work, you may at your option
|
||||
remove any additional permissions from that copy, or from any part of
|
||||
it. (Additional permissions may be written to require their own
|
||||
removal in certain cases when you modify the work.) You may place
|
||||
additional permissions on material, added by you to a covered work,
|
||||
for which you have or can give appropriate copyright permission.
|
||||
|
||||
Notwithstanding any other provision of this License, for material you
|
||||
add to a covered work, you may (if authorized by the copyright holders of
|
||||
that material) supplement the terms of this License with terms:
|
||||
|
||||
a) Disclaiming warranty or limiting liability differently from the
|
||||
terms of sections 15 and 16 of this License; or
|
||||
|
||||
b) Requiring preservation of specified reasonable legal notices or
|
||||
author attributions in that material or in the Appropriate Legal
|
||||
Notices displayed by works containing it; or
|
||||
|
||||
c) Prohibiting misrepresentation of the origin of that material, or
|
||||
requiring that modified versions of such material be marked in
|
||||
reasonable ways as different from the original version; or
|
||||
|
||||
d) Limiting the use for publicity purposes of names of licensors or
|
||||
authors of the material; or
|
||||
|
||||
e) Declining to grant rights under trademark law for use of some
|
||||
trade names, trademarks, or service marks; or
|
||||
|
||||
f) Requiring indemnification of licensors and authors of that
|
||||
material by anyone who conveys the material (or modified versions of
|
||||
it) with contractual assumptions of liability to the recipient, for
|
||||
any liability that these contractual assumptions directly impose on
|
||||
those licensors and authors.
|
||||
|
||||
All other non-permissive additional terms are considered "further
|
||||
restrictions" within the meaning of section 10. If the Program as you
|
||||
received it, or any part of it, contains a notice stating that it is
|
||||
governed by this License along with a term that is a further
|
||||
restriction, you may remove that term. If a license document contains
|
||||
a further restriction but permits relicensing or conveying under this
|
||||
License, you may add to a covered work material governed by the terms
|
||||
of that license document, provided that the further restriction does
|
||||
not survive such relicensing or conveying.
|
||||
|
||||
If you add terms to a covered work in accord with this section, you
|
||||
must place, in the relevant source files, a statement of the
|
||||
additional terms that apply to those files, or a notice indicating
|
||||
where to find the applicable terms.
|
||||
|
||||
Additional terms, permissive or non-permissive, may be stated in the
|
||||
form of a separately written license, or stated as exceptions;
|
||||
the above requirements apply either way.
|
||||
|
||||
8. Termination.
|
||||
|
||||
You may not propagate or modify a covered work except as expressly
|
||||
provided under this License. Any attempt otherwise to propagate or
|
||||
modify it is void, and will automatically terminate your rights under
|
||||
this License (including any patent licenses granted under the third
|
||||
paragraph of section 11).
|
||||
|
||||
However, if you cease all violation of this License, then your
|
||||
license from a particular copyright holder is reinstated (a)
|
||||
provisionally, unless and until the copyright holder explicitly and
|
||||
finally terminates your license, and (b) permanently, if the copyright
|
||||
holder fails to notify you of the violation by some reasonable means
|
||||
prior to 60 days after the cessation.
|
||||
|
||||
Moreover, your license from a particular copyright holder is
|
||||
reinstated permanently if the copyright holder notifies you of the
|
||||
violation by some reasonable means, this is the first time you have
|
||||
received notice of violation of this License (for any work) from that
|
||||
copyright holder, and you cure the violation prior to 30 days after
|
||||
your receipt of the notice.
|
||||
|
||||
Termination of your rights under this section does not terminate the
|
||||
licenses of parties who have received copies or rights from you under
|
||||
this License. If your rights have been terminated and not permanently
|
||||
reinstated, you do not qualify to receive new licenses for the same
|
||||
material under section 10.
|
||||
|
||||
9. Acceptance Not Required for Having Copies.
|
||||
|
||||
You are not required to accept this License in order to receive or
|
||||
run a copy of the Program. Ancillary propagation of a covered work
|
||||
occurring solely as a consequence of using peer-to-peer transmission
|
||||
to receive a copy likewise does not require acceptance. However,
|
||||
nothing other than this License grants you permission to propagate or
|
||||
modify any covered work. These actions infringe copyright if you do
|
||||
not accept this License. Therefore, by modifying or propagating a
|
||||
covered work, you indicate your acceptance of this License to do so.
|
||||
|
||||
10. Automatic Licensing of Downstream Recipients.
|
||||
|
||||
Each time you convey a covered work, the recipient automatically
|
||||
receives a license from the original licensors, to run, modify and
|
||||
propagate that work, subject to this License. You are not responsible
|
||||
for enforcing compliance by third parties with this License.
|
||||
|
||||
An "entity transaction" is a transaction transferring control of an
|
||||
organization, or substantially all assets of one, or subdividing an
|
||||
organization, or merging organizations. If propagation of a covered
|
||||
work results from an entity transaction, each party to that
|
||||
transaction who receives a copy of the work also receives whatever
|
||||
licenses to the work the party's predecessor in interest had or could
|
||||
give under the previous paragraph, plus a right to possession of the
|
||||
Corresponding Source of the work from the predecessor in interest, if
|
||||
the predecessor has it or can get it with reasonable efforts.
|
||||
|
||||
You may not impose any further restrictions on the exercise of the
|
||||
rights granted or affirmed under this License. For example, you may
|
||||
not impose a license fee, royalty, or other charge for exercise of
|
||||
rights granted under this License, and you may not initiate litigation
|
||||
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||
any patent claim is infringed by making, using, selling, offering for
|
||||
sale, or importing the Program or any portion of it.
|
||||
|
||||
11. Patents.
|
||||
|
||||
A "contributor" is a copyright holder who authorizes use under this
|
||||
License of the Program or a work on which the Program is based. The
|
||||
work thus licensed is called the contributor's "contributor version".
|
||||
|
||||
A contributor's "essential patent claims" are all patent claims
|
||||
owned or controlled by the contributor, whether already acquired or
|
||||
hereafter acquired, that would be infringed by some manner, permitted
|
||||
by this License, of making, using, or selling its contributor version,
|
||||
but do not include claims that would be infringed only as a
|
||||
consequence of further modification of the contributor version. For
|
||||
purposes of this definition, "control" includes the right to grant
|
||||
patent sublicenses in a manner consistent with the requirements of
|
||||
this License.
|
||||
|
||||
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||
patent license under the contributor's essential patent claims, to
|
||||
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||
propagate the contents of its contributor version.
|
||||
|
||||
In the following three paragraphs, a "patent license" is any express
|
||||
agreement or commitment, however denominated, not to enforce a patent
|
||||
(such as an express permission to practice a patent or covenant not to
|
||||
sue for patent infringement). To "grant" such a patent license to a
|
||||
party means to make such an agreement or commitment not to enforce a
|
||||
patent against the party.
|
||||
|
||||
If you convey a covered work, knowingly relying on a patent license,
|
||||
and the Corresponding Source of the work is not available for anyone
|
||||
to copy, free of charge and under the terms of this License, through a
|
||||
publicly available network server or other readily accessible means,
|
||||
then you must either (1) cause the Corresponding Source to be so
|
||||
available, or (2) arrange to deprive yourself of the benefit of the
|
||||
patent license for this particular work, or (3) arrange, in a manner
|
||||
consistent with the requirements of this License, to extend the patent
|
||||
license to downstream recipients. "Knowingly relying" means you have
|
||||
actual knowledge that, but for the patent license, your conveying the
|
||||
covered work in a country, or your recipient's use of the covered work
|
||||
in a country, would infringe one or more identifiable patents in that
|
||||
country that you have reason to believe are valid.
|
||||
|
||||
If, pursuant to or in connection with a single transaction or
|
||||
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||
covered work, and grant a patent license to some of the parties
|
||||
receiving the covered work authorizing them to use, propagate, modify
|
||||
or convey a specific copy of the covered work, then the patent license
|
||||
you grant is automatically extended to all recipients of the covered
|
||||
work and works based on it.
|
||||
|
||||
A patent license is "discriminatory" if it does not include within
|
||||
the scope of its coverage, prohibits the exercise of, or is
|
||||
conditioned on the non-exercise of one or more of the rights that are
|
||||
specifically granted under this License. You may not convey a covered
|
||||
work if you are a party to an arrangement with a third party that is
|
||||
in the business of distributing software, under which you make payment
|
||||
to the third party based on the extent of your activity of conveying
|
||||
the work, and under which the third party grants, to any of the
|
||||
parties who would receive the covered work from you, a discriminatory
|
||||
patent license (a) in connection with copies of the covered work
|
||||
conveyed by you (or copies made from those copies), or (b) primarily
|
||||
for and in connection with specific products or compilations that
|
||||
contain the covered work, unless you entered into that arrangement,
|
||||
or that patent license was granted, prior to 28 March 2007.
|
||||
|
||||
Nothing in this License shall be construed as excluding or limiting
|
||||
any implied license or other defenses to infringement that may
|
||||
otherwise be available to you under applicable patent law.
|
||||
|
||||
12. No Surrender of Others' Freedom.
|
||||
|
||||
If 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 convey a
|
||||
covered work so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you may
|
||||
not convey it at all. For example, if you agree to terms that obligate you
|
||||
to collect a royalty for further conveying from those to whom you convey
|
||||
the Program, the only way you could satisfy both those terms and this
|
||||
License would be to refrain entirely from conveying the Program.
|
||||
|
||||
13. Use with the GNU Affero General Public License.
|
||||
|
||||
Notwithstanding any other provision of this License, you have
|
||||
permission to link or combine any covered work with a work licensed
|
||||
under version 3 of the GNU Affero General Public License into a single
|
||||
combined work, and to convey the resulting work. The terms of this
|
||||
License will continue to apply to the part which is the covered work,
|
||||
but the special requirements of the GNU Affero General Public License,
|
||||
section 13, concerning interaction through a network will apply to the
|
||||
combination as such.
|
||||
|
||||
14. Revised Versions of this License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions of
|
||||
the GNU 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 that a certain numbered version of the GNU General
|
||||
Public License "or any later version" applies to it, you have the
|
||||
option of following the terms and conditions either of that numbered
|
||||
version or of any later version published by the Free Software
|
||||
Foundation. If the Program does not specify a version number of the
|
||||
GNU General Public License, you may choose any version ever published
|
||||
by the Free Software Foundation.
|
||||
|
||||
If the Program specifies that a proxy can decide which future
|
||||
versions of the GNU General Public License can be used, that proxy's
|
||||
public statement of acceptance of a version permanently authorizes you
|
||||
to choose that version for the Program.
|
||||
|
||||
Later license versions may give you additional or different
|
||||
permissions. However, no additional obligations are imposed on any
|
||||
author or copyright holder as a result of your choosing to follow a
|
||||
later version.
|
||||
|
||||
15. Disclaimer of Warranty.
|
||||
|
||||
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.
|
||||
|
||||
16. Limitation of Liability.
|
||||
|
||||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||
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.
|
||||
|
||||
17. Interpretation of Sections 15 and 16.
|
||||
|
||||
If the disclaimer of warranty and limitation of liability provided
|
||||
above cannot be given local legal effect according to their terms,
|
||||
reviewing courts shall apply local law that most closely approximates
|
||||
an absolute waiver of all civil liability in connection with the
|
||||
Program, unless a warranty or assumption of liability accompanies a
|
||||
copy of the Program in return for a fee.
|
||||
|
||||
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
|
||||
state 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program does terminal interaction, make it output a short
|
||||
notice like this when it starts in an interactive mode:
|
||||
|
||||
<program> Copyright (C) <year> <name of author>
|
||||
This program 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, your program's commands
|
||||
might be different; for a GUI interface, you would use an "about box".
|
||||
|
||||
You should also get your employer (if you work as a programmer) or school,
|
||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||
For more information on this, and how to apply and follow the GNU GPL, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
|
||||
The GNU 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. But first, please read
|
||||
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
|
|
@ -0,0 +1,88 @@
|
|||
# Legacy Bios build system
|
||||
#
|
||||
# Copyright (C) 2008 Kevin O'Connor <kevin@koconnor.net>
|
||||
#
|
||||
# This file may be distributed under the terms of the GNU GPLv3 license.
|
||||
|
||||
# Output directory
|
||||
OUT=out/
|
||||
|
||||
# Source files
|
||||
SRC16=floppy.c disk.c system.c clock.c serial.c kbd.c output.c boot.c
|
||||
SRC32=post.c output.c
|
||||
|
||||
# Default compiler flags (note -march=armv4 is needed for 16 bit insns)
|
||||
CFLAGS = -Wall -Os -MD -m32 -march=i386 -mregparm=2 -ffreestanding
|
||||
CFLAGS16 = -Wall -Os -MD -m32 -DMODE16 -march=i386 -mregparm=2 -ffreestanding -fno-jump-tables
|
||||
|
||||
all: $(OUT) $(OUT)rom.bin
|
||||
|
||||
# Run with "make V=1" to see the actual compile commands
|
||||
ifdef V
|
||||
Q=
|
||||
else
|
||||
Q=@
|
||||
endif
|
||||
|
||||
.PHONY : all FORCE
|
||||
|
||||
vpath %.c src
|
||||
vpath %.S src
|
||||
|
||||
################ Build rules
|
||||
$(OUT)%.proc.16.s: $(OUT)%.16.s
|
||||
@echo " Moving data sections to text in $<"
|
||||
$(Q)sed 's/\t.section\t.rodata.*// ; s/\t.data//' < $< > $@
|
||||
|
||||
$(OUT)%.16.s: %.c
|
||||
@echo " Generating assembler for $<"
|
||||
$(Q)$(CC) $(CFLAGS16) -fwhole-program -S -combine -c $< -o $@
|
||||
|
||||
$(OUT)%.lds: %.lds.S
|
||||
@echo " Precompiling $<"
|
||||
$(Q)$(CPP) -P $< -o $@
|
||||
|
||||
$(OUT)%.bin: $(OUT)%.o
|
||||
@echo " Extracting binary $@"
|
||||
$(Q)objcopy -O binary $< $@
|
||||
|
||||
$(OUT)%.offset.auto.h: $(OUT)%.o
|
||||
@echo " Generating symbol offset header $@"
|
||||
$(Q)nm $< | ./tools/defsyms.py > $@
|
||||
|
||||
$(OUT)blob.16.s:
|
||||
@echo " Generating whole program assembler $@"
|
||||
$(Q)$(CC) $(CFLAGS16) -fwhole-program -S -combine -c $(addprefix src/, $(SRC16)) -o $@
|
||||
|
||||
$(OUT)romlayout16.o: romlayout.S $(OUT)blob.proc.16.s $(OUT)font.proc.16.s $(OUT)cbt.proc.16.s
|
||||
@echo " Generating 16bit layout of $@"
|
||||
$(Q)$(CC) $(CFLAGS16) -c $< -o $@
|
||||
|
||||
$(OUT)rom16.o: $(OUT)romlayout16.o
|
||||
@echo " Linking $@"
|
||||
$(Q)ld -melf_i386 -Ttext 0 $< -o $@
|
||||
|
||||
$(OUT)rom16.bin: $(OUT)rom16.o
|
||||
@echo " Extracting binary $@"
|
||||
$(Q)objcopy -O binary $< $@
|
||||
|
||||
$(OUT)romlayout32.o: $(OUT)rom16.offset.auto.h
|
||||
@echo " Compiling whole program $@"
|
||||
$(Q)$(CC) $(CFLAGS) -fwhole-program -combine -c $(addprefix src/, $(SRC32)) -o $@
|
||||
|
||||
$(OUT)rom32.o: $(OUT)romlayout32.o $(OUT)rombios32.lds
|
||||
@echo " Linking $@"
|
||||
$(Q)ld -T $(OUT)rombios32.lds $< -o $@
|
||||
|
||||
$(OUT)rom.bin: $(OUT)rom16.bin $(OUT)rom32.bin $(OUT)rom16.offset.auto.h $(OUT)rom32.offset.auto.h
|
||||
@echo " Building $@"
|
||||
$(Q)./tools/buildrom.py
|
||||
|
||||
####### Generic rules
|
||||
clean:
|
||||
rm -rf $(OUT)
|
||||
|
||||
$(OUT):
|
||||
mkdir $@
|
||||
|
||||
-include $(OUT)*.d
|
|
@ -0,0 +1,71 @@
|
|||
This code implements an X86 legacy bios. It is intended to be
|
||||
compiled using standard gnu tools (eg, gas and gcc).
|
||||
|
||||
To build, one should be able to run "make" in the main directory. The
|
||||
resulting file "out/rom.bin" contains the processed bios image.
|
||||
|
||||
The code has been successfully compiled with gcc 4.1.2 and gas
|
||||
2.17.50.0.18.
|
||||
|
||||
|
||||
Overview of files:
|
||||
|
||||
The src/ directory contains the bios source code. The post.c code is
|
||||
compiled in 32bit mode. The output.c code is compiled twice - once in
|
||||
16bit mode and once in 32bit mode. The remaining c files are compiled
|
||||
in 16bit mode.
|
||||
|
||||
The tools/ directory contains helper utilities for manipulating and
|
||||
building the final rom.
|
||||
|
||||
The out/ directory is created by the build process - it contains all
|
||||
temporary and final files.
|
||||
|
||||
|
||||
Build overview:
|
||||
|
||||
The 16bit code is compiled via gcc to assembler (file out/blob.16.s).
|
||||
The gcc "-fwhole-program" option is used to optimize the process so
|
||||
that gcc can efficiently compile and discard unneeded code.
|
||||
|
||||
This resulting assembler code is pulled into romlayout.S. The gas
|
||||
option ".code16gcc" is used prior to including the gcc generated
|
||||
assembler - this option enables gcc to be used to generate valid 16
|
||||
bit code. The romlayout.S also defines all the mandatory bios visible
|
||||
memory locations.
|
||||
|
||||
The post code (post.c) is written in 32bits. The 16bit post vector
|
||||
(in romlayout.S) transitions the cpu into 32 bit mode before calling
|
||||
the initialization code in post.c.
|
||||
|
||||
In the last step, the compiled 32 bit code is merged into the 16 bit
|
||||
code so that one binary file contains both. Currently, both 16bit and
|
||||
32bit code will be located in the 64K block at segment 0xf000.
|
||||
|
||||
|
||||
GCC 16 bit limitations:
|
||||
|
||||
Although the 16bit code is compiled with gcc, developers need to be
|
||||
aware of the environment. In particular, global variables _must_ be
|
||||
treated specially.
|
||||
|
||||
The code has full access to stack variables and general purpose
|
||||
registers. The entry code in romlayout.S will push the original
|
||||
registers on the stack before calling the C code and then pop them off
|
||||
(including any required changes) before returning from the interrupt.
|
||||
Changes to CS, DS, and ES segment registers in C code is also safe.
|
||||
Changes to other segment registers (SS, FS, GS) need to be restored
|
||||
manually.
|
||||
|
||||
Stack variables (and pointers to stack variables) work as they
|
||||
normally do in standard C code.
|
||||
|
||||
However, variables stored outside the stack need to be accessed via
|
||||
the GET_VAR and SET_VAR macros. This is due to the 16bit segment
|
||||
nature of the X86 cpu when it is in "real mode". The C entry code
|
||||
will set DS and SS to point to the stack segment. Variables not on
|
||||
the stack need to be accessed via an explicit segment register.
|
||||
Global constant definitions (those in 0xf000) can be accessed via the
|
||||
CS segment register. Any other access requires altering one of the
|
||||
other segment registers (usually ES) and then accessing the variable
|
||||
via that segment register.
|
|
@ -0,0 +1,22 @@
|
|||
Make header files work with either 32bit or 16bit code.
|
||||
|
||||
Fix makefiles so that they rebuild the required files automatically.
|
||||
|
||||
Make sure gdt/idt tables are properly aligned
|
||||
|
||||
Cleanup setting of ES on GET/SET_BDA
|
||||
|
||||
Make sure inline assembly isn't preventing inlining of calling
|
||||
functions.
|
||||
|
||||
Convert remaining parts of rombios.c to new code.
|
||||
|
||||
Convert rombios32 and apm bios stuff to new code.
|
||||
|
||||
Allow one to select adding 32 bit code to 0xf000 or in a separate
|
||||
location.
|
||||
|
||||
Try generating bios tables at compile time.
|
||||
|
||||
Move e820 map generation to post time (just have e820 code copy pre
|
||||
made tables back to user).
|
|
@ -0,0 +1,184 @@
|
|||
// Variable layouts of bios.
|
||||
//
|
||||
// Copyright (C) 2008 Kevin O'Connor <kevin@koconnor.net>
|
||||
//
|
||||
// This file may be distributed under the terms of the GNU GPLv3 license.
|
||||
|
||||
#include "types.h" // u8
|
||||
#include "farptr.h" // SET_SEG
|
||||
|
||||
|
||||
/****************************************************************
|
||||
* Bios Data Area (BDA)
|
||||
****************************************************************/
|
||||
|
||||
struct ivec {
|
||||
u16 offset;
|
||||
u16 seg;
|
||||
};
|
||||
|
||||
struct bios_data_area_s {
|
||||
// 00:00
|
||||
struct ivec ivecs[256];
|
||||
// 30:00
|
||||
// u8 stack[256];
|
||||
// 40:00
|
||||
u16 port_com1, port_com2, port_com3, port_com4;
|
||||
u16 port_lpt1, port_lpt2, port_lpt3;
|
||||
u16 ebda_seg;
|
||||
// 40:10
|
||||
u16 equipment_list_flags;
|
||||
u8 pad1;
|
||||
u16 mem_size_kb;
|
||||
u8 pad2;
|
||||
u8 ps2_ctrl_flag;
|
||||
u16 kbd_flag;
|
||||
u8 alt_keypad;
|
||||
u16 kbd_buf_head;
|
||||
u16 kbd_buf_tail;
|
||||
// 40:1e
|
||||
u8 kbd_buf[32];
|
||||
u8 floppy_recalibration_status;
|
||||
u8 floppy_motor_status;
|
||||
// 40:40
|
||||
u8 floppy_motor_counter;
|
||||
u8 floppy_last_status;
|
||||
u8 floppy_return_status[7];
|
||||
u8 other1[0x7];
|
||||
// 40:50
|
||||
u8 other2[0x1c];
|
||||
// 40:6c
|
||||
u32 timer_counter;
|
||||
// 40:70
|
||||
u8 timer_rollover;
|
||||
u8 other4[0x0f];
|
||||
// 40:80
|
||||
u16 kbd_buf_start_offset;
|
||||
u16 kbd_buf_end_offset;
|
||||
u8 other5[7];
|
||||
u8 floppy_last_data_rate;
|
||||
u8 other6[3];
|
||||
u8 floppy_harddisk_info;
|
||||
// 40:90
|
||||
u8 floppy_media_state[4];
|
||||
u8 floppy_track0;
|
||||
u8 floppy_track1;
|
||||
u8 kbd_mode;
|
||||
u8 kbd_led;
|
||||
u32 ptr_user_wait_complete_flag;
|
||||
u32 user_wait_timeout;
|
||||
// 40:A0
|
||||
u8 rtc_wait_flag;
|
||||
} __attribute__((packed));
|
||||
|
||||
// BDA floppy_recalibration_status bitdefs
|
||||
#define FRS_TIMEOUT (1<<7)
|
||||
|
||||
// BDA rtc_wait_flag bitdefs
|
||||
#define RWS_WAIT_PENDING (1<<0)
|
||||
#define RWS_WAIT_ELAPSED (1<<7)
|
||||
|
||||
// BDA floppy_media_state bitdefs
|
||||
#define FMS_DRIVE_STATE_MASK (0x07)
|
||||
#define FMS_MEDIA_DRIVE_ESTABLISHED (1<<4)
|
||||
#define FMS_DOUBLE_STEPPING (1<<5)
|
||||
#define FMS_DATA_RATE_MASK (0xc0)
|
||||
|
||||
// Accessor functions
|
||||
#define GET_BDA(var) ({ \
|
||||
SET_SEG(ES, 0x0000); \
|
||||
GET_VAR(ES, ((struct bios_data_area_s *)0)->var); })
|
||||
#define SET_BDA(var, val) do { \
|
||||
SET_SEG(ES, 0x0000); \
|
||||
SET_VAR(ES, ((struct bios_data_area_s *)0)->var, val); \
|
||||
} while (0)
|
||||
#define CLEARBITS_BDA(var, val) do { \
|
||||
typeof(((struct bios_data_area_s *)0)->var) __val = GET_BDA(var); \
|
||||
SET_BDA(var, (__val & ~(val))); \
|
||||
} while (0)
|
||||
#define SETBITS_BDA(var, val) do { \
|
||||
typeof(((struct bios_data_area_s *)0)->var) __val = GET_BDA(var); \
|
||||
SET_BDA(var, (__val | (val))); \
|
||||
} while (0)
|
||||
|
||||
|
||||
/****************************************************************
|
||||
* Extended Bios Data Area (EBDA)
|
||||
****************************************************************/
|
||||
|
||||
struct extended_bios_data_area_s {
|
||||
u8 size;
|
||||
u8 other1[0x3c];
|
||||
|
||||
// FDPT - Can be splitted in data members if needed
|
||||
u8 fdpt0[0x10];
|
||||
u8 fdpt1[0x10];
|
||||
|
||||
u8 other2[0xC4];
|
||||
|
||||
// ATA Driver data
|
||||
//ata_t ata;
|
||||
|
||||
#if BX_ELTORITO_BOOT
|
||||
// El Torito Emulation data
|
||||
cdemu_t cdemu;
|
||||
#endif // BX_ELTORITO_BOOT
|
||||
};
|
||||
|
||||
|
||||
/****************************************************************
|
||||
* Extended Bios Data Area (EBDA)
|
||||
****************************************************************/
|
||||
|
||||
#define UREG(ER, R, RH, RL) union { u32 ER; struct { u16 R; u16 R ## _hi; }; struct { u8 RL; u8 RH; u8 R ## _hilo; u8 R ## _hihi; }; }
|
||||
|
||||
struct bregs {
|
||||
u16 ds;
|
||||
u16 es;
|
||||
UREG(edi, di, di_hi, di_lo);
|
||||
UREG(esi, si, si_hi, si_lo);
|
||||
UREG(ebp, bp, bp_hi, bp_lo);
|
||||
UREG(esp, sp, sp_hi, sp_lo);
|
||||
UREG(ebx, bx, bh, bl);
|
||||
UREG(edx, dx, dh, dl);
|
||||
UREG(ecx, cx, ch, cl);
|
||||
UREG(eax, ax, ah, al);
|
||||
u16 ip;
|
||||
u16 cs;
|
||||
u16 flags;
|
||||
} __attribute__((packed));
|
||||
|
||||
// bregs flags bitdefs
|
||||
#define F_CF (1<<9)
|
||||
|
||||
static inline void
|
||||
set_cf(struct bregs *regs, int cond)
|
||||
{
|
||||
if (cond)
|
||||
regs->flags |= F_CF;
|
||||
else
|
||||
regs->flags &= ~F_CF;
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************
|
||||
* Bios Config Table
|
||||
****************************************************************/
|
||||
|
||||
struct bios_config_table_s {
|
||||
// XXX
|
||||
u8 x;
|
||||
};
|
||||
|
||||
extern struct bios_config_table_s BIOS_CONFIG_TABLE;
|
||||
|
||||
|
||||
/****************************************************************
|
||||
* Memory layout info
|
||||
****************************************************************/
|
||||
|
||||
#define SEG_BIOS 0xf000
|
||||
|
||||
#define EBDA_SEG 0x9FC0
|
||||
#define EBDA_SIZE 1 // In KiB
|
||||
#define BASE_MEM_IN_K (640 - EBDA_SIZE)
|
|
@ -0,0 +1,118 @@
|
|||
// 16bit code to load disk image and start system boot.
|
||||
//
|
||||
// Copyright (C) 2008 Kevin O'Connor <kevin@koconnor.net>
|
||||
// Copyright (C) 2002 MandrakeSoft S.A.
|
||||
//
|
||||
// This file may be distributed under the terms of the GNU GPLv3 license.
|
||||
|
||||
#include "types.h" // VISIBLE
|
||||
#include "util.h" // irq_enable
|
||||
#include "biosvar.h" // struct bregs
|
||||
#include "farptr.h" // SET_SEG
|
||||
|
||||
static inline void
|
||||
__call_irq(u8 nr)
|
||||
{
|
||||
asm volatile("int %0" : : "N" (nr));
|
||||
}
|
||||
|
||||
static inline u32
|
||||
call_irq(u8 nr, struct bregs *callregs)
|
||||
{
|
||||
u32 flags;
|
||||
asm volatile(
|
||||
// Save current registers
|
||||
"pushal\n"
|
||||
// Pull in calling registers.
|
||||
"movl 0x04(%%eax), %%edi\n"
|
||||
"movl 0x08(%%eax), %%esi\n"
|
||||
"movl 0x0c(%%eax), %%ebp\n"
|
||||
"movl 0x14(%%eax), %%ebx\n"
|
||||
"movl 0x18(%%eax), %%edx\n"
|
||||
"movl 0x1c(%%eax), %%ecx\n"
|
||||
"movl 0x20(%%eax), %%eax\n"
|
||||
// Invoke interrupt
|
||||
"int %1\n"
|
||||
// Restore registers
|
||||
"popal\n"
|
||||
// Exract flags
|
||||
"pushfw\n"
|
||||
"popl %%eax\n"
|
||||
: "=a" (flags): "N" (nr), "a" (callregs), "m" (*callregs));
|
||||
return flags;
|
||||
}
|
||||
|
||||
static void
|
||||
print_boot_failure()
|
||||
{
|
||||
bprintf(0, "Boot failed\n");
|
||||
}
|
||||
|
||||
static void
|
||||
try_boot()
|
||||
{
|
||||
// XXX - assume floppy
|
||||
u16 bootseg = 0x07c0;
|
||||
u8 bootdrv = 0;
|
||||
|
||||
// Read sector
|
||||
struct bregs cr;
|
||||
memset(&cr, 0, sizeof(cr));
|
||||
cr.dl = bootdrv;
|
||||
SET_SEG(ES, bootseg);
|
||||
cr.bx = 0;
|
||||
cr.ah = 2;
|
||||
cr.al = 1;
|
||||
cr.ch = 0;
|
||||
cr.cl = 1;
|
||||
cr.dh = 0;
|
||||
u32 status = call_irq(0x13, &cr);
|
||||
|
||||
if (status & F_CF) {
|
||||
print_boot_failure();
|
||||
return;
|
||||
}
|
||||
|
||||
u16 bootip = (bootseg & 0x0fff) << 4;
|
||||
bootseg &= 0xf000;
|
||||
|
||||
u32 segoff = (bootseg << 16) | bootip;
|
||||
asm volatile (
|
||||
"pushf\n"
|
||||
"pushl %0\n"
|
||||
"movb %b1, %%dl\n"
|
||||
// Set the magic number in ax and the boot drive in dl.
|
||||
"movw $0xaa55, %%ax\n"
|
||||
// Zero some of the other registers.
|
||||
"xorw %%bx, %%bx\n"
|
||||
"movw %%bx, %%ds\n"
|
||||
"movw %%bx, %%es\n"
|
||||
"movw %%bx, %%bp\n"
|
||||
// Go!
|
||||
"iretw\n"
|
||||
: : "r" (segoff), "ri" (bootdrv));
|
||||
}
|
||||
|
||||
// Boot Failure recovery: try the next device.
|
||||
void VISIBLE
|
||||
handle_18(struct bregs *regs)
|
||||
{
|
||||
debug_enter(regs);
|
||||
try_boot();
|
||||
}
|
||||
|
||||
// INT 19h Boot Load Service Entry Point
|
||||
void VISIBLE
|
||||
handle_19(struct bregs *regs)
|
||||
{
|
||||
debug_enter(regs);
|
||||
try_boot();
|
||||
}
|
||||
|
||||
// Callback from 32bit entry - start boot process
|
||||
void VISIBLE
|
||||
begin_boot()
|
||||
{
|
||||
irq_enable();
|
||||
__call_irq(0x19);
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
#include "biosvar.h" // CONFIG_BIOS_TABLE
|
||||
|
||||
// bios variables
|
||||
|
||||
struct bios_config_table_s BIOS_CONFIG_TABLE = {
|
||||
// XXX
|
||||
18,
|
||||
};
|
|
@ -0,0 +1,54 @@
|
|||
// 16bit code to handle system clocks.
|
||||
//
|
||||
// Copyright (C) 2008 Kevin O'Connor <kevin@koconnor.net>
|
||||
// Copyright (C) 2002 MandrakeSoft S.A.
|
||||
//
|
||||
// This file may be distributed under the terms of the GNU GPLv3 license.
|
||||
|
||||
#include "biosvar.h" // struct bregs
|
||||
#include "util.h" // debug_enter
|
||||
#include "disk.h" // floppy_tick
|
||||
|
||||
// INT 1Ah Time-of-day Service Entry Point
|
||||
void VISIBLE
|
||||
handle_1a(struct bregs *regs)
|
||||
{
|
||||
debug_enter(regs);
|
||||
set_cf(regs, 1);
|
||||
}
|
||||
|
||||
// User Timer Tick
|
||||
void VISIBLE
|
||||
handle_1c(struct bregs *regs)
|
||||
{
|
||||
debug_enter(regs);
|
||||
}
|
||||
|
||||
// INT 08h System Timer ISR Entry Point
|
||||
void VISIBLE
|
||||
handle_08(struct bregs *regs)
|
||||
{
|
||||
// debug_enter(regs);
|
||||
|
||||
floppy_tick();
|
||||
|
||||
u32 counter = GET_BDA(timer_counter);
|
||||
counter++;
|
||||
// compare to one days worth of timer ticks at 18.2 hz
|
||||
if (counter >= 0x001800B0) {
|
||||
// there has been a midnight rollover at this point
|
||||
counter = 0;
|
||||
SET_BDA(timer_rollover, GET_BDA(timer_rollover) + 1);
|
||||
}
|
||||
|
||||
SET_BDA(timer_counter, counter);
|
||||
// XXX - int #0x1c
|
||||
eoi_master_pic();
|
||||
}
|
||||
|
||||
// int70h: IRQ8 - CMOS RTC
|
||||
void VISIBLE
|
||||
handle_70(struct bregs *regs)
|
||||
{
|
||||
debug_enter(regs);
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
// Definitions for X86 CMOS non-volatile memory access.
|
||||
//
|
||||
// Copyright (C) 2008 Kevin O'Connor <kevin@koconnor.net>
|
||||
//
|
||||
// This file may be distributed under the terms of the GNU GPLv3 license.
|
||||
#ifndef __CMOS_H
|
||||
#define __CMOS_H
|
||||
|
||||
#include "ioport.h" // inb, outb
|
||||
|
||||
#define CMOS_RTC_SECONDS 0x00
|
||||
#define CMOS_RTC_SECONDS_ALARM 0x01
|
||||
#define CMOS_RTC_MINUTES 0x02
|
||||
#define CMOS_RTC_MINUTES_ALARM 0x03
|
||||
#define CMOS_RTC_HOURS 0x04
|
||||
#define CMOS_RTC_HOURS_ALARM 0x05
|
||||
#define CMOS_STATUS_B 0x0b
|
||||
#define CMOS_RESET_CODE 0x0f
|
||||
#define CMOS_FLOPPY_DRIVE_TYPE 0x10
|
||||
#define CMOS_EQUIPMENT_INFO 0x14
|
||||
#define CMOS_EXTMEM_LOW 0x30
|
||||
#define CMOS_EXTMEM_HIGH 0x31
|
||||
#define CMOS_EXTMEM2_LOW 0x34
|
||||
#define CMOS_EXTMEM2_HIGH 0x35
|
||||
|
||||
// CMOS_STATUS_B bitdefs
|
||||
#define CSB_EN_ALARM_IRQ (1<<5)
|
||||
|
||||
// CMOS_FLOPPY_DRIVE_TYPE bitdefs
|
||||
#define CFD_NO_DRIVE 0
|
||||
#define CFD_360KB 1
|
||||
#define CFD_12MB 2
|
||||
#define CFD_720KB 3
|
||||
#define CFD_144MB 4
|
||||
#define CFD_288MB 5
|
||||
|
||||
static inline u8
|
||||
inb_cmos(u8 reg)
|
||||
{
|
||||
outb(reg, PORT_CMOS_INDEX);
|
||||
return inb(PORT_CMOS_DATA);
|
||||
}
|
||||
|
||||
static inline void
|
||||
outb_cmos(u8 val, u8 reg)
|
||||
{
|
||||
outb(reg, PORT_CMOS_INDEX);
|
||||
outb(val, PORT_CMOS_DATA);
|
||||
}
|
||||
|
||||
#endif // cmos.h
|
|
@ -0,0 +1,8 @@
|
|||
// Configuration definitions.
|
||||
|
||||
#define CONFIG_FLOPPY_SUPPORT 1
|
||||
#define CONFIG_PS2_MOUSE 0
|
||||
#define CONFIG_ATA 0
|
||||
#define CONFIG_STACK16_SEGMENT 0x00
|
||||
#define CONFIG_STACK16_OFFSET 0xfffe
|
||||
#define CONFIG_STACK32_OFFSET 0x80000
|
|
@ -0,0 +1,67 @@
|
|||
// 16bit code to access hard drives.
|
||||
//
|
||||
// Copyright (C) 2008 Kevin O'Connor <kevin@koconnor.net>
|
||||
// Copyright (C) 2002 MandrakeSoft S.A.
|
||||
//
|
||||
// This file may be distributed under the terms of the GNU GPLv3 license.
|
||||
|
||||
#include "disk.h" // floppy_13
|
||||
#include "biosvar.h" // struct bregs
|
||||
#include "util.h" // debug_enter
|
||||
|
||||
static void
|
||||
disk_13(struct bregs *regs, u8 drive)
|
||||
{
|
||||
set_cf(regs, 1);
|
||||
}
|
||||
|
||||
static void
|
||||
handle_legacy_disk(struct bregs *regs, u8 drive)
|
||||
{
|
||||
if (drive < 0x80) {
|
||||
floppy_13(regs, drive);
|
||||
return;
|
||||
}
|
||||
#if BX_USE_ATADRV
|
||||
if (drive >= 0xE0) {
|
||||
int13_cdrom(regs); // xxx
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
disk_13(regs, drive);
|
||||
}
|
||||
|
||||
void VISIBLE
|
||||
handle_40(struct bregs *regs)
|
||||
{
|
||||
debug_enter(regs);
|
||||
handle_legacy_disk(regs, regs->dl);
|
||||
debug_exit(regs);
|
||||
}
|
||||
|
||||
// INT 13h Fixed Disk Services Entry Point
|
||||
void VISIBLE
|
||||
handle_13(struct bregs *regs)
|
||||
{
|
||||
debug_enter(regs);
|
||||
u8 drive = regs->dl;
|
||||
#if BX_ELTORITO_BOOT
|
||||
if (regs->ah >= 0x4a || regs->ah <= 0x4d) {
|
||||
int13_eltorito(regs);
|
||||
} else if (cdemu_isactive() && cdrom_emulated_drive()) {
|
||||
int13_cdemu(regs);
|
||||
} else
|
||||
#endif
|
||||
handle_legacy_disk(regs, drive);
|
||||
debug_exit(regs);
|
||||
}
|
||||
|
||||
// record completion in BIOS task complete flag
|
||||
void VISIBLE
|
||||
handle_76(struct bregs *regs)
|
||||
{
|
||||
debug_enter(regs);
|
||||
SET_BDA(floppy_harddisk_info, 0xff);
|
||||
eoi_both_pics();
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
// Definitions for X86 bios disks.
|
||||
//
|
||||
// Copyright (C) 2008 Kevin O'Connor <kevin@koconnor.net>
|
||||
//
|
||||
// This file may be distributed under the terms of the GNU GPLv3 license.
|
||||
|
||||
#include "ioport.h" // outb
|
||||
|
||||
#define DISK_RET_SUCCESS 0x00
|
||||
#define DISK_RET_EPARAM 0x01
|
||||
#define DISK_RET_ECHANGED 0x06
|
||||
#define DISK_RET_EBOUNDARY 0x09
|
||||
#define DISK_RET_ECONTROLLER 0x20
|
||||
#define DISK_RET_ETIMEOUT 0x80
|
||||
#define DISK_RET_EMEDIA 0xC0
|
||||
|
||||
static inline void
|
||||
eoi_master_pic()
|
||||
{
|
||||
outb(PIC1_IRQ5, PORT_PIC1);
|
||||
}
|
||||
|
||||
static inline void
|
||||
eoi_both_pics()
|
||||
{
|
||||
outb(PIC2_IRQ13, PORT_PIC2);
|
||||
eoi_master_pic();
|
||||
}
|
||||
|
||||
// floppy.c
|
||||
struct bregs;
|
||||
void floppy_13(struct bregs *regs, u8 drive);
|
||||
void floppy_tick();
|
|
@ -0,0 +1,57 @@
|
|||
// Code to access multiple segments within gcc.
|
||||
//
|
||||
// Copyright (C) 2008 Kevin O'Connor <kevin@koconnor.net>
|
||||
//
|
||||
// This file may be distributed under the terms of the GNU GPLv3 license.
|
||||
|
||||
#define READ8_SEG(SEG, var) ({ \
|
||||
u8 __value; \
|
||||
__asm__ __volatile__("movb %%" #SEG ":%1, %b0" \
|
||||
: "=Qi"(__value) : "m"(var)); \
|
||||
__value; })
|
||||
#define READ16_SEG(SEG, var) ({ \
|
||||
u16 __value; \
|
||||
__asm__ __volatile__("movw %%" #SEG ":%1, %w0" \
|
||||
: "=ri"(__value) : "m"(var)); \
|
||||
__value; })
|
||||
#define READ32_SEG(SEG, var) ({ \
|
||||
u32 __value; \
|
||||
__asm__ __volatile__("movl %%" #SEG ":%1, %0" \
|
||||
: "=ri"(__value) : "m"(var)); \
|
||||
__value; })
|
||||
#define WRITE8_SEG(SEG, var, value) \
|
||||
__asm__ __volatile__("movb %b0, %%" #SEG ":%1" \
|
||||
: : "Q"(value), "m"(var))
|
||||
#define WRITE16_SEG(SEG, var, value) \
|
||||
__asm__ __volatile__("movw %w0, %%" #SEG ":%1" \
|
||||
: : "r"(value), "m"(var))
|
||||
#define WRITE32_SEG(SEG, var, value) \
|
||||
__asm__ __volatile__("movl %0, %%" #SEG ":%1" \
|
||||
: : "r"(value), "m"(var))
|
||||
|
||||
#define GET_VAR(seg, var) ({ \
|
||||
typeof(var) __val; \
|
||||
if (__builtin_types_compatible_p(typeof(__val), u8)) \
|
||||
__val = READ8_SEG(seg, var); \
|
||||
else if (__builtin_types_compatible_p(typeof(__val), u16)) \
|
||||
__val = READ16_SEG(seg, var); \
|
||||
else if (__builtin_types_compatible_p(typeof(__val), u32)) \
|
||||
__val = READ32_SEG(seg, var); \
|
||||
__val; })
|
||||
|
||||
#define SET_VAR(seg, var, val) do { \
|
||||
if (__builtin_types_compatible_p(typeof(var), u8)) \
|
||||
WRITE8_SEG(seg, var, (val)); \
|
||||
else if (__builtin_types_compatible_p(typeof(var), u16)) \
|
||||
WRITE16_SEG(seg, var, (val)); \
|
||||
else if (__builtin_types_compatible_p(typeof(var), u32)) \
|
||||
WRITE32_SEG(seg, var, (val)); \
|
||||
} while (0)
|
||||
|
||||
#define SET_SEG(SEG, value) \
|
||||
__asm__ __volatile__("movw %w0, %%" #SEG : : "r"(value))
|
||||
#define GET_SEG(SEG) ({ \
|
||||
u16 __seg; \
|
||||
__asm__ __volatile__("movw %%" #SEG ", %w0" : "=r"(__seg)); \
|
||||
__seg;})
|
||||
|
|
@ -0,0 +1,757 @@
|
|||
// 16bit code to access floppy drives.
|
||||
//
|
||||
// Copyright (C) 2008 Kevin O'Connor <kevin@koconnor.net>
|
||||
// Copyright (C) 2002 MandrakeSoft S.A.
|
||||
//
|
||||
// This file may be distributed under the terms of the GNU GPLv3 license.
|
||||
|
||||
#include "types.h" // u8
|
||||
#include "disk.h" // DISK_RET_SUCCESS
|
||||
#include "config.h" // CONFIG_FLOPPY_SUPPORT
|
||||
#include "biosvar.h" // struct bregs
|
||||
#include "util.h" // irq_disable
|
||||
#include "cmos.h" // inb_cmos
|
||||
|
||||
#define BX_FLOPPY_ON_CNT 37 /* 2 seconds */
|
||||
|
||||
////.org 0xefc7
|
||||
// Since no provisions are made for multiple drive types, most
|
||||
// values in this table are ignored. I set parameters for 1.44M
|
||||
// floppy here
|
||||
char diskette_param_table[11] = {
|
||||
0xAF,
|
||||
0x02, // head load time 0000001, DMA used
|
||||
0x25,
|
||||
0x02,
|
||||
18,
|
||||
0x1B,
|
||||
0xFF,
|
||||
0x6C,
|
||||
0xF6,
|
||||
0x0F,
|
||||
0x08,
|
||||
};
|
||||
|
||||
// New diskette parameter table adding 3 parameters from IBM
|
||||
// Since no provisions are made for multiple drive types, most
|
||||
// values in this table are ignored. I set parameters for 1.44M
|
||||
// floppy here
|
||||
char diskette_param_table2[14] VISIBLE = {
|
||||
0xAF,
|
||||
0x02, // head load time 0000001, DMA used
|
||||
0x25,
|
||||
0x02,
|
||||
18,
|
||||
0x1B,
|
||||
0xFF,
|
||||
0x6C,
|
||||
0xF6,
|
||||
0x0F,
|
||||
0x08,
|
||||
79, // maximum track
|
||||
0, // data transfer rate
|
||||
4, // drive type in cmos
|
||||
};
|
||||
|
||||
// Oddities:
|
||||
// Return codes vary greatly - AL not cleared consistenlty, BDA return
|
||||
// status not set consistently, sometimes panics.
|
||||
// Extra outb(0x000a, 0x02) in read?
|
||||
// Does not disable interrupts on failure paths.
|
||||
// numfloppies used before set in int_1308
|
||||
// int_1305 verifies track but doesn't use it?
|
||||
|
||||
static inline void
|
||||
set_diskette_current_cyl(u8 drive, u8 cyl)
|
||||
{
|
||||
if (drive)
|
||||
SET_BDA(floppy_track1, cyl);
|
||||
else
|
||||
SET_BDA(floppy_track0, cyl);
|
||||
}
|
||||
|
||||
static u16
|
||||
get_drive_type(u8 drive)
|
||||
{
|
||||
// check CMOS to see if drive exists
|
||||
u8 drive_type = inb_cmos(CMOS_FLOPPY_DRIVE_TYPE);
|
||||
if (drive == 0)
|
||||
drive_type >>= 4;
|
||||
else
|
||||
drive_type &= 0x0f;
|
||||
return drive_type;
|
||||
}
|
||||
|
||||
static u16
|
||||
floppy_media_known(u8 drive)
|
||||
{
|
||||
if (!(GET_BDA(floppy_recalibration_status) & (1<<drive)))
|
||||
return 0;
|
||||
u8 v = GET_BDA(floppy_media_state[drive]);
|
||||
if (!(v & FMS_MEDIA_DRIVE_ESTABLISHED))
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void
|
||||
floppy_reset_controller()
|
||||
{
|
||||
// Reset controller
|
||||
u8 val8 = inb(PORT_FD_DOR);
|
||||
outb(val8 & ~0x04, PORT_FD_DOR);
|
||||
outb(val8 | 0x04, PORT_FD_DOR);
|
||||
|
||||
// Wait for controller to come out of reset
|
||||
while ((inb(PORT_FD_STATUS) & 0xc0) != 0x80)
|
||||
;
|
||||
}
|
||||
|
||||
static void
|
||||
floppy_prepare_controller(u8 drive)
|
||||
{
|
||||
CLEARBITS_BDA(floppy_recalibration_status, FRS_TIMEOUT);
|
||||
|
||||
// turn on motor of selected drive, DMA & int enabled, normal operation
|
||||
u8 prev_reset = inb(PORT_FD_DOR) & 0x04;
|
||||
u8 dor = 0x10;
|
||||
if (drive)
|
||||
dor = 0x20;
|
||||
dor |= 0x0c;
|
||||
dor |= drive;
|
||||
outb(dor, PORT_FD_DOR);
|
||||
|
||||
// reset the disk motor timeout value of INT 08
|
||||
SET_BDA(floppy_motor_counter, BX_FLOPPY_ON_CNT);
|
||||
|
||||
// wait for drive readiness
|
||||
while ((inb(PORT_FD_STATUS) & 0xc0) != 0x80)
|
||||
;
|
||||
|
||||
if (prev_reset == 0) {
|
||||
irq_enable();
|
||||
u8 v;
|
||||
do {
|
||||
v = GET_BDA(floppy_recalibration_status);
|
||||
} while ((v & FRS_TIMEOUT) == 0);
|
||||
irq_disable();
|
||||
|
||||
v &= ~FRS_TIMEOUT;
|
||||
SET_BDA(floppy_recalibration_status, v);
|
||||
}
|
||||
}
|
||||
|
||||
static u8
|
||||
floppy_pio(u8 *cmd, u8 cmdlen)
|
||||
{
|
||||
floppy_prepare_controller(cmd[1] & 1);
|
||||
|
||||
// send command to controller
|
||||
u8 i;
|
||||
for (i=0; i<cmdlen; i++)
|
||||
outb(cmd[i], PORT_FD_DATA);
|
||||
|
||||
irq_enable();
|
||||
u8 v;
|
||||
do {
|
||||
if (!GET_BDA(floppy_motor_counter)) {
|
||||
irq_disable();
|
||||
floppy_reset_controller();
|
||||
return DISK_RET_ETIMEOUT;
|
||||
}
|
||||
v = GET_BDA(floppy_recalibration_status);
|
||||
} while (!(v & FRS_TIMEOUT));
|
||||
irq_disable();
|
||||
|
||||
v &= ~FRS_TIMEOUT;
|
||||
SET_BDA(floppy_recalibration_status, v);
|
||||
|
||||
if ((inb(PORT_FD_STATUS) & 0xc0) != 0xc0)
|
||||
BX_PANIC("int13_diskette: ctrl not ready\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u8
|
||||
floppy_cmd(struct bregs *regs, u16 count, u8 *cmd, u8 cmdlen)
|
||||
{
|
||||
// es:bx = pointer to where to place information from diskette
|
||||
// port 04: DMA-1 base and current address, channel 2
|
||||
// port 05: DMA-1 base and current count, channel 2
|
||||
u16 page = regs->es >> 12; // upper 4 bits
|
||||
u16 base_es = regs->es << 4; // lower 16bits contributed by ES
|
||||
u16 base_address = base_es + regs->bx; // lower 16 bits of address
|
||||
// contributed by ES:BX
|
||||
if (base_address < base_es)
|
||||
// in case of carry, adjust page by 1
|
||||
page++;
|
||||
|
||||
// check for 64K boundary overrun
|
||||
u16 last_addr = base_address + count;
|
||||
if (last_addr < base_address)
|
||||
return DISK_RET_EBOUNDARY;
|
||||
|
||||
u8 mode_register = 0x4a; // single mode, increment, autoinit disable,
|
||||
if (cmd[0] == 0xe6)
|
||||
// read
|
||||
mode_register = 0x46;
|
||||
|
||||
DEBUGF("floppy dma c2");
|
||||
outb(0x06, PORT_DMA1_MASK_REG);
|
||||
outb(0x00, PORT_DMA1_CLEAR_FF_REG); // clear flip-flop
|
||||
outb(base_address, PORT_DMA_ADDR_2);
|
||||
outb(base_address>>8, PORT_DMA_ADDR_2);
|
||||
outb(0x00, PORT_DMA1_CLEAR_FF_REG); // clear flip-flop
|
||||
outb(count, PORT_DMA_CNT_2);
|
||||
outb(count>>8, PORT_DMA_CNT_2);
|
||||
|
||||
// port 0b: DMA-1 Mode Register
|
||||
// transfer type=write, channel 2
|
||||
outb(mode_register, PORT_DMA1_MODE_REG);
|
||||
|
||||
// port 81: DMA-1 Page Register, channel 2
|
||||
outb(page, PORT_DMA_PAGE_2);
|
||||
|
||||
outb(0x02, PORT_DMA1_MASK_REG); // unmask channel 2
|
||||
|
||||
u8 ret = floppy_pio(cmd, cmdlen);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
// read 7 return status bytes from controller
|
||||
u8 i;
|
||||
for (i=0; i<7; i++) {
|
||||
u8 v = inb(PORT_FD_DATA);
|
||||
cmd[i] = v;
|
||||
SET_BDA(floppy_return_status[i], v);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
floppy_drive_recal(u8 drive)
|
||||
{
|
||||
// send Recalibrate command (2 bytes) to controller
|
||||
u8 data[12];
|
||||
data[0] = 0x07; // 07: Recalibrate
|
||||
data[1] = drive; // 0=drive0, 1=drive1
|
||||
floppy_pio(data, 2);
|
||||
|
||||
SETBITS_BDA(floppy_recalibration_status, 1<<drive);
|
||||
set_diskette_current_cyl(drive, 0);
|
||||
}
|
||||
|
||||
static u16
|
||||
floppy_media_sense(u8 drive)
|
||||
{
|
||||
u16 rv;
|
||||
u8 config_data, media_state;
|
||||
|
||||
floppy_drive_recal(drive);
|
||||
|
||||
// for now cheat and get drive type from CMOS,
|
||||
// assume media is same as drive type
|
||||
|
||||
// ** config_data **
|
||||
// Bitfields for diskette media control:
|
||||
// Bit(s) Description (Table M0028)
|
||||
// 7-6 last data rate set by controller
|
||||
// 00=500kbps, 01=300kbps, 10=250kbps, 11=1Mbps
|
||||
// 5-4 last diskette drive step rate selected
|
||||
// 00=0Ch, 01=0Dh, 10=0Eh, 11=0Ah
|
||||
// 3-2 {data rate at start of operation}
|
||||
// 1-0 reserved
|
||||
|
||||
// ** media_state **
|
||||
// Bitfields for diskette drive media state:
|
||||
// Bit(s) Description (Table M0030)
|
||||
// 7-6 data rate
|
||||
// 00=500kbps, 01=300kbps, 10=250kbps, 11=1Mbps
|
||||
// 5 double stepping required (e.g. 360kB in 1.2MB)
|
||||
// 4 media type established
|
||||
// 3 drive capable of supporting 4MB media
|
||||
// 2-0 on exit from BIOS, contains
|
||||
// 000 trying 360kB in 360kB
|
||||
// 001 trying 360kB in 1.2MB
|
||||
// 010 trying 1.2MB in 1.2MB
|
||||
// 011 360kB in 360kB established
|
||||
// 100 360kB in 1.2MB established
|
||||
// 101 1.2MB in 1.2MB established
|
||||
// 110 reserved
|
||||
// 111 all other formats/drives
|
||||
|
||||
switch (get_drive_type(drive)) {
|
||||
case 1:
|
||||
// 360K 5.25" drive
|
||||
config_data = 0x00; // 0000 0000
|
||||
media_state = 0x25; // 0010 0101
|
||||
rv = 1;
|
||||
break;
|
||||
case 2:
|
||||
// 1.2 MB 5.25" drive
|
||||
config_data = 0x00; // 0000 0000
|
||||
media_state = 0x25; // 0010 0101 // need double stepping??? (bit 5)
|
||||
rv = 1;
|
||||
break;
|
||||
case 3:
|
||||
// 720K 3.5" drive
|
||||
config_data = 0x00; // 0000 0000 ???
|
||||
media_state = 0x17; // 0001 0111
|
||||
rv = 1;
|
||||
break;
|
||||
case 4:
|
||||
// 1.44 MB 3.5" drive
|
||||
config_data = 0x00; // 0000 0000
|
||||
media_state = 0x17; // 0001 0111
|
||||
rv = 1;
|
||||
break;
|
||||
case 5:
|
||||
// 2.88 MB 3.5" drive
|
||||
config_data = 0xCC; // 1100 1100
|
||||
media_state = 0xD7; // 1101 0111
|
||||
rv = 1;
|
||||
break;
|
||||
//
|
||||
// Extended floppy size uses special cmos setting
|
||||
case 6:
|
||||
// 160k 5.25" drive
|
||||
config_data = 0x00; // 0000 0000
|
||||
media_state = 0x27; // 0010 0111
|
||||
rv = 1;
|
||||
break;
|
||||
case 7:
|
||||
// 180k 5.25" drive
|
||||
config_data = 0x00; // 0000 0000
|
||||
media_state = 0x27; // 0010 0111
|
||||
rv = 1;
|
||||
break;
|
||||
case 8:
|
||||
// 320k 5.25" drive
|
||||
config_data = 0x00; // 0000 0000
|
||||
media_state = 0x27; // 0010 0111
|
||||
rv = 1;
|
||||
break;
|
||||
default:
|
||||
// not recognized
|
||||
config_data = 0x00; // 0000 0000
|
||||
media_state = 0x00; // 0000 0000
|
||||
rv = 0;
|
||||
}
|
||||
|
||||
SET_BDA(floppy_last_data_rate, config_data);
|
||||
SET_BDA(floppy_media_state[drive], media_state);
|
||||
return rv;
|
||||
}
|
||||
|
||||
static inline void
|
||||
floppy_ret(struct bregs *regs, u8 code)
|
||||
{
|
||||
regs->ah = code;
|
||||
SET_BDA(floppy_last_status, code);
|
||||
set_cf(regs, code);
|
||||
}
|
||||
|
||||
static inline void
|
||||
floppy_fail(struct bregs *regs, u8 code)
|
||||
{
|
||||
regs->al = 0; // no sectors read
|
||||
floppy_ret(regs, code);
|
||||
}
|
||||
|
||||
static u16
|
||||
check_drive(struct bregs *regs, u8 drive)
|
||||
{
|
||||
// see if drive exists
|
||||
if (drive > 1 || !get_drive_type(drive)) {
|
||||
floppy_fail(regs, DISK_RET_ETIMEOUT);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// see if media in drive, and type is known
|
||||
if (floppy_media_known(drive) == 0 && floppy_media_sense(drive) == 0) {
|
||||
floppy_fail(regs, DISK_RET_EMEDIA);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// diskette controller reset
|
||||
static void
|
||||
floppy_1300(struct bregs *regs, u8 drive)
|
||||
{
|
||||
if (drive > 1) {
|
||||
floppy_ret(regs, DISK_RET_EPARAM);
|
||||
return;
|
||||
}
|
||||
if (!get_drive_type(drive)) {
|
||||
floppy_ret(regs, DISK_RET_ETIMEOUT);
|
||||
return;
|
||||
}
|
||||
set_diskette_current_cyl(drive, 0); // current cylinder
|
||||
floppy_ret(regs, DISK_RET_SUCCESS);
|
||||
}
|
||||
|
||||
// Read Diskette Status
|
||||
static void
|
||||
floppy_1301(struct bregs *regs, u8 drive)
|
||||
{
|
||||
u8 v = GET_BDA(floppy_last_status);
|
||||
regs->ah = v;
|
||||
set_cf(regs, v);
|
||||
}
|
||||
|
||||
// Read Diskette Sectors
|
||||
static void
|
||||
floppy_1302(struct bregs *regs, u8 drive)
|
||||
{
|
||||
if (check_drive(regs, drive))
|
||||
return;
|
||||
|
||||
u8 num_sectors = regs->al;
|
||||
u8 track = regs->ch;
|
||||
u8 sector = regs->cl;
|
||||
u8 head = regs->dh;
|
||||
|
||||
if (head > 1 || sector == 0 || num_sectors == 0
|
||||
|| track > 79 || num_sectors > 72) {
|
||||
BX_INFO("int13_diskette: read/write/verify: parameter out of range\n");
|
||||
floppy_fail(regs, DISK_RET_EPARAM);
|
||||
return;
|
||||
}
|
||||
|
||||
// send read-normal-data command (9 bytes) to controller
|
||||
u8 data[12];
|
||||
data[0] = 0xe6; // e6: read normal data
|
||||
data[1] = (head << 2) | drive; // HD DR1 DR2
|
||||
data[2] = track;
|
||||
data[3] = head;
|
||||
data[4] = sector;
|
||||
data[5] = 2; // 512 byte sector size
|
||||
data[6] = sector + num_sectors - 1; // last sector to read on track
|
||||
data[7] = 0; // Gap length
|
||||
data[8] = 0xff; // Gap length
|
||||
|
||||
u16 ret = floppy_cmd(regs, (num_sectors * 512) - 1, data, 9);
|
||||
if (ret) {
|
||||
floppy_fail(regs, ret);
|
||||
return;
|
||||
}
|
||||
|
||||
if (data[0] & 0xc0) {
|
||||
floppy_fail(regs, DISK_RET_ECONTROLLER);
|
||||
return;
|
||||
}
|
||||
|
||||
// ??? should track be new val from return_status[3] ?
|
||||
set_diskette_current_cyl(drive, track);
|
||||
// AL = number of sectors read (same value as passed)
|
||||
floppy_ret(regs, DISK_RET_SUCCESS);
|
||||
}
|
||||
|
||||
// Write Diskette Sectors
|
||||
static void
|
||||
floppy_1303(struct bregs *regs, u8 drive)
|
||||
{
|
||||
if (check_drive(regs, drive))
|
||||
return;
|
||||
|
||||
u8 num_sectors = regs->al;
|
||||
u8 track = regs->ch;
|
||||
u8 sector = regs->cl;
|
||||
u8 head = regs->dh;
|
||||
|
||||
if (head > 1 || sector == 0 || num_sectors == 0
|
||||
|| track > 79 || num_sectors > 72) {
|
||||
BX_INFO("int13_diskette: read/write/verify: parameter out of range\n");
|
||||
floppy_fail(regs, DISK_RET_EPARAM);
|
||||
return;
|
||||
}
|
||||
|
||||
// send write-normal-data command (9 bytes) to controller
|
||||
u8 data[12];
|
||||
data[0] = 0xc5; // c5: write normal data
|
||||
data[1] = (head << 2) | drive; // HD DR1 DR2
|
||||
data[2] = track;
|
||||
data[3] = head;
|
||||
data[4] = sector;
|
||||
data[5] = 2; // 512 byte sector size
|
||||
data[6] = sector + num_sectors - 1; // last sector to write on track
|
||||
data[7] = 0; // Gap length
|
||||
data[8] = 0xff; // Gap length
|
||||
|
||||
u8 ret = floppy_cmd(regs, (num_sectors * 512) - 1, data, 9);
|
||||
if (ret) {
|
||||
floppy_fail(regs, ret);
|
||||
return;
|
||||
}
|
||||
|
||||
if (data[0] & 0xc0) {
|
||||
if (data[1] & 0x02) {
|
||||
regs->ax = 0x0300;
|
||||
set_cf(regs, 1);
|
||||
return;
|
||||
}
|
||||
BX_PANIC("int13_diskette_function: read error\n");
|
||||
}
|
||||
|
||||
// ??? should track be new val from return_status[3] ?
|
||||
set_diskette_current_cyl(drive, track);
|
||||
// AL = number of sectors read (same value as passed)
|
||||
floppy_ret(regs, DISK_RET_SUCCESS);
|
||||
}
|
||||
|
||||
// Verify Diskette Sectors
|
||||
static void
|
||||
floppy_1304(struct bregs *regs, u8 drive)
|
||||
{
|
||||
if (check_drive(regs, drive))
|
||||
return;
|
||||
|
||||
u8 num_sectors = regs->al;
|
||||
u8 track = regs->ch;
|
||||
u8 sector = regs->cl;
|
||||
u8 head = regs->dh;
|
||||
|
||||
if (head > 1 || sector == 0 || num_sectors == 0
|
||||
|| track > 79 || num_sectors > 72) {
|
||||
BX_INFO("int13_diskette: read/write/verify: parameter out of range\n");
|
||||
floppy_fail(regs, DISK_RET_EPARAM);
|
||||
return;
|
||||
}
|
||||
|
||||
// ??? should track be new val from return_status[3] ?
|
||||
set_diskette_current_cyl(drive, track);
|
||||
// AL = number of sectors verified (same value as passed)
|
||||
floppy_ret(regs, DISK_RET_SUCCESS);
|
||||
}
|
||||
|
||||
// format diskette track
|
||||
static void
|
||||
floppy_1305(struct bregs *regs, u8 drive)
|
||||
{
|
||||
DEBUGF("floppy f05\n");
|
||||
|
||||
if (check_drive(regs, drive))
|
||||
return;
|
||||
|
||||
u8 num_sectors = regs->al;
|
||||
u8 head = regs->dh;
|
||||
|
||||
if (head > 1 || num_sectors == 0 || num_sectors > 18) {
|
||||
BX_INFO("int13_diskette: read/write/verify: parameter out of range\n");
|
||||
floppy_fail(regs, DISK_RET_EPARAM);
|
||||
return;
|
||||
}
|
||||
|
||||
// send format-track command (6 bytes) to controller
|
||||
u8 data[12];
|
||||
data[0] = 0x4d; // 4d: format track
|
||||
data[1] = (head << 2) | drive; // HD DR1 DR2
|
||||
data[2] = 2; // 512 byte sector size
|
||||
data[3] = num_sectors; // number of sectors per track
|
||||
data[4] = 0; // Gap length
|
||||
data[5] = 0xf6; // Fill byte
|
||||
|
||||
u8 ret = floppy_cmd(regs, (num_sectors * 4) - 1, data, 6);
|
||||
if (ret) {
|
||||
floppy_fail(regs, ret);
|
||||
return;
|
||||
}
|
||||
|
||||
if (data[0] & 0xc0) {
|
||||
if (data[1] & 0x02) {
|
||||
regs->ax = 0x0300;
|
||||
set_cf(regs, 1);
|
||||
return;
|
||||
}
|
||||
BX_PANIC("int13_diskette_function: read error\n");
|
||||
}
|
||||
|
||||
set_diskette_current_cyl(drive, 0);
|
||||
floppy_ret(regs, 0);
|
||||
}
|
||||
|
||||
// read diskette drive parameters
|
||||
static void
|
||||
floppy_1308(struct bregs *regs, u8 drive)
|
||||
{
|
||||
DEBUGF("floppy f08\n");
|
||||
|
||||
u8 drive_type = inb_cmos(CMOS_FLOPPY_DRIVE_TYPE);
|
||||
u8 num_floppies = 0;
|
||||
if (drive_type & 0xf0)
|
||||
num_floppies++;
|
||||
if (drive_type & 0x0f)
|
||||
num_floppies++;
|
||||
|
||||
if (drive > 1) {
|
||||
regs->ax = 0;
|
||||
regs->bx = 0;
|
||||
regs->cx = 0;
|
||||
regs->dx = 0;
|
||||
regs->es = 0;
|
||||
regs->di = 0;
|
||||
regs->dl = num_floppies;
|
||||
set_cf(regs, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
if (drive == 0)
|
||||
drive_type >>= 4;
|
||||
else
|
||||
drive_type &= 0x0f;
|
||||
|
||||
regs->bh = 0;
|
||||
regs->bl = drive_type;
|
||||
regs->ah = 0;
|
||||
regs->al = 0;
|
||||
regs->dl = num_floppies;
|
||||
|
||||
switch (drive_type) {
|
||||
case 0: // none
|
||||
regs->cx = 0;
|
||||
regs->dh = 0; // max head #
|
||||
break;
|
||||
|
||||
case 1: // 360KB, 5.25"
|
||||
regs->cx = 0x2709; // 40 tracks, 9 sectors
|
||||
regs->dh = 1; // max head #
|
||||
break;
|
||||
|
||||
case 2: // 1.2MB, 5.25"
|
||||
regs->cx = 0x4f0f; // 80 tracks, 15 sectors
|
||||
regs->dh = 1; // max head #
|
||||
break;
|
||||
|
||||
case 3: // 720KB, 3.5"
|
||||
regs->cx = 0x4f09; // 80 tracks, 9 sectors
|
||||
regs->dh = 1; // max head #
|
||||
break;
|
||||
|
||||
case 4: // 1.44MB, 3.5"
|
||||
regs->cx = 0x4f12; // 80 tracks, 18 sectors
|
||||
regs->dh = 1; // max head #
|
||||
break;
|
||||
|
||||
case 5: // 2.88MB, 3.5"
|
||||
regs->cx = 0x4f24; // 80 tracks, 36 sectors
|
||||
regs->dh = 1; // max head #
|
||||
break;
|
||||
|
||||
case 6: // 160k, 5.25"
|
||||
regs->cx = 0x2708; // 40 tracks, 8 sectors
|
||||
regs->dh = 0; // max head #
|
||||
break;
|
||||
|
||||
case 7: // 180k, 5.25"
|
||||
regs->cx = 0x2709; // 40 tracks, 9 sectors
|
||||
regs->dh = 0; // max head #
|
||||
break;
|
||||
|
||||
case 8: // 320k, 5.25"
|
||||
regs->cx = 0x2708; // 40 tracks, 8 sectors
|
||||
regs->dh = 1; // max head #
|
||||
break;
|
||||
|
||||
default: // ?
|
||||
BX_PANIC("floppy: int13: bad floppy type\n");
|
||||
}
|
||||
|
||||
/* set es & di to point to 11 byte diskette param table in ROM */
|
||||
regs->es = SEG_BIOS;
|
||||
regs->di = (u16)diskette_param_table2;
|
||||
/* disk status not changed upon success */
|
||||
}
|
||||
|
||||
// read diskette drive type
|
||||
static void
|
||||
floppy_1315(struct bregs *regs, u8 drive)
|
||||
{
|
||||
DEBUGF("floppy f15\n");
|
||||
if (drive > 1) {
|
||||
regs->ah = 0; // only 2 drives supported
|
||||
// set_diskette_ret_status here ???
|
||||
set_cf(regs, 1);
|
||||
return;
|
||||
}
|
||||
u8 drive_type = get_drive_type(drive);
|
||||
|
||||
regs->ah = (drive_type != 0);
|
||||
set_cf(regs, 0);
|
||||
}
|
||||
|
||||
// get diskette change line status
|
||||
static void
|
||||
floppy_1316(struct bregs *regs, u8 drive)
|
||||
{
|
||||
DEBUGF("floppy f16\n");
|
||||
if (drive > 1) {
|
||||
floppy_ret(regs, DISK_RET_EPARAM);
|
||||
return;
|
||||
}
|
||||
floppy_ret(regs, DISK_RET_ECHANGED);
|
||||
}
|
||||
|
||||
static void
|
||||
floppy_13XX(struct bregs *regs, u8 drive)
|
||||
{
|
||||
BX_INFO("int13_diskette: unsupported AH=%02x\n", GET_AH());
|
||||
floppy_ret(regs, DISK_RET_EPARAM);
|
||||
}
|
||||
|
||||
void
|
||||
floppy_13(struct bregs *regs, u8 drive)
|
||||
{
|
||||
if (CONFIG_FLOPPY_SUPPORT) {
|
||||
switch (regs->ah) {
|
||||
case 0x00: floppy_1300(regs, drive); break;
|
||||
case 0x01: floppy_1301(regs, drive); break;
|
||||
case 0x02: floppy_1302(regs, drive); break;
|
||||
case 0x03: floppy_1303(regs, drive); break;
|
||||
case 0x04: floppy_1304(regs, drive); break;
|
||||
case 0x05: floppy_1305(regs, drive); break;
|
||||
case 0x08: floppy_1308(regs, drive); break;
|
||||
case 0x15: floppy_1315(regs, drive); break;
|
||||
case 0x16: floppy_1316(regs, drive); break;
|
||||
default: floppy_13XX(regs, drive); break;
|
||||
}
|
||||
} else {
|
||||
switch (regs->ah) {
|
||||
case 0x01: floppy_1301(regs, drive); break;
|
||||
default: floppy_13XX(regs, drive); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// INT 0Eh Diskette Hardware ISR Entry Point
|
||||
void VISIBLE
|
||||
handle_0e(struct bregs *regs)
|
||||
{
|
||||
debug_enter(regs);
|
||||
if ((inb(PORT_FD_STATUS) & 0xc0) != 0xc0) {
|
||||
outb(0x08, PORT_FD_DATA); // sense interrupt status
|
||||
while ((inb(PORT_FD_STATUS) & 0xc0) != 0xc0)
|
||||
;
|
||||
do {
|
||||
inb(PORT_FD_DATA);
|
||||
} while ((inb(PORT_FD_STATUS) & 0xc0) == 0xc0);
|
||||
}
|
||||
eoi_master_pic();
|
||||
// diskette interrupt has occurred
|
||||
SETBITS_BDA(floppy_recalibration_status, FRS_TIMEOUT);
|
||||
}
|
||||
|
||||
// Called from int08 handler.
|
||||
void
|
||||
floppy_tick()
|
||||
{
|
||||
// time to turn off drive(s)?
|
||||
u8 fcount = GET_BDA(floppy_motor_counter);
|
||||
if (fcount) {
|
||||
fcount--;
|
||||
SET_BDA(floppy_motor_counter, fcount);
|
||||
if (fcount == 0)
|
||||
// turn motor(s) off
|
||||
outb(inb(PORT_FD_DOR) & 0xcf, PORT_FD_DOR);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,139 @@
|
|||
#include "types.h" // u8
|
||||
|
||||
// Character Font for 320x200 & 640x200 Graphics (lower 128 characters)
|
||||
|
||||
/*
|
||||
* This font comes from the fntcol16.zip package (c) by Joseph Gil
|
||||
* found at ftp://ftp.simtel.net/pub/simtelnet/msdos/screen/fntcol16.zip
|
||||
* This font is public domain
|
||||
*/
|
||||
const u8 vgafont8[128*8] __attribute__((aligned (1))) = {
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x7e, 0x81, 0xa5, 0x81, 0xbd, 0x99, 0x81, 0x7e,
|
||||
0x7e, 0xff, 0xdb, 0xff, 0xc3, 0xe7, 0xff, 0x7e,
|
||||
0x6c, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00,
|
||||
0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x10, 0x00,
|
||||
0x38, 0x7c, 0x38, 0xfe, 0xfe, 0x7c, 0x38, 0x7c,
|
||||
0x10, 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x7c,
|
||||
0x00, 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x00, 0x00,
|
||||
0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff,
|
||||
0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00,
|
||||
0xff, 0xc3, 0x99, 0xbd, 0xbd, 0x99, 0xc3, 0xff,
|
||||
0x0f, 0x07, 0x0f, 0x7d, 0xcc, 0xcc, 0xcc, 0x78,
|
||||
0x3c, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18,
|
||||
0x3f, 0x33, 0x3f, 0x30, 0x30, 0x70, 0xf0, 0xe0,
|
||||
0x7f, 0x63, 0x7f, 0x63, 0x63, 0x67, 0xe6, 0xc0,
|
||||
0x99, 0x5a, 0x3c, 0xe7, 0xe7, 0x3c, 0x5a, 0x99,
|
||||
0x80, 0xe0, 0xf8, 0xfe, 0xf8, 0xe0, 0x80, 0x00,
|
||||
0x02, 0x0e, 0x3e, 0xfe, 0x3e, 0x0e, 0x02, 0x00,
|
||||
0x18, 0x3c, 0x7e, 0x18, 0x18, 0x7e, 0x3c, 0x18,
|
||||
0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x00,
|
||||
0x7f, 0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x00,
|
||||
0x3e, 0x63, 0x38, 0x6c, 0x6c, 0x38, 0xcc, 0x78,
|
||||
0x00, 0x00, 0x00, 0x00, 0x7e, 0x7e, 0x7e, 0x00,
|
||||
0x18, 0x3c, 0x7e, 0x18, 0x7e, 0x3c, 0x18, 0xff,
|
||||
0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x00,
|
||||
0x18, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00,
|
||||
0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00,
|
||||
0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00,
|
||||
0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xfe, 0x00, 0x00,
|
||||
0x00, 0x24, 0x66, 0xff, 0x66, 0x24, 0x00, 0x00,
|
||||
0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x00, 0x00,
|
||||
0x00, 0xff, 0xff, 0x7e, 0x3c, 0x18, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x30, 0x78, 0x78, 0x30, 0x30, 0x00, 0x30, 0x00,
|
||||
0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x6c, 0x6c, 0xfe, 0x6c, 0xfe, 0x6c, 0x6c, 0x00,
|
||||
0x30, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x30, 0x00,
|
||||
0x00, 0xc6, 0xcc, 0x18, 0x30, 0x66, 0xc6, 0x00,
|
||||
0x38, 0x6c, 0x38, 0x76, 0xdc, 0xcc, 0x76, 0x00,
|
||||
0x60, 0x60, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x18, 0x30, 0x60, 0x60, 0x60, 0x30, 0x18, 0x00,
|
||||
0x60, 0x30, 0x18, 0x18, 0x18, 0x30, 0x60, 0x00,
|
||||
0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00,
|
||||
0x00, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x60,
|
||||
0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00,
|
||||
0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00,
|
||||
0x7c, 0xc6, 0xce, 0xde, 0xf6, 0xe6, 0x7c, 0x00,
|
||||
0x30, 0x70, 0x30, 0x30, 0x30, 0x30, 0xfc, 0x00,
|
||||
0x78, 0xcc, 0x0c, 0x38, 0x60, 0xcc, 0xfc, 0x00,
|
||||
0x78, 0xcc, 0x0c, 0x38, 0x0c, 0xcc, 0x78, 0x00,
|
||||
0x1c, 0x3c, 0x6c, 0xcc, 0xfe, 0x0c, 0x1e, 0x00,
|
||||
0xfc, 0xc0, 0xf8, 0x0c, 0x0c, 0xcc, 0x78, 0x00,
|
||||
0x38, 0x60, 0xc0, 0xf8, 0xcc, 0xcc, 0x78, 0x00,
|
||||
0xfc, 0xcc, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x00,
|
||||
0x78, 0xcc, 0xcc, 0x78, 0xcc, 0xcc, 0x78, 0x00,
|
||||
0x78, 0xcc, 0xcc, 0x7c, 0x0c, 0x18, 0x70, 0x00,
|
||||
0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x00,
|
||||
0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x60,
|
||||
0x18, 0x30, 0x60, 0xc0, 0x60, 0x30, 0x18, 0x00,
|
||||
0x00, 0x00, 0xfc, 0x00, 0x00, 0xfc, 0x00, 0x00,
|
||||
0x60, 0x30, 0x18, 0x0c, 0x18, 0x30, 0x60, 0x00,
|
||||
0x78, 0xcc, 0x0c, 0x18, 0x30, 0x00, 0x30, 0x00,
|
||||
0x7c, 0xc6, 0xde, 0xde, 0xde, 0xc0, 0x78, 0x00,
|
||||
0x30, 0x78, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0x00,
|
||||
0xfc, 0x66, 0x66, 0x7c, 0x66, 0x66, 0xfc, 0x00,
|
||||
0x3c, 0x66, 0xc0, 0xc0, 0xc0, 0x66, 0x3c, 0x00,
|
||||
0xf8, 0x6c, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00,
|
||||
0xfe, 0x62, 0x68, 0x78, 0x68, 0x62, 0xfe, 0x00,
|
||||
0xfe, 0x62, 0x68, 0x78, 0x68, 0x60, 0xf0, 0x00,
|
||||
0x3c, 0x66, 0xc0, 0xc0, 0xce, 0x66, 0x3e, 0x00,
|
||||
0xcc, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0xcc, 0x00,
|
||||
0x78, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
|
||||
0x1e, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78, 0x00,
|
||||
0xe6, 0x66, 0x6c, 0x78, 0x6c, 0x66, 0xe6, 0x00,
|
||||
0xf0, 0x60, 0x60, 0x60, 0x62, 0x66, 0xfe, 0x00,
|
||||
0xc6, 0xee, 0xfe, 0xfe, 0xd6, 0xc6, 0xc6, 0x00,
|
||||
0xc6, 0xe6, 0xf6, 0xde, 0xce, 0xc6, 0xc6, 0x00,
|
||||
0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x00,
|
||||
0xfc, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00,
|
||||
0x78, 0xcc, 0xcc, 0xcc, 0xdc, 0x78, 0x1c, 0x00,
|
||||
0xfc, 0x66, 0x66, 0x7c, 0x6c, 0x66, 0xe6, 0x00,
|
||||
0x78, 0xcc, 0xe0, 0x70, 0x1c, 0xcc, 0x78, 0x00,
|
||||
0xfc, 0xb4, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
|
||||
0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xfc, 0x00,
|
||||
0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00,
|
||||
0xc6, 0xc6, 0xc6, 0xd6, 0xfe, 0xee, 0xc6, 0x00,
|
||||
0xc6, 0xc6, 0x6c, 0x38, 0x38, 0x6c, 0xc6, 0x00,
|
||||
0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x30, 0x78, 0x00,
|
||||
0xfe, 0xc6, 0x8c, 0x18, 0x32, 0x66, 0xfe, 0x00,
|
||||
0x78, 0x60, 0x60, 0x60, 0x60, 0x60, 0x78, 0x00,
|
||||
0xc0, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x02, 0x00,
|
||||
0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78, 0x00,
|
||||
0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
|
||||
0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x76, 0x00,
|
||||
0xe0, 0x60, 0x60, 0x7c, 0x66, 0x66, 0xdc, 0x00,
|
||||
0x00, 0x00, 0x78, 0xcc, 0xc0, 0xcc, 0x78, 0x00,
|
||||
0x1c, 0x0c, 0x0c, 0x7c, 0xcc, 0xcc, 0x76, 0x00,
|
||||
0x00, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00,
|
||||
0x38, 0x6c, 0x60, 0xf0, 0x60, 0x60, 0xf0, 0x00,
|
||||
0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8,
|
||||
0xe0, 0x60, 0x6c, 0x76, 0x66, 0x66, 0xe6, 0x00,
|
||||
0x30, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00,
|
||||
0x0c, 0x00, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78,
|
||||
0xe0, 0x60, 0x66, 0x6c, 0x78, 0x6c, 0xe6, 0x00,
|
||||
0x70, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
|
||||
0x00, 0x00, 0xcc, 0xfe, 0xfe, 0xd6, 0xc6, 0x00,
|
||||
0x00, 0x00, 0xf8, 0xcc, 0xcc, 0xcc, 0xcc, 0x00,
|
||||
0x00, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0x78, 0x00,
|
||||
0x00, 0x00, 0xdc, 0x66, 0x66, 0x7c, 0x60, 0xf0,
|
||||
0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0x1e,
|
||||
0x00, 0x00, 0xdc, 0x76, 0x66, 0x60, 0xf0, 0x00,
|
||||
0x00, 0x00, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x00,
|
||||
0x10, 0x30, 0x7c, 0x30, 0x30, 0x34, 0x18, 0x00,
|
||||
0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00,
|
||||
0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00,
|
||||
0x00, 0x00, 0xc6, 0xd6, 0xfe, 0xfe, 0x6c, 0x00,
|
||||
0x00, 0x00, 0xc6, 0x6c, 0x38, 0x6c, 0xc6, 0x00,
|
||||
0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8,
|
||||
0x00, 0x00, 0xfc, 0x98, 0x30, 0x64, 0xfc, 0x00,
|
||||
0x1c, 0x30, 0x30, 0xe0, 0x30, 0x30, 0x1c, 0x00,
|
||||
0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00,
|
||||
0xe0, 0x30, 0x30, 0x1c, 0x30, 0x30, 0xe0, 0x00,
|
||||
0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0x00,
|
||||
};
|
|
@ -0,0 +1,56 @@
|
|||
// Definitions for X86 IO port access.
|
||||
//
|
||||
// Copyright (C) 2008 Kevin O'Connor <kevin@koconnor.net>
|
||||
//
|
||||
// This file may be distributed under the terms of the GNU GPLv3 license.
|
||||
#ifndef __IOPORT_H
|
||||
#define __IOPORT_H
|
||||
|
||||
#include "types.h" // u8
|
||||
|
||||
#define PORT_DMA_ADDR_2 0x0004
|
||||
#define PORT_DMA_CNT_2 0x0005
|
||||
#define PORT_DMA1_MASK_REG 0x000a
|
||||
#define PORT_DMA1_MODE_REG 0x000b
|
||||
#define PORT_DMA1_CLEAR_FF_REG 0x000c
|
||||
#define PORT_DMA1_MASTER_CLEAR 0x000d
|
||||
#define PORT_PIC1 0x0020
|
||||
#define PORT_PIC1_DATA 0x0021
|
||||
#define PORT_PIT_COUNTER0 0x0040
|
||||
#define PORT_PIT_COUNTER1 0x0041
|
||||
#define PORT_PIT_COUNTER2 0x0042
|
||||
#define PORT_PIT_MODE 0x0043
|
||||
#define PORT_KBD_CTRLB 0x0061
|
||||
#define PORT_CMOS_INDEX 0x0070
|
||||
#define PORT_CMOS_DATA 0x0071
|
||||
#define PORT_DMA_PAGE_2 0x0081
|
||||
#define PORT_A20 0x0092
|
||||
#define PORT_PIC2 0x00a0
|
||||
#define PORT_PIC2_DATA 0x00a1
|
||||
#define PORT_DMA2_MASK_REG 0x00d4
|
||||
#define PORT_DMA2_MODE_REG 0x00d6
|
||||
#define PORT_DMA2_MASTER_CLEAR 0x00da
|
||||
#define PORT_FD_DOR 0x03f2
|
||||
#define PORT_FD_STATUS 0x03f4
|
||||
#define PORT_FD_DATA 0x03f5
|
||||
|
||||
// PORT_PIC1 bitdefs
|
||||
#define PIC1_IRQ5 (1<<5)
|
||||
// PORT_PIC2 bitdefs
|
||||
#define PIC2_IRQ8 (1<<0)
|
||||
#define PIC2_IRQ13 (1<<5)
|
||||
|
||||
// PORT_KBD_CTRLB bitdefs
|
||||
#define KBD_REFRESH (1<<4)
|
||||
|
||||
|
||||
static inline void outb(u8 value, u16 port) {
|
||||
__asm__ __volatile__("outb %b0, %w1" : : "a"(value), "Nd"(port));
|
||||
}
|
||||
static inline u8 inb(u16 port) {
|
||||
u8 value;
|
||||
__asm__ __volatile__("inb %w1, %b0" : "=a"(value) : "Nd"(port));
|
||||
return value;
|
||||
}
|
||||
|
||||
#endif // ioport.h
|
|
@ -0,0 +1,35 @@
|
|||
// 16bit code to handle keyboard requests.
|
||||
//
|
||||
// Copyright (C) 2008 Kevin O'Connor <kevin@koconnor.net>
|
||||
// Copyright (C) 2002 MandrakeSoft S.A.
|
||||
//
|
||||
// This file may be distributed under the terms of the GNU GPLv3 license.
|
||||
|
||||
#include "biosvar.h" // struct bregs
|
||||
#include "util.h" // debug_enter
|
||||
|
||||
void
|
||||
handle_15c2(struct bregs *regs)
|
||||
{
|
||||
}
|
||||
|
||||
// INT 16h Keyboard Service Entry Point
|
||||
void VISIBLE
|
||||
handle_16(struct bregs *regs)
|
||||
{
|
||||
//debug_enter(regs);
|
||||
}
|
||||
|
||||
// INT09h : Keyboard Hardware Service Entry Point
|
||||
void VISIBLE
|
||||
handle_09(struct bregs *regs)
|
||||
{
|
||||
debug_enter(regs);
|
||||
}
|
||||
|
||||
// INT74h : PS/2 mouse hardware interrupt
|
||||
void VISIBLE
|
||||
handle_74(struct bregs *regs)
|
||||
{
|
||||
debug_enter(regs);
|
||||
}
|
|
@ -0,0 +1,161 @@
|
|||
// Raw screen writing code.
|
||||
//
|
||||
// Copyright (C) 2008 Kevin O'Connor <kevin@koconnor.net>
|
||||
//
|
||||
// This file may be distributed under the terms of the GNU GPLv3 license.
|
||||
|
||||
#include <stdarg.h> // va_list
|
||||
|
||||
#include "farptr.h" // GET_VAR
|
||||
#include "util.h" // bprintf
|
||||
#include "biosvar.h" // struct bregs
|
||||
|
||||
static void
|
||||
screenc(char c)
|
||||
{
|
||||
// XXX
|
||||
}
|
||||
|
||||
// XXX
|
||||
#define PORT_DEBUG 0x403
|
||||
|
||||
// Write a charcter to the framebuffer.
|
||||
static void
|
||||
putc(u16 action, char c)
|
||||
{
|
||||
screenc(c);
|
||||
outb(c, PORT_DEBUG);
|
||||
}
|
||||
|
||||
// Write a string to the framebuffer.
|
||||
static void
|
||||
puts(u16 action, const char *s)
|
||||
{
|
||||
for (; *s; s++)
|
||||
putc(action, *s);
|
||||
}
|
||||
|
||||
// Write a string to the framebuffer.
|
||||
static void
|
||||
puts_cs(u16 action, const char *s)
|
||||
{
|
||||
for (;; s++) {
|
||||
char c = GET_VAR(CS, (u8)*s);
|
||||
if (!c)
|
||||
break;
|
||||
putc(action, c);
|
||||
}
|
||||
}
|
||||
|
||||
// Write an unsigned integer to the screen.
|
||||
static void
|
||||
putuint(u16 action, u32 val)
|
||||
{
|
||||
char buf[12];
|
||||
char *d = &buf[sizeof(buf) - 1];
|
||||
*d-- = '\0';
|
||||
for (;;) {
|
||||
*d = val % 10;
|
||||
val /= 10;
|
||||
if (!val)
|
||||
break;
|
||||
d--;
|
||||
}
|
||||
puts(action, d);
|
||||
}
|
||||
|
||||
// Write a single digit hex character to the screen.
|
||||
static inline void
|
||||
putsinglehex(u16 action, u32 val)
|
||||
{
|
||||
if (val <= 9)
|
||||
val = '0' + val;
|
||||
else
|
||||
val = 'a' + val - 10;
|
||||
putc(action, val);
|
||||
}
|
||||
|
||||
// Write an integer in hexadecimal to the screen.
|
||||
static void
|
||||
puthex(u16 action, u32 val)
|
||||
{
|
||||
putsinglehex(action, (val >> 28) & 0xf);
|
||||
putsinglehex(action, (val >> 24) & 0xf);
|
||||
putsinglehex(action, (val >> 20) & 0xf);
|
||||
putsinglehex(action, (val >> 16) & 0xf);
|
||||
putsinglehex(action, (val >> 12) & 0xf);
|
||||
putsinglehex(action, (val >> 8) & 0xf);
|
||||
putsinglehex(action, (val >> 4) & 0xf);
|
||||
putsinglehex(action, (val >> 0) & 0xf);
|
||||
}
|
||||
|
||||
void
|
||||
bprintf(u16 action, const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
const char *s = fmt;
|
||||
for (;; s++) {
|
||||
char c = GET_VAR(CS, (u8)*s);
|
||||
if (!c)
|
||||
break;
|
||||
if (c != '%') {
|
||||
putc(action, c);
|
||||
continue;
|
||||
}
|
||||
const char *n = s+1;
|
||||
c = GET_VAR(CS, (u8)*n);
|
||||
s32 val;
|
||||
const char *sarg;
|
||||
switch (c) {
|
||||
case '%':
|
||||
putc(action, '%');
|
||||
break;
|
||||
case 'd':
|
||||
val = va_arg(args, s32);
|
||||
if (val < 0) {
|
||||
putc(action, '-');
|
||||
val = -val;
|
||||
}
|
||||
putuint(action, val);
|
||||
break;
|
||||
case 'u':
|
||||
val = va_arg(args, s32);
|
||||
putuint(action, val);
|
||||
break;
|
||||
case 'x':
|
||||
val = va_arg(args, s32);
|
||||
puthex(action, val);
|
||||
break;
|
||||
case 's':
|
||||
sarg = va_arg(args, const char *);
|
||||
puts_cs(action, sarg);
|
||||
break;
|
||||
default:
|
||||
putc(action, *s);
|
||||
n = s;
|
||||
}
|
||||
s = n;
|
||||
}
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
// Function called on handler startup.
|
||||
void
|
||||
__debug_enter(const char *fname, struct bregs *regs)
|
||||
{
|
||||
bprintf(0, "enter %s: a=%x b=%x c=%x d=%x si=%x di=%x\n"
|
||||
, fname, regs->eax, regs->ebx, regs->ecx, regs->edx
|
||||
, regs->esi, regs->edi);
|
||||
bprintf(0, "&=%x ds=%x es=%x bp=%x sp=%x ip=%x cs=%x f=%x\n"
|
||||
, (u32)regs, regs->ds, regs->es, regs->ebp, regs->esp
|
||||
, regs->ip, regs->cs, regs->flags);
|
||||
}
|
||||
|
||||
void
|
||||
__debug_exit(const char *fname, struct bregs *regs)
|
||||
{
|
||||
bprintf(0, "exit %s: a=%x b=%x c=%x d=%x s=%x i=%x\n"
|
||||
, fname, regs->eax, regs->ebx, regs->ecx, regs->edx
|
||||
, regs->esi, regs->edi);
|
||||
}
|
|
@ -0,0 +1,312 @@
|
|||
// 32bit code to Power On Self Test (POST) a machine.
|
||||
//
|
||||
// Copyright (C) 2008 Kevin O'Connor <kevin@koconnor.net>
|
||||
// Copyright (C) 2002 MandrakeSoft S.A.
|
||||
//
|
||||
// This file may be distributed under the terms of the GNU GPLv3 license.
|
||||
|
||||
#include "ioport.h" // PORT_*
|
||||
#include "../out/rom16.offset.auto.h" // OFFSET_*
|
||||
#include "config.h" // CONFIG_*
|
||||
#include "cmos.h" // CMOS_*
|
||||
#include "util.h" // memset
|
||||
#include "biosvar.h" // struct bios_data_area_s
|
||||
|
||||
#define bda ((struct bios_data_area_s *)0)
|
||||
#define ebda ((struct extended_bios_data_area_s *)(EBDA_SEG<<4))
|
||||
|
||||
static void
|
||||
init_bda()
|
||||
{
|
||||
memset(bda, 0, sizeof(*bda));
|
||||
|
||||
int i;
|
||||
for (i=0; i<256; i++) {
|
||||
bda->ivecs[i].seg = 0xf000;
|
||||
bda->ivecs[i].offset = OFFSET_dummy_iret_handler;
|
||||
}
|
||||
|
||||
bda->mem_size_kb = BASE_MEM_IN_K;
|
||||
}
|
||||
|
||||
static void
|
||||
init_handlers()
|
||||
{
|
||||
// set vector 0x79 to zero
|
||||
// this is used by 'gardian angel' protection system
|
||||
bda->ivecs[0x79].seg = 0;
|
||||
bda->ivecs[0x79].offset = 0;
|
||||
|
||||
bda->ivecs[0x40].offset = OFFSET_entry_40;
|
||||
bda->ivecs[0x0e].offset = OFFSET_entry_0e;
|
||||
bda->ivecs[0x13].offset = OFFSET_entry_13;
|
||||
bda->ivecs[0x76].offset = OFFSET_entry_76;
|
||||
bda->ivecs[0x17].offset = OFFSET_entry_17;
|
||||
bda->ivecs[0x18].offset = OFFSET_entry_18;
|
||||
bda->ivecs[0x19].offset = OFFSET_entry_19;
|
||||
bda->ivecs[0x1c].offset = OFFSET_entry_1c;
|
||||
bda->ivecs[0x12].offset = OFFSET_entry_12;
|
||||
bda->ivecs[0x11].offset = OFFSET_entry_11;
|
||||
bda->ivecs[0x15].offset = OFFSET_entry_15;
|
||||
bda->ivecs[0x08].offset = OFFSET_entry_08;
|
||||
bda->ivecs[0x09].offset = OFFSET_entry_09;
|
||||
bda->ivecs[0x16].offset = OFFSET_entry_16;
|
||||
bda->ivecs[0x14].offset = OFFSET_entry_14;
|
||||
bda->ivecs[0x1a].offset = OFFSET_entry_1a;
|
||||
bda->ivecs[0x70].offset = OFFSET_entry_70;
|
||||
bda->ivecs[0x74].offset = OFFSET_entry_74;
|
||||
bda->ivecs[0x75].offset = OFFSET_entry_75;
|
||||
bda->ivecs[0x10].offset = OFFSET_entry_10;
|
||||
}
|
||||
|
||||
static void
|
||||
init_ebda()
|
||||
{
|
||||
ebda->size = EBDA_SIZE;
|
||||
bda->ebda_seg = EBDA_SEG;
|
||||
bda->ivecs[0x41].seg = EBDA_SEG;
|
||||
bda->ivecs[0x41].offset = 0x3d; // XXX
|
||||
bda->ivecs[0x46].seg = EBDA_SEG;
|
||||
bda->ivecs[0x46].offset = 0x4d; // XXX
|
||||
}
|
||||
|
||||
static void
|
||||
pit_setup()
|
||||
{
|
||||
// timer0: binary count, 16bit count, mode 2
|
||||
outb(0x34, PORT_PIT_MODE);
|
||||
// maximum count of 0000H = 18.2Hz
|
||||
outb(0x0, PORT_PIT_COUNTER0);
|
||||
outb(0x0, PORT_PIT_COUNTER0);
|
||||
}
|
||||
|
||||
static void
|
||||
kbd_init()
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
kbd_setup()
|
||||
{
|
||||
bda->kbd_mode = 0x10;
|
||||
bda->kbd_buf_head = bda->kbd_buf_tail = offsetof(struct bios_data_area_s, kbd_buf);
|
||||
bda->kbd_buf_start_offset = offsetof(struct bios_data_area_s, kbd_buf);
|
||||
bda->kbd_buf_end_offset = offsetof(struct bios_data_area_s, kbd_buf[sizeof(bda->kbd_buf)]);
|
||||
kbd_init();
|
||||
|
||||
// XXX
|
||||
u16 eqb = bda->equipment_list_flags;
|
||||
eqb = (eqb & 0xff00) | inb_cmos(CMOS_EQUIPMENT_INFO);
|
||||
bda->equipment_list_flags = eqb;
|
||||
}
|
||||
|
||||
static void
|
||||
lpt_setup()
|
||||
{
|
||||
// XXX
|
||||
}
|
||||
|
||||
static void
|
||||
serial_setup()
|
||||
{
|
||||
// XXX
|
||||
}
|
||||
|
||||
static u32
|
||||
bcd2bin(u8 val)
|
||||
{
|
||||
return (val & 0xf) + ((val >> 4) * 10);
|
||||
}
|
||||
|
||||
static void
|
||||
timer_setup()
|
||||
{
|
||||
u32 seconds = bcd2bin(inb_cmos(CMOS_RTC_SECONDS));
|
||||
u32 ticks = (seconds * 18206507) / 1000000;
|
||||
u32 minutes = bcd2bin(inb_cmos(CMOS_RTC_MINUTES));
|
||||
ticks += (minutes * 10923904) / 10000;
|
||||
u32 hours = bcd2bin(inb_cmos(CMOS_RTC_HOURS));
|
||||
ticks += (hours * 65543427) / 1000;
|
||||
bda->timer_counter = ticks;
|
||||
bda->timer_rollover = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
pic_setup()
|
||||
{
|
||||
outb(0x11, PORT_PIC1);
|
||||
outb(0x11, PORT_PIC2_DATA);
|
||||
outb(0x08, PORT_PIC1_DATA);
|
||||
outb(0x70, PORT_PIC2_DATA);
|
||||
outb(0x04, PORT_PIC1_DATA);
|
||||
outb(0x02, PORT_PIC2_DATA);
|
||||
outb(0x01, PORT_PIC1_DATA);
|
||||
outb(0x01, PORT_PIC2_DATA);
|
||||
outb(0xb8, PORT_PIC1_DATA);
|
||||
if (CONFIG_PS2_MOUSE)
|
||||
outb(0x8f, PORT_PIC2_DATA);
|
||||
else
|
||||
outb(0x9f, PORT_PIC2_DATA);
|
||||
}
|
||||
|
||||
static void
|
||||
floppy_drive_post()
|
||||
{
|
||||
u8 type = inb_cmos(CMOS_FLOPPY_DRIVE_TYPE);
|
||||
u8 out = 0;
|
||||
if (type & 0xf0)
|
||||
out |= 0x07;
|
||||
if (type & 0x0f)
|
||||
out |= 0x70;
|
||||
bda->floppy_harddisk_info = out;
|
||||
outb(0x02, PORT_DMA1_MASK_REG);
|
||||
|
||||
bda->ivecs[0x1E].offset = OFFSET_diskette_param_table2;
|
||||
}
|
||||
|
||||
static void
|
||||
cdemu_init()
|
||||
{
|
||||
//ebda->cdemu.active = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
ata_init()
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
ata_detect()
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
hard_drive_post()
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
init_boot_vectors()
|
||||
{
|
||||
}
|
||||
|
||||
static void __attribute__((noinline))
|
||||
call16(u16 seg, u16 offset)
|
||||
{
|
||||
u32 segoff = (seg << 16) | offset;
|
||||
asm volatile(
|
||||
"pushal\n" // Save registers
|
||||
"ljmp $0x20, %0\n" // Jump to 16bit transition code
|
||||
".globl call16_resume\n"
|
||||
"call16_resume:\n" // point of return
|
||||
"popal\n" // restore registers
|
||||
: : "Z" (OFFSET_call16), "b" (segoff));
|
||||
}
|
||||
|
||||
static int
|
||||
checksum(u8 *p, u32 len)
|
||||
{
|
||||
u32 i;
|
||||
u8 sum = 0;
|
||||
for (i=0; i<len; i++)
|
||||
sum += p[i];
|
||||
return sum;
|
||||
}
|
||||
|
||||
#define PTR_TO_SEG(p) ((((u32)(p)) >> 4) & 0xf000)
|
||||
#define PTR_TO_OFFSET(p) (((u32)(p)) & 0xffff)
|
||||
|
||||
static void
|
||||
rom_scan()
|
||||
{
|
||||
u8 *p = (u8*)0xc0000;
|
||||
for (; p <= (u8*)0xe0000; p += 2048) {
|
||||
u8 *rom = p;
|
||||
if (*(u16*)rom != 0xaa55)
|
||||
continue;
|
||||
u32 len = rom[2] * 512;
|
||||
if (checksum(rom, len) != 0)
|
||||
continue;
|
||||
p = (u8*)(((u32)p + len) / 2048 * 2048);
|
||||
call16(PTR_TO_SEG(rom), PTR_TO_OFFSET(rom + 3));
|
||||
|
||||
// Look at the ROM's PnP Expansion header. Properly, we're supposed
|
||||
// to init all the ROMs and then go back and build an IPL table of
|
||||
// all the bootable devices, but we can get away with one pass.
|
||||
if (rom[0x1a] != '$' || rom[0x1b] != 'P'
|
||||
|| rom[0x1c] != 'n' || rom[0x1d] != 'P')
|
||||
continue;
|
||||
// 0x1A is also the offset into the expansion header of...
|
||||
// the Bootstrap Entry Vector, or zero if there is none.
|
||||
u16 entry = *(u16*)&rom[0x1a+0x1a];
|
||||
if (!entry)
|
||||
continue;
|
||||
// Found a device that thinks it can boot the system. Record
|
||||
// its BEV and product name string.
|
||||
|
||||
// XXX
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
status_restart(u8 status)
|
||||
{
|
||||
#if 0
|
||||
if (status == 0x05)
|
||||
eoi_jmp_post();
|
||||
#endif
|
||||
|
||||
BX_PANIC("Unimplemented shutdown status: %02x\n",(Bit8u)status);
|
||||
}
|
||||
|
||||
static void
|
||||
post()
|
||||
{
|
||||
// first reset the DMA controllers
|
||||
outb(0, PORT_DMA1_MASTER_CLEAR);
|
||||
outb(0, PORT_DMA2_MASTER_CLEAR);
|
||||
|
||||
// then initialize the DMA controllers
|
||||
outb(0xc0, PORT_DMA2_MODE_REG);
|
||||
outb(0x00, PORT_DMA2_MASK_REG);
|
||||
|
||||
// Get and then clear CMOS shutdown status.
|
||||
u8 status = inb_cmos(CMOS_RESET_CODE);
|
||||
outb_cmos(0, CMOS_RESET_CODE);
|
||||
|
||||
if (status != 0x00 && status != 0x09 && status < 0x0d)
|
||||
status_restart(status);
|
||||
|
||||
BX_INFO("Start bios");
|
||||
|
||||
init_bda();
|
||||
init_handlers();
|
||||
init_ebda();
|
||||
|
||||
pit_setup();
|
||||
kbd_setup();
|
||||
lpt_setup();
|
||||
serial_setup();
|
||||
timer_setup();
|
||||
pic_setup();
|
||||
//pci_setup();
|
||||
init_boot_vectors();
|
||||
rom_scan();
|
||||
|
||||
printf("BIOS - begin\n\n");
|
||||
|
||||
floppy_drive_post();
|
||||
hard_drive_post();
|
||||
if (CONFIG_ATA) {
|
||||
ata_init();
|
||||
ata_detect();
|
||||
}
|
||||
cdemu_init();
|
||||
call16(0xf000, OFFSET_begin_boot);
|
||||
}
|
||||
|
||||
void VISIBLE
|
||||
_start()
|
||||
{
|
||||
post();
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
// Linker definitions for 32bit code
|
||||
//
|
||||
// Copyright (C) 2008 Kevin O'Connor <kevin@koconnor.net>
|
||||
// Copyright (C) 2002 MandrakeSoft S.A.
|
||||
//
|
||||
// This file may be distributed under the terms of the GNU GPLv3 license.
|
||||
|
||||
#include "config.h"
|
||||
#include "../out/rom16.offset.auto.h"
|
||||
|
||||
OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
|
||||
OUTPUT_ARCH(i386)
|
||||
ENTRY(_start);
|
||||
SECTIONS
|
||||
{
|
||||
. = (OFFSET_bios16c_end | 0xf0000);
|
||||
. = ALIGN(16);
|
||||
_text32_start = . ;
|
||||
.text : { *(.text) }
|
||||
.rodata : { *(.rodata) }
|
||||
. = ALIGN(16);
|
||||
.data : { *(.data) }
|
||||
__bss_start = . ;
|
||||
.bss : { *(.bss) *(COMMON) }
|
||||
_end = . ;
|
||||
/DISCARD/ : { *(.stab)
|
||||
*(.stabstr)
|
||||
*(.comment)
|
||||
*(.note)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,304 @@
|
|||
// Rom layout and bios assembler to C interface.
|
||||
//
|
||||
// Copyright (C) 2008 Kevin O'Connor <kevin@koconnor.net>
|
||||
// Copyright (C) 2002 MandrakeSoft S.A.
|
||||
//
|
||||
// This file may be distributed under the terms of the GNU GPLv3 license.
|
||||
|
||||
#include "config.h"
|
||||
|
||||
.code16gcc
|
||||
.text
|
||||
.globl bios16c_start, bios16c_end
|
||||
bios16c_start:
|
||||
.include "out/blob.proc.16.s"
|
||||
.text
|
||||
bios16c_end:
|
||||
|
||||
|
||||
.org 0xe05b
|
||||
.globl _start
|
||||
_start:
|
||||
.globl post16
|
||||
post16:
|
||||
|
||||
// Entry point of rombios32 code - the actual instruction is
|
||||
// altered later in the build process.
|
||||
.globl set_entry32
|
||||
set_entry32:
|
||||
mov $0xf0000000, %ebx
|
||||
|
||||
// init the stack pointer
|
||||
movl $ CONFIG_STACK32_OFFSET , %esp
|
||||
|
||||
transition32:
|
||||
// Disable irqs
|
||||
cli
|
||||
|
||||
// enable a20
|
||||
inb $0x92, %al
|
||||
orb $0x02, %al
|
||||
outb %al, $0x92
|
||||
|
||||
// Set segment descriptors
|
||||
lidt %cs:pmode_IDT_info
|
||||
lgdt %cs:rombios32_gdt_48
|
||||
|
||||
// set PE bit in CR0
|
||||
movl %cr0, %eax
|
||||
orb $0x01, %al
|
||||
movl %eax, %cr0
|
||||
|
||||
// start protected mode code
|
||||
.word 0xea66, 1f, 0x000f, 0x0010 // ljmpl $0x10, $(post32 | 0xf0000)
|
||||
|
||||
.code32
|
||||
1:
|
||||
// init data segments
|
||||
movl $0x18, %eax
|
||||
movw %ax, %ds
|
||||
movw %ax, %es
|
||||
movw %ax, %ss
|
||||
xorl %eax, %eax
|
||||
movw %ax, %fs
|
||||
movw %ax, %gs
|
||||
|
||||
cld
|
||||
|
||||
jmp *%ebx
|
||||
|
||||
.code16gcc
|
||||
|
||||
// We need a copy of this string, but we are not actually a PnP BIOS,
|
||||
// so make sure it is *not* aligned, so OSes will not see it if they
|
||||
// scan.
|
||||
.align 2
|
||||
.byte 0
|
||||
pnp_string:
|
||||
.ascii "$PnP"
|
||||
|
||||
// Return from 32bit code to 16bit code - must pass in destination
|
||||
// code segment,offset (%ebx) and the return stack position (%esp).
|
||||
|
||||
.globl call16
|
||||
call16:
|
||||
// restore data segment limits to 0xffff
|
||||
movw $0x28, %ax
|
||||
movw %ax, %ds
|
||||
movw %ax, %es
|
||||
movw %ax, %ss
|
||||
movw %ax, %fs
|
||||
movw %ax, %gs
|
||||
|
||||
// reset PE bit in CR0
|
||||
movl %cr0, %eax
|
||||
andb $0xfe, %al
|
||||
movl %eax, %cr0
|
||||
|
||||
// far jump to flush CPU queue after transition to real mode
|
||||
ljmpw $0xf000, $1f
|
||||
1:
|
||||
// restore IDT to normal real-mode defaults
|
||||
lidt %cs:rmode_IDT_info
|
||||
|
||||
// Setup segment registers
|
||||
xorw %ax, %ax
|
||||
movw %ax, %ds
|
||||
movw %ax, %fs
|
||||
movw %ax, %gs
|
||||
movw $0xf000, %ax
|
||||
movw %ax, %es
|
||||
lea pnp_string, %di
|
||||
movw $ CONFIG_STACK16_SEGMENT , %ax
|
||||
movw %ax, %ss
|
||||
movl %esp, %eax
|
||||
movl $ CONFIG_STACK16_OFFSET , %esp
|
||||
|
||||
// Save info
|
||||
pushl %eax
|
||||
pushl %ebx
|
||||
movl %esp, %ebp
|
||||
|
||||
lcallw %ss:*(%bp)
|
||||
|
||||
// Restore stack and jump back to 32bit mode.
|
||||
popl %eax
|
||||
popl %esp
|
||||
|
||||
// Resume point of rombios32 code - the actual instruction is
|
||||
// altered later in the build process.
|
||||
.globl set_resume32
|
||||
set_resume32:
|
||||
mov $0xf0000000, %ebx
|
||||
|
||||
jmp transition32
|
||||
|
||||
|
||||
// Protected mode IDT descriptor
|
||||
//
|
||||
// I just make the limit 0, so the machine will shutdown
|
||||
// if an exception occurs during protected mode memory
|
||||
// transfers.
|
||||
//
|
||||
// Set base to f0000 to correspond to beginning of BIOS,
|
||||
// in case I actually define an IDT later
|
||||
// Set limit to 0
|
||||
pmode_IDT_info:
|
||||
.word 0x0000 // limit 15:00
|
||||
.word 0x0000 // base 15:00
|
||||
.byte 0x0f // base 23:16
|
||||
|
||||
// Real mode IDT descriptor
|
||||
//
|
||||
// Set to typical real-mode values.
|
||||
// base = 000000
|
||||
// limit = 03ff
|
||||
rmode_IDT_info:
|
||||
.word 0x03ff // limit 15:00
|
||||
.word 0x0000 // base 15:00
|
||||
.byte 0x00 // base 23:16
|
||||
|
||||
rombios32_gdt_48:
|
||||
.word 0x30
|
||||
.word rombios32_gdt
|
||||
.word 0x000f
|
||||
|
||||
rombios32_gdt:
|
||||
.word 0, 0, 0, 0
|
||||
.word 0, 0, 0, 0
|
||||
.word 0xffff, 0, 0x9b00, 0x00cf // 32 bit flat code segment (0x10)
|
||||
.word 0xffff, 0, 0x9300, 0x00cf // 32 bit flat data segment (0x18)
|
||||
.word 0xffff, 0, 0x9b0f, 0x0000 // 16 bit code segment base=0xf0000 limit=0xffff
|
||||
.word 0xffff, 0, 0x9300, 0x0000 // 16 bit data segment base=0x0 limit=0xffff
|
||||
|
||||
|
||||
.macro ENTRY cfunc
|
||||
pushal
|
||||
pushw %es
|
||||
pushw %ds
|
||||
movw %ss, %ax
|
||||
movw %ax, %ds
|
||||
mov %esp, %eax
|
||||
call \cfunc
|
||||
popw %ds
|
||||
popw %es
|
||||
popal
|
||||
.endm
|
||||
|
||||
.macro IRQ_ENTRY num
|
||||
.globl entry_\num
|
||||
entry_\num :
|
||||
ENTRY handle_\num
|
||||
iretw
|
||||
.endm
|
||||
|
||||
|
||||
.org 0xe2c3
|
||||
IRQ_ENTRY nmi
|
||||
|
||||
IRQ_ENTRY 13
|
||||
IRQ_ENTRY 19
|
||||
IRQ_ENTRY 12
|
||||
IRQ_ENTRY 11
|
||||
IRQ_ENTRY 76
|
||||
IRQ_ENTRY 18
|
||||
IRQ_ENTRY 1c
|
||||
IRQ_ENTRY 70
|
||||
IRQ_ENTRY 74
|
||||
IRQ_ENTRY 75
|
||||
|
||||
.org 0xe3fe
|
||||
jmp entry_13
|
||||
|
||||
.org 0xe401
|
||||
// XXX - Fixed Disk Parameter Table
|
||||
|
||||
.org 0xe6f2
|
||||
jmp entry_19
|
||||
|
||||
.org 0xe6f5
|
||||
.include "out/cbt.proc.16.s"
|
||||
.text
|
||||
|
||||
.org 0xe729
|
||||
// XXX - Baud Rate Generator Table
|
||||
|
||||
.org 0xe739
|
||||
IRQ_ENTRY 14
|
||||
|
||||
.org 0xe82e
|
||||
IRQ_ENTRY 16
|
||||
|
||||
.org 0xe987
|
||||
IRQ_ENTRY 09
|
||||
|
||||
.org 0xec59
|
||||
IRQ_ENTRY 40
|
||||
|
||||
.org 0xef57
|
||||
IRQ_ENTRY 0e
|
||||
|
||||
.org 0xefc7
|
||||
// XXX - Diskette Controller Parameter Table
|
||||
|
||||
.org 0xefd2
|
||||
IRQ_ENTRY 17
|
||||
|
||||
.org 0xf045
|
||||
// XXX int 10
|
||||
iretw
|
||||
|
||||
.org 0xf065
|
||||
IRQ_ENTRY 10
|
||||
|
||||
.org 0xf0a4
|
||||
// XXX int 1D
|
||||
iretw
|
||||
|
||||
.org 0xf841
|
||||
jmp entry_12
|
||||
|
||||
.org 0xf84d
|
||||
jmp entry_11
|
||||
|
||||
.org 0xf859
|
||||
IRQ_ENTRY 15
|
||||
|
||||
.org 0xfa6e
|
||||
.include "out/font.proc.16.s"
|
||||
.text
|
||||
|
||||
.org 0xfe6e
|
||||
IRQ_ENTRY 1a
|
||||
|
||||
.org 0xfea5
|
||||
IRQ_ENTRY 08
|
||||
|
||||
.org 0xfef3
|
||||
// XXX - Initial Interrupt Vector Offsets Loaded by POST
|
||||
|
||||
.org 0xff00
|
||||
// XXX - BIOS_COPYRIGHT_STRING
|
||||
.ascii "(c) 2002 MandrakeSoft S.A. Written by Kevin Lawton & the Bochs team."
|
||||
|
||||
.org 0xff53
|
||||
.globl dummy_iret_handler
|
||||
dummy_iret_handler:
|
||||
iretw
|
||||
|
||||
.org 0xff54
|
||||
IRQ_ENTRY 05
|
||||
|
||||
.org 0xfff0 // Power-up Entry Point
|
||||
ljmpw $0xf000, $post16
|
||||
|
||||
.org 0xfff5
|
||||
// BIOS build date
|
||||
.ascii "06/23/99"
|
||||
|
||||
.org 0xfffe
|
||||
// model byte 0xFC = AT
|
||||
.byte 0xfc
|
||||
.byte 0x00
|
||||
|
||||
.end
|
|
@ -0,0 +1,23 @@
|
|||
// 16bit code to handle serial and printer services.
|
||||
//
|
||||
// Copyright (C) 2008 Kevin O'Connor <kevin@koconnor.net>
|
||||
// Copyright (C) 2002 MandrakeSoft S.A.
|
||||
//
|
||||
// This file may be distributed under the terms of the GNU GPLv3 license.
|
||||
|
||||
#include "biosvar.h" // struct bregs
|
||||
#include "util.h" // debug_enter
|
||||
|
||||
// INT 14h Serial Communications Service Entry Point
|
||||
void VISIBLE
|
||||
handle_14(struct bregs *regs)
|
||||
{
|
||||
debug_enter(regs);
|
||||
}
|
||||
|
||||
// INT17h : Printer Service Entry Point
|
||||
void VISIBLE
|
||||
handle_17(struct bregs *regs)
|
||||
{
|
||||
debug_enter(regs);
|
||||
}
|
|
@ -0,0 +1,529 @@
|
|||
// 16bit system callbacks
|
||||
//
|
||||
// Copyright (C) 2008 Kevin O'Connor <kevin@koconnor.net>
|
||||
// Copyright (C) 2002 MandrakeSoft S.A.
|
||||
//
|
||||
// This file may be distributed under the terms of the GNU GPLv3 license.
|
||||
|
||||
#include "util.h" // irq_restore
|
||||
#include "biosvar.h" // CONFIG_BIOS_TABLE
|
||||
#include "ioport.h" // inb
|
||||
#include "cmos.h" // inb_cmos
|
||||
|
||||
#define RET_EUNSUPPORTED 0x86
|
||||
|
||||
|
||||
// Use PS2 System Control port A to set A20 enable
|
||||
static inline u8
|
||||
set_a20(u8 cond)
|
||||
{
|
||||
// get current setting first
|
||||
u8 newval, oldval = inb(PORT_A20);
|
||||
if (cond)
|
||||
newval = oldval | 0x02;
|
||||
else
|
||||
newval = oldval & ~0x02;
|
||||
outb(newval, PORT_A20);
|
||||
|
||||
return (newval & 0x02) != 0;
|
||||
}
|
||||
|
||||
static inline void
|
||||
handle_ret(struct bregs *regs, u8 code)
|
||||
{
|
||||
regs->ah = code;
|
||||
set_cf(regs, code);
|
||||
}
|
||||
|
||||
static void
|
||||
handle_152400(struct bregs *regs)
|
||||
{
|
||||
set_a20(0);
|
||||
handle_ret(regs, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
handle_152401(struct bregs *regs)
|
||||
{
|
||||
set_a20(1);
|
||||
handle_ret(regs, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
handle_152402(struct bregs *regs)
|
||||
{
|
||||
regs->al = !!(inb(PORT_A20) & 0x20);
|
||||
handle_ret(regs, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
handle_152403(struct bregs *regs)
|
||||
{
|
||||
regs->bx = 3;
|
||||
handle_ret(regs, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
handle_1524XX(struct bregs *regs)
|
||||
{
|
||||
handle_ret(regs, RET_EUNSUPPORTED);
|
||||
}
|
||||
|
||||
// removable media eject
|
||||
static void
|
||||
handle_1552(struct bregs *regs)
|
||||
{
|
||||
handle_ret(regs, 0);
|
||||
}
|
||||
|
||||
// Set Interval requested.
|
||||
static void
|
||||
handle_158300(struct bregs *regs)
|
||||
{
|
||||
if (GET_BDA(rtc_wait_flag) & RWS_WAIT_PENDING) {
|
||||
// Interval already set.
|
||||
DEBUGF("int15: Func 83h, failed, already waiting.\n" );
|
||||
handle_ret(regs, RET_EUNSUPPORTED);
|
||||
}
|
||||
// Interval not already set.
|
||||
SET_BDA(rtc_wait_flag, RWS_WAIT_PENDING); // Set status byte.
|
||||
u32 v = (regs->es << 16) | regs->bx;
|
||||
SET_BDA(ptr_user_wait_complete_flag, v);
|
||||
v = (regs->dx << 16) | regs->cx;
|
||||
SET_BDA(user_wait_timeout, v);
|
||||
|
||||
// Unmask IRQ8 so INT70 will get through.
|
||||
u8 irqDisable = inb(PORT_PIC2_DATA);
|
||||
outb(irqDisable & ~PIC2_IRQ8, PORT_PIC2_DATA);
|
||||
// Turn on the Periodic Interrupt timer
|
||||
u8 bRegister = inb_cmos(CMOS_STATUS_B);
|
||||
outb_cmos(CMOS_STATUS_B, bRegister | CSB_EN_ALARM_IRQ);
|
||||
|
||||
set_cf(regs, 0); // XXX - no set ah?
|
||||
}
|
||||
|
||||
// Clear interval requested
|
||||
static void
|
||||
handle_158301(struct bregs *regs)
|
||||
{
|
||||
SET_BDA(rtc_wait_flag, 0); // Clear status byte
|
||||
// Turn off the Periodic Interrupt timer
|
||||
u8 bRegister = inb_cmos(CMOS_STATUS_B);
|
||||
outb_cmos(CMOS_STATUS_B, bRegister & ~CSB_EN_ALARM_IRQ);
|
||||
set_cf(regs, 0); // XXX - no set ah?
|
||||
}
|
||||
|
||||
static void
|
||||
handle_1583XX(struct bregs *regs)
|
||||
{
|
||||
regs->al--;
|
||||
handle_ret(regs, RET_EUNSUPPORTED);
|
||||
}
|
||||
|
||||
// Sleep for n microseconds. currently using the
|
||||
// refresh request port 0x61 bit4, toggling every 15usec
|
||||
static void
|
||||
usleep(u32 count)
|
||||
{
|
||||
count = count / 15;
|
||||
u8 kbd = inb(PORT_KBD_CTRLB);
|
||||
while (count)
|
||||
if ((inb(PORT_KBD_CTRLB) ^ kbd) & KBD_REFRESH)
|
||||
count--;
|
||||
}
|
||||
|
||||
// Wait for CX:DX microseconds. currently using the
|
||||
// refresh request port 0x61 bit4, toggling every 15usec
|
||||
static void
|
||||
handle_1586(struct bregs *regs)
|
||||
{
|
||||
irq_enable();
|
||||
usleep((regs->cx << 16) | regs->dx);
|
||||
irq_disable();
|
||||
}
|
||||
|
||||
static void
|
||||
handle_1587(struct bregs *regs)
|
||||
{
|
||||
// +++ should probably have descriptor checks
|
||||
// +++ should have exception handlers
|
||||
|
||||
// turn off interrupts
|
||||
unsigned long flags = irq_save();
|
||||
|
||||
u8 prev_a20_enable = set_a20(1); // enable A20 line
|
||||
|
||||
// 128K max of transfer on 386+ ???
|
||||
// source == destination ???
|
||||
|
||||
// ES:SI points to descriptor table
|
||||
// offset use initially comments
|
||||
// ==============================================
|
||||
// 00..07 Unused zeros Null descriptor
|
||||
// 08..0f GDT zeros filled in by BIOS
|
||||
// 10..17 source ssssssss source of data
|
||||
// 18..1f dest dddddddd destination of data
|
||||
// 20..27 CS zeros filled in by BIOS
|
||||
// 28..2f SS zeros filled in by BIOS
|
||||
|
||||
//es:si
|
||||
//eeee0
|
||||
//0ssss
|
||||
//-----
|
||||
|
||||
// check for access rights of source & dest here
|
||||
|
||||
// Initialize GDT descriptor
|
||||
u16 si = regs->si;
|
||||
u16 base15_00 = (regs->es << 4) + si;
|
||||
u16 base23_16 = regs->es >> 12;
|
||||
if (base15_00 < (regs->es<<4))
|
||||
base23_16++;
|
||||
SET_VAR(ES, *(u16*)(si+0x08+0), 47); // limit 15:00 = 6 * 8bytes/descriptor
|
||||
SET_VAR(ES, *(u16*)(si+0x08+2), base15_00);// base 15:00
|
||||
SET_VAR(ES, *(u8 *)(si+0x08+4), base23_16);// base 23:16
|
||||
SET_VAR(ES, *(u8 *)(si+0x08+5), 0x93); // access
|
||||
SET_VAR(ES, *(u16*)(si+0x08+6), 0x0000); // base 31:24/reserved/limit 19:16
|
||||
|
||||
// Initialize CS descriptor
|
||||
SET_VAR(ES, *(u16*)(si+0x20+0), 0xffff);// limit 15:00 = normal 64K limit
|
||||
SET_VAR(ES, *(u16*)(si+0x20+2), 0x0000);// base 15:00
|
||||
SET_VAR(ES, *(u8 *)(si+0x20+4), 0x000f);// base 23:16
|
||||
SET_VAR(ES, *(u8 *)(si+0x20+5), 0x9b); // access
|
||||
SET_VAR(ES, *(u16*)(si+0x20+6), 0x0000);// base 31:24/reserved/limit 19:16
|
||||
|
||||
// Initialize SS descriptor
|
||||
u16 ss = GET_SEG(SS);
|
||||
base15_00 = ss << 4;
|
||||
base23_16 = ss >> 12;
|
||||
SET_VAR(ES, *(u16*)(si+0x28+0), 0xffff); // limit 15:00 = normal 64K limit
|
||||
SET_VAR(ES, *(u16*)(si+0x28+2), base15_00);// base 15:00
|
||||
SET_VAR(ES, *(u8 *)(si+0x28+4), base23_16);// base 23:16
|
||||
SET_VAR(ES, *(u8 *)(si+0x28+5), 0x93); // access
|
||||
SET_VAR(ES, *(u16*)(si+0x28+6), 0x0000); // base 31:24/reserved/limit 19:16
|
||||
|
||||
asm volatile(
|
||||
// Save registers
|
||||
"pushw %%ds\n"
|
||||
"pushw %%es\n"
|
||||
"pushal\n"
|
||||
|
||||
// Load new descriptor tables
|
||||
"lgdt %%es:(%1)\n"
|
||||
"lidt %%cs:pmode_IDT_info\n"
|
||||
|
||||
// set PE bit in CR0
|
||||
"movl %%cr0, %%eax\n"
|
||||
"orb $0x01, %%al\n"
|
||||
"movl %%eax, %%cr0\n"
|
||||
|
||||
// far jump to flush CPU queue after transition to protected mode
|
||||
"ljmpw $0xf000, $1f\n"
|
||||
"1:\n"
|
||||
|
||||
// GDT points to valid descriptor table, now load DS, ES
|
||||
"movw $0x10, %%ax\n" // 010 000 = 2nd descriptor in table, TI=GDT, RPL=00
|
||||
"movw %%ax, %%ds\n"
|
||||
"movw $0x18, %%ax\n" // 011 000 = 3rd descriptor in table, TI=GDT, RPL=00
|
||||
"movw %%ax, %%es\n"
|
||||
|
||||
// move CX words from DS:SI to ES:DI
|
||||
"xorw %%si, %%si\n"
|
||||
"xorw %%di, %%di\n"
|
||||
"cld\n"
|
||||
"rep movsw\n"
|
||||
|
||||
// reset PG bit in CR0 ???
|
||||
"movl %%cr0, %%eax\n"
|
||||
"andb $0xfe, %%al\n"
|
||||
"movl %%eax, %%cr0\n"
|
||||
|
||||
// far jump to flush CPU queue after transition to real mode
|
||||
"ljmpw $0xf000, $2f\n"
|
||||
"2:\n"
|
||||
|
||||
// restore IDT to normal real-mode defaults
|
||||
"lidt %%cs:rmode_IDT_info\n"
|
||||
|
||||
// restore regisers
|
||||
"popal\n"
|
||||
"popw %%es\n"
|
||||
"popw %%ds\n" : : "c" (regs->cx), "r" (si + 8));
|
||||
|
||||
set_a20(prev_a20_enable);
|
||||
|
||||
irq_restore(flags);
|
||||
|
||||
handle_ret(regs, 0);
|
||||
}
|
||||
|
||||
// Get the amount of extended memory (above 1M)
|
||||
static void
|
||||
handle_1588(struct bregs *regs)
|
||||
{
|
||||
regs->al = inb_cmos(CMOS_EXTMEM_LOW);
|
||||
regs->ah = inb_cmos(CMOS_EXTMEM_HIGH);
|
||||
// According to Ralf Brown's interrupt the limit should be 15M,
|
||||
// but real machines mostly return max. 63M.
|
||||
if (regs->ax > 0xffc0)
|
||||
regs->ax = 0xffc0;
|
||||
set_cf(regs, 0);
|
||||
}
|
||||
|
||||
// Device busy interrupt. Called by Int 16h when no key available
|
||||
static void
|
||||
handle_1590(struct bregs *regs)
|
||||
{
|
||||
}
|
||||
|
||||
// Interrupt complete. Called by Int 16h when key becomes available
|
||||
static void
|
||||
handle_1591(struct bregs *regs)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
handle_15c0(struct bregs *regs)
|
||||
{
|
||||
regs->es = SEG_BIOS;
|
||||
regs->bx = (u16)&BIOS_CONFIG_TABLE;
|
||||
}
|
||||
|
||||
static void
|
||||
handle_15c1(struct bregs *regs)
|
||||
{
|
||||
regs->es = GET_BDA(ebda_seg);
|
||||
set_cf(regs, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
handle_15e801(struct bregs *regs)
|
||||
{
|
||||
// my real system sets ax and bx to 0
|
||||
// this is confirmed by Ralph Brown list
|
||||
// but syslinux v1.48 is known to behave
|
||||
// strangely if ax is set to 0
|
||||
// regs.u.r16.ax = 0;
|
||||
// regs.u.r16.bx = 0;
|
||||
|
||||
// Get the amount of extended memory (above 1M)
|
||||
regs->cl = inb_cmos(CMOS_EXTMEM_LOW);
|
||||
regs->ch = inb_cmos(CMOS_EXTMEM_HIGH);
|
||||
|
||||
// limit to 15M
|
||||
if (regs->cx > 0x3c00)
|
||||
regs->cx = 0x3c00;
|
||||
|
||||
// Get the amount of extended memory above 16M in 64k blocs
|
||||
regs->dl = inb_cmos(CMOS_EXTMEM2_LOW);
|
||||
regs->dh = inb_cmos(CMOS_EXTMEM2_HIGH);
|
||||
|
||||
// Set configured memory equal to extended memory
|
||||
regs->ax = regs->cx;
|
||||
regs->bx = regs->dx;
|
||||
|
||||
set_cf(regs, 0);
|
||||
}
|
||||
|
||||
#define ACPI_DATA_SIZE 0x00010000L
|
||||
|
||||
static void
|
||||
set_e820_range(u16 DI, u32 start, u32 end, u16 type)
|
||||
{
|
||||
SET_VAR(ES, *(u16*)(DI+0), start);
|
||||
SET_VAR(ES, *(u16*)(DI+2), start >> 16);
|
||||
SET_VAR(ES, *(u16*)(DI+4), 0x00);
|
||||
SET_VAR(ES, *(u16*)(DI+6), 0x00);
|
||||
|
||||
end -= start;
|
||||
SET_VAR(ES, *(u16*)(DI+8), end);
|
||||
SET_VAR(ES, *(u16*)(DI+10), end >> 16);
|
||||
SET_VAR(ES, *(u16*)(DI+12), 0x0000);
|
||||
SET_VAR(ES, *(u16*)(DI+14), 0x0000);
|
||||
|
||||
SET_VAR(ES, *(u16*)(DI+16), type);
|
||||
SET_VAR(ES, *(u16*)(DI+18), 0x0);
|
||||
}
|
||||
|
||||
// XXX - should create e820 memory map in post and just copy it here.
|
||||
static void
|
||||
handle_15e820(struct bregs *regs)
|
||||
{
|
||||
if (regs->edx != 0x534D4150) {
|
||||
handle_ret(regs, RET_EUNSUPPORTED);
|
||||
return;
|
||||
}
|
||||
|
||||
u32 extended_memory_size = inb_cmos(CMOS_EXTMEM2_HIGH);
|
||||
extended_memory_size <<= 8;
|
||||
extended_memory_size |= inb_cmos(CMOS_EXTMEM2_LOW);
|
||||
extended_memory_size *= 64;
|
||||
// greater than EFF00000???
|
||||
if (extended_memory_size > 0x3bc000)
|
||||
// everything after this is reserved memory until we get to 0x100000000
|
||||
extended_memory_size = 0x3bc000;
|
||||
extended_memory_size *= 1024;
|
||||
extended_memory_size += (16L * 1024 * 1024);
|
||||
|
||||
if (extended_memory_size <= (16L * 1024 * 1024)) {
|
||||
extended_memory_size = inb_cmos(CMOS_EXTMEM_HIGH);
|
||||
extended_memory_size <<= 8;
|
||||
extended_memory_size |= inb_cmos(CMOS_EXTMEM_LOW);
|
||||
extended_memory_size *= 1024;
|
||||
}
|
||||
|
||||
switch (regs->bx) {
|
||||
case 0:
|
||||
set_e820_range(regs->di, 0x0000000L, 0x0009fc00L, 1);
|
||||
regs->ebx = 1;
|
||||
regs->eax = 0x534D4150;
|
||||
regs->ecx = 0x14;
|
||||
set_cf(regs, 0);
|
||||
break;
|
||||
case 1:
|
||||
set_e820_range(regs->di, 0x0009fc00L, 0x000a0000L, 2);
|
||||
regs->ebx = 2;
|
||||
regs->eax = 0x534D4150;
|
||||
regs->ecx = 0x14;
|
||||
set_cf(regs, 0);
|
||||
break;
|
||||
case 2:
|
||||
set_e820_range(regs->di, 0x000e8000L, 0x00100000L, 2);
|
||||
regs->ebx = 3;
|
||||
regs->eax = 0x534D4150;
|
||||
regs->ecx = 0x14;
|
||||
set_cf(regs, 0);
|
||||
break;
|
||||
case 3:
|
||||
set_e820_range(regs->di, 0x00100000L,
|
||||
extended_memory_size - ACPI_DATA_SIZE, 1);
|
||||
regs->ebx = 4;
|
||||
regs->eax = 0x534D4150;
|
||||
regs->ecx = 0x14;
|
||||
set_cf(regs, 0);
|
||||
break;
|
||||
case 4:
|
||||
set_e820_range(regs->di,
|
||||
extended_memory_size - ACPI_DATA_SIZE,
|
||||
extended_memory_size, 3); // ACPI RAM
|
||||
regs->ebx = 5;
|
||||
regs->eax = 0x534D4150;
|
||||
regs->ecx = 0x14;
|
||||
set_cf(regs, 0);
|
||||
break;
|
||||
case 5:
|
||||
/* 256KB BIOS area at the end of 4 GB */
|
||||
set_e820_range(regs->di, 0xfffc0000L, 0x00000000L, 2);
|
||||
regs->ebx = 0;
|
||||
regs->eax = 0x534D4150;
|
||||
regs->ecx = 0x14;
|
||||
set_cf(regs, 0);
|
||||
break;
|
||||
default: /* AX=E820, DX=534D4150, BX unrecognized */
|
||||
handle_ret(regs, RET_EUNSUPPORTED);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
handle_15e8XX(struct bregs *regs)
|
||||
{
|
||||
regs->al--;
|
||||
handle_ret(regs, RET_EUNSUPPORTED);
|
||||
}
|
||||
|
||||
static void
|
||||
handle_15XX(struct bregs *regs)
|
||||
{
|
||||
regs->al--;
|
||||
handle_ret(regs, RET_EUNSUPPORTED);
|
||||
}
|
||||
|
||||
// INT 15h System Services Entry Point
|
||||
void VISIBLE
|
||||
handle_15(struct bregs *regs)
|
||||
{
|
||||
debug_enter(regs);
|
||||
switch (regs->ah) {
|
||||
case 0x24:
|
||||
switch (regs->al) {
|
||||
case 0x00: handle_152400(regs); break;
|
||||
case 0x01: handle_152401(regs); break;
|
||||
case 0x02: handle_152402(regs); break;
|
||||
case 0x03: handle_152403(regs); break;
|
||||
default: handle_1524XX(regs); break;
|
||||
}
|
||||
break;
|
||||
case 0x52: handle_1552(regs); break;
|
||||
case 0x83:
|
||||
switch (regs->al) {
|
||||
case 0x00: handle_158300(regs); break;
|
||||
case 0x01: handle_158301(regs); break;
|
||||
default: handle_1583XX(regs); break;
|
||||
}
|
||||
break;
|
||||
case 0x86: handle_1586(regs); break;
|
||||
case 0x87: handle_1587(regs); break;
|
||||
case 0x88: handle_1588(regs); break;
|
||||
case 0x90: handle_1590(regs); break;
|
||||
case 0x91: handle_1591(regs); break;
|
||||
case 0xc0: handle_15c0(regs); break;
|
||||
case 0xc1: handle_15c1(regs); break;
|
||||
case 0xc2: handle_15c2(regs); break;
|
||||
case 0xe8:
|
||||
switch (regs->al) {
|
||||
case 0x01: handle_15e801(regs); break;
|
||||
case 0x20: handle_15e820(regs); break;
|
||||
default: handle_15e8XX(regs); break;
|
||||
}
|
||||
break;
|
||||
default: handle_15XX(regs); break;
|
||||
}
|
||||
debug_exit(regs);
|
||||
}
|
||||
|
||||
// INT 12h Memory Size Service Entry Point
|
||||
void VISIBLE
|
||||
handle_12(struct bregs *regs)
|
||||
{
|
||||
debug_enter(regs);
|
||||
regs->ax = GET_BDA(mem_size_kb);
|
||||
debug_exit(regs);
|
||||
}
|
||||
|
||||
// INT 11h Equipment List Service Entry Point
|
||||
void VISIBLE
|
||||
handle_11(struct bregs *regs)
|
||||
{
|
||||
debug_enter(regs);
|
||||
regs->ax = GET_BDA(equipment_list_flags);
|
||||
debug_exit(regs);
|
||||
}
|
||||
|
||||
// INT 05h Print Screen Service Entry Point
|
||||
void VISIBLE
|
||||
handle_05(struct bregs *regs)
|
||||
{
|
||||
debug_enter(regs);
|
||||
}
|
||||
|
||||
// INT 10h Video Support Service Entry Point
|
||||
void VISIBLE
|
||||
handle_10(struct bregs *regs)
|
||||
{
|
||||
debug_enter(regs);
|
||||
// dont do anything, since the VGA BIOS handles int10h requests
|
||||
}
|
||||
|
||||
void VISIBLE
|
||||
handle_nmi(struct bregs *regs)
|
||||
{
|
||||
debug_enter(regs);
|
||||
// XXX
|
||||
}
|
||||
|
||||
// INT 75 - IRQ13 - MATH COPROCESSOR EXCEPTION
|
||||
void VISIBLE
|
||||
handle_75(struct bregs *regs)
|
||||
{
|
||||
debug_enter(regs);
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
// Basic type definitions for X86 cpus.
|
||||
//
|
||||
// Copyright (C) 2008 Kevin O'Connor <kevin@koconnor.net>
|
||||
//
|
||||
// This file may be distributed under the terms of the GNU GPLv3 license.
|
||||
#ifndef __TYPES_H
|
||||
#define __TYPES_H
|
||||
|
||||
typedef unsigned char u8;
|
||||
typedef signed char s8;
|
||||
typedef unsigned short u16;
|
||||
typedef signed short s16;
|
||||
typedef unsigned int u32;
|
||||
typedef signed int s32;
|
||||
typedef u32 size_t;
|
||||
|
||||
#define VISIBLE __attribute__((externally_visible))
|
||||
|
||||
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
|
||||
|
||||
#endif // types.h
|
|
@ -0,0 +1,55 @@
|
|||
// Basic x86 asm functions and function defs.
|
||||
//
|
||||
// Copyright (C) 2008 Kevin O'Connor <kevin@koconnor.net>
|
||||
//
|
||||
// This file may be distributed under the terms of the GNU GPLv3 license.
|
||||
|
||||
#include "ioport.h" // outb
|
||||
|
||||
static inline void irq_disable(void) {
|
||||
asm volatile("cli": : :"memory");
|
||||
}
|
||||
|
||||
static inline void irq_enable(void) {
|
||||
asm volatile("sti": : :"memory");
|
||||
}
|
||||
|
||||
static inline unsigned long irq_save(void)
|
||||
{
|
||||
unsigned long flags;
|
||||
asm volatile("pushfl ; popl %0" : "=g" (flags));
|
||||
irq_disable();
|
||||
return flags;
|
||||
}
|
||||
|
||||
static inline void irq_restore(unsigned long flags)
|
||||
{
|
||||
asm volatile("pushl %0 ; popfl" : : "g" (flags) : "memory", "cc");
|
||||
}
|
||||
|
||||
#define DEBUGF(fmt, args...)
|
||||
#define BX_PANIC(fmt, args...)
|
||||
#define BX_INFO(fmt, args...)
|
||||
|
||||
static inline void
|
||||
memset(void *s, int c, size_t n)
|
||||
{
|
||||
while (n)
|
||||
((char *)s)[n--] = c;
|
||||
}
|
||||
|
||||
// output.c
|
||||
void bprintf(u16 action, const char *fmt, ...)
|
||||
__attribute__ ((format (printf, 2, 3)));
|
||||
struct bregs;
|
||||
void __debug_enter(const char *fname, struct bregs *regs);
|
||||
void __debug_exit(const char *fname, struct bregs *regs);
|
||||
#define debug_enter(regs) \
|
||||
__debug_enter(__func__, regs)
|
||||
#define debug_exit(regs) \
|
||||
__debug_exit(__func__, regs)
|
||||
#define printf(fmt, args...) \
|
||||
bprintf(0, fmt , ##args )
|
||||
|
||||
// kbd.c
|
||||
void handle_15c2(struct bregs *regs);
|
|
@ -0,0 +1,78 @@
|
|||
#!/usr/bin/env python
|
||||
# Script to merge a rom32.bin file into a rom16.bin file.
|
||||
#
|
||||
# Copyright (C) 2008 Kevin O'Connor <kevin@koconnor.net>
|
||||
#
|
||||
# This file may be distributed under the terms of the GNU GPLv3 license.
|
||||
|
||||
import sys
|
||||
import struct
|
||||
|
||||
ROM16='out/rom16.bin'
|
||||
ROM32='out/rom32.bin'
|
||||
OFFSETS16='out/rom16.offset.auto.h'
|
||||
OFFSETS32='out/rom32.offset.auto.h'
|
||||
OUT='out/rom.bin'
|
||||
|
||||
def align(v, a):
|
||||
return (v + a - 1) // a * a
|
||||
|
||||
def scanconfig(file):
|
||||
f = open(file, 'rb')
|
||||
opts = {}
|
||||
for l in f.readlines():
|
||||
parts = l.split()
|
||||
if len(parts) != 3:
|
||||
continue
|
||||
if parts[0] != '#define':
|
||||
continue
|
||||
opts[parts[1]] = parts[2]
|
||||
return opts
|
||||
|
||||
def alteraddr(data, offset, ptr):
|
||||
rel = struct.pack("<i", ptr)
|
||||
return data[:offset] + rel + data[offset+4:]
|
||||
|
||||
|
||||
def main():
|
||||
# Read in files
|
||||
f = open(ROM16, 'rb')
|
||||
data16 = f.read()
|
||||
f = open(ROM32, 'rb')
|
||||
data32 = f.read()
|
||||
|
||||
if len(data16) != 65536:
|
||||
print "16bit code is not 65536 bytes long"
|
||||
sys.exit(1)
|
||||
|
||||
# Get config options
|
||||
o16 = scanconfig(OFFSETS16)
|
||||
o32 = scanconfig(OFFSETS32)
|
||||
|
||||
# Inject 32bit code
|
||||
spos = align(int(o16['OFFSET_bios16c_end'], 16), 16)
|
||||
epos = int(o16['OFFSET_post16'], 16)
|
||||
size32 = len(data32)
|
||||
freespace = epos - spos
|
||||
if size32 > freespace:
|
||||
print "32bit code too large (%d vs %d)" % (size32, freespace)
|
||||
sys.exit(1)
|
||||
outrom = data16[:spos] + data32 + data16[spos+size32:]
|
||||
|
||||
# Fixup initial jump to 32 bit code
|
||||
jmppos = int(o16['OFFSET_set_entry32'], 16)
|
||||
start32 = int(o32['OFFSET__start'], 16)
|
||||
outrom = alteraddr(outrom, jmppos+2, start32)
|
||||
|
||||
# Fixup resume from 16 jump to 32 bit code
|
||||
jmppos = int(o16['OFFSET_set_resume32'], 16)
|
||||
resume32 = int(o32['OFFSET_call16_resume'], 16)
|
||||
outrom = alteraddr(outrom, jmppos+2, resume32)
|
||||
|
||||
# Write output rom
|
||||
f = open(OUT, 'wb')
|
||||
f.write(outrom)
|
||||
f.close()
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
|
@ -0,0 +1,38 @@
|
|||
#!/usr/bin/env python
|
||||
# Simple script to convert the output from 'nm' to a C style header
|
||||
# file with defined offsets.
|
||||
#
|
||||
# Copyright (C) 2008 Kevin O'Connor <kevin@koconnor.net>
|
||||
#
|
||||
# This file may be distributed under the terms of the GNU GPLv3 license.
|
||||
|
||||
import sys
|
||||
import string
|
||||
|
||||
def main():
|
||||
syms = []
|
||||
lines = sys.stdin.readlines()
|
||||
for line in lines:
|
||||
addr, type, sym = line.split()
|
||||
if type not in 'TA':
|
||||
# Only interested in global symbols in text segment
|
||||
continue
|
||||
for c in sym:
|
||||
if c not in string.letters + string.digits + '_':
|
||||
break
|
||||
else:
|
||||
syms.append((sym, addr))
|
||||
print """
|
||||
#ifndef __OFFSET16_AUTO_H
|
||||
#define __OFFSET16_AUTO_H
|
||||
// Auto generated file - please see defsyms.py.
|
||||
// This file contains symbol offsets of a compiled binary.
|
||||
"""
|
||||
for sym, addr in syms:
|
||||
print "#define OFFSET_%s 0x%s" % (sym, addr)
|
||||
print """
|
||||
#endif // __OFFSET16_AUTO_H
|
||||
"""
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
Loading…
Reference in New Issue