Initial revision
This commit is contained in:
commit
6a161fa938
80 changed files with 23264 additions and 0 deletions
8
.cvsignore
Normal file
8
.cvsignore
Normal file
|
@ -0,0 +1,8 @@
|
|||
Makefile
|
||||
config.cache
|
||||
config.h
|
||||
config.log
|
||||
config.status
|
||||
stamp-h
|
||||
stamp-h1
|
||||
autom4te.cache
|
1
AUTHORS
Normal file
1
AUTHORS
Normal file
|
@ -0,0 +1 @@
|
|||
Yoshinori K. Okuji designed and implemented everything.
|
340
COPYING
Normal file
340
COPYING
Normal file
|
@ -0,0 +1,340 @@
|
|||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
|
||||
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Library General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) 19yy <name of author>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) 19yy name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Library General
|
||||
Public License instead of this License.
|
4
ChangeLog
Normal file
4
ChangeLog
Normal file
|
@ -0,0 +1,4 @@
|
|||
2002-12-27 Yoshinori K. Okuji <okuji@enbug.org>
|
||||
|
||||
* Changelog: New file.
|
||||
|
157
INSTALL
Normal file
157
INSTALL
Normal file
|
@ -0,0 +1,157 @@
|
|||
-*- Text -*-
|
||||
|
||||
This is the PUPA. Welcome.
|
||||
|
||||
This file contains instructions for compiling and installing the PUPA.
|
||||
|
||||
The Requirements
|
||||
================
|
||||
|
||||
PUPA depends on some software packages installed into your system. If
|
||||
you don't have any of them, please obtain and install them before
|
||||
configuring the PUPA.
|
||||
|
||||
* GCC 2.95 or later
|
||||
* GNU Make
|
||||
* GNU binutils 2.9.1.0.23 or later
|
||||
* Other standard GNU/Unix tools
|
||||
|
||||
If you'd like to develop PUPA, these below are also required.
|
||||
|
||||
* Ruby 1.6 or later
|
||||
* Autoconf 2.53 or later
|
||||
|
||||
Configuring the PUPA
|
||||
====================
|
||||
|
||||
The `configure' shell script attempts to guess correct values for
|
||||
various system-dependent variables used during compilation. It uses
|
||||
those values to create a `Makefile' in each directory of the package.
|
||||
It may also create one or more `.h' files containing system-dependent
|
||||
definitions. Finally, it creates a shell script `config.status' that
|
||||
you can run in the future to recreate the current configuration, a
|
||||
file `config.cache' that saves the results of its tests to speed up
|
||||
reconfiguring, and a file `config.log' containing compiler output
|
||||
(useful mainly for debugging `configure').
|
||||
|
||||
If you need to do unusual things to compile the package, please try to
|
||||
figure out how `configure' could check whether to do them, and mail
|
||||
diffs or instructions to the address given in the `README' so they can
|
||||
be considered for the next release. If at some point `config.cache'
|
||||
contains results you don't want to keep, you may remove or edit it.
|
||||
|
||||
The file `configure.ac' is used to create `configure' by a program
|
||||
called `autoconf'. You only need `configure.in' if you want to change
|
||||
it or regenerate `configure' using a newer version of `autoconf'.
|
||||
|
||||
|
||||
Building the PUPA
|
||||
=================
|
||||
|
||||
The simplest way to compile this package is:
|
||||
|
||||
1. `cd' to the directory containing the package's source code and
|
||||
type `./configure' to configure the package for your system. If
|
||||
you're using `csh' on an old version of System V, you might need
|
||||
to type `sh ./configure' instead to prevent `csh' from trying to
|
||||
execute `configure' itself.
|
||||
|
||||
Running `configure' takes awhile. While running, it prints some
|
||||
messages telling which features it is checking for.
|
||||
|
||||
2. Type `make' to compile the package.
|
||||
|
||||
3. Optionally, type `make check' to run any self-tests that come with
|
||||
the package.
|
||||
|
||||
4. Type `make install' to install the programs and any data files and
|
||||
documentation.
|
||||
|
||||
5. You can remove the program binaries and object files from the
|
||||
source code directory by typing `make clean'. To also remove the
|
||||
files that `configure' created (so you can compile the package for
|
||||
a different kind of computer), type `make distclean'. There is
|
||||
also a `make maintainer-clean' target, but that is intended mainly
|
||||
for the package's developers. If you use it, you may have to get
|
||||
all sorts of other programs in order to regenerate files that came
|
||||
with the distribution.
|
||||
|
||||
|
||||
Compiling For Multiple Architectures
|
||||
====================================
|
||||
|
||||
You can compile the package for more than one kind of computer at the
|
||||
same time, by placing the object files for each architecture in their
|
||||
own directory. `cd' to the directory where you want the object files
|
||||
and executables to go and run the `configure' script. `configure'
|
||||
automatically checks for the source code in the directory that
|
||||
`configure' is in and in `..'.
|
||||
|
||||
|
||||
Installation Names
|
||||
==================
|
||||
|
||||
By default, `make install' will install the package's files in
|
||||
`/usr/local/bin', `/usr/local/man', etc. You can specify an
|
||||
installation prefix by giving `configure' the option `--prefix=PATH'.
|
||||
|
||||
You can specify separate installation prefixes for
|
||||
architecture-specific files and architecture-independent files. If
|
||||
you give `configure' the option `--exec-prefix=PATH', the package will
|
||||
use PATH as the prefix for installing programs and libraries.
|
||||
Documentation and other data files will still use the regular prefix.
|
||||
|
||||
In addition, if you use an unusual directory layout you can give
|
||||
options like `--bindir=PATH' to specify different values for
|
||||
particular kinds of files. Run `configure --help' for a list of the
|
||||
directories you can set and what kinds of files go in them.
|
||||
|
||||
If the package supports it, you can cause programs to be installed
|
||||
with an extra prefix or suffix on their names by giving `configure'
|
||||
the option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
|
||||
|
||||
Please note, however, that the PUPA knows where it is located in the
|
||||
filesystem. If you have installed it in an unusual location, the
|
||||
system might not work properly, or at all. The chief utility of these
|
||||
options for the PUPA is to allow you to "install" in some alternate
|
||||
location, and then copy these to the actual root filesystem later.
|
||||
|
||||
|
||||
Sharing Defaults
|
||||
================
|
||||
|
||||
If you want to set default values for `configure' scripts to share,
|
||||
you can create a site shell script called `config.site' that gives
|
||||
default values for variables like `CC', `cache_file', and `prefix'.
|
||||
`configure' looks for `PREFIX/share/config.site' if it exists, then
|
||||
`PREFIX/etc/config.site' if it exists. Or, you can set the
|
||||
`CONFIG_SITE' environment variable to the location of the site script.
|
||||
A warning: not all `configure' scripts look for a site script.
|
||||
|
||||
|
||||
Operation Controls
|
||||
==================
|
||||
|
||||
`configure' recognizes the following options to control how it
|
||||
operates.
|
||||
|
||||
`--cache-file=FILE'
|
||||
Use and save the results of the tests in FILE instead of
|
||||
`./config.cache'. Set FILE to `/dev/null' to disable caching, for
|
||||
debugging `configure'.
|
||||
|
||||
`--help'
|
||||
Print a summary of the options to `configure', and exit.
|
||||
|
||||
`--quiet'
|
||||
`--silent'
|
||||
`-q'
|
||||
Do not print messages saying which checks are being made.
|
||||
|
||||
`--srcdir=DIR'
|
||||
Look for the package's source code in directory DIR. Usually
|
||||
`configure' can determine that directory automatically.
|
||||
|
||||
`--version'
|
||||
Print the version of Autoconf used to generate the `configure'
|
||||
script, and exit.
|
259
Makefile.in
Normal file
259
Makefile.in
Normal file
|
@ -0,0 +1,259 @@
|
|||
# -*- makefile -*-
|
||||
#
|
||||
# Copyright (C) 1994,1995,1996,1997,1998,1999,2000,2001 Free Software Foundation, Inc.
|
||||
# Copyright (C) 2002 Yoshinori K. Okuji <okuji@enbug.org>
|
||||
#
|
||||
# This Makefile.in is free software; the author
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
# with or without modifications, as long as this notice is preserved.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
|
||||
# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||
# PARTICULAR PURPOSE.
|
||||
|
||||
### The configure script will replace these variables.
|
||||
|
||||
SHELL = /bin/sh
|
||||
|
||||
@SET_MAKE@
|
||||
|
||||
srcdir = @srcdir@
|
||||
top_srcdir = @top_srcdir@
|
||||
VPATH = @srcdir@
|
||||
prefix = @prefix@
|
||||
exec_prefix = @exec_prefix@
|
||||
|
||||
bindir = @bindir@
|
||||
sbindir = @sbindir@
|
||||
libexecdir = @libexecdir@
|
||||
datadir = @datadir@
|
||||
sysconfdir = @sysconfdir@
|
||||
sharedstatedir = @sharedstatedir@
|
||||
localstatedir = @localstatedir@
|
||||
libdir = @libdir@
|
||||
infodir = @infodir@
|
||||
mandir = @mandir@
|
||||
includedir = @includedir@
|
||||
pkgdatadir = $(datadir)/@PACKAGE_TARNAME@/$(host_cpu)-$(host_vendor)
|
||||
pkglibdir = $(libdir)/@PACKAGE_TARNAME@
|
||||
|
||||
PACKAGE_NAME = @PACKAGE_NAME@
|
||||
PACKAGE_TARNAME = @PACKAGE_TARNAME@
|
||||
PACKAGE_VERSION = @PACKAGE_VERSION@
|
||||
PACKAGE_STRING = @PACKAGE_STRING@
|
||||
PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
|
||||
|
||||
host_cpu = @host_cpu@
|
||||
host_vendor = @host_vendor@
|
||||
|
||||
INSTALL = @INSTALL@
|
||||
INSTALL_PROGRAM = @INSTALL_PROGRAM@
|
||||
INSTALL_DATA = @INSTALL_DATA@
|
||||
INSTALL_SCRIPT = @INSTALL_SCRIPT@
|
||||
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
|
||||
|
||||
mkinstalldirs = $(srcdir)/mkinstalldirs
|
||||
|
||||
CC = @CC@
|
||||
CFLAGS = @CFLAGS@
|
||||
CPPFLAGS = -I. -Iinclude -I$(srcdir)/include -Wall -W
|
||||
BUILD_CC = @CC@
|
||||
BUILD_CFLAGS = -g -O2
|
||||
BUILD_CPPFLAGS = -I. -Iinclude -I$(srcdir)/include -Wall -W \
|
||||
-DPUPA_DATADIR=\"$(pkgdatadir)\"
|
||||
OBJCOPY = @OBJCOPY@
|
||||
STRIP = @STRIP@
|
||||
NM = @NM@
|
||||
RUBY = @RUBY@
|
||||
|
||||
### General variables.
|
||||
|
||||
RMKFILES = $(addprefix conf/,i386-pc.rmk)
|
||||
MKFILES = $(patsubst %.rmk,%.mk,$(RMKFILES))
|
||||
|
||||
COMMON_DISTFILES = AUTHORS COPYING ChangeLog INSTALL NEWS README \
|
||||
THANKS TODO Makefile.in aclocal.m4 autogen.sh config.guess \
|
||||
config.h.in config.sub configure configure.ac genkernsyms.sh \
|
||||
genmk.rb genmodsrc.sh gensymlist.sh install-sh mkinstalldirs \
|
||||
stamp-h.in
|
||||
|
||||
BOOT_DISTFILES = $(addprefix boot/i386/pc/,boot.S diskboot.S)
|
||||
|
||||
CONF_DISTFILES = $(RMKFILES) $(MKFILES)
|
||||
|
||||
DISK_DISTFILES = $(addprefix disk/i386/pc/,biosdisk.c partition.c)
|
||||
|
||||
FS_DISTFILES = $(addprefix fs/,fat.c)
|
||||
|
||||
INCLUDE_DISTFILES = $(addprefix include/pupa/,boot.h device.h disk.h \
|
||||
dl.h elf.h err.h file.h fs.h kernel.h loader.h misc.h mm.h \
|
||||
net.h rescue.h symbol.h term.h types.h) \
|
||||
$(addprefix include/pupa/util/,misc.h resolve.h) \
|
||||
include/pupa/i386/types.h \
|
||||
$(addprefix include/pupa/i386/pc/,biosdisk.h boot.h \
|
||||
console.h init.h kernel.h loader.h memory.h partition.h)
|
||||
|
||||
KERN_DISTFILES = $(addprefix kern/,device.c disk.c dl.c err.c file.c \
|
||||
fs.c loader.c main.c misc.c mm.c rescue.c term.c) \
|
||||
kern/i386/dl.c \
|
||||
$(addprefix kern/i386/pc/,init.c startup.S)
|
||||
|
||||
LOADER_DISTFILES = $(addprefix loader/i386/pc/,chainloader.c)
|
||||
|
||||
TERM_DISTFILES = $(addprefix term/i386/pc/,console.c)
|
||||
|
||||
UTIL_DISTFILES = $(addprefix util/,genmoddep.c misc.c resolve.c) \
|
||||
util/i386/pc/pupa-mkimage.c
|
||||
|
||||
DISTFILES = $(COMMON_DISTFILES) $(BOOT_DISTFILES) $(CONF_DISTFILES) \
|
||||
$(DISK_DISTFILES) $(FS_DISTFILES) $(INCLUDE_DISTFILES) \
|
||||
$(KERN_DISTFILES) $(LOADER_DISTFILES) $(TERM_DISTFILES) \
|
||||
$(UTIL_DISTFILES)
|
||||
|
||||
DATA = $(pkgdata_IMAGES) $(pkgdata_MODULES)
|
||||
PROGRAMS = $(bin_UTILITIES) $(sbin_UTILITIES)
|
||||
SCRIPTS =
|
||||
|
||||
CLEANFILES =
|
||||
MOSTLYCLEANFILES =
|
||||
DISTCLEANFILES = config.status config.cache config.log config.h \
|
||||
Makefile stamp-h include/pupa/cpu include/pupa/machine
|
||||
MAINTAINER_CLEANFILES = $(srcdir)/configure $(addprefix $(srcdir)/,$(MKFILES))
|
||||
|
||||
# The default target.
|
||||
all: all-local
|
||||
|
||||
### Include an arch-specific Makefile.
|
||||
$(addprefix $(srcdir)/,$(MKFILES)): %.mk: %.rmk genmk.rb
|
||||
if test "x$(RUBY)" = x; then \
|
||||
touch $@; \
|
||||
else \
|
||||
$(RUBY) $(srcdir)/genmk.rb < $< > $@; \
|
||||
fi
|
||||
|
||||
include $(srcdir)/conf/$(host_cpu)-$(host_vendor).mk
|
||||
|
||||
### General targets.
|
||||
|
||||
all-local: $(PROGRAMS) $(DATA) $(SCRIPTS)
|
||||
|
||||
install: install-local
|
||||
|
||||
install-local: all
|
||||
$(mkinstalldirs) $(DESTDIR)$(pkgdatadir)
|
||||
@list='$(pkgdata_IMAGES) $(pkgdata_MODULES)'; for file in $$list; do \
|
||||
if test -f "$$file"; then dir=; else dir="$(srcdir)"; fi; \
|
||||
dest="`echo $$file | sed 's,.*/,,'`"; \
|
||||
$(INSTALL_DATA) $$dir$$file $(DESTDIR)$(pkgdatadir)/$$dest; \
|
||||
done
|
||||
$(mkinstalldirs) $(DESTDIR)$(bindir)
|
||||
@list='$(bin_UTILITIES)'; for file in $$list; do \
|
||||
if test -f "$$file"; then dir=; else dir="$(srcdir)"; fi; \
|
||||
dest="`echo $$file | sed 's,.*/,,'`"; \
|
||||
$(INSTALL_PROGRAM) $$dir$$file $(DESTDIR)$(bindir)/$$dest; \
|
||||
done
|
||||
|
||||
install-strip:
|
||||
$(MAKE) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" install
|
||||
|
||||
uninstall:
|
||||
@list='$(pkgdata_IMAGES) $(pkgdata_MODULES)'; for file in $$list; do \
|
||||
dest="`echo $$file | sed 's,.*/,,'`"; \
|
||||
rm -f $(DESTDIR)$(pkgdatadir)/$$dest; \
|
||||
done
|
||||
@list = '$(bin_UTILITIES)'; for file in $$list; do \
|
||||
dest="`echo $$file | sed 's,.*/,,'`"; \
|
||||
rm -f $(DESTDIR)$(bindir)/$$dest; \
|
||||
done
|
||||
|
||||
clean:
|
||||
-test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
|
||||
|
||||
mostlyclean: clean
|
||||
-test -z "$(MOSTLYCLEANFILES)" || rm -f $(MOSTLYCLEANFILES)
|
||||
|
||||
distclean: mostlyclean
|
||||
-test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES)
|
||||
-rm -rf $(srcdir)/autom4te.cache
|
||||
|
||||
maintainer-clean: distclean
|
||||
-test -z "$(MAINTAINER_CLEANFILES)" || rm -f $(MAINTAINER_CLEANFILES)
|
||||
|
||||
info:
|
||||
|
||||
dvi:
|
||||
|
||||
distdir=$(PACKAGE_TARNAME)-$(PACKAGE_VERSION)
|
||||
|
||||
distdir: $(DISTFILES)
|
||||
-chmod -R a+w $(distdir) >/dev/null 2>&1; rm -rf $(distdir)
|
||||
$(mkinstalldirs) $(distdir)
|
||||
for i in $(DISTFILES); do \
|
||||
dir=`echo "$$i" | sed 's:/[^/]*$$::'`; \
|
||||
if test -d $(srcdir)/$$dir; then \
|
||||
$(mkinstalldirs) $(distdir)/$$dir; \
|
||||
fi; \
|
||||
cp -p $(srcdir)/$$i $(distdir)/$$i || exit 1; \
|
||||
done
|
||||
chmod -R a+r $(distdir)
|
||||
|
||||
GZIP_ENV = --best
|
||||
|
||||
dist: distdir
|
||||
tar chof - $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz
|
||||
-chmod -R a+w $(distdir) >/dev/null 2>&1; rm -rf $(distdir)
|
||||
|
||||
distcheck: dist
|
||||
-chmod -R a+w $(distdir) >/dev/null 2>&1; rm -rf $(distdir)
|
||||
GZIP=$(GZIP_ENV) gzip -cd $(distdir).tar.gz | tar xf -
|
||||
chmod -R a-w $(distdir)
|
||||
chmod a+w $(distdir)
|
||||
mkdir $(distdir)/=build
|
||||
mkdir $(distdir)/=inst
|
||||
chmod a-w $(distdir)
|
||||
dc_instdir=`CDPATH=: && cd $(distdir)/=inst && pwd` \
|
||||
&& cd $(distdir)/=build \
|
||||
&& ../configure --srcdir=.. --prefix=$$dc_instdir \
|
||||
&& $(MAKE) all dvi check install uninstall \
|
||||
&& (test `find $$dc_instdir -type f -print | wc -l` -le 1 \
|
||||
|| (echo "Error: files left after uninstall" 1>&2; \
|
||||
exit 1)) \
|
||||
&& $(MAKE) dist distclean \
|
||||
&& rm -f $(distdir).tar.gz \
|
||||
&& (test `find . -type f -print | wc -l` -eq 0 \
|
||||
|| (echo "Error: files left after distclean" 1>&2; \
|
||||
exit 1))
|
||||
-chmod -R a+w $(distdir) > /dev/null 2>&1; rm -rf $(distdir)
|
||||
@echo "$(distdir).tar.gz is ready for distribution" | \
|
||||
sed 'h;s/./=/g;p;x;p;x'
|
||||
|
||||
check:
|
||||
|
||||
.SUFFIX:
|
||||
.SUFFIX: .c .o .S .d
|
||||
|
||||
# Regenerate configure and Makefile automatically.
|
||||
$(srcdir)/configure: configure.ac aclocal.m4
|
||||
cd $(srcdir) && autoconf
|
||||
|
||||
$(srcdir)/config.h.in: stamp-h.in
|
||||
$(srcdir)/stamp-h.in: configure.ac aclocal.m4
|
||||
cd $(srcdir) && autoheader
|
||||
echo timestamp > $(srcdir)/stamp-h.in
|
||||
|
||||
config.h: stamp-h
|
||||
stamp-h: config.h.in config.status
|
||||
./config.status
|
||||
|
||||
Makefile: Makefile.in config.status
|
||||
./config.status
|
||||
|
||||
config.status: configure
|
||||
./config.status --recheck
|
||||
|
||||
.PHONY: all install install-strip uninstall clean mostlyclean distclean
|
||||
.PHONY: maintainer-clean info dvi dist check
|
||||
|
||||
# Prevent an overflow.
|
||||
.NOEXPORT:
|
12
NEWS
Normal file
12
NEWS
Normal file
|
@ -0,0 +1,12 @@
|
|||
New in 0.6 - 2002-12-27, Yoshinori K. Okuji:
|
||||
|
||||
* The chainloader and the FAT filesystem are modularized.
|
||||
|
||||
* The structure of the source tree is a bit changed.
|
||||
|
||||
* Support for building loadable modules is added.
|
||||
|
||||
* Some generic parts of pupa-mkimage are segregated.
|
||||
|
||||
* Some documentation files are added, according to the GNU Coding
|
||||
Standards.
|
26
README
Normal file
26
README
Normal file
|
@ -0,0 +1,26 @@
|
|||
This is PUPA, the Preliminary Universal Programming Architecture for
|
||||
GRUB. PUPA is a research project for the next generation of GNU GRUB.
|
||||
The most important goal is to make GNU GRUB cleaner, safer, more robust,
|
||||
more powerful, and more portable.
|
||||
|
||||
See the file NEWS for a description of recent changes to PUPA.
|
||||
|
||||
See the file INSTALL for instructions on how to build and install the
|
||||
PUPA data and program files.
|
||||
|
||||
Please visit the official web page of PUPA, for more information.
|
||||
The URL is <http://www.nongnu.org/pupa/>.
|
||||
|
||||
|
||||
|
||||
Because PUPA is still in developmental stage, PUPA is not for general
|
||||
use (yet). For now, you can install PUPA into a floppy by these
|
||||
instructions:
|
||||
|
||||
$ configure && make
|
||||
$ ./pupa-mkimage -v -d . -o core.img chain fat
|
||||
$ dd if=boot.img of=/dev/fd0 bs=512 count=1
|
||||
$ dd if=core.img of=/dev/fd0 bs=512 seek=1
|
||||
|
||||
It would be easier to use Bochs <http://bochs.sf.net/> than a real
|
||||
machine.
|
16
THANKS
Normal file
16
THANKS
Normal file
|
@ -0,0 +1,16 @@
|
|||
PUPA would not be what it is today without the invaluable help of
|
||||
everybody who was kind enough to spend time testing it and reporting
|
||||
bugs.
|
||||
|
||||
The following people made especially gracious contributions of their
|
||||
time and energy in helping to track down bugs, add new features, and
|
||||
generally assist in the PUPA maintainership process:
|
||||
|
||||
NIIBE Yutaka <gniibe@m17n.org>
|
||||
Tsuneyoshi Yasuo <tuneyoshi@naic.co.jp>
|
||||
|
||||
Also, we thank the projects GNU GRUB and GNU Automake. Some code were
|
||||
stolen from them.
|
||||
|
||||
This project is supported by Information-technology Promotion Agency,
|
||||
Japan.
|
37
TODO
Normal file
37
TODO
Normal file
|
@ -0,0 +1,37 @@
|
|||
-*- Mode: Outline -*-
|
||||
|
||||
Before working on anything in this file, it's very important that you
|
||||
make contact with the core PUPA developers. Things herein might be
|
||||
slightly out of date or otherwise not easy to understand at first
|
||||
glance. So write to <pupa-devel@nongnu.org> first.
|
||||
|
||||
Priorities:
|
||||
Reported bugs generally have top priority.
|
||||
Non-reported and non-encountered bugs (things we know don't work,
|
||||
but don't really impede things) have lower priority.
|
||||
Things in this file are ranked with one to three !; the more, the
|
||||
higher priority.
|
||||
|
||||
|
||||
* Add more filesystems (such as ext2fs, ffs, and reiserfs). !
|
||||
|
||||
* Add support for internationalization. !!!
|
||||
|
||||
* Add more loaders (such as Multiboot, Linux and FreeBSD). !!
|
||||
|
||||
* Implement an installer. !!!
|
||||
|
||||
* Add more terminals (such as serial). !
|
||||
|
||||
* Implement a normal mode. !!!
|
||||
|
||||
* Write a manual.
|
||||
|
||||
* Shrink the kernel code.
|
||||
|
||||
* Add support for compressed files.
|
||||
|
||||
* Add support for network devices.
|
||||
|
||||
* Compress the core image and decompress it at loading time, to make it
|
||||
smaller. ?
|
292
aclocal.m4
vendored
Normal file
292
aclocal.m4
vendored
Normal file
|
@ -0,0 +1,292 @@
|
|||
dnl pupa_ASM_USCORE checks if C symbols get an underscore after
|
||||
dnl compiling to assembler.
|
||||
dnl Written by Pavel Roskin. Based on grub_ASM_EXT_C written by
|
||||
dnl Erich Boleyn and modified by Yoshinori K. Okuji.
|
||||
AC_DEFUN(pupa_ASM_USCORE,
|
||||
[AC_REQUIRE([AC_PROG_CC])
|
||||
AC_MSG_CHECKING([if C symbols get an underscore after compilation])
|
||||
AC_CACHE_VAL(pupa_cv_asm_uscore,
|
||||
[cat > conftest.c <<\EOF
|
||||
int
|
||||
func (int *list)
|
||||
{
|
||||
*list = 0;
|
||||
return *list;
|
||||
}
|
||||
EOF
|
||||
|
||||
if AC_TRY_COMMAND([${CC-cc} ${CFLAGS} -S conftest.c]) && test -s conftest.s; then
|
||||
true
|
||||
else
|
||||
AC_MSG_ERROR([${CC-cc} failed to produce assembly code])
|
||||
fi
|
||||
|
||||
if grep _func conftest.s >/dev/null 2>&1; then
|
||||
pupa_cv_asm_uscore=yes
|
||||
else
|
||||
pupa_cv_asm_uscore=no
|
||||
fi
|
||||
|
||||
rm -f conftest*])
|
||||
|
||||
if test "x$pupa_cv_asm_uscore" = xyes; then
|
||||
AC_DEFINE_UNQUOTED([HAVE_ASM_USCORE], $pupa_cv_asm_uscore,
|
||||
[Define if C symbols get an underscore after compilation])
|
||||
fi
|
||||
|
||||
AC_MSG_RESULT([$pupa_cv_asm_uscore])
|
||||
])
|
||||
|
||||
|
||||
dnl Some versions of `objcopy -O binary' vary their output depending
|
||||
dnl on the link address.
|
||||
AC_DEFUN(pupa_PROG_OBJCOPY_ABSOLUTE,
|
||||
[AC_MSG_CHECKING([whether ${OBJCOPY} works for absolute addresses])
|
||||
AC_CACHE_VAL(pupa_cv_prog_objcopy_absolute,
|
||||
[cat > conftest.c <<\EOF
|
||||
void
|
||||
cmain (void)
|
||||
{
|
||||
*((int *) 0x1000) = 2;
|
||||
}
|
||||
EOF
|
||||
|
||||
if AC_TRY_EVAL(ac_compile) && test -s conftest.o; then :
|
||||
else
|
||||
AC_MSG_ERROR([${CC-cc} cannot compile C source code])
|
||||
fi
|
||||
pupa_cv_prog_objcopy_absolute=yes
|
||||
for link_addr in 2000 8000 7C00; do
|
||||
if AC_TRY_COMMAND([${CC-cc} ${CFLAGS} -nostdlib -Wl,-N -Wl,-Ttext -Wl,$link_addr conftest.o -o conftest.exec]); then :
|
||||
else
|
||||
AC_MSG_ERROR([${CC-cc} cannot link at address $link_addr])
|
||||
fi
|
||||
if AC_TRY_COMMAND([${OBJCOPY-objcopy} -O binary conftest.exec conftest]); then :
|
||||
else
|
||||
AC_MSG_ERROR([${OBJCOPY-objcopy} cannot create binary files])
|
||||
fi
|
||||
if test ! -f conftest.old || AC_TRY_COMMAND([cmp -s conftest.old conftest]); then
|
||||
mv -f conftest conftest.old
|
||||
else
|
||||
pupa_cv_prog_objcopy_absolute=no
|
||||
break
|
||||
fi
|
||||
done
|
||||
rm -f conftest*])
|
||||
AC_MSG_RESULT([$pupa_cv_prog_objcopy_absolute])
|
||||
|
||||
if test "x$pupa_cv_prog_objcopy_absolute" = xno; then
|
||||
AC_MSG_ERROR([PUPA requires a working absolute objcopy; upgrade your binutils])
|
||||
fi
|
||||
])
|
||||
|
||||
|
||||
dnl Mass confusion!
|
||||
dnl Older versions of GAS interpret `.code16' to mean ``generate 32-bit
|
||||
dnl instructions, but implicitly insert addr32 and data32 bytes so
|
||||
dnl that the code works in real mode''.
|
||||
dnl
|
||||
dnl Newer versions of GAS interpret `.code16' to mean ``generate 16-bit
|
||||
dnl instructions,'' which seems right. This requires the programmer
|
||||
dnl to explicitly insert addr32 and data32 instructions when they want
|
||||
dnl them.
|
||||
dnl
|
||||
dnl We only support the newer versions, because the old versions cause
|
||||
dnl major pain, by requiring manual assembly to get 16-bit instructions into
|
||||
dnl asm files.
|
||||
AC_DEFUN(pupa_I386_ASM_ADDR32,
|
||||
[AC_REQUIRE([AC_PROG_CC])
|
||||
AC_REQUIRE([pupa_I386_ASM_PREFIX_REQUIREMENT])
|
||||
AC_MSG_CHECKING([for .code16 addr32 assembler support])
|
||||
AC_CACHE_VAL(pupa_cv_i386_asm_addr32,
|
||||
[cat > conftest.s.in <<\EOF
|
||||
.code16
|
||||
l1: @ADDR32@ movb %al, l1
|
||||
EOF
|
||||
|
||||
if test "x$pupa_cv_i386_asm_prefix_requirement" = xyes; then
|
||||
sed -e s/@ADDR32@/addr32/ < conftest.s.in > conftest.s
|
||||
else
|
||||
sed -e s/@ADDR32@/addr32\;/ < conftest.s.in > conftest.s
|
||||
fi
|
||||
|
||||
if AC_TRY_COMMAND([${CC-cc} ${CFLAGS} -c conftest.s]) && test -s conftest.o; then
|
||||
pupa_cv_i386_asm_addr32=yes
|
||||
else
|
||||
pupa_cv_i386_asm_addr32=no
|
||||
fi
|
||||
|
||||
rm -f conftest*])
|
||||
|
||||
AC_MSG_RESULT([$pupa_cv_i386_asm_addr32])])
|
||||
|
||||
|
||||
dnl Later versions of GAS requires that addr32 and data32 prefixes
|
||||
dnl appear in the same lines as the instructions they modify, while
|
||||
dnl earlier versions requires that they appear in separate lines.
|
||||
AC_DEFUN(pupa_I386_ASM_PREFIX_REQUIREMENT,
|
||||
[AC_REQUIRE([AC_PROG_CC])
|
||||
AC_MSG_CHECKING(dnl
|
||||
[whether addr32 must be in the same line as the instruction])
|
||||
AC_CACHE_VAL(pupa_cv_i386_asm_prefix_requirement,
|
||||
[cat > conftest.s <<\EOF
|
||||
.code16
|
||||
l1: addr32 movb %al, l1
|
||||
EOF
|
||||
|
||||
if AC_TRY_COMMAND([${CC-cc} ${CFLAGS} -c conftest.s]) && test -s conftest.o; then
|
||||
pupa_cv_i386_asm_prefix_requirement=yes
|
||||
else
|
||||
pupa_cv_i386_asm_prefix_requirement=no
|
||||
fi
|
||||
|
||||
rm -f conftest*])
|
||||
|
||||
if test "x$pupa_cv_i386_asm_prefix_requirement" = xyes; then
|
||||
pupa_tmp_addr32="addr32"
|
||||
pupa_tmp_data32="data32"
|
||||
else
|
||||
pupa_tmp_addr32="addr32;"
|
||||
pupa_tmp_data32="data32;"
|
||||
fi
|
||||
|
||||
AC_DEFINE_UNQUOTED([ADDR32], $pupa_tmp_addr32,
|
||||
[Define it to \"addr32\" or \"addr32;\" to make GAS happy])
|
||||
AC_DEFINE_UNQUOTED([DATA32], $pupa_tmp_data32,
|
||||
[Define it to \"data32\" or \"data32;\" to make GAS happy])
|
||||
|
||||
AC_MSG_RESULT([$pupa_cv_i386_asm_prefix_requirement])])
|
||||
|
||||
|
||||
dnl Older versions of GAS require that absolute indirect calls/jumps are
|
||||
dnl not prefixed with `*', while later versions warn if not prefixed.
|
||||
AC_DEFUN(pupa_I386_ASM_ABSOLUTE_WITHOUT_ASTERISK,
|
||||
[AC_REQUIRE([AC_PROG_CC])
|
||||
AC_MSG_CHECKING(dnl
|
||||
[whether an absolute indirect call/jump must not be prefixed with an asterisk])
|
||||
AC_CACHE_VAL(pupa_cv_i386_asm_absolute_without_asterisk,
|
||||
[cat > conftest.s <<\EOF
|
||||
lcall *(offset)
|
||||
offset:
|
||||
.long 0
|
||||
.word 0
|
||||
EOF
|
||||
|
||||
if AC_TRY_COMMAND([${CC-cc} ${CFLAGS} -c conftest.s]) && test -s conftest.o; then
|
||||
pupa_cv_i386_asm_absolute_without_asterisk=no
|
||||
else
|
||||
pupa_cv_i386_asm_absolute_without_asterisk=yes
|
||||
fi
|
||||
|
||||
rm -f conftest*])
|
||||
|
||||
if test "x$pupa_cv_i386_asm_absolute_without_asterisk" = xyes; then
|
||||
AC_DEFINE([ABSOLUTE_WITHOUT_ASTERISK], 1,
|
||||
[Define it if GAS requires that absolute indirect calls/jumps are not prefixed with an asterisk])
|
||||
fi
|
||||
|
||||
AC_MSG_RESULT([$pupa_cv_i386_asm_absolute_without_asterisk])])
|
||||
|
||||
|
||||
dnl Check what symbol is defined as a start symbol.
|
||||
dnl Written by Yoshinori K. Okuji.
|
||||
AC_DEFUN(pupa_CHECK_START_SYMBOL,
|
||||
[AC_REQUIRE([AC_PROG_CC])
|
||||
AC_MSG_CHECKING([if start is defined by the compiler])
|
||||
AC_CACHE_VAL(pupa_cv_check_start_symbol,
|
||||
[AC_TRY_LINK([], [asm ("incl start")],
|
||||
pupa_cv_check_start_symbol=yes,
|
||||
pupa_cv_check_start_symbol=no)])
|
||||
|
||||
AC_MSG_RESULT([$pupa_cv_check_start_symbol])
|
||||
|
||||
AC_MSG_CHECKING([if _start is defined by the compiler])
|
||||
AC_CACHE_VAL(pupa_cv_check_uscore_start_symbol,
|
||||
[AC_TRY_LINK([], [asm ("incl _start")],
|
||||
pupa_cv_check_uscore_start_symbol=yes,
|
||||
pupa_cv_check_uscore_start_symbol=no)])
|
||||
|
||||
AC_MSG_RESULT([$pupa_cv_check_uscore_start_symbol])
|
||||
|
||||
AH_TEMPLATE([START_SYMBOL], [Define it to either start or _start])
|
||||
|
||||
if test "x$pupa_cv_check_start_symbol" = xyes; then
|
||||
AC_DEFINE([START_SYMBOL], [start])
|
||||
elif test "x$pupa_cv_check_uscore_start_symbol" = xyes; then
|
||||
AC_DEFINE([START_SYMBOL], [_start])
|
||||
else
|
||||
AC_MSG_ERROR([neither start nor _start is defined])
|
||||
fi
|
||||
])
|
||||
|
||||
dnl Check what symbol is defined as a bss start symbol.
|
||||
dnl Written by Michael Hohmoth and Yoshinori K. Okuji.
|
||||
AC_DEFUN(pupa_CHECK_BSS_START_SYMBOL,
|
||||
[AC_REQUIRE([AC_PROG_CC])
|
||||
AC_MSG_CHECKING([if __bss_start is defined by the compiler])
|
||||
AC_CACHE_VAL(pupa_cv_check_uscore_uscore_bss_start_symbol,
|
||||
[AC_TRY_LINK([], [asm ("incl __bss_start")],
|
||||
pupa_cv_check_uscore_uscore_bss_start_symbol=yes,
|
||||
pupa_cv_check_uscore_uscore_bss_start_symbol=no)])
|
||||
|
||||
AC_MSG_RESULT([$pupa_cv_check_uscore_uscore_bss_start_symbol])
|
||||
|
||||
AC_MSG_CHECKING([if edata is defined by the compiler])
|
||||
AC_CACHE_VAL(pupa_cv_check_edata_symbol,
|
||||
[AC_TRY_LINK([], [asm ("incl edata")],
|
||||
pupa_cv_check_edata_symbol=yes,
|
||||
pupa_cv_check_edata_symbol=no)])
|
||||
|
||||
AC_MSG_RESULT([$pupa_cv_check_edata_symbol])
|
||||
|
||||
AC_MSG_CHECKING([if _edata is defined by the compiler])
|
||||
AC_CACHE_VAL(pupa_cv_check_uscore_edata_symbol,
|
||||
[AC_TRY_LINK([], [asm ("incl _edata")],
|
||||
pupa_cv_check_uscore_edata_symbol=yes,
|
||||
pupa_cv_check_uscore_edata_symbol=no)])
|
||||
|
||||
AC_MSG_RESULT([$pupa_cv_check_uscore_edata_symbol])
|
||||
|
||||
AH_TEMPLATE([BSS_START_SYMBOL], [Define it to one of __bss_start, edata and _edata])
|
||||
|
||||
if test "x$pupa_cv_check_uscore_uscore_bss_start_symbol" = xyes; then
|
||||
AC_DEFINE([BSS_START_SYMBOL], [__bss_start])
|
||||
elif test "x$pupa_cv_check_edata_symbol" = xyes; then
|
||||
AC_DEFINE([BSS_START_SYMBOL], [edata])
|
||||
elif test "x$pupa_cv_check_uscore_edata_symbol" = xyes; then
|
||||
AC_DEFINE([BSS_START_SYMBOL], [_edata])
|
||||
else
|
||||
AC_MSG_ERROR([none of __bss_start, edata or _edata is defined])
|
||||
fi
|
||||
])
|
||||
|
||||
dnl Check what symbol is defined as an end symbol.
|
||||
dnl Written by Yoshinori K. Okuji.
|
||||
AC_DEFUN(pupa_CHECK_END_SYMBOL,
|
||||
[AC_REQUIRE([AC_PROG_CC])
|
||||
AC_MSG_CHECKING([if end is defined by the compiler])
|
||||
AC_CACHE_VAL(pupa_cv_check_end_symbol,
|
||||
[AC_TRY_LINK([], [asm ("incl end")],
|
||||
pupa_cv_check_end_symbol=yes,
|
||||
pupa_cv_check_end_symbol=no)])
|
||||
|
||||
AC_MSG_RESULT([$pupa_cv_check_end_symbol])
|
||||
|
||||
AC_MSG_CHECKING([if _end is defined by the compiler])
|
||||
AC_CACHE_VAL(pupa_cv_check_uscore_end_symbol,
|
||||
[AC_TRY_LINK([], [asm ("incl _end")],
|
||||
pupa_cv_check_uscore_end_symbol=yes,
|
||||
pupa_cv_check_uscore_end_symbol=no)])
|
||||
|
||||
AC_MSG_RESULT([$pupa_cv_check_uscore_end_symbol])
|
||||
|
||||
AH_TEMPLATE([END_SYMBOL], [Define it to either end or _end])
|
||||
|
||||
if test "x$pupa_cv_check_end_symbol" = xyes; then
|
||||
AC_DEFINE([END_SYMBOL], [end])
|
||||
elif test "x$pupa_cv_check_uscore_end_symbol" = xyes; then
|
||||
AC_DEFINE([END_SYMBOL], [_end])
|
||||
else
|
||||
AC_MSG_ERROR([neither end nor _end is defined])
|
||||
fi
|
||||
])
|
11
autogen.sh
Normal file
11
autogen.sh
Normal file
|
@ -0,0 +1,11 @@
|
|||
#! /bin/sh
|
||||
|
||||
set -e
|
||||
|
||||
autoconf
|
||||
autoheader
|
||||
for rmk in conf/*.rmk; do
|
||||
ruby genmk.rb < $rmk > `echo $rmk | sed 's/\.rmk$/.mk/'`
|
||||
done
|
||||
|
||||
exit 0
|
487
boot/i386/pc/boot.S
Normal file
487
boot/i386/pc/boot.S
Normal file
|
@ -0,0 +1,487 @@
|
|||
/* -*-Asm-*- */
|
||||
/*
|
||||
* PUPA -- Preliminary Universal Programming Architecture for GRUB
|
||||
* Copyright (C) 1999,2000,2001 Free Software Foundation, Inc.
|
||||
* Copyright (C) 2002 Yoshinori K. Okuji <okuji@enbug.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <pupa/boot.h>
|
||||
#include <pupa/machine/boot.h>
|
||||
|
||||
/*
|
||||
* defines for the code go here
|
||||
*/
|
||||
|
||||
/* Absolute addresses
|
||||
This makes the assembler generate the address without support
|
||||
from the linker. (ELF can't relocate 16-bit addresses!) */
|
||||
#define ABS(x) (x-_start+0x7c00)
|
||||
|
||||
/* Print message string */
|
||||
#define MSG(x) movw $ABS(x), %si; call message
|
||||
|
||||
/* XXX: binutils-2.9.1.0.x doesn't produce a short opcode for this. */
|
||||
#define MOV_MEM_TO_AL(x) .byte 0xa0; .word x
|
||||
|
||||
.file "boot.S"
|
||||
|
||||
.text
|
||||
|
||||
/* Tell GAS to generate 16-bit instructions so that this code works
|
||||
in real mode. */
|
||||
.code16
|
||||
|
||||
.globl _start; _start:
|
||||
/*
|
||||
* _start is loaded at 0x7c00 and is jumped to with CS:IP 0:0x7c00
|
||||
*/
|
||||
|
||||
/*
|
||||
* Beginning of the sector is compatible with the FAT/HPFS BIOS
|
||||
* parameter block.
|
||||
*/
|
||||
|
||||
jmp after_BPB
|
||||
nop /* do I care about this ??? */
|
||||
|
||||
/*
|
||||
* This space is for the BIOS parameter block!!!! Don't change
|
||||
* the first jump, nor start the code anywhere but right after
|
||||
* this area.
|
||||
*/
|
||||
|
||||
. = _start + 4
|
||||
|
||||
/* scratch space */
|
||||
mode:
|
||||
.byte 0
|
||||
disk_address_packet:
|
||||
sectors:
|
||||
.long 0
|
||||
heads:
|
||||
.long 0
|
||||
cylinders:
|
||||
.word 0
|
||||
sector_start:
|
||||
.byte 0
|
||||
head_start:
|
||||
.byte 0
|
||||
cylinder_start:
|
||||
.word 0
|
||||
/* more space... */
|
||||
|
||||
. = _start + PUPA_BOOT_MACHINE_BPBEND
|
||||
|
||||
/*
|
||||
* End of BIOS parameter block.
|
||||
*/
|
||||
|
||||
boot_version:
|
||||
.byte PUPA_BOOT_VERSION_MAJOR, PUPA_BOOT_VERSION_MINOR
|
||||
boot_drive:
|
||||
.byte 0xff /* the disk to load kernel from */
|
||||
/* 0xff means use the boot drive */
|
||||
force_lba:
|
||||
.byte 0
|
||||
kernel_address:
|
||||
.word PUPA_BOOT_MACHINE_KERNEL_ADDR
|
||||
kernel_sector:
|
||||
.long 1
|
||||
kernel_segment:
|
||||
.word PUPA_BOOT_MACHINE_KERNEL_SEG
|
||||
|
||||
after_BPB:
|
||||
|
||||
/* general setup */
|
||||
cli /* we're not safe here! */
|
||||
|
||||
/*
|
||||
* ljmp to the next instruction because some bogus BIOSes
|
||||
* jump to 07C0:0000 instead of 0000:7C00.
|
||||
*/
|
||||
ljmp $0, $ABS(real_start)
|
||||
|
||||
real_start:
|
||||
|
||||
/* set up %ds and %ss as offset from 0 */
|
||||
xorw %ax, %ax
|
||||
movw %ax, %ds
|
||||
movw %ax, %ss
|
||||
|
||||
/* set up the REAL stack */
|
||||
movw $PUPA_BOOT_MACHINE_STACK_SEG, %sp
|
||||
|
||||
sti /* we're safe again */
|
||||
|
||||
/*
|
||||
* Check if we have a forced disk reference here
|
||||
*/
|
||||
MOV_MEM_TO_AL(ABS(boot_drive)) /* movb ABS(boot_drive), %al */
|
||||
cmpb $0xff, %al
|
||||
je 1f
|
||||
movb %al, %dl
|
||||
1:
|
||||
/* save drive reference first thing! */
|
||||
pushw %dx
|
||||
|
||||
/* print a notification message on the screen */
|
||||
MSG(notification_string)
|
||||
|
||||
/* do not probe LBA if the drive is a floppy */
|
||||
testb $PUPA_BOOT_MACHINE_BIOS_HD_FLAG, %dl
|
||||
jz chs_mode
|
||||
|
||||
/* check if LBA is supported */
|
||||
movb $0x41, %ah
|
||||
movw $0x55aa, %bx
|
||||
int $0x13
|
||||
|
||||
/*
|
||||
* %dl may have been clobbered by INT 13, AH=41H.
|
||||
* This happens, for example, with AST BIOS 1.04.
|
||||
*/
|
||||
popw %dx
|
||||
pushw %dx
|
||||
|
||||
/* use CHS if fails */
|
||||
jc chs_mode
|
||||
cmpw $0xaa55, %bx
|
||||
jne chs_mode
|
||||
|
||||
/* check if AH=0x42 is supported if FORCE_LBA is zero */
|
||||
MOV_MEM_TO_AL(ABS(force_lba)) /* movb ABS(force_lba), %al */
|
||||
testb %al, %al
|
||||
jnz lba_mode
|
||||
andw $1, %cx
|
||||
jz chs_mode
|
||||
|
||||
lba_mode:
|
||||
/* save the total number of sectors */
|
||||
movl 0x10(%si), %ecx
|
||||
|
||||
/* set %si to the disk address packet */
|
||||
movw $ABS(disk_address_packet), %si
|
||||
|
||||
/* set the mode to non-zero */
|
||||
movb $1, -1(%si)
|
||||
|
||||
movl ABS(kernel_sector), %ebx
|
||||
|
||||
/* the size and the reserved byte */
|
||||
movw $0x0010, (%si)
|
||||
|
||||
/* the blocks */
|
||||
movw $1, 2(%si)
|
||||
|
||||
/* the absolute address (low 32 bits) */
|
||||
movl %ebx, 8(%si)
|
||||
|
||||
/* the segment of buffer address */
|
||||
movw $PUPA_BOOT_MACHINE_BUFFER_SEG, 6(%si)
|
||||
|
||||
xorl %eax, %eax
|
||||
movw %ax, 4(%si)
|
||||
movl %eax, 12(%si)
|
||||
|
||||
/*
|
||||
* BIOS call "INT 0x13 Function 0x42" to read sectors from disk into memory
|
||||
* Call with %ah = 0x42
|
||||
* %dl = drive number
|
||||
* %ds:%si = segment:offset of disk address packet
|
||||
* Return:
|
||||
* %al = 0x0 on success; err code on failure
|
||||
*/
|
||||
|
||||
movb $0x42, %ah
|
||||
int $0x13
|
||||
|
||||
/* LBA read is not supported, so fallback to CHS. */
|
||||
jc chs_mode
|
||||
|
||||
movw $PUPA_BOOT_MACHINE_BUFFER_SEG, %bx
|
||||
jmp copy_buffer
|
||||
|
||||
chs_mode:
|
||||
/*
|
||||
* Determine the hard disk geometry from the BIOS!
|
||||
* We do this first, so that LS-120 IDE floppies work correctly.
|
||||
*/
|
||||
movb $8, %ah
|
||||
int $0x13
|
||||
jnc final_init
|
||||
|
||||
/*
|
||||
* The call failed, so maybe use the floppy probe instead.
|
||||
*/
|
||||
testb $PUPA_BOOT_MACHINE_BIOS_HD_FLAG, %dl
|
||||
jz floppy_probe
|
||||
|
||||
/* Nope, we definitely have a hard disk, and we're screwed. */
|
||||
jmp hd_probe_error
|
||||
|
||||
final_init:
|
||||
|
||||
movw $ABS(sectors), %si
|
||||
|
||||
/* set the mode to zero */
|
||||
movb $0, -1(%si)
|
||||
|
||||
/* save number of heads */
|
||||
xorl %eax, %eax
|
||||
movb %dh, %al
|
||||
incw %ax
|
||||
movl %eax, 4(%si)
|
||||
|
||||
xorw %dx, %dx
|
||||
movb %cl, %dl
|
||||
shlw $2, %dx
|
||||
movb %ch, %al
|
||||
movb %dh, %ah
|
||||
|
||||
/* save number of cylinders */
|
||||
incw %ax
|
||||
movw %ax, 8(%si)
|
||||
|
||||
xorw %ax, %ax
|
||||
movb %dl, %al
|
||||
shrb $2, %al
|
||||
|
||||
/* save number of sectors */
|
||||
movl %eax, (%si)
|
||||
|
||||
setup_sectors:
|
||||
/* load logical sector start (bottom half) */
|
||||
movl ABS(kernel_sector), %eax
|
||||
|
||||
/* zero %edx */
|
||||
xorl %edx, %edx
|
||||
|
||||
/* divide by number of sectors */
|
||||
divl (%si)
|
||||
|
||||
/* save sector start */
|
||||
movb %dl, 10(%si)
|
||||
|
||||
xorl %edx, %edx /* zero %edx */
|
||||
divl 4(%si) /* divide by number of heads */
|
||||
|
||||
/* save head start */
|
||||
movb %dl, 11(%si)
|
||||
|
||||
/* save cylinder start */
|
||||
movw %ax, 12(%si)
|
||||
|
||||
/* do we need too many cylinders? */
|
||||
cmpw 8(%si), %ax
|
||||
jge geometry_error
|
||||
|
||||
/*
|
||||
* This is the loop for taking care of BIOS geometry translation (ugh!)
|
||||
*/
|
||||
|
||||
/* get high bits of cylinder */
|
||||
movb 13(%si), %dl
|
||||
|
||||
shlb $6, %dl /* shift left by 6 bits */
|
||||
movb 10(%si), %cl /* get sector */
|
||||
|
||||
incb %cl /* normalize sector (sectors go
|
||||
from 1-N, not 0-(N-1) ) */
|
||||
orb %dl, %cl /* composite together */
|
||||
movb 12(%si), %ch /* sector+hcyl in cl, cylinder in ch */
|
||||
|
||||
/* restore %dx */
|
||||
popw %dx
|
||||
|
||||
/* head number */
|
||||
movb 11(%si), %dh
|
||||
|
||||
/*
|
||||
* BIOS call "INT 0x13 Function 0x2" to read sectors from disk into memory
|
||||
* Call with %ah = 0x2
|
||||
* %al = number of sectors
|
||||
* %ch = cylinder
|
||||
* %cl = sector (bits 6-7 are high bits of "cylinder")
|
||||
* %dh = head
|
||||
* %dl = drive (0x80 for hard disk, 0x0 for floppy disk)
|
||||
* %es:%bx = segment:offset of buffer
|
||||
* Return:
|
||||
* %al = 0x0 on success; err code on failure
|
||||
*/
|
||||
|
||||
movw $PUPA_BOOT_MACHINE_BUFFER_SEG, %bx
|
||||
movw %bx, %es /* load %es segment with disk buffer */
|
||||
|
||||
xorw %bx, %bx /* %bx = 0, put it at 0 in the segment */
|
||||
movw $0x0201, %ax /* function 2 */
|
||||
int $0x13
|
||||
|
||||
jc read_error
|
||||
|
||||
movw %es, %bx
|
||||
|
||||
copy_buffer:
|
||||
movw ABS(kernel_segment), %es
|
||||
|
||||
/*
|
||||
* We need to save %cx and %si because the startup code in
|
||||
* kernel uses them without initializing them.
|
||||
*/
|
||||
pusha
|
||||
pushw %ds
|
||||
|
||||
movw $0x100, %cx
|
||||
movw %bx, %ds
|
||||
xorw %si, %si
|
||||
xorw %di, %di
|
||||
|
||||
cld
|
||||
|
||||
rep
|
||||
movsw
|
||||
|
||||
popw %ds
|
||||
popa
|
||||
|
||||
/* boot kernel */
|
||||
jmp *(kernel_address)
|
||||
|
||||
/* END OF MAIN LOOP */
|
||||
|
||||
/*
|
||||
* BIOS Geometry translation error (past the end of the disk geometry!).
|
||||
*/
|
||||
geometry_error:
|
||||
MSG(geometry_error_string)
|
||||
jmp general_error
|
||||
|
||||
/*
|
||||
* Disk probe failure.
|
||||
*/
|
||||
hd_probe_error:
|
||||
MSG(hd_probe_error_string)
|
||||
jmp general_error
|
||||
|
||||
/*
|
||||
* Read error on the disk.
|
||||
*/
|
||||
read_error:
|
||||
MSG(read_error_string)
|
||||
|
||||
general_error:
|
||||
MSG(general_error_string)
|
||||
|
||||
/* go here when you need to stop the machine hard after an error condition */
|
||||
stop: jmp stop
|
||||
|
||||
notification_string: .string "PUPA "
|
||||
geometry_error_string: .string "Geom"
|
||||
hd_probe_error_string: .string "Hard Disk"
|
||||
read_error_string: .string "Read"
|
||||
general_error_string: .string " Error"
|
||||
|
||||
/*
|
||||
* message: write the string pointed to by %si
|
||||
*
|
||||
* WARNING: trashes %si, %ax, and %bx
|
||||
*/
|
||||
|
||||
/*
|
||||
* Use BIOS "int 10H Function 0Eh" to write character in teletype mode
|
||||
* %ah = 0xe %al = character
|
||||
* %bh = page %bl = foreground color (graphics modes)
|
||||
*/
|
||||
1:
|
||||
movw $0x0001, %bx
|
||||
movb $0xe, %ah
|
||||
int $0x10 /* display a byte */
|
||||
message:
|
||||
lodsb
|
||||
cmpb $0, %al
|
||||
jne 1b /* if not end of string, jmp to display */
|
||||
ret
|
||||
|
||||
/*
|
||||
* Windows NT breaks compatibility by embedding a magic
|
||||
* number here.
|
||||
*/
|
||||
|
||||
. = _start + PUPA_BOOT_MACHINE_WINDOWS_NT_MAGIC
|
||||
nt_magic:
|
||||
.long 0
|
||||
.word 0
|
||||
|
||||
/*
|
||||
* This is where an MBR would go if on a hard disk. The code
|
||||
* here isn't even referenced unless we're on a floppy. Kinda
|
||||
* sneaky, huh?
|
||||
*/
|
||||
|
||||
part_start:
|
||||
. = _start + PUPA_BOOT_MACHINE_PART_START
|
||||
|
||||
probe_values:
|
||||
.byte 36, 18, 15, 9, 0
|
||||
|
||||
floppy_probe:
|
||||
/*
|
||||
* Perform floppy probe.
|
||||
*/
|
||||
|
||||
movw $ABS(probe_values-1), %si
|
||||
|
||||
probe_loop:
|
||||
/* reset floppy controller INT 13h AH=0 */
|
||||
xorw %ax, %ax
|
||||
int $0x13
|
||||
|
||||
incw %si
|
||||
movb (%si), %cl
|
||||
|
||||
/* if number of sectors is 0, display error and die */
|
||||
cmpb $0, %cl
|
||||
jne 1f
|
||||
|
||||
/*
|
||||
* Floppy disk probe failure.
|
||||
*/
|
||||
MSG(fd_probe_error_string)
|
||||
jmp general_error
|
||||
|
||||
fd_probe_error_string: .string "Floppy"
|
||||
|
||||
1:
|
||||
/* perform read */
|
||||
movw $PUPA_BOOT_MACHINE_BUFFER_SEG, %bx
|
||||
movw $0x201, %ax
|
||||
movb $0, %ch
|
||||
movb $0, %dh
|
||||
int $0x13
|
||||
|
||||
/* if error, jump to "probe_loop" */
|
||||
jc probe_loop
|
||||
|
||||
/* %cl is already the correct value! */
|
||||
movb $1, %dh
|
||||
movb $79, %ch
|
||||
|
||||
jmp final_init
|
||||
|
||||
. = _start + PUPA_BOOT_MACHINE_PART_END
|
||||
|
||||
/* the last 2 bytes in the sector 0 contain the signature */
|
||||
.word PUPA_BOOT_MACHINE_SIGNATURE
|
387
boot/i386/pc/diskboot.S
Normal file
387
boot/i386/pc/diskboot.S
Normal file
|
@ -0,0 +1,387 @@
|
|||
/*
|
||||
* PUPA -- Preliminary Universal Programming Architecture for GRUB
|
||||
* Copyright (C) 1999,2000,2001 Free Software Foundation, Inc.
|
||||
* Copyright (C) 2002 Yoshinori K. Okuji <okuji@enbug.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <pupa/machine/boot.h>
|
||||
|
||||
/*
|
||||
* defines for the code go here
|
||||
*/
|
||||
|
||||
/* Absolute addresses
|
||||
This makes the assembler generate the address without support
|
||||
from the linker. (ELF can't relocate 16-bit addresses!) */
|
||||
#define ABS(x) (x-_start+PUPA_BOOT_MACHINE_KERNEL_ADDR)
|
||||
|
||||
/* Print message string */
|
||||
#define MSG(x) movw $ABS(x), %si; call message
|
||||
|
||||
.file "diskboot.S"
|
||||
|
||||
.text
|
||||
|
||||
/* Tell GAS to generate 16-bit instructions so that this code works
|
||||
in real mode. */
|
||||
.code16
|
||||
|
||||
.globl start, _start
|
||||
start:
|
||||
_start:
|
||||
/*
|
||||
* _start is loaded at 0x2000 and is jumped to with
|
||||
* CS:IP 0:0x2000 in kernel.
|
||||
*/
|
||||
|
||||
/*
|
||||
* we continue to use the stack for boot.img and assume that
|
||||
* some registers are set to correct values. See boot.S
|
||||
* for more information.
|
||||
*/
|
||||
|
||||
/* save drive reference first thing! */
|
||||
pushw %dx
|
||||
|
||||
/* print a notification message on the screen */
|
||||
pushw %si
|
||||
MSG(notification_string)
|
||||
popw %si
|
||||
|
||||
/* this sets up for the first run through "bootloop" */
|
||||
movw $ABS(firstlist - PUPA_BOOT_MACHINE_LIST_SIZE), %di
|
||||
|
||||
/* save the sector number of the second sector in %ebp */
|
||||
movl (%di), %ebp
|
||||
|
||||
/* this is the loop for reading the rest of the kernel in */
|
||||
bootloop:
|
||||
|
||||
/* check the number of sectors to read */
|
||||
cmpw $0, 4(%di)
|
||||
|
||||
/* if zero, go to the start function */
|
||||
je bootit
|
||||
|
||||
setup_sectors:
|
||||
/* check if we use LBA or CHS */
|
||||
cmpb $0, -1(%si)
|
||||
|
||||
/* jump to chs_mode if zero */
|
||||
je chs_mode
|
||||
|
||||
lba_mode:
|
||||
/* load logical sector start */
|
||||
movl (%di), %ebx
|
||||
|
||||
/* the maximum is limited to 0x7f because of Phoenix EDD */
|
||||
xorl %eax, %eax
|
||||
movb $0x7f, %al
|
||||
|
||||
/* how many do we really want to read? */
|
||||
cmpw %ax, 4(%di) /* compare against total number of sectors */
|
||||
|
||||
/* which is greater? */
|
||||
jg 1f
|
||||
|
||||
/* if less than, set to total */
|
||||
movw 4(%di), %ax
|
||||
|
||||
1:
|
||||
/* subtract from total */
|
||||
subw %ax, 4(%di)
|
||||
|
||||
/* add into logical sector start */
|
||||
addl %eax, (%di)
|
||||
|
||||
/* set up disk address packet */
|
||||
|
||||
/* the size and the reserved byte */
|
||||
movw $0x0010, (%si)
|
||||
|
||||
/* the number of sectors */
|
||||
movw %ax, 2(%si)
|
||||
|
||||
/* the absolute address (low 32 bits) */
|
||||
movl %ebx, 8(%si)
|
||||
|
||||
/* the segment of buffer address */
|
||||
movw $PUPA_BOOT_MACHINE_BUFFER_SEG, 6(%si)
|
||||
|
||||
/* save %ax from destruction! */
|
||||
pushw %ax
|
||||
|
||||
/* zero %eax */
|
||||
xorl %eax, %eax
|
||||
|
||||
/* the offset of buffer address */
|
||||
movw %ax, 4(%si)
|
||||
|
||||
/* the absolute address (high 32 bits) */
|
||||
movl %eax, 12(%si)
|
||||
|
||||
|
||||
/*
|
||||
* BIOS call "INT 0x13 Function 0x42" to read sectors from disk into memory
|
||||
* Call with %ah = 0x42
|
||||
* %dl = drive number
|
||||
* %ds:%si = segment:offset of disk address packet
|
||||
* Return:
|
||||
* %al = 0x0 on success; err code on failure
|
||||
*/
|
||||
|
||||
movb $0x42, %ah
|
||||
int $0x13
|
||||
|
||||
jc read_error
|
||||
|
||||
movw $PUPA_BOOT_MACHINE_BUFFER_SEG, %bx
|
||||
jmp copy_buffer
|
||||
|
||||
chs_mode:
|
||||
/* load logical sector start (bottom half) */
|
||||
movl (%di), %eax
|
||||
|
||||
/* zero %edx */
|
||||
xorl %edx, %edx
|
||||
|
||||
/* divide by number of sectors */
|
||||
divl (%si)
|
||||
|
||||
/* save sector start */
|
||||
movb %dl, 10(%si)
|
||||
|
||||
xorl %edx, %edx /* zero %edx */
|
||||
divl 4(%si) /* divide by number of heads */
|
||||
|
||||
/* save head start */
|
||||
movb %dl, 11(%si)
|
||||
|
||||
/* save cylinder start */
|
||||
movw %ax, 12(%si)
|
||||
|
||||
/* do we need too many cylinders? */
|
||||
cmpw 8(%si), %ax
|
||||
jge geometry_error
|
||||
|
||||
/* determine the maximum sector length of this read */
|
||||
movw (%si), %ax /* get number of sectors per track/head */
|
||||
|
||||
/* subtract sector start */
|
||||
subb 10(%si), %al
|
||||
|
||||
/* how many do we really want to read? */
|
||||
cmpw %ax, 4(%di) /* compare against total number of sectors */
|
||||
|
||||
|
||||
/* which is greater? */
|
||||
jg 2f
|
||||
|
||||
/* if less than, set to total */
|
||||
movw 4(%di), %ax
|
||||
|
||||
2:
|
||||
/* subtract from total */
|
||||
subw %ax, 4(%di)
|
||||
|
||||
/* add into logical sector start */
|
||||
addl %eax, (%di)
|
||||
|
||||
/*
|
||||
* This is the loop for taking care of BIOS geometry translation (ugh!)
|
||||
*/
|
||||
|
||||
/* get high bits of cylinder */
|
||||
movb 13(%si), %dl
|
||||
|
||||
shlb $6, %dl /* shift left by 6 bits */
|
||||
movb 10(%si), %cl /* get sector */
|
||||
|
||||
incb %cl /* normalize sector (sectors go
|
||||
from 1-N, not 0-(N-1) ) */
|
||||
orb %dl, %cl /* composite together */
|
||||
movb 12(%si), %ch /* sector+hcyl in cl, cylinder in ch */
|
||||
|
||||
/* restore %dx */
|
||||
popw %dx
|
||||
pushw %dx
|
||||
|
||||
/* head number */
|
||||
movb 11(%si), %dh
|
||||
|
||||
pushw %ax /* save %ax from destruction! */
|
||||
|
||||
/*
|
||||
* BIOS call "INT 0x13 Function 0x2" to read sectors from disk into memory
|
||||
* Call with %ah = 0x2
|
||||
* %al = number of sectors
|
||||
* %ch = cylinder
|
||||
* %cl = sector (bits 6-7 are high bits of "cylinder")
|
||||
* %dh = head
|
||||
* %dl = drive (0x80 for hard disk, 0x0 for floppy disk)
|
||||
* %es:%bx = segment:offset of buffer
|
||||
* Return:
|
||||
* %al = 0x0 on success; err code on failure
|
||||
*/
|
||||
|
||||
movw $PUPA_BOOT_MACHINE_BUFFER_SEG, %bx
|
||||
movw %bx, %es /* load %es segment with disk buffer */
|
||||
|
||||
xorw %bx, %bx /* %bx = 0, put it at 0 in the segment */
|
||||
movb $0x2, %ah /* function 2 */
|
||||
int $0x13
|
||||
|
||||
jc read_error
|
||||
|
||||
/* save source segment */
|
||||
movw %es, %bx
|
||||
|
||||
copy_buffer:
|
||||
|
||||
/* load addresses for copy from disk buffer to destination */
|
||||
movw 6(%di), %es /* load destination segment */
|
||||
|
||||
/* restore %ax */
|
||||
popw %ax
|
||||
|
||||
/* determine the next possible destination address (presuming
|
||||
512 byte sectors!) */
|
||||
shlw $5, %ax /* shift %ax five bits to the left */
|
||||
addw %ax, 6(%di) /* add the corrected value to the destination
|
||||
address for next time */
|
||||
|
||||
/* save addressing regs */
|
||||
pusha
|
||||
pushw %ds
|
||||
|
||||
/* get the copy length */
|
||||
shlw $3, %ax
|
||||
movw %ax, %cx
|
||||
|
||||
xorw %di, %di /* zero offset of destination addresses */
|
||||
xorw %si, %si /* zero offset of source addresses */
|
||||
movw %bx, %ds /* restore the source segment */
|
||||
|
||||
cld /* sets the copy direction to forward */
|
||||
|
||||
/* perform copy */
|
||||
rep /* sets a repeat */
|
||||
movsw /* this runs the actual copy */
|
||||
|
||||
/* restore addressing regs and print a dot with correct DS
|
||||
(MSG modifies SI, which is saved, and unused AX and BX) */
|
||||
popw %ds
|
||||
MSG(notification_step)
|
||||
popa
|
||||
|
||||
/* check if finished with this dataset */
|
||||
cmpw $0, 4(%di)
|
||||
jne setup_sectors
|
||||
|
||||
/* update position to load from */
|
||||
subw $PUPA_BOOT_MACHINE_LIST_SIZE, %di
|
||||
|
||||
/* jump to bootloop */
|
||||
jmp bootloop
|
||||
|
||||
/* END OF MAIN LOOP */
|
||||
|
||||
bootit:
|
||||
/* print a newline */
|
||||
MSG(notification_done)
|
||||
popw %dx /* this makes sure %dl is our "boot" drive */
|
||||
ljmp $0, $(PUPA_BOOT_MACHINE_KERNEL_ADDR + 0x200)
|
||||
|
||||
|
||||
/*
|
||||
* BIOS Geometry translation error (past the end of the disk geometry!).
|
||||
*/
|
||||
geometry_error:
|
||||
MSG(geometry_error_string)
|
||||
jmp general_error
|
||||
|
||||
/*
|
||||
* Read error on the disk.
|
||||
*/
|
||||
read_error:
|
||||
MSG(read_error_string)
|
||||
|
||||
general_error:
|
||||
MSG(general_error_string)
|
||||
|
||||
/* go here when you need to stop the machine hard after an error condition */
|
||||
stop: jmp stop
|
||||
|
||||
notification_string: .string "Loading kernel"
|
||||
|
||||
notification_step: .string "."
|
||||
notification_done: .string "\r\n"
|
||||
|
||||
geometry_error_string: .string "Geom"
|
||||
read_error_string: .string "Read"
|
||||
general_error_string: .string " Error"
|
||||
|
||||
/*
|
||||
* message: write the string pointed to by %si
|
||||
*
|
||||
* WARNING: trashes %si, %ax, and %bx
|
||||
*/
|
||||
|
||||
/*
|
||||
* Use BIOS "int 10H Function 0Eh" to write character in teletype mode
|
||||
* %ah = 0xe %al = character
|
||||
* %bh = page %bl = foreground color (graphics modes)
|
||||
*/
|
||||
1:
|
||||
movw $0x0001, %bx
|
||||
movb $0xe, %ah
|
||||
int $0x10 /* display a byte */
|
||||
|
||||
incw %si
|
||||
message:
|
||||
movb (%si), %al
|
||||
cmpb $0, %al
|
||||
jne 1b /* if not end of string, jmp to display */
|
||||
ret
|
||||
lastlist:
|
||||
|
||||
/*
|
||||
* This area is an empty space between the main body of code below which
|
||||
* grows up (fixed after compilation, but between releases it may change
|
||||
* in size easily), and the lists of sectors to read, which grows down
|
||||
* from a fixed top location.
|
||||
*/
|
||||
|
||||
.word 0
|
||||
.word 0
|
||||
|
||||
. = _start + 0x200 - PUPA_BOOT_MACHINE_LIST_SIZE
|
||||
|
||||
/* fill the first data listing with the default */
|
||||
blocklist_default_start:
|
||||
/* this is the sector start parameter, in logical sectors from
|
||||
the start of the disk, sector 0 */
|
||||
.long 2
|
||||
blocklist_default_len:
|
||||
/* this is the number of sectors to read the command "install"
|
||||
will fill this up */
|
||||
.word 0
|
||||
blocklist_default_seg:
|
||||
/* this is the segment of the starting address to load the data into */
|
||||
.word (PUPA_BOOT_MACHINE_KERNEL_SEG + 0x20)
|
||||
|
||||
firstlist: /* this label has to be after the list data!!! */
|
379
conf/i386-pc.mk
Normal file
379
conf/i386-pc.mk
Normal file
|
@ -0,0 +1,379 @@
|
|||
# -*- makefile -*-
|
||||
|
||||
COMMON_ASFLAGS = -nostdinc -fno-builtin
|
||||
COMMON_CFLAGS = -fno-builtin
|
||||
|
||||
# Images.
|
||||
pkgdata_IMAGES = boot.img diskboot.img kernel.img
|
||||
|
||||
# For boot.img.
|
||||
boot_img_SOURCES = boot/i386/pc/boot.S
|
||||
CLEANFILES += boot.img boot.exec boot_img-boot_i386_pc_boot.o
|
||||
MOSTLYCLEANFILES += boot_img-boot_i386_pc_boot.d
|
||||
|
||||
boot.img: boot.exec
|
||||
$(OBJCOPY) -O binary -R .note -R .comment $< $@
|
||||
|
||||
boot.exec: boot_img-boot_i386_pc_boot.o
|
||||
$(CC) $(LDFLAGS) $(boot_img_LDFLAGS) -o $@ $^
|
||||
|
||||
boot_img-boot_i386_pc_boot.o: boot/i386/pc/boot.S
|
||||
$(CC) -Iboot/i386/pc -I$(srcdir)/boot/i386/pc $(CPPFLAGS) -DASM_FILE=1 $(ASFLAGS) $(boot_img_ASFLAGS) -c -o $@ $<
|
||||
|
||||
boot_img-boot_i386_pc_boot.d: boot/i386/pc/boot.S
|
||||
set -e; $(CC) -Iboot/i386/pc -I$(srcdir)/boot/i386/pc $(CPPFLAGS) -DASM_FILE=1 $(ASFLAGS) $(boot_img_ASFLAGS) -M $< | sed 's,boot\.o[ :]*,boot_img-boot_i386_pc_boot.o $@ : ,g' > $@; [ -s $@ ] || rm -f $@
|
||||
|
||||
-include boot_img-boot_i386_pc_boot.d
|
||||
|
||||
boot_img_ASFLAGS = $(COMMON_ASFLAGS)
|
||||
boot_img_LDFLAGS = -nostdlib -Wl,-N,-Ttext,7C00
|
||||
|
||||
# For diskboot.img.
|
||||
diskboot_img_SOURCES = boot/i386/pc/diskboot.S
|
||||
CLEANFILES += diskboot.img diskboot.exec diskboot_img-boot_i386_pc_diskboot.o
|
||||
MOSTLYCLEANFILES += diskboot_img-boot_i386_pc_diskboot.d
|
||||
|
||||
diskboot.img: diskboot.exec
|
||||
$(OBJCOPY) -O binary -R .note -R .comment $< $@
|
||||
|
||||
diskboot.exec: diskboot_img-boot_i386_pc_diskboot.o
|
||||
$(CC) $(LDFLAGS) $(diskboot_img_LDFLAGS) -o $@ $^
|
||||
|
||||
diskboot_img-boot_i386_pc_diskboot.o: boot/i386/pc/diskboot.S
|
||||
$(CC) -Iboot/i386/pc -I$(srcdir)/boot/i386/pc $(CPPFLAGS) -DASM_FILE=1 $(ASFLAGS) $(diskboot_img_ASFLAGS) -c -o $@ $<
|
||||
|
||||
diskboot_img-boot_i386_pc_diskboot.d: boot/i386/pc/diskboot.S
|
||||
set -e; $(CC) -Iboot/i386/pc -I$(srcdir)/boot/i386/pc $(CPPFLAGS) -DASM_FILE=1 $(ASFLAGS) $(diskboot_img_ASFLAGS) -M $< | sed 's,diskboot\.o[ :]*,diskboot_img-boot_i386_pc_diskboot.o $@ : ,g' > $@; [ -s $@ ] || rm -f $@
|
||||
|
||||
-include diskboot_img-boot_i386_pc_diskboot.d
|
||||
|
||||
diskboot_img_ASFLAGS = $(COMMON_ASFLAGS)
|
||||
diskboot_img_LDFLAGS = -nostdlib -Wl,-N,-Ttext,8000
|
||||
|
||||
# For kernel.img.
|
||||
kernel_img_SOURCES = kern/i386/pc/startup.S kern/main.c kern/device.c \
|
||||
kern/disk.c kern/dl.c kern/file.c kern/fs.c kern/err.c \
|
||||
kern/misc.c kern/mm.c kern/loader.c kern/rescue.c kern/term.c \
|
||||
kern/i386/dl.c kern/i386/pc/init.c disk/i386/pc/partition.c \
|
||||
disk/i386/pc/biosdisk.c \
|
||||
term/i386/pc/console.c \
|
||||
symlist.c
|
||||
CLEANFILES += kernel.img kernel.exec kernel_img-kern_i386_pc_startup.o kernel_img-kern_main.o kernel_img-kern_device.o kernel_img-kern_disk.o kernel_img-kern_dl.o kernel_img-kern_file.o kernel_img-kern_fs.o kernel_img-kern_err.o kernel_img-kern_misc.o kernel_img-kern_mm.o kernel_img-kern_loader.o kernel_img-kern_rescue.o kernel_img-kern_term.o kernel_img-kern_i386_dl.o kernel_img-kern_i386_pc_init.o kernel_img-disk_i386_pc_partition.o kernel_img-disk_i386_pc_biosdisk.o kernel_img-term_i386_pc_console.o kernel_img-symlist.o
|
||||
MOSTLYCLEANFILES += kernel_img-kern_i386_pc_startup.d kernel_img-kern_main.d kernel_img-kern_device.d kernel_img-kern_disk.d kernel_img-kern_dl.d kernel_img-kern_file.d kernel_img-kern_fs.d kernel_img-kern_err.d kernel_img-kern_misc.d kernel_img-kern_mm.d kernel_img-kern_loader.d kernel_img-kern_rescue.d kernel_img-kern_term.d kernel_img-kern_i386_dl.d kernel_img-kern_i386_pc_init.d kernel_img-disk_i386_pc_partition.d kernel_img-disk_i386_pc_biosdisk.d kernel_img-term_i386_pc_console.d kernel_img-symlist.d
|
||||
|
||||
kernel.img: kernel.exec
|
||||
$(OBJCOPY) -O binary -R .note -R .comment $< $@
|
||||
|
||||
kernel.exec: kernel_img-kern_i386_pc_startup.o kernel_img-kern_main.o kernel_img-kern_device.o kernel_img-kern_disk.o kernel_img-kern_dl.o kernel_img-kern_file.o kernel_img-kern_fs.o kernel_img-kern_err.o kernel_img-kern_misc.o kernel_img-kern_mm.o kernel_img-kern_loader.o kernel_img-kern_rescue.o kernel_img-kern_term.o kernel_img-kern_i386_dl.o kernel_img-kern_i386_pc_init.o kernel_img-disk_i386_pc_partition.o kernel_img-disk_i386_pc_biosdisk.o kernel_img-term_i386_pc_console.o kernel_img-symlist.o
|
||||
$(CC) $(LDFLAGS) $(kernel_img_LDFLAGS) -o $@ $^
|
||||
|
||||
kernel_img-kern_i386_pc_startup.o: kern/i386/pc/startup.S
|
||||
$(CC) -Ikern/i386/pc -I$(srcdir)/kern/i386/pc $(CPPFLAGS) -DASM_FILE=1 $(ASFLAGS) $(kernel_img_ASFLAGS) -c -o $@ $<
|
||||
|
||||
kernel_img-kern_i386_pc_startup.d: kern/i386/pc/startup.S
|
||||
set -e; $(CC) -Ikern/i386/pc -I$(srcdir)/kern/i386/pc $(CPPFLAGS) -DASM_FILE=1 $(ASFLAGS) $(kernel_img_ASFLAGS) -M $< | sed 's,startup\.o[ :]*,kernel_img-kern_i386_pc_startup.o $@ : ,g' > $@; [ -s $@ ] || rm -f $@
|
||||
|
||||
-include kernel_img-kern_i386_pc_startup.d
|
||||
|
||||
kernel_img-kern_main.o: kern/main.c
|
||||
$(CC) -Ikern -I$(srcdir)/kern $(CPPFLAGS) $(CFLAGS) $(kernel_img_CFLAGS) -c -o $@ $<
|
||||
|
||||
kernel_img-kern_main.d: kern/main.c
|
||||
set -e; $(CC) -Ikern -I$(srcdir)/kern $(CPPFLAGS) $(CFLAGS) $(kernel_img_CFLAGS) -M $< | sed 's,main\.o[ :]*,kernel_img-kern_main.o $@ : ,g' > $@; [ -s $@ ] || rm -f $@
|
||||
|
||||
-include kernel_img-kern_main.d
|
||||
|
||||
kernel_img-kern_device.o: kern/device.c
|
||||
$(CC) -Ikern -I$(srcdir)/kern $(CPPFLAGS) $(CFLAGS) $(kernel_img_CFLAGS) -c -o $@ $<
|
||||
|
||||
kernel_img-kern_device.d: kern/device.c
|
||||
set -e; $(CC) -Ikern -I$(srcdir)/kern $(CPPFLAGS) $(CFLAGS) $(kernel_img_CFLAGS) -M $< | sed 's,device\.o[ :]*,kernel_img-kern_device.o $@ : ,g' > $@; [ -s $@ ] || rm -f $@
|
||||
|
||||
-include kernel_img-kern_device.d
|
||||
|
||||
kernel_img-kern_disk.o: kern/disk.c
|
||||
$(CC) -Ikern -I$(srcdir)/kern $(CPPFLAGS) $(CFLAGS) $(kernel_img_CFLAGS) -c -o $@ $<
|
||||
|
||||
kernel_img-kern_disk.d: kern/disk.c
|
||||
set -e; $(CC) -Ikern -I$(srcdir)/kern $(CPPFLAGS) $(CFLAGS) $(kernel_img_CFLAGS) -M $< | sed 's,disk\.o[ :]*,kernel_img-kern_disk.o $@ : ,g' > $@; [ -s $@ ] || rm -f $@
|
||||
|
||||
-include kernel_img-kern_disk.d
|
||||
|
||||
kernel_img-kern_dl.o: kern/dl.c
|
||||
$(CC) -Ikern -I$(srcdir)/kern $(CPPFLAGS) $(CFLAGS) $(kernel_img_CFLAGS) -c -o $@ $<
|
||||
|
||||
kernel_img-kern_dl.d: kern/dl.c
|
||||
set -e; $(CC) -Ikern -I$(srcdir)/kern $(CPPFLAGS) $(CFLAGS) $(kernel_img_CFLAGS) -M $< | sed 's,dl\.o[ :]*,kernel_img-kern_dl.o $@ : ,g' > $@; [ -s $@ ] || rm -f $@
|
||||
|
||||
-include kernel_img-kern_dl.d
|
||||
|
||||
kernel_img-kern_file.o: kern/file.c
|
||||
$(CC) -Ikern -I$(srcdir)/kern $(CPPFLAGS) $(CFLAGS) $(kernel_img_CFLAGS) -c -o $@ $<
|
||||
|
||||
kernel_img-kern_file.d: kern/file.c
|
||||
set -e; $(CC) -Ikern -I$(srcdir)/kern $(CPPFLAGS) $(CFLAGS) $(kernel_img_CFLAGS) -M $< | sed 's,file\.o[ :]*,kernel_img-kern_file.o $@ : ,g' > $@; [ -s $@ ] || rm -f $@
|
||||
|
||||
-include kernel_img-kern_file.d
|
||||
|
||||
kernel_img-kern_fs.o: kern/fs.c
|
||||
$(CC) -Ikern -I$(srcdir)/kern $(CPPFLAGS) $(CFLAGS) $(kernel_img_CFLAGS) -c -o $@ $<
|
||||
|
||||
kernel_img-kern_fs.d: kern/fs.c
|
||||
set -e; $(CC) -Ikern -I$(srcdir)/kern $(CPPFLAGS) $(CFLAGS) $(kernel_img_CFLAGS) -M $< | sed 's,fs\.o[ :]*,kernel_img-kern_fs.o $@ : ,g' > $@; [ -s $@ ] || rm -f $@
|
||||
|
||||
-include kernel_img-kern_fs.d
|
||||
|
||||
kernel_img-kern_err.o: kern/err.c
|
||||
$(CC) -Ikern -I$(srcdir)/kern $(CPPFLAGS) $(CFLAGS) $(kernel_img_CFLAGS) -c -o $@ $<
|
||||
|
||||
kernel_img-kern_err.d: kern/err.c
|
||||
set -e; $(CC) -Ikern -I$(srcdir)/kern $(CPPFLAGS) $(CFLAGS) $(kernel_img_CFLAGS) -M $< | sed 's,err\.o[ :]*,kernel_img-kern_err.o $@ : ,g' > $@; [ -s $@ ] || rm -f $@
|
||||
|
||||
-include kernel_img-kern_err.d
|
||||
|
||||
kernel_img-kern_misc.o: kern/misc.c
|
||||
$(CC) -Ikern -I$(srcdir)/kern $(CPPFLAGS) $(CFLAGS) $(kernel_img_CFLAGS) -c -o $@ $<
|
||||
|
||||
kernel_img-kern_misc.d: kern/misc.c
|
||||
set -e; $(CC) -Ikern -I$(srcdir)/kern $(CPPFLAGS) $(CFLAGS) $(kernel_img_CFLAGS) -M $< | sed 's,misc\.o[ :]*,kernel_img-kern_misc.o $@ : ,g' > $@; [ -s $@ ] || rm -f $@
|
||||
|
||||
-include kernel_img-kern_misc.d
|
||||
|
||||
kernel_img-kern_mm.o: kern/mm.c
|
||||
$(CC) -Ikern -I$(srcdir)/kern $(CPPFLAGS) $(CFLAGS) $(kernel_img_CFLAGS) -c -o $@ $<
|
||||
|
||||
kernel_img-kern_mm.d: kern/mm.c
|
||||
set -e; $(CC) -Ikern -I$(srcdir)/kern $(CPPFLAGS) $(CFLAGS) $(kernel_img_CFLAGS) -M $< | sed 's,mm\.o[ :]*,kernel_img-kern_mm.o $@ : ,g' > $@; [ -s $@ ] || rm -f $@
|
||||
|
||||
-include kernel_img-kern_mm.d
|
||||
|
||||
kernel_img-kern_loader.o: kern/loader.c
|
||||
$(CC) -Ikern -I$(srcdir)/kern $(CPPFLAGS) $(CFLAGS) $(kernel_img_CFLAGS) -c -o $@ $<
|
||||
|
||||
kernel_img-kern_loader.d: kern/loader.c
|
||||
set -e; $(CC) -Ikern -I$(srcdir)/kern $(CPPFLAGS) $(CFLAGS) $(kernel_img_CFLAGS) -M $< | sed 's,loader\.o[ :]*,kernel_img-kern_loader.o $@ : ,g' > $@; [ -s $@ ] || rm -f $@
|
||||
|
||||
-include kernel_img-kern_loader.d
|
||||
|
||||
kernel_img-kern_rescue.o: kern/rescue.c
|
||||
$(CC) -Ikern -I$(srcdir)/kern $(CPPFLAGS) $(CFLAGS) $(kernel_img_CFLAGS) -c -o $@ $<
|
||||
|
||||
kernel_img-kern_rescue.d: kern/rescue.c
|
||||
set -e; $(CC) -Ikern -I$(srcdir)/kern $(CPPFLAGS) $(CFLAGS) $(kernel_img_CFLAGS) -M $< | sed 's,rescue\.o[ :]*,kernel_img-kern_rescue.o $@ : ,g' > $@; [ -s $@ ] || rm -f $@
|
||||
|
||||
-include kernel_img-kern_rescue.d
|
||||
|
||||
kernel_img-kern_term.o: kern/term.c
|
||||
$(CC) -Ikern -I$(srcdir)/kern $(CPPFLAGS) $(CFLAGS) $(kernel_img_CFLAGS) -c -o $@ $<
|
||||
|
||||
kernel_img-kern_term.d: kern/term.c
|
||||
set -e; $(CC) -Ikern -I$(srcdir)/kern $(CPPFLAGS) $(CFLAGS) $(kernel_img_CFLAGS) -M $< | sed 's,term\.o[ :]*,kernel_img-kern_term.o $@ : ,g' > $@; [ -s $@ ] || rm -f $@
|
||||
|
||||
-include kernel_img-kern_term.d
|
||||
|
||||
kernel_img-kern_i386_dl.o: kern/i386/dl.c
|
||||
$(CC) -Ikern/i386 -I$(srcdir)/kern/i386 $(CPPFLAGS) $(CFLAGS) $(kernel_img_CFLAGS) -c -o $@ $<
|
||||
|
||||
kernel_img-kern_i386_dl.d: kern/i386/dl.c
|
||||
set -e; $(CC) -Ikern/i386 -I$(srcdir)/kern/i386 $(CPPFLAGS) $(CFLAGS) $(kernel_img_CFLAGS) -M $< | sed 's,dl\.o[ :]*,kernel_img-kern_i386_dl.o $@ : ,g' > $@; [ -s $@ ] || rm -f $@
|
||||
|
||||
-include kernel_img-kern_i386_dl.d
|
||||
|
||||
kernel_img-kern_i386_pc_init.o: kern/i386/pc/init.c
|
||||
$(CC) -Ikern/i386/pc -I$(srcdir)/kern/i386/pc $(CPPFLAGS) $(CFLAGS) $(kernel_img_CFLAGS) -c -o $@ $<
|
||||
|
||||
kernel_img-kern_i386_pc_init.d: kern/i386/pc/init.c
|
||||
set -e; $(CC) -Ikern/i386/pc -I$(srcdir)/kern/i386/pc $(CPPFLAGS) $(CFLAGS) $(kernel_img_CFLAGS) -M $< | sed 's,init\.o[ :]*,kernel_img-kern_i386_pc_init.o $@ : ,g' > $@; [ -s $@ ] || rm -f $@
|
||||
|
||||
-include kernel_img-kern_i386_pc_init.d
|
||||
|
||||
kernel_img-disk_i386_pc_partition.o: disk/i386/pc/partition.c
|
||||
$(CC) -Idisk/i386/pc -I$(srcdir)/disk/i386/pc $(CPPFLAGS) $(CFLAGS) $(kernel_img_CFLAGS) -c -o $@ $<
|
||||
|
||||
kernel_img-disk_i386_pc_partition.d: disk/i386/pc/partition.c
|
||||
set -e; $(CC) -Idisk/i386/pc -I$(srcdir)/disk/i386/pc $(CPPFLAGS) $(CFLAGS) $(kernel_img_CFLAGS) -M $< | sed 's,partition\.o[ :]*,kernel_img-disk_i386_pc_partition.o $@ : ,g' > $@; [ -s $@ ] || rm -f $@
|
||||
|
||||
-include kernel_img-disk_i386_pc_partition.d
|
||||
|
||||
kernel_img-disk_i386_pc_biosdisk.o: disk/i386/pc/biosdisk.c
|
||||
$(CC) -Idisk/i386/pc -I$(srcdir)/disk/i386/pc $(CPPFLAGS) $(CFLAGS) $(kernel_img_CFLAGS) -c -o $@ $<
|
||||
|
||||
kernel_img-disk_i386_pc_biosdisk.d: disk/i386/pc/biosdisk.c
|
||||
set -e; $(CC) -Idisk/i386/pc -I$(srcdir)/disk/i386/pc $(CPPFLAGS) $(CFLAGS) $(kernel_img_CFLAGS) -M $< | sed 's,biosdisk\.o[ :]*,kernel_img-disk_i386_pc_biosdisk.o $@ : ,g' > $@; [ -s $@ ] || rm -f $@
|
||||
|
||||
-include kernel_img-disk_i386_pc_biosdisk.d
|
||||
|
||||
kernel_img-term_i386_pc_console.o: term/i386/pc/console.c
|
||||
$(CC) -Iterm/i386/pc -I$(srcdir)/term/i386/pc $(CPPFLAGS) $(CFLAGS) $(kernel_img_CFLAGS) -c -o $@ $<
|
||||
|
||||
kernel_img-term_i386_pc_console.d: term/i386/pc/console.c
|
||||
set -e; $(CC) -Iterm/i386/pc -I$(srcdir)/term/i386/pc $(CPPFLAGS) $(CFLAGS) $(kernel_img_CFLAGS) -M $< | sed 's,console\.o[ :]*,kernel_img-term_i386_pc_console.o $@ : ,g' > $@; [ -s $@ ] || rm -f $@
|
||||
|
||||
-include kernel_img-term_i386_pc_console.d
|
||||
|
||||
kernel_img-symlist.o: symlist.c
|
||||
$(CC) -I. -I$(srcdir)/. $(CPPFLAGS) $(CFLAGS) $(kernel_img_CFLAGS) -c -o $@ $<
|
||||
|
||||
kernel_img-symlist.d: symlist.c
|
||||
set -e; $(CC) -I. -I$(srcdir)/. $(CPPFLAGS) $(CFLAGS) $(kernel_img_CFLAGS) -M $< | sed 's,symlist\.o[ :]*,kernel_img-symlist.o $@ : ,g' > $@; [ -s $@ ] || rm -f $@
|
||||
|
||||
-include kernel_img-symlist.d
|
||||
|
||||
kernel_img_HEADERS = boot.h device.h disk.h dl.h elf.h err.h \
|
||||
file.h fs.h kernel.h loader.h misc.h mm.h net.h rescue.h symbol.h \
|
||||
term.h types.h machine/biosdisk.h machine/boot.h \
|
||||
machine/console.h machine/init.h machine/memory.h \
|
||||
machine/loader.h machine/partition.h
|
||||
kernel_img_CFLAGS = $(COMMON_CFLAGS)
|
||||
kernel_img_ASFLAGS = $(COMMON_ASFLAGS)
|
||||
kernel_img_LDFLAGS = -nostdlib -Wl,-N,-Ttext,8200
|
||||
|
||||
MOSTLYCLEANFILES += symlist.c kernel_syms.lst
|
||||
DEFSYMFILES += kernel_syms.lst
|
||||
|
||||
symlist.c: $(addprefix include/pupa/,$(kernel_img_HEADERS)) gensymlist.sh
|
||||
sh $(srcdir)/gensymlist.sh $(filter %.h,$^) > $@
|
||||
|
||||
kernel_syms.lst: $(addprefix include/pupa/,$(kernel_img_HEADERS)) genkernsyms.sh
|
||||
sh $(srcdir)/genkernsyms.sh $(filter %h,$^) > $@
|
||||
|
||||
# Utilities.
|
||||
bin_UTILITIES = pupa-mkimage
|
||||
noinst_UTILITIES = genmoddep
|
||||
|
||||
# For pupa-mkimage.
|
||||
pupa_mkimage_SOURCES = util/i386/pc/pupa-mkimage.c util/misc.c \
|
||||
util/resolve.c
|
||||
CLEANFILES += pupa-mkimage pupa_mkimage-util_i386_pc_pupa_mkimage.o pupa_mkimage-util_misc.o pupa_mkimage-util_resolve.o
|
||||
MOSTLYCLEANFILES += pupa_mkimage-util_i386_pc_pupa_mkimage.d pupa_mkimage-util_misc.d pupa_mkimage-util_resolve.d
|
||||
|
||||
pupa-mkimage: pupa_mkimage-util_i386_pc_pupa_mkimage.o pupa_mkimage-util_misc.o pupa_mkimage-util_resolve.o
|
||||
$(BUILD_CC) $(BUILD_LDFLAGS) $(pupa_mkimage_LDFLAGS) -o $@ $^
|
||||
|
||||
pupa_mkimage-util_i386_pc_pupa_mkimage.o: util/i386/pc/pupa-mkimage.c
|
||||
$(BUILD_CC) -Iutil/i386/pc -I$(srcdir)/util/i386/pc $(BUILD_CPPFLAGS) -DPUPA_UTIL=1 $(pupa_mkimage_CFLAGS) -c -o $@ $<
|
||||
|
||||
pupa_mkimage-util_i386_pc_pupa_mkimage.d: util/i386/pc/pupa-mkimage.c
|
||||
set -e; $(BUILD_CC) -Iutil/i386/pc -I$(srcdir)/util/i386/pc $(BUILD_CPPFLAGS) -DPUPA_UTIL=1 $(pupa_mkimage_CFLAGS) -M $< | sed 's,pupa\-mkimage\.o[ :]*,pupa_mkimage-util_i386_pc_pupa_mkimage.o $@ : ,g' > $@; [ -s $@ ] || rm -f $@
|
||||
|
||||
-include pupa_mkimage-util_i386_pc_pupa_mkimage.d
|
||||
|
||||
pupa_mkimage-util_misc.o: util/misc.c
|
||||
$(BUILD_CC) -Iutil -I$(srcdir)/util $(BUILD_CPPFLAGS) -DPUPA_UTIL=1 $(pupa_mkimage_CFLAGS) -c -o $@ $<
|
||||
|
||||
pupa_mkimage-util_misc.d: util/misc.c
|
||||
set -e; $(BUILD_CC) -Iutil -I$(srcdir)/util $(BUILD_CPPFLAGS) -DPUPA_UTIL=1 $(pupa_mkimage_CFLAGS) -M $< | sed 's,misc\.o[ :]*,pupa_mkimage-util_misc.o $@ : ,g' > $@; [ -s $@ ] || rm -f $@
|
||||
|
||||
-include pupa_mkimage-util_misc.d
|
||||
|
||||
pupa_mkimage-util_resolve.o: util/resolve.c
|
||||
$(BUILD_CC) -Iutil -I$(srcdir)/util $(BUILD_CPPFLAGS) -DPUPA_UTIL=1 $(pupa_mkimage_CFLAGS) -c -o $@ $<
|
||||
|
||||
pupa_mkimage-util_resolve.d: util/resolve.c
|
||||
set -e; $(BUILD_CC) -Iutil -I$(srcdir)/util $(BUILD_CPPFLAGS) -DPUPA_UTIL=1 $(pupa_mkimage_CFLAGS) -M $< | sed 's,resolve\.o[ :]*,pupa_mkimage-util_resolve.o $@ : ,g' > $@; [ -s $@ ] || rm -f $@
|
||||
|
||||
-include pupa_mkimage-util_resolve.d
|
||||
|
||||
|
||||
# For genmoddep.
|
||||
genmoddep_SOURCES = util/genmoddep.c
|
||||
CLEANFILES += genmoddep genmoddep-util_genmoddep.o
|
||||
MOSTLYCLEANFILES += genmoddep-util_genmoddep.d
|
||||
|
||||
genmoddep: genmoddep-util_genmoddep.o
|
||||
$(BUILD_CC) $(BUILD_LDFLAGS) $(genmoddep_LDFLAGS) -o $@ $^
|
||||
|
||||
genmoddep-util_genmoddep.o: util/genmoddep.c
|
||||
$(BUILD_CC) -Iutil -I$(srcdir)/util $(BUILD_CPPFLAGS) -DPUPA_UTIL=1 $(genmoddep_CFLAGS) -c -o $@ $<
|
||||
|
||||
genmoddep-util_genmoddep.d: util/genmoddep.c
|
||||
set -e; $(BUILD_CC) -Iutil -I$(srcdir)/util $(BUILD_CPPFLAGS) -DPUPA_UTIL=1 $(genmoddep_CFLAGS) -M $< | sed 's,genmoddep\.o[ :]*,genmoddep-util_genmoddep.o $@ : ,g' > $@; [ -s $@ ] || rm -f $@
|
||||
|
||||
-include genmoddep-util_genmoddep.d
|
||||
|
||||
|
||||
# Modules.
|
||||
pkgdata_MODULES = chain.mod fat.mod
|
||||
|
||||
# For chain.mod.
|
||||
chain_mod_SOURCES = loader/i386/pc/chainloader.c
|
||||
CLEANFILES += chain.mod mod-chain.o mod-chain.c pre-chain.o chain_mod-loader_i386_pc_chainloader.o def-chain.lst und-chain.lst
|
||||
MOSTLYCLEANFILES += chain_mod-loader_i386_pc_chainloader.d
|
||||
DEFSYMFILES += def-chain.lst
|
||||
UNDSYMFILES += und-chain.lst
|
||||
|
||||
chain.mod: pre-chain.o mod-chain.o
|
||||
-rm -f $@
|
||||
$(LD) -r -o $@ $^
|
||||
$(STRIP) --strip-unneeded -K pupa_mod_init -K pupa_mod_fini -R .note -R .comment $@
|
||||
|
||||
pre-chain.o: chain_mod-loader_i386_pc_chainloader.o
|
||||
-rm -f $@
|
||||
$(LD) -r -o $@ $^
|
||||
|
||||
mod-chain.o: mod-chain.c
|
||||
$(CC) $(CPPFLAGS) $(CFLAGS) -c -o $@ $<
|
||||
|
||||
mod-chain.c: moddep.lst genmodsrc.sh
|
||||
sh $(srcdir)/genmodsrc.sh 'chain' $< > $@ || (rm -f $@; exit 1)
|
||||
|
||||
def-chain.lst: pre-chain.o
|
||||
$(NM) -g --defined-only -P -p $< | sed 's/^\([^ ]*\).*/\1 chain/' > $@
|
||||
|
||||
und-chain.lst: pre-chain.o
|
||||
echo 'chain' > $@
|
||||
$(NM) -u -P -p $< >> $@
|
||||
|
||||
chain_mod-loader_i386_pc_chainloader.o: loader/i386/pc/chainloader.c
|
||||
$(CC) -Iloader/i386/pc -I$(srcdir)/loader/i386/pc $(CPPFLAGS) $(CFLAGS) $(chain_mod_CFLAGS) -c -o $@ $<
|
||||
|
||||
chain_mod-loader_i386_pc_chainloader.d: loader/i386/pc/chainloader.c
|
||||
set -e; $(CC) -Iloader/i386/pc -I$(srcdir)/loader/i386/pc $(CPPFLAGS) $(CFLAGS) $(chain_mod_CFLAGS) -M $< | sed 's,chainloader\.o[ :]*,chain_mod-loader_i386_pc_chainloader.o $@ : ,g' > $@; [ -s $@ ] || rm -f $@
|
||||
|
||||
-include chain_mod-loader_i386_pc_chainloader.d
|
||||
|
||||
chain_mod_CFLAGS = $(COMMON_CFLAGS)
|
||||
|
||||
# For fat.mod.
|
||||
fat_mod_SOURCES = fs/fat.c
|
||||
CLEANFILES += fat.mod mod-fat.o mod-fat.c pre-fat.o fat_mod-fs_fat.o def-fat.lst und-fat.lst
|
||||
MOSTLYCLEANFILES += fat_mod-fs_fat.d
|
||||
DEFSYMFILES += def-fat.lst
|
||||
UNDSYMFILES += und-fat.lst
|
||||
|
||||
fat.mod: pre-fat.o mod-fat.o
|
||||
-rm -f $@
|
||||
$(LD) -r -o $@ $^
|
||||
$(STRIP) --strip-unneeded -K pupa_mod_init -K pupa_mod_fini -R .note -R .comment $@
|
||||
|
||||
pre-fat.o: fat_mod-fs_fat.o
|
||||
-rm -f $@
|
||||
$(LD) -r -o $@ $^
|
||||
|
||||
mod-fat.o: mod-fat.c
|
||||
$(CC) $(CPPFLAGS) $(CFLAGS) -c -o $@ $<
|
||||
|
||||
mod-fat.c: moddep.lst genmodsrc.sh
|
||||
sh $(srcdir)/genmodsrc.sh 'fat' $< > $@ || (rm -f $@; exit 1)
|
||||
|
||||
def-fat.lst: pre-fat.o
|
||||
$(NM) -g --defined-only -P -p $< | sed 's/^\([^ ]*\).*/\1 fat/' > $@
|
||||
|
||||
und-fat.lst: pre-fat.o
|
||||
echo 'fat' > $@
|
||||
$(NM) -u -P -p $< >> $@
|
||||
|
||||
fat_mod-fs_fat.o: fs/fat.c
|
||||
$(CC) -Ifs -I$(srcdir)/fs $(CPPFLAGS) $(CFLAGS) $(fat_mod_CFLAGS) -c -o $@ $<
|
||||
|
||||
fat_mod-fs_fat.d: fs/fat.c
|
||||
set -e; $(CC) -Ifs -I$(srcdir)/fs $(CPPFLAGS) $(CFLAGS) $(fat_mod_CFLAGS) -M $< | sed 's,fat\.o[ :]*,fat_mod-fs_fat.o $@ : ,g' > $@; [ -s $@ ] || rm -f $@
|
||||
|
||||
-include fat_mod-fs_fat.d
|
||||
|
||||
fat_mod_CFLAGS = $(COMMON_CFLAGS)
|
||||
CLEANFILES += moddep.lst
|
||||
pkgdata_DATA += moddep.lst
|
||||
moddep.lst: $(DEFSYMFILES) $(UNDSYMFILES) genmoddep
|
||||
cat $(DEFSYMFILES) /dev/null | ./genmoddep $(UNDSYMFILES) > $@ \
|
||||
|| (rm -f $@; exit 1)
|
65
conf/i386-pc.rmk
Normal file
65
conf/i386-pc.rmk
Normal file
|
@ -0,0 +1,65 @@
|
|||
# -*- makefile -*-
|
||||
|
||||
COMMON_ASFLAGS = -nostdinc -fno-builtin
|
||||
COMMON_CFLAGS = -fno-builtin
|
||||
|
||||
# Images.
|
||||
pkgdata_IMAGES = boot.img diskboot.img kernel.img
|
||||
|
||||
# For boot.img.
|
||||
boot_img_SOURCES = boot/i386/pc/boot.S
|
||||
boot_img_ASFLAGS = $(COMMON_ASFLAGS)
|
||||
boot_img_LDFLAGS = -nostdlib -Wl,-N,-Ttext,7C00
|
||||
|
||||
# For diskboot.img.
|
||||
diskboot_img_SOURCES = boot/i386/pc/diskboot.S
|
||||
diskboot_img_ASFLAGS = $(COMMON_ASFLAGS)
|
||||
diskboot_img_LDFLAGS = -nostdlib -Wl,-N,-Ttext,8000
|
||||
|
||||
# For kernel.img.
|
||||
kernel_img_SOURCES = kern/i386/pc/startup.S kern/main.c kern/device.c \
|
||||
kern/disk.c kern/dl.c kern/file.c kern/fs.c kern/err.c \
|
||||
kern/misc.c kern/mm.c kern/loader.c kern/rescue.c kern/term.c \
|
||||
kern/i386/dl.c kern/i386/pc/init.c disk/i386/pc/partition.c \
|
||||
disk/i386/pc/biosdisk.c \
|
||||
term/i386/pc/console.c \
|
||||
symlist.c
|
||||
kernel_img_HEADERS = boot.h device.h disk.h dl.h elf.h err.h \
|
||||
file.h fs.h kernel.h loader.h misc.h mm.h net.h rescue.h symbol.h \
|
||||
term.h types.h machine/biosdisk.h machine/boot.h \
|
||||
machine/console.h machine/init.h machine/memory.h \
|
||||
machine/loader.h machine/partition.h
|
||||
kernel_img_CFLAGS = $(COMMON_CFLAGS)
|
||||
kernel_img_ASFLAGS = $(COMMON_ASFLAGS)
|
||||
kernel_img_LDFLAGS = -nostdlib -Wl,-N,-Ttext,8200
|
||||
|
||||
MOSTLYCLEANFILES += symlist.c kernel_syms.lst
|
||||
DEFSYMFILES += kernel_syms.lst
|
||||
|
||||
symlist.c: $(addprefix include/pupa/,$(kernel_img_HEADERS)) gensymlist.sh
|
||||
sh $(srcdir)/gensymlist.sh $(filter %.h,$^) > $@
|
||||
|
||||
kernel_syms.lst: $(addprefix include/pupa/,$(kernel_img_HEADERS)) genkernsyms.sh
|
||||
sh $(srcdir)/genkernsyms.sh $(filter %h,$^) > $@
|
||||
|
||||
# Utilities.
|
||||
bin_UTILITIES = pupa-mkimage
|
||||
noinst_UTILITIES = genmoddep
|
||||
|
||||
# For pupa-mkimage.
|
||||
pupa_mkimage_SOURCES = util/i386/pc/pupa-mkimage.c util/misc.c \
|
||||
util/resolve.c
|
||||
|
||||
# For genmoddep.
|
||||
genmoddep_SOURCES = util/genmoddep.c
|
||||
|
||||
# Modules.
|
||||
pkgdata_MODULES = chain.mod fat.mod
|
||||
|
||||
# For chain.mod.
|
||||
chain_mod_SOURCES = loader/i386/pc/chainloader.c
|
||||
chain_mod_CFLAGS = $(COMMON_CFLAGS)
|
||||
|
||||
# For fat.mod.
|
||||
fat_mod_SOURCES = fs/fat.c
|
||||
fat_mod_CFLAGS = $(COMMON_CFLAGS)
|
1321
config.guess
vendored
Normal file
1321
config.guess
vendored
Normal file
File diff suppressed because it is too large
Load diff
78
config.h.in
Normal file
78
config.h.in
Normal file
|
@ -0,0 +1,78 @@
|
|||
/* config.h.in. Generated from configure.ac by autoheader. */
|
||||
|
||||
/* Define it if GAS requires that absolute indirect calls/jumps are not
|
||||
prefixed with an asterisk */
|
||||
#undef ABSOLUTE_WITHOUT_ASTERISK
|
||||
|
||||
/* Define it to "addr32" or "addr32;" to make GAS happy */
|
||||
#undef ADDR32
|
||||
|
||||
/* Define it to one of __bss_start, edata and _edata */
|
||||
#undef BSS_START_SYMBOL
|
||||
|
||||
/* Define it to "data32" or "data32;" to make GAS happy */
|
||||
#undef DATA32
|
||||
|
||||
/* Define it to either end or _end */
|
||||
#undef END_SYMBOL
|
||||
|
||||
/* Define if C symbols get an underscore after compilation */
|
||||
#undef HAVE_ASM_USCORE
|
||||
|
||||
/* Define to 1 if you have the <inttypes.h> header file. */
|
||||
#undef HAVE_INTTYPES_H
|
||||
|
||||
/* Define to 1 if you have the <memory.h> header file. */
|
||||
#undef HAVE_MEMORY_H
|
||||
|
||||
/* Define to 1 if you have the <stdint.h> header file. */
|
||||
#undef HAVE_STDINT_H
|
||||
|
||||
/* Define to 1 if you have the <stdlib.h> header file. */
|
||||
#undef HAVE_STDLIB_H
|
||||
|
||||
/* Define to 1 if you have the <strings.h> header file. */
|
||||
#undef HAVE_STRINGS_H
|
||||
|
||||
/* Define to 1 if you have the <string.h> header file. */
|
||||
#undef HAVE_STRING_H
|
||||
|
||||
/* Define to 1 if you have the <sys/stat.h> header file. */
|
||||
#undef HAVE_SYS_STAT_H
|
||||
|
||||
/* Define to 1 if you have the <sys/types.h> header file. */
|
||||
#undef HAVE_SYS_TYPES_H
|
||||
|
||||
/* Define to 1 if you have the <unistd.h> header file. */
|
||||
#undef HAVE_UNISTD_H
|
||||
|
||||
/* Define to the address where bug reports for this package should be sent. */
|
||||
#undef PACKAGE_BUGREPORT
|
||||
|
||||
/* Define to the full name of this package. */
|
||||
#undef PACKAGE_NAME
|
||||
|
||||
/* Define to the full name and version of this package. */
|
||||
#undef PACKAGE_STRING
|
||||
|
||||
/* Define to the one symbol short name of this package. */
|
||||
#undef PACKAGE_TARNAME
|
||||
|
||||
/* Define to the version of this package. */
|
||||
#undef PACKAGE_VERSION
|
||||
|
||||
/* The size of a `long', as computed by sizeof. */
|
||||
#undef SIZEOF_LONG
|
||||
|
||||
/* The size of a `void *', as computed by sizeof. */
|
||||
#undef SIZEOF_VOID_P
|
||||
|
||||
/* Define it to either start or _start */
|
||||
#undef START_SYMBOL
|
||||
|
||||
/* Define to 1 if you have the ANSI C header files. */
|
||||
#undef STDC_HEADERS
|
||||
|
||||
/* Define to 1 if your processor stores words with the most significant byte
|
||||
first (like Motorola and SPARC, unlike Intel and VAX). */
|
||||
#undef WORDS_BIGENDIAN
|
1443
config.sub
vendored
Normal file
1443
config.sub
vendored
Normal file
File diff suppressed because it is too large
Load diff
124
configure.ac
Normal file
124
configure.ac
Normal file
|
@ -0,0 +1,124 @@
|
|||
# Process this file with autoconf to produce a configure script.
|
||||
|
||||
# Copyright (C) 2002 Yoshinori K. Okuji <okuji@enbug.org>
|
||||
#
|
||||
# This configure.ac is free software; the author
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
# with or without modifications, as long as this notice is preserved.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
|
||||
# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||
# PARTICULAR PURPOSE.
|
||||
|
||||
AC_INIT(PUPA, 0.6, [okuji@enbug.org])
|
||||
AC_PREREQ(2.53)
|
||||
AC_CONFIG_SRCDIR([include/pupa/dl.h])
|
||||
AC_CONFIG_HEADER([config.h])
|
||||
|
||||
# Checks for build and host systems.
|
||||
AC_CANONICAL_BUILD
|
||||
AC_CANONICAL_HOST
|
||||
|
||||
case "$host_cpu" in
|
||||
i[[3456]]86) host_cpu=i386 ;;
|
||||
*) AC_MSG_ERROR([unsupported CPU type]) ;;
|
||||
esac
|
||||
|
||||
case "$host_cpu"-"$host_vendor" in
|
||||
i386-*) host_vendor=pc ;;
|
||||
*) AC_MSG_ERROR([unsupported machine type]) ;;
|
||||
esac
|
||||
|
||||
AC_SUBST(host_cpu)
|
||||
AC_SUBST(host_vendor)
|
||||
|
||||
# Checks for programs.
|
||||
if test "x$CFLAGS" = x; then
|
||||
default_CFLAGS=yes
|
||||
fi
|
||||
|
||||
AC_PROG_CC
|
||||
|
||||
# Must be GCC.
|
||||
test "x$GCC" = xyes || AC_MSG_ERROR([GCC is required])
|
||||
|
||||
if test "x$default_CFLAGS" = xyes; then
|
||||
# debug flags.
|
||||
tmp_CFLAGS="-Wall -W -g"
|
||||
|
||||
# optimization flags.
|
||||
AC_CACHE_CHECK([whether optimization for size works], size_flag, [
|
||||
CFLAGS=-Os
|
||||
AC_TRY_COMPILE(, , size_flag=yes, size_flag=no)
|
||||
])
|
||||
if test "x$size_flag" = xyes; then
|
||||
tmp_CFLAGS="$tmp_CFLAGS -Os"
|
||||
else
|
||||
tmp_CFLAGS="$tmp_CFLAGS -O2 -fno-strength-reduce -fno-unroll-loops"
|
||||
fi
|
||||
|
||||
# Force no alignment to save space on i386.
|
||||
if test "x$host_cpu" = xi386; then
|
||||
AC_CACHE_CHECK([whether -falign-loops works], [falign_loop_flag], [
|
||||
CFLAGS="-falign-loops=1"
|
||||
AC_TRY_COMPILE(, , [falign_loop_flag=yes], [falign_loop_flag=no])
|
||||
])
|
||||
|
||||
if test "x$falign_loop_flag" = xyes; then
|
||||
tmp_CFLAGS="$tmp_CFLAGS -falign-jumps=1 -falign-loops=1 -falign-functions=1"
|
||||
else
|
||||
tmp_CFLAGS="$tmp_CFLAGS -malign-jumps=1 -malign-loops=1 -malign-functions=1"
|
||||
fi
|
||||
fi
|
||||
|
||||
CFLAGS="$tmp_CFLAGS"
|
||||
fi
|
||||
AC_SUBST(CFLAGS)
|
||||
|
||||
# Defined in aclocal.m4.
|
||||
pupa_ASM_USCORE
|
||||
pupa_CHECK_START_SYMBOL
|
||||
pupa_CHECK_BSS_START_SYMBOL
|
||||
pupa_CHECK_END_SYMBOL
|
||||
|
||||
if test "x$host_cpu" = xi386; then
|
||||
pupa_I386_ASM_PREFIX_REQUIREMENT
|
||||
pupa_I386_ASM_ADDR32
|
||||
pupa_I386_ASM_ABSOLUTE_WITHOUT_ASTERISK
|
||||
fi
|
||||
|
||||
|
||||
AC_PROG_INSTALL
|
||||
AC_PROG_MAKE_SET
|
||||
AC_CHECK_TOOL(OBJCOPY, objcopy)
|
||||
pupa_PROG_OBJCOPY_ABSOLUTE
|
||||
AC_CHECK_TOOL(STRIP, strip)
|
||||
AC_CHECK_TOOL(NM, nm)
|
||||
|
||||
# This is not a "must".
|
||||
AC_PATH_PROG(RUBY, ruby)
|
||||
|
||||
# For cross-compiling.
|
||||
if test "x$build" = "x$host"; then
|
||||
BUILD_CC="$CC"
|
||||
AC_SUBST(BUILD_CC)
|
||||
else
|
||||
AC_CHECK_PROGS(BUILD_CC, [gcc egcs cc],
|
||||
[AC_MSG_ERROR([none of gcc, egcs and cc is found. set BUILD_CC manually.])])
|
||||
fi
|
||||
|
||||
# Test the C compiler for the build environment.
|
||||
pupa_tmp_CC="$CC"
|
||||
CC="$BUILD_CC"
|
||||
AC_C_BIGENDIAN
|
||||
AC_CHECK_SIZEOF(void *)
|
||||
AC_CHECK_SIZEOF(long)
|
||||
CC="$pupa_tmp_CC"
|
||||
|
||||
# Output files.
|
||||
AC_CONFIG_LINKS([include/pupa/cpu:include/pupa/$host_cpu
|
||||
include/pupa/machine:include/pupa/$host_cpu/$host_vendor])
|
||||
AC_CONFIG_FILES([Makefile])
|
||||
AC_CONFIG_FILES([stamp-h], [echo timestamp > stamp-h])
|
||||
AC_OUTPUT
|
335
disk/i386/pc/biosdisk.c
Normal file
335
disk/i386/pc/biosdisk.c
Normal file
|
@ -0,0 +1,335 @@
|
|||
/*
|
||||
* PUPA -- Preliminary Universal Programming Architecture for GRUB
|
||||
* Copyright (C) 1999,2000,2001,2002 Free Software Foundation, Inc.
|
||||
* Copyright (C) 2002 Yoshinori K. Okuji <okuji@enbug.org>
|
||||
*
|
||||
* PUPA is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with PUPA; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <pupa/machine/biosdisk.h>
|
||||
#include <pupa/machine/memory.h>
|
||||
#include <pupa/disk.h>
|
||||
#include <pupa/mm.h>
|
||||
#include <pupa/types.h>
|
||||
#include <pupa/misc.h>
|
||||
#include <pupa/err.h>
|
||||
#include <pupa/term.h>
|
||||
|
||||
/* Drive Parameters. */
|
||||
struct pupa_biosdisk_drp
|
||||
{
|
||||
pupa_uint16_t size;
|
||||
pupa_uint16_t flags;
|
||||
pupa_uint32_t cylinders;
|
||||
pupa_uint32_t heads;
|
||||
pupa_uint32_t sectors;
|
||||
pupa_uint64_t total_sectors;
|
||||
pupa_uint16_t bytes_per_sector;
|
||||
/* ver 2.0 or higher */
|
||||
pupa_uint32_t EDD_configuration_parameters;
|
||||
/* ver 3.0 or higher */
|
||||
pupa_uint16_t signature_dpi;
|
||||
pupa_uint8_t length_dpi;
|
||||
pupa_uint8_t reserved[3];
|
||||
pupa_uint8_t name_of_host_bus[4];
|
||||
pupa_uint8_t name_of_interface_type[8];
|
||||
pupa_uint8_t interface_path[8];
|
||||
pupa_uint8_t device_path[8];
|
||||
pupa_uint8_t reserved2;
|
||||
pupa_uint8_t checksum;
|
||||
|
||||
/* XXX: This is necessary, because the BIOS of Thinkpad X20
|
||||
writes a garbage to the tail of drive parameters,
|
||||
regardless of a size specified in a caller. */
|
||||
pupa_uint8_t dummy[16];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/* Disk Address Packet. */
|
||||
struct pupa_biosdisk_dap
|
||||
{
|
||||
pupa_uint8_t length;
|
||||
pupa_uint8_t reserved;
|
||||
pupa_uint16_t blocks;
|
||||
pupa_uint32_t buffer;
|
||||
pupa_uint64_t block;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
|
||||
static int
|
||||
pupa_biosdisk_get_drive (const char *name)
|
||||
{
|
||||
unsigned long drive;
|
||||
|
||||
if ((name[0] != 'f' && name[0] != 'h') || name[1] != 'd')
|
||||
goto fail;
|
||||
|
||||
drive = pupa_strtoul (name + 2, 0, 10);
|
||||
if (pupa_errno != PUPA_ERR_NONE)
|
||||
goto fail;
|
||||
|
||||
if (name[0] == 'h')
|
||||
drive += 0x80;
|
||||
|
||||
return (int) drive ;
|
||||
|
||||
fail:
|
||||
pupa_error (PUPA_ERR_UNKNOWN_DEVICE, "not a biosdisk");
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
pupa_biosdisk_call_hook (int (*hook) (const char *name), int drive)
|
||||
{
|
||||
char name[4];
|
||||
|
||||
pupa_sprintf (name, (drive & 0x80) ? "hd%d" : "fd%d", drive & (~0x80));
|
||||
return hook (name);
|
||||
}
|
||||
|
||||
static int
|
||||
pupa_biosdisk_iterate (int (*hook) (const char *name))
|
||||
{
|
||||
int drive;
|
||||
int num_floppies;
|
||||
|
||||
/* For floppy disks, we can get the number safely. */
|
||||
num_floppies = pupa_biosdisk_get_num_floppies ();
|
||||
for (drive = 0; drive < num_floppies; drive++)
|
||||
if (pupa_biosdisk_call_hook (hook, drive))
|
||||
return 1;
|
||||
|
||||
/* For hard disks, attempt to read the MBR. */
|
||||
for (drive = 0x80; drive < 0x88; drive++)
|
||||
{
|
||||
if (pupa_biosdisk_rw_standard (0x02, drive, 0, 0, 1, 1,
|
||||
PUPA_MEMORY_MACHINE_SCRATCH_SEG) != 0)
|
||||
break;
|
||||
|
||||
if (pupa_biosdisk_call_hook (hook, drive))
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static pupa_err_t
|
||||
pupa_biosdisk_open (const char *name, pupa_disk_t disk)
|
||||
{
|
||||
unsigned long total_sectors = 0;
|
||||
int drive;
|
||||
struct pupa_biosdisk_data *data;
|
||||
|
||||
drive = pupa_biosdisk_get_drive (name);
|
||||
if (drive < 0)
|
||||
return pupa_errno;
|
||||
|
||||
disk->has_partitions = (drive & 0x80);
|
||||
disk->id = drive;
|
||||
|
||||
data = (struct pupa_biosdisk_data *) pupa_malloc (sizeof (*data));
|
||||
if (! data)
|
||||
return pupa_errno;
|
||||
|
||||
data->drive = drive;
|
||||
data->flags = 0;
|
||||
|
||||
if (drive & 0x80)
|
||||
{
|
||||
/* HDD */
|
||||
int version;
|
||||
|
||||
version = pupa_biosdisk_check_int13_extensions (drive);
|
||||
if (version)
|
||||
{
|
||||
struct pupa_biosdisk_drp *drp
|
||||
= (struct pupa_biosdisk_drp *) PUPA_MEMORY_MACHINE_SCRATCH_ADDR;
|
||||
|
||||
/* Clear out the DRP. */
|
||||
pupa_memset (drp, 0, sizeof (*drp));
|
||||
drp->size = sizeof (*drp);
|
||||
if (pupa_biosdisk_get_diskinfo_int13_extensions (drive, drp))
|
||||
{
|
||||
data->flags = PUPA_BIOSDISK_FLAG_LBA;
|
||||
|
||||
/* FIXME: 2TB limit. */
|
||||
if (drp->total_sectors)
|
||||
total_sectors = drp->total_sectors & ~0L;
|
||||
else
|
||||
/* Some buggy BIOSes doesn't return the total sectors
|
||||
correctly but returns zero. So if it is zero, compute
|
||||
it by C/H/S returned by the LBA BIOS call. */
|
||||
total_sectors = drp->cylinders * drp->heads * drp->sectors;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (pupa_biosdisk_get_diskinfo_standard (drive,
|
||||
&data->cylinders,
|
||||
&data->heads,
|
||||
&data->sectors) != 0)
|
||||
{
|
||||
pupa_free (data);
|
||||
return pupa_error (PUPA_ERR_BAD_DEVICE, "cannot get C/H/S values");
|
||||
}
|
||||
|
||||
if (! total_sectors)
|
||||
total_sectors = data->cylinders * data->heads * data->sectors;
|
||||
|
||||
disk->total_sectors = total_sectors;
|
||||
disk->data = data;
|
||||
|
||||
return PUPA_ERR_NONE;
|
||||
}
|
||||
|
||||
static void
|
||||
pupa_biosdisk_close (pupa_disk_t disk)
|
||||
{
|
||||
pupa_free (disk->data);
|
||||
}
|
||||
|
||||
/* For readability. */
|
||||
#define PUPA_BIOSDISK_READ 0
|
||||
#define PUPA_BIOSDISK_WRITE 1
|
||||
|
||||
static pupa_err_t
|
||||
pupa_biosdisk_rw (int cmd, pupa_disk_t disk,
|
||||
unsigned long sector, unsigned long size,
|
||||
unsigned segment)
|
||||
{
|
||||
struct pupa_biosdisk_data *data = disk->data;
|
||||
|
||||
if (data->flags & PUPA_BIOSDISK_FLAG_LBA)
|
||||
{
|
||||
struct pupa_biosdisk_dap *dap;
|
||||
|
||||
dap = (struct pupa_biosdisk_dap *) (PUPA_MEMORY_MACHINE_SCRATCH_ADDR
|
||||
+ (data->sectors
|
||||
<< PUPA_DISK_SECTOR_BITS));
|
||||
dap->length = sizeof (*dap);
|
||||
dap->reserved = 0;
|
||||
dap->blocks = size;
|
||||
dap->buffer = segment << 16; /* The format SEGMENT:ADDRESS. */
|
||||
dap->block = sector;
|
||||
|
||||
if (pupa_biosdisk_rw_int13_extensions (cmd + 0x42, data->drive, dap))
|
||||
{
|
||||
/* Fall back to the CHS mode. */
|
||||
data->flags &= ~PUPA_BIOSDISK_FLAG_LBA;
|
||||
disk->total_sectors = data->cylinders * data->heads * data->sectors;
|
||||
return pupa_biosdisk_rw (cmd, disk, sector, size, segment);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned coff, hoff, soff;
|
||||
unsigned head;
|
||||
|
||||
soff = sector % data->sectors + 1;
|
||||
head = sector / data->sectors;
|
||||
hoff = head % data->heads;
|
||||
coff = head / data->heads;
|
||||
|
||||
if (coff >= data->cylinders)
|
||||
return pupa_error (PUPA_ERR_OUT_OF_RANGE, "out of disk");
|
||||
|
||||
if (pupa_biosdisk_rw_standard (cmd + 0x02, data->drive,
|
||||
coff, hoff, soff, size, segment))
|
||||
{
|
||||
switch (cmd)
|
||||
{
|
||||
case PUPA_BIOSDISK_READ:
|
||||
return pupa_error (PUPA_ERR_READ_ERROR, "biosdisk read error");
|
||||
case PUPA_BIOSDISK_WRITE:
|
||||
return pupa_error (PUPA_ERR_WRITE_ERROR, "biosdisk write error");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return PUPA_ERR_NONE;
|
||||
}
|
||||
|
||||
static pupa_err_t
|
||||
pupa_biosdisk_read (pupa_disk_t disk, unsigned long sector,
|
||||
unsigned long size, char *buf)
|
||||
{
|
||||
struct pupa_biosdisk_data *data = disk->data;
|
||||
|
||||
while (size)
|
||||
{
|
||||
unsigned long len;
|
||||
|
||||
len = data->sectors - (sector % data->sectors);
|
||||
if (len > size)
|
||||
len = size;
|
||||
|
||||
if (pupa_biosdisk_rw (PUPA_BIOSDISK_READ, disk, sector, len,
|
||||
PUPA_MEMORY_MACHINE_SCRATCH_SEG))
|
||||
return pupa_errno;
|
||||
|
||||
pupa_memcpy (buf, (void *) PUPA_MEMORY_MACHINE_SCRATCH_ADDR,
|
||||
len << PUPA_DISK_SECTOR_BITS);
|
||||
buf += len << PUPA_DISK_SECTOR_BITS;
|
||||
sector += len;
|
||||
size -= len;
|
||||
}
|
||||
|
||||
return pupa_errno;
|
||||
}
|
||||
|
||||
static pupa_err_t
|
||||
pupa_biosdisk_write (pupa_disk_t disk, unsigned long sector,
|
||||
unsigned long size, const char *buf)
|
||||
{
|
||||
struct pupa_biosdisk_data *data = disk->data;
|
||||
|
||||
while (size)
|
||||
{
|
||||
unsigned long len;
|
||||
|
||||
len = data->sectors - (sector % data->sectors);
|
||||
if (len > size)
|
||||
len = size;
|
||||
|
||||
pupa_memcpy ((void *) PUPA_MEMORY_MACHINE_SCRATCH_ADDR, buf,
|
||||
len << PUPA_DISK_SECTOR_BITS);
|
||||
|
||||
if (pupa_biosdisk_rw (PUPA_BIOSDISK_WRITE, disk, sector, len,
|
||||
PUPA_MEMORY_MACHINE_SCRATCH_SEG))
|
||||
return pupa_errno;
|
||||
|
||||
buf += len << PUPA_DISK_SECTOR_BITS;
|
||||
sector += len;
|
||||
size -= len;
|
||||
}
|
||||
|
||||
return pupa_errno;
|
||||
}
|
||||
|
||||
static struct pupa_disk_dev pupa_biosdisk_dev =
|
||||
{
|
||||
.name = "biosdisk",
|
||||
.iterate = pupa_biosdisk_iterate,
|
||||
.open = pupa_biosdisk_open,
|
||||
.close = pupa_biosdisk_close,
|
||||
.read = pupa_biosdisk_read,
|
||||
.write = pupa_biosdisk_write,
|
||||
.next = 0
|
||||
};
|
||||
|
||||
void
|
||||
pupa_biosdisk_init (void)
|
||||
{
|
||||
pupa_disk_dev_register (&pupa_biosdisk_dev);
|
||||
}
|
248
disk/i386/pc/partition.c
Normal file
248
disk/i386/pc/partition.c
Normal file
|
@ -0,0 +1,248 @@
|
|||
/*
|
||||
* PUPA -- Preliminary Universal Programming Architecture for GRUB
|
||||
* Copyright (C) 2002 Yoshinori K. Okuji <okuji@enbug.org>
|
||||
*
|
||||
* PUPA is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with PUPA; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <pupa/machine/partition.h>
|
||||
#include <pupa/disk.h>
|
||||
#include <pupa/mm.h>
|
||||
#include <pupa/misc.h>
|
||||
|
||||
/* Parse the partition representation in STR and return a partition. */
|
||||
static pupa_partition_t
|
||||
pupa_partition_parse (const char *str)
|
||||
{
|
||||
pupa_partition_t p;
|
||||
char *s = (char *) str;
|
||||
|
||||
p = (pupa_partition_t) pupa_malloc (sizeof (*p));
|
||||
if (! p)
|
||||
return 0;
|
||||
|
||||
/* Initialize some of the fields with invalid values. */
|
||||
p->bsd_part = p->dos_type = p->bsd_type = p->index = -1;
|
||||
|
||||
/* Get the DOS partition number. */
|
||||
p->dos_part = pupa_strtoul (s, &s, 0);
|
||||
|
||||
if (pupa_errno)
|
||||
{
|
||||
/* Not found. Maybe only a BSD label is specified. */
|
||||
p->dos_part = -1;
|
||||
pupa_errno = PUPA_ERR_NONE;
|
||||
}
|
||||
else if (*s == ',')
|
||||
s++;
|
||||
|
||||
if (*s)
|
||||
{
|
||||
if (*s >= 'a' && *s <= 'h')
|
||||
{
|
||||
p->bsd_part = *s - 'a';
|
||||
s++;
|
||||
}
|
||||
|
||||
if (*s)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (p->dos_part == -1 && p->bsd_part == -1)
|
||||
goto fail;
|
||||
|
||||
return p;
|
||||
|
||||
fail:
|
||||
pupa_free (p);
|
||||
pupa_error (PUPA_ERR_BAD_FILENAME, "invalid partition");
|
||||
return 0;
|
||||
}
|
||||
|
||||
pupa_err_t
|
||||
pupa_partition_iterate (pupa_disk_t disk,
|
||||
int (*hook) (const pupa_partition_t partition))
|
||||
{
|
||||
struct pupa_partition p;
|
||||
struct pupa_partition_mbr mbr;
|
||||
struct pupa_partition_disk_label label;
|
||||
struct pupa_disk raw;
|
||||
|
||||
/* Enforce raw disk access. */
|
||||
raw = *disk;
|
||||
raw.partition = 0;
|
||||
|
||||
p.offset = 0;
|
||||
p.ext_offset = 0;
|
||||
p.dos_part = -1;
|
||||
|
||||
while (1)
|
||||
{
|
||||
int i;
|
||||
struct pupa_partition_entry *e;
|
||||
|
||||
/* Read the MBR. */
|
||||
if (pupa_disk_read (&raw, p.offset, 0, sizeof (mbr), (char *) &mbr))
|
||||
goto finish;
|
||||
|
||||
/* Check if it is valid. */
|
||||
if (mbr.signature != pupa_cpu_to_le16 (PUPA_PARTITION_SIGNATURE))
|
||||
return pupa_error (PUPA_ERR_BAD_PART_TABLE, "no signature");
|
||||
|
||||
/* Analyze DOS partitions. */
|
||||
for (p.index = 0; p.index < 4; p.index++)
|
||||
{
|
||||
e = mbr.entries + p.index;
|
||||
|
||||
p.start = p.offset + pupa_le_to_cpu32 (e->start);
|
||||
p.len = pupa_le_to_cpu32 (e->length);
|
||||
p.bsd_part = -1;
|
||||
p.dos_type = e->type;
|
||||
p.bsd_type = -1;
|
||||
|
||||
/* If this partition is a normal one, call the hook. */
|
||||
if (! pupa_partition_is_empty (e->type)
|
||||
&& ! pupa_partition_is_extended (e->type))
|
||||
{
|
||||
p.dos_part++;
|
||||
|
||||
if (hook (&p))
|
||||
goto finish;
|
||||
|
||||
/* Check if this is a BSD partition. */
|
||||
if (pupa_partition_is_bsd (e->type))
|
||||
{
|
||||
/* Check if the BSD label is within the DOS partition. */
|
||||
if (p.len <= PUPA_PARTITION_BSD_LABEL_SECTOR)
|
||||
return pupa_error (PUPA_ERR_BAD_PART_TABLE,
|
||||
"no space for disk label");
|
||||
|
||||
/* Read the BSD label. */
|
||||
if (pupa_disk_read (&raw,
|
||||
(p.start
|
||||
+ PUPA_PARTITION_BSD_LABEL_SECTOR),
|
||||
0,
|
||||
sizeof (label),
|
||||
(char *) &label))
|
||||
goto finish;
|
||||
|
||||
/* Check if it is valid. */
|
||||
if (label.magic
|
||||
!= pupa_cpu_to_le32 (PUPA_PARTITION_BSD_LABEL_MAGIC))
|
||||
return pupa_error (PUPA_ERR_BAD_PART_TABLE,
|
||||
"invalid disk label magic");
|
||||
|
||||
for (p.bsd_part = 0;
|
||||
p.bsd_part < pupa_cpu_to_le16 (label.num_partitions);
|
||||
p.bsd_part++)
|
||||
{
|
||||
struct pupa_partition_bsd_entry *be
|
||||
= label.entries + p.bsd_part;
|
||||
|
||||
p.start = pupa_le_to_cpu32 (be->offset);
|
||||
p.len = pupa_le_to_cpu32 (be->size);
|
||||
p.bsd_type = be->fs_type;
|
||||
|
||||
if (be->fs_type != PUPA_PARTITION_BSD_TYPE_UNUSED)
|
||||
if (hook (&p))
|
||||
goto finish;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (p.dos_part < 4)
|
||||
/* If this partition is a logical one, shouldn't increase the
|
||||
partition number. */
|
||||
p.dos_part++;
|
||||
}
|
||||
|
||||
/* Find an extended partition. */
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
e = mbr.entries + i;
|
||||
|
||||
if (pupa_partition_is_extended (e->type))
|
||||
{
|
||||
p.offset = p.ext_offset + pupa_le_to_cpu32 (e->start);
|
||||
if (! p.ext_offset)
|
||||
p.ext_offset = p.offset;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* If no extended partition, the end. */
|
||||
if (i == 4)
|
||||
break;
|
||||
}
|
||||
|
||||
finish:
|
||||
return pupa_errno;
|
||||
}
|
||||
|
||||
pupa_partition_t
|
||||
pupa_partition_probe (pupa_disk_t disk, const char *str)
|
||||
{
|
||||
pupa_partition_t p;
|
||||
auto int find_func (const pupa_partition_t partition);
|
||||
|
||||
int find_func (const pupa_partition_t partition)
|
||||
{
|
||||
if ((p->dos_part == partition->dos_part || p->dos_part == -1)
|
||||
&& p->bsd_part == partition->bsd_part)
|
||||
{
|
||||
pupa_memcpy (p, partition, sizeof (*p));
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
p = pupa_partition_parse (str);
|
||||
if (! p)
|
||||
return 0;
|
||||
|
||||
|
||||
if (pupa_partition_iterate (disk, find_func))
|
||||
goto fail;
|
||||
|
||||
if (p->index < 0)
|
||||
{
|
||||
pupa_error (PUPA_ERR_BAD_DEVICE, "no such partition");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
return p;
|
||||
|
||||
fail:
|
||||
pupa_free (p);
|
||||
return 0;
|
||||
}
|
||||
|
||||
char *
|
||||
pupa_partition_get_name (const pupa_partition_t p)
|
||||
{
|
||||
char *name;
|
||||
|
||||
name = pupa_malloc (13);
|
||||
if (! name)
|
||||
return 0;
|
||||
|
||||
if (p->bsd_part < 0)
|
||||
pupa_sprintf (name, "%d", p->dos_part);
|
||||
else
|
||||
pupa_sprintf (name, "%d,%c", p->dos_part, p->bsd_part + 'a');
|
||||
|
||||
return name;
|
||||
}
|
756
fs/fat.c
Normal file
756
fs/fat.c
Normal file
|
@ -0,0 +1,756 @@
|
|||
/* fat.c - FAT filesystem */
|
||||
/*
|
||||
* PUPA -- Preliminary Universal Programming Architecture for GRUB
|
||||
* Copyright (C) 2000,2001 Free Software Foundation, Inc.
|
||||
* Copyright (C) 2002 Yoshinori K. Okuji <okuji@enbug.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <pupa/fs.h>
|
||||
#include <pupa/disk.h>
|
||||
#include <pupa/file.h>
|
||||
#include <pupa/types.h>
|
||||
#include <pupa/misc.h>
|
||||
#include <pupa/mm.h>
|
||||
#include <pupa/err.h>
|
||||
#include <pupa/dl.h>
|
||||
|
||||
#define PUPA_FAT_DIR_ENTRY_SIZE 32
|
||||
|
||||
#define PUPA_FAT_ATTR_READ_ONLY 0x01
|
||||
#define PUPA_FAT_ATTR_HIDDEN 0x02
|
||||
#define PUPA_FAT_ATTR_SYSTEM 0x04
|
||||
#define PUPA_FAT_ATTR_VOLUME_ID 0x08
|
||||
#define PUPA_FAT_ATTR_DIRECTORY 0x10
|
||||
#define PUPA_FAT_ATTR_ARCHIVE 0x20
|
||||
|
||||
#define PUPA_FAT_ATTR_LONG_NAME (PUPA_FAT_ATTR_READ_ONLY \
|
||||
| PUPA_FAT_ATTR_HIDDEN \
|
||||
| PUPA_FAT_ATTR_SYSTEM \
|
||||
| PUPA_FAT_ATTR_VOLUME_ID)
|
||||
#define PUPA_FAT_ATTR_VALID (PUPA_FAT_ATTR_READ_ONLY \
|
||||
| PUPA_FAT_ATTR_HIDDEN \
|
||||
| PUPA_FAT_ATTR_SYSTEM \
|
||||
| PUPA_FAT_ATTR_DIRECTORY \
|
||||
| PUPA_FAT_ATTR_ARCHIVE)
|
||||
|
||||
struct pupa_fat_bpb
|
||||
{
|
||||
pupa_uint8_t jmp_boot[3];
|
||||
pupa_uint8_t oem_name[8];
|
||||
pupa_uint16_t bytes_per_sector;
|
||||
pupa_uint8_t sectors_per_cluster;
|
||||
pupa_uint16_t num_reserved_sectors;
|
||||
pupa_uint8_t num_fats;
|
||||
pupa_uint16_t num_root_entries;
|
||||
pupa_uint16_t num_total_sectors_16;
|
||||
pupa_uint8_t media;
|
||||
pupa_uint16_t sectors_per_fat_16;
|
||||
pupa_uint16_t sectors_per_track;
|
||||
pupa_uint16_t num_heads;
|
||||
pupa_uint32_t num_hidden_sectors;
|
||||
pupa_uint32_t num_total_sectors_32;
|
||||
|
||||
/* The following fields are only used by FAT32. */
|
||||
pupa_uint32_t sectors_per_fat_32;
|
||||
pupa_uint16_t extended_flags;
|
||||
pupa_uint16_t fs_version;
|
||||
pupa_uint32_t root_cluster;
|
||||
pupa_uint16_t fs_info;
|
||||
pupa_uint16_t backup_boot_sector;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct pupa_fat_dir_entry
|
||||
{
|
||||
pupa_uint8_t name[11];
|
||||
pupa_uint8_t attr;
|
||||
pupa_uint8_t nt_reserved;
|
||||
pupa_uint8_t c_time_tenth;
|
||||
pupa_uint16_t c_time;
|
||||
pupa_uint16_t c_date;
|
||||
pupa_uint16_t a_date;
|
||||
pupa_uint16_t first_cluster_high;
|
||||
pupa_uint16_t w_time;
|
||||
pupa_uint16_t w_date;
|
||||
pupa_uint16_t first_cluster_low;
|
||||
pupa_uint32_t file_size;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct pupa_fat_long_name_entry
|
||||
{
|
||||
pupa_uint8_t id;
|
||||
pupa_uint16_t name1[5];
|
||||
pupa_uint8_t attr;
|
||||
pupa_uint8_t reserved;
|
||||
pupa_uint8_t checksum;
|
||||
pupa_uint16_t name2[6];
|
||||
pupa_uint16_t first_cluster;
|
||||
pupa_uint16_t name3[2];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct pupa_fat_data
|
||||
{
|
||||
int logical_sector_bits;
|
||||
pupa_uint32_t num_sectors;
|
||||
|
||||
pupa_uint16_t fat_sector;
|
||||
pupa_uint32_t sectors_per_fat;
|
||||
int fat_size;
|
||||
|
||||
pupa_uint32_t root_cluster;
|
||||
pupa_uint32_t root_sector;
|
||||
pupa_uint32_t num_root_sectors;
|
||||
|
||||
int cluster_bits;
|
||||
pupa_uint32_t cluster_eof_mark;
|
||||
pupa_uint32_t cluster_sector;
|
||||
pupa_uint32_t num_clusters;
|
||||
|
||||
pupa_uint8_t attr;
|
||||
pupa_ssize_t file_size;
|
||||
pupa_uint32_t file_cluster;
|
||||
pupa_uint32_t cur_cluster_num;
|
||||
pupa_uint32_t cur_cluster;
|
||||
};
|
||||
|
||||
static int
|
||||
log2 (unsigned x)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (x == 0)
|
||||
return -1;
|
||||
|
||||
for (i = 0; (x & 1) == 0; i++)
|
||||
x >>= 1;
|
||||
|
||||
if (x != 1)
|
||||
return -1;
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
static struct pupa_fat_data *
|
||||
pupa_fat_mount (pupa_disk_t disk)
|
||||
{
|
||||
struct pupa_fat_bpb bpb;
|
||||
struct pupa_fat_data *data = 0;
|
||||
pupa_uint32_t first_fat, magic;
|
||||
|
||||
if (! disk)
|
||||
goto fail;
|
||||
|
||||
data = (struct pupa_fat_data *) pupa_malloc (sizeof (*data));
|
||||
if (! data)
|
||||
goto fail;
|
||||
|
||||
/* Read the BPB. */
|
||||
if (pupa_disk_read (disk, 0, 0, sizeof (bpb), (char *) &bpb))
|
||||
goto fail;
|
||||
|
||||
/* Get the sizes of logical sectors and clusters. */
|
||||
data->logical_sector_bits = log2 (pupa_le_to_cpu16 (bpb.bytes_per_sector));
|
||||
if (data->logical_sector_bits < PUPA_DISK_SECTOR_BITS)
|
||||
goto fail;
|
||||
data->logical_sector_bits -= PUPA_DISK_SECTOR_BITS;
|
||||
|
||||
data->cluster_bits = log2 (bpb.sectors_per_cluster);
|
||||
if (data->cluster_bits < 0)
|
||||
goto fail;
|
||||
data->cluster_bits += data->logical_sector_bits;
|
||||
|
||||
/* Get information about FATs. */
|
||||
data->fat_sector = (pupa_le_to_cpu16 (bpb.num_reserved_sectors)
|
||||
<< data->logical_sector_bits);
|
||||
if (data->fat_sector == 0)
|
||||
goto fail;
|
||||
|
||||
data->sectors_per_fat = ((bpb.sectors_per_fat_16
|
||||
? pupa_le_to_cpu16 (bpb.sectors_per_fat_16)
|
||||
: pupa_le_to_cpu32 (bpb.sectors_per_fat_32))
|
||||
<< data->logical_sector_bits);
|
||||
if (data->sectors_per_fat == 0)
|
||||
goto fail;
|
||||
|
||||
/* Get the number of sectors in this volume. */
|
||||
data->num_sectors = ((bpb.num_total_sectors_16
|
||||
? pupa_le_to_cpu16 (bpb.num_total_sectors_16)
|
||||
: pupa_le_to_cpu32 (bpb.num_total_sectors_32))
|
||||
<< data->logical_sector_bits);
|
||||
if (data->num_sectors == 0)
|
||||
goto fail;
|
||||
|
||||
/* Get information about the root directory. */
|
||||
if (bpb.num_fats == 0)
|
||||
goto fail;
|
||||
|
||||
data->root_sector = data->fat_sector + bpb.num_fats * data->sectors_per_fat;
|
||||
data->num_root_sectors
|
||||
= ((((pupa_uint32_t) pupa_le_to_cpu16 (bpb.num_root_entries)
|
||||
* PUPA_FAT_DIR_ENTRY_SIZE
|
||||
+ pupa_le_to_cpu16 (bpb.bytes_per_sector) - 1)
|
||||
>> (data->logical_sector_bits + PUPA_DISK_SECTOR_BITS))
|
||||
<< (data->logical_sector_bits));
|
||||
|
||||
data->cluster_sector = data->root_sector + data->num_root_sectors;
|
||||
data->num_clusters = (((data->num_sectors - data->cluster_sector)
|
||||
>> (data->cluster_bits + data->logical_sector_bits))
|
||||
+ 2);
|
||||
|
||||
if (data->num_clusters <= 2)
|
||||
goto fail;
|
||||
|
||||
if (! bpb.sectors_per_fat_16)
|
||||
{
|
||||
/* FAT32. */
|
||||
pupa_uint16_t flags = pupa_le_to_cpu16 (bpb.extended_flags);
|
||||
|
||||
data->root_cluster = pupa_le_to_cpu32 (bpb.root_cluster);
|
||||
data->fat_size = 32;
|
||||
data->cluster_eof_mark = 0x0ffffff8;
|
||||
|
||||
if (flags & 0x80)
|
||||
{
|
||||
/* Get an active FAT. */
|
||||
unsigned active_fat = flags & 0xf;
|
||||
|
||||
if (active_fat > bpb.num_fats)
|
||||
goto fail;
|
||||
|
||||
data->fat_sector += active_fat * data->sectors_per_fat;
|
||||
}
|
||||
|
||||
if (bpb.num_root_entries != 0 || bpb.fs_version != 0)
|
||||
goto fail;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* FAT12 or FAT16. */
|
||||
data->root_cluster = ~0UL;
|
||||
|
||||
if (data->num_clusters <= 4085 + 2)
|
||||
{
|
||||
/* FAT12. */
|
||||
data->fat_size = 12;
|
||||
data->cluster_eof_mark = 0x0ff8;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* FAT16. */
|
||||
data->fat_size = 16;
|
||||
data->cluster_eof_mark = 0xfff8;
|
||||
}
|
||||
}
|
||||
|
||||
/* More sanity checks. */
|
||||
if (data->num_sectors <= data->fat_sector)
|
||||
goto fail;
|
||||
|
||||
if (pupa_disk_read (disk,
|
||||
data->fat_sector,
|
||||
0,
|
||||
sizeof (first_fat),
|
||||
(char *) &first_fat))
|
||||
goto fail;
|
||||
|
||||
first_fat = pupa_le_to_cpu32 (first_fat);
|
||||
|
||||
if (data->fat_size == 32)
|
||||
{
|
||||
first_fat &= 0x0fffffff;
|
||||
magic = 0x0fffff00;
|
||||
}
|
||||
else if (data->fat_size == 16)
|
||||
{
|
||||
first_fat &= 0x0000ffff;
|
||||
magic = 0xff00;
|
||||
}
|
||||
else
|
||||
{
|
||||
first_fat &= 0x00000fff;
|
||||
magic = 0x0f00;
|
||||
}
|
||||
|
||||
if (first_fat != (magic | bpb.media))
|
||||
goto fail;
|
||||
|
||||
/* Start from the root directory. */
|
||||
data->file_cluster = data->root_cluster;
|
||||
data->cur_cluster_num = ~0UL;
|
||||
data->attr = PUPA_FAT_ATTR_DIRECTORY;
|
||||
return data;
|
||||
|
||||
fail:
|
||||
|
||||
pupa_free (data);
|
||||
pupa_error (PUPA_ERR_BAD_FS, "not a fat filesystem");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Convert UTF-16 (little endian) to UTF8. */
|
||||
static pupa_uint8_t *
|
||||
pupa_fat_utf16_to_utf8 (pupa_uint8_t *dest, pupa_uint16_t *src,
|
||||
pupa_size_t size)
|
||||
{
|
||||
pupa_uint32_t code_high = 0;
|
||||
|
||||
while (size--)
|
||||
{
|
||||
pupa_uint32_t code = pupa_le_to_cpu16 (*src++);
|
||||
|
||||
if (code_high)
|
||||
{
|
||||
if (code >= 0xDC00 && code <= 0xDFFF)
|
||||
{
|
||||
/* Surrogate pair. */
|
||||
code = ((code_high - 0xD800) << 12) + (code - 0xDC00) + 0x10000;
|
||||
|
||||
*dest++ = (code >> 18) | 0xF0;
|
||||
*dest++ = ((code >> 12) & 0x3F) | 0x80;
|
||||
*dest++ = ((code >> 6) & 0x3F) | 0x80;
|
||||
*dest++ = (code & 0x3F) | 0x80;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Error... */
|
||||
*dest++ = '?';
|
||||
}
|
||||
|
||||
code_high = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (code <= 0x007F)
|
||||
*dest++ = code;
|
||||
else if (code <= 0x07FF)
|
||||
{
|
||||
*dest++ = (code >> 6) | 0xC0;
|
||||
*dest++ = (code & 0x3F) | 0x80;
|
||||
}
|
||||
else if (code >= 0xD800 && code <= 0xDBFF)
|
||||
{
|
||||
code_high = code;
|
||||
continue;
|
||||
}
|
||||
else if (code >= 0xDC00 && code <= 0xDFFF)
|
||||
{
|
||||
/* Error... */
|
||||
*dest++ = '?';
|
||||
}
|
||||
else
|
||||
{
|
||||
*dest++ = (code >> 16) | 0xE0;
|
||||
*dest++ = ((code >> 12) & 0x3F) | 0x80;
|
||||
*dest++ = (code & 0x3F) | 0x80;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
static pupa_ssize_t
|
||||
pupa_fat_read_data (pupa_disk_t disk, struct pupa_fat_data *data,
|
||||
void (*read_hook) (unsigned long sector,
|
||||
unsigned offset, unsigned length),
|
||||
pupa_ssize_t offset, pupa_ssize_t len, char *buf)
|
||||
{
|
||||
pupa_ssize_t size;
|
||||
pupa_uint32_t logical_cluster;
|
||||
unsigned logical_cluster_bits;
|
||||
pupa_ssize_t ret = 0;
|
||||
unsigned long sector;
|
||||
|
||||
/* This is a special case. FAT12 and FAT16 doesn't have the root directory
|
||||
in clusters. */
|
||||
if (data->file_cluster == ~0UL)
|
||||
{
|
||||
size = (data->num_root_sectors << PUPA_DISK_SECTOR_BITS) - offset;
|
||||
if (size > len)
|
||||
size = len;
|
||||
|
||||
if (pupa_disk_read (disk, data->root_sector, offset, size, buf))
|
||||
return -1;
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
/* Calculate the logical cluster number and offset. */
|
||||
logical_cluster_bits = (data->cluster_bits
|
||||
+ data->logical_sector_bits
|
||||
+ PUPA_DISK_SECTOR_BITS);
|
||||
logical_cluster = offset >> logical_cluster_bits;
|
||||
offset &= (1 << logical_cluster_bits) - 1;
|
||||
|
||||
if (logical_cluster < data->cur_cluster_num)
|
||||
{
|
||||
data->cur_cluster_num = 0;
|
||||
data->cur_cluster = data->file_cluster;
|
||||
}
|
||||
|
||||
while (len)
|
||||
{
|
||||
while (logical_cluster > data->cur_cluster_num)
|
||||
{
|
||||
/* Find next cluster. */
|
||||
pupa_uint32_t next_cluster;
|
||||
unsigned long fat_offset;
|
||||
|
||||
switch (data->fat_size)
|
||||
{
|
||||
case 32:
|
||||
fat_offset = data->cur_cluster << 2;
|
||||
break;
|
||||
case 16:
|
||||
fat_offset = data->cur_cluster << 1;
|
||||
break;
|
||||
default:
|
||||
/* case 12: */
|
||||
fat_offset = data->cur_cluster + (data->cur_cluster >> 1);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Read the FAT. */
|
||||
if (pupa_disk_read (disk, data->fat_sector, fat_offset,
|
||||
(data->fat_size + 7) >> 3,
|
||||
(char *) &next_cluster))
|
||||
return -1;
|
||||
|
||||
next_cluster = pupa_le_to_cpu32 (next_cluster);
|
||||
switch (data->fat_size)
|
||||
{
|
||||
case 16:
|
||||
next_cluster &= 0xFFFF;
|
||||
break;
|
||||
case 12:
|
||||
if (data->cur_cluster & 1)
|
||||
next_cluster >>= 12;
|
||||
|
||||
next_cluster &= 0x0FFF;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Check the end. */
|
||||
if (next_cluster >= data->cluster_eof_mark)
|
||||
return ret;
|
||||
|
||||
if (next_cluster < 2 || next_cluster >= data->num_clusters)
|
||||
{
|
||||
pupa_error (PUPA_ERR_BAD_FS, "invalid cluster");
|
||||
return -1;
|
||||
}
|
||||
|
||||
data->cur_cluster = next_cluster;
|
||||
data->cur_cluster_num++;
|
||||
}
|
||||
|
||||
/* Read the data here. */
|
||||
sector = (data->cluster_sector
|
||||
+ ((data->cur_cluster - 2)
|
||||
<< (data->cluster_bits + data->logical_sector_bits)));
|
||||
size = (1 << logical_cluster_bits) - offset;
|
||||
if (size > len)
|
||||
size = len;
|
||||
|
||||
disk->read_hook = read_hook;
|
||||
pupa_disk_read (disk, sector, offset, size, buf);
|
||||
disk->read_hook = 0;
|
||||
if (pupa_errno)
|
||||
return -1;
|
||||
|
||||
len -= size;
|
||||
buf += size;
|
||||
ret += size;
|
||||
logical_cluster++;
|
||||
offset = 0;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Find the underlying directory or file in PATH and return the
|
||||
next path. If there is no next path or an error occurs, return NULL.
|
||||
If HOOK is specified, call it with each file name. */
|
||||
static char *
|
||||
pupa_fat_find_dir (pupa_disk_t disk, struct pupa_fat_data *data,
|
||||
const char *path,
|
||||
int (*hook) (const char *filename, int dir))
|
||||
{
|
||||
struct pupa_fat_dir_entry dir;
|
||||
char *dirname, *dirp;
|
||||
char *filename, *filep = 0;
|
||||
pupa_uint16_t *unibuf;
|
||||
int slot = -1, slots = -1;
|
||||
int checksum = -1;
|
||||
pupa_ssize_t offset = -sizeof(dir);
|
||||
int call_hook;
|
||||
|
||||
if (! (data->attr & PUPA_FAT_ATTR_DIRECTORY))
|
||||
{
|
||||
pupa_error (PUPA_ERR_BAD_FILE_TYPE, "not a directory");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Extract a directory name. */
|
||||
while (*path == '/')
|
||||
path++;
|
||||
|
||||
dirp = pupa_strchr (path, '/');
|
||||
if (dirp)
|
||||
{
|
||||
unsigned len = dirp - path;
|
||||
|
||||
dirname = pupa_malloc (len + 1);
|
||||
if (! dirname)
|
||||
return 0;
|
||||
|
||||
pupa_memcpy (dirname, path, len);
|
||||
dirname[len] = '\0';
|
||||
}
|
||||
else
|
||||
/* This is actually a file. */
|
||||
dirname = pupa_strdup (path);
|
||||
|
||||
call_hook = (! dirp && hook);
|
||||
|
||||
/* Allocate space enough to hold a long name. */
|
||||
filename = pupa_malloc (0x40 * 13 * 4 + 1);
|
||||
unibuf = (pupa_uint16_t *) pupa_malloc (0x40 * 13 * 2);
|
||||
if (! filename || ! unibuf)
|
||||
{
|
||||
pupa_free (filename);
|
||||
pupa_free (unibuf);
|
||||
pupa_free (dirname);
|
||||
return 0;
|
||||
}
|
||||
|
||||
while (1)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
/* Adjust the offset. */
|
||||
offset += sizeof (dir);
|
||||
|
||||
/* Read a directory entry. */
|
||||
if ((pupa_fat_read_data (disk, data, 0,
|
||||
offset, sizeof (dir), (char *) &dir)
|
||||
!= sizeof (dir))
|
||||
|| dir.name[0] == 0)
|
||||
{
|
||||
if (pupa_errno == PUPA_ERR_NONE && ! call_hook)
|
||||
pupa_error (PUPA_ERR_FILE_NOT_FOUND, "file not found");
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
/* Handle long name entries. */
|
||||
if (dir.attr == PUPA_FAT_ATTR_LONG_NAME)
|
||||
{
|
||||
struct pupa_fat_long_name_entry *long_name
|
||||
= (struct pupa_fat_long_name_entry *) &dir;
|
||||
pupa_uint8_t id = long_name->id;
|
||||
|
||||
if (id & 0x40)
|
||||
{
|
||||
id &= 0x3f;
|
||||
slots = slot = id;
|
||||
checksum = long_name->checksum;
|
||||
}
|
||||
|
||||
if (id != slot || slot == 0 || checksum != long_name->checksum)
|
||||
{
|
||||
checksum = -1;
|
||||
continue;
|
||||
}
|
||||
|
||||
slot--;
|
||||
pupa_memcpy (unibuf + slot * 13, long_name->name1, 5 * 2);
|
||||
pupa_memcpy (unibuf + slot * 13 + 5, long_name->name2, 6 * 2);
|
||||
pupa_memcpy (unibuf + slot * 13 + 11, long_name->name3, 2 * 2);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Check if this entry is valid. */
|
||||
if (dir.name[0] == 0xe5 || (dir.attr & ~PUPA_FAT_ATTR_VALID))
|
||||
continue;
|
||||
|
||||
/* This is a workaround for Japanese. */
|
||||
if (dir.name[0] == 0x05)
|
||||
dir.name[0] = 0xe5;
|
||||
|
||||
if (checksum != -1 && slot == 0)
|
||||
{
|
||||
pupa_uint8_t sum;
|
||||
|
||||
for (sum = 0, i = 0; i < sizeof (dir.name); i++)
|
||||
sum = ((sum >> 1) | (sum << 7)) + dir.name[i];
|
||||
|
||||
if (sum == checksum)
|
||||
{
|
||||
*pupa_fat_utf16_to_utf8 (filename, unibuf, slots * 13) = '\0';
|
||||
|
||||
if (*dirname == '\0' && call_hook)
|
||||
{
|
||||
if (hook (filename, dir.attr & PUPA_FAT_ATTR_DIRECTORY))
|
||||
break;
|
||||
|
||||
checksum = -1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (pupa_strcmp (dirname, filename) == 0)
|
||||
{
|
||||
if (call_hook)
|
||||
hook (filename, dir.attr & PUPA_FAT_ATTR_DIRECTORY);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
checksum = -1;
|
||||
}
|
||||
|
||||
/* Convert the 8.3 file name. */
|
||||
filep = filename;
|
||||
|
||||
for (i = 0; i < 8 && dir.name[i] && ! pupa_isspace (dir.name[i]); i++)
|
||||
*filep++ = pupa_tolower (dir.name[i]);
|
||||
|
||||
*filep = '.';
|
||||
|
||||
for (i = 8; i < 11 && dir.name[i] && ! pupa_isspace (dir.name[i]); i++)
|
||||
*++filep = pupa_tolower (dir.name[i]);
|
||||
|
||||
if (*filep != '.')
|
||||
filep++;
|
||||
|
||||
*filep = '\0';
|
||||
|
||||
if (*dirname == '\0' && call_hook)
|
||||
{
|
||||
if (hook (filename, dir.attr & PUPA_FAT_ATTR_DIRECTORY))
|
||||
break;
|
||||
}
|
||||
else if (pupa_strcmp (dirname, filename) == 0)
|
||||
{
|
||||
if (call_hook)
|
||||
hook (filename, dir.attr & PUPA_FAT_ATTR_DIRECTORY);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
pupa_free (filename);
|
||||
pupa_free (dirname);
|
||||
|
||||
data->attr = dir.attr;
|
||||
data->file_size = pupa_le_to_cpu32 (dir.file_size);
|
||||
data->file_cluster = ((pupa_le_to_cpu16 (dir.first_cluster_high) << 16)
|
||||
| pupa_le_to_cpu16 (dir.first_cluster_low));
|
||||
data->cur_cluster_num = ~0UL;
|
||||
|
||||
return dirp;
|
||||
}
|
||||
|
||||
static pupa_err_t
|
||||
pupa_fat_dir (pupa_device_t device, const char *path,
|
||||
int (*hook) (const char *filename, int dir))
|
||||
{
|
||||
struct pupa_fat_data *data;
|
||||
pupa_disk_t disk = device->disk;
|
||||
char *p = (char *) path;
|
||||
|
||||
data = pupa_fat_mount (disk);
|
||||
if (! data)
|
||||
return pupa_errno;
|
||||
|
||||
do
|
||||
{
|
||||
p = pupa_fat_find_dir (disk, data, p, hook);
|
||||
}
|
||||
while (p && pupa_errno == PUPA_ERR_NONE);
|
||||
|
||||
pupa_free (data);
|
||||
return pupa_errno;
|
||||
}
|
||||
|
||||
static pupa_err_t
|
||||
pupa_fat_open (pupa_file_t file, const char *name)
|
||||
{
|
||||
struct pupa_fat_data *data;
|
||||
char *p = (char *) name;
|
||||
|
||||
data = pupa_fat_mount (file->device->disk);
|
||||
if (! data)
|
||||
return pupa_errno;
|
||||
|
||||
do
|
||||
{
|
||||
p = pupa_fat_find_dir (file->device->disk, data, p, 0);
|
||||
if (pupa_errno != PUPA_ERR_NONE)
|
||||
goto fail;
|
||||
}
|
||||
while (p);
|
||||
|
||||
if (data->attr & PUPA_FAT_ATTR_DIRECTORY)
|
||||
{
|
||||
pupa_error (PUPA_ERR_BAD_FILE_TYPE, "not a file");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
file->data = data;
|
||||
file->size = data->file_size;
|
||||
|
||||
return PUPA_ERR_NONE;
|
||||
|
||||
fail:
|
||||
pupa_free (data);
|
||||
return pupa_errno;
|
||||
}
|
||||
|
||||
static pupa_ssize_t
|
||||
pupa_fat_read (pupa_file_t file, char *buf, pupa_ssize_t len)
|
||||
{
|
||||
return pupa_fat_read_data (file->device->disk, file->data, file->read_hook,
|
||||
file->offset, len, buf);
|
||||
}
|
||||
|
||||
static pupa_err_t
|
||||
pupa_fat_close (pupa_file_t file)
|
||||
{
|
||||
pupa_free (file->data);
|
||||
return pupa_errno;
|
||||
}
|
||||
|
||||
static struct pupa_fs pupa_fat_fs =
|
||||
{
|
||||
.name = "fat",
|
||||
.dir = pupa_fat_dir,
|
||||
.open = pupa_fat_open,
|
||||
.read = pupa_fat_read,
|
||||
.close = pupa_fat_close,
|
||||
.next = 0
|
||||
};
|
||||
|
||||
PUPA_MOD_INIT
|
||||
{
|
||||
pupa_fs_register (&pupa_fat_fs);
|
||||
}
|
||||
|
||||
PUPA_MOD_FINI
|
||||
{
|
||||
pupa_fs_unregister (&pupa_fat_fs);
|
||||
}
|
15
genkernsyms.sh
Normal file
15
genkernsyms.sh
Normal file
|
@ -0,0 +1,15 @@
|
|||
#! /bin/sh
|
||||
#
|
||||
# Copyright (C) 2002 Yoshinori K. Okuji <okuji@enbug.org>
|
||||
#
|
||||
# This gensymlist.sh is free software; the author
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
# with or without modifications, as long as this notice is preserved.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
|
||||
# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||
# PARTICULAR PURPOSE.
|
||||
|
||||
cat $* | grep -v '^#' | sed -n '/EXPORT_FUNC *([a-zA-Z0-9_]*)/{s/.*EXPORT_FUNC *(\([a-zA-Z0-9_]*\)).*/\1 kernel/;p;}'
|
||||
cat $* | grep -v '^#' | sed -n '/EXPORT_VAR *([a-zA-Z0-9_]*)/{s/.*EXPORT_VAR *(\([a-zA-Z0-9_]*\)).*/\1 kernel/;p;}'
|
269
genmk.rb
Normal file
269
genmk.rb
Normal file
|
@ -0,0 +1,269 @@
|
|||
#! /usr/bin/ruby -w
|
||||
#
|
||||
# Copyright (C) 2002 Yoshinori K. Okuji <okuji@enbug.org>
|
||||
#
|
||||
# This genmk.rb is free software; the author
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
# with or without modifications, as long as this notice is preserved.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
|
||||
# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||
# PARTICULAR PURPOSE.
|
||||
|
||||
module Enumerable
|
||||
def collect_with_index
|
||||
ret = []
|
||||
self.each_with_index do |item, index|
|
||||
ret.push(yield(item, index))
|
||||
end
|
||||
ret
|
||||
end
|
||||
end
|
||||
|
||||
class String
|
||||
def to_var
|
||||
self.gsub(/[^a-zA-Z0-9_@]/, '_')
|
||||
end
|
||||
|
||||
def suffix(str)
|
||||
self.sub(/\.[^\.]*$/, '') + '.' + str
|
||||
end
|
||||
|
||||
def to_obj
|
||||
self.sub(/\.[^\.]*$/, '').to_var + '.o'
|
||||
end
|
||||
end
|
||||
|
||||
class Image
|
||||
def initialize(dir, name)
|
||||
@dir = dir
|
||||
@name = name
|
||||
end
|
||||
attr_reader :dir, :name
|
||||
|
||||
def rule(sources)
|
||||
prefix = @name.to_var
|
||||
exe = @name.suffix('exec')
|
||||
objs = sources.collect do |src|
|
||||
raise "unknown source file `#{src}'" if /\.[cS]$/ !~ src
|
||||
prefix + '-' + src.to_obj
|
||||
end
|
||||
objs_str = objs.join(' ')
|
||||
deps = objs.collect {|obj| obj.suffix('d')}
|
||||
deps_str = deps.join(' ')
|
||||
|
||||
"CLEANFILES += #{@name} #{exe} #{objs_str}
|
||||
MOSTLYCLEANFILES += #{deps_str}
|
||||
|
||||
#{@name}: #{exe}
|
||||
$(OBJCOPY) -O binary -R .note -R .comment $< $@
|
||||
|
||||
#{exe}: #{objs_str}
|
||||
$(CC) $(LDFLAGS) $(#{prefix}_LDFLAGS) -o $@ $^
|
||||
|
||||
" + objs.collect_with_index do |obj, i|
|
||||
src = sources[i]
|
||||
fake_obj = File.basename(src).suffix('o')
|
||||
dep = deps[i]
|
||||
flag = if /\.c$/ =~ src then 'CFLAGS' else 'ASFLAGS' end
|
||||
extra_flags = if /\.S$/ =~ src then '-DASM_FILE=1' else '' end
|
||||
dir = File.dirname(src)
|
||||
|
||||
"#{obj}: #{src}
|
||||
$(CC) -I#{dir} -I$(srcdir)/#{dir} $(CPPFLAGS) #{extra_flags} $(#{flag}) $(#{prefix}_#{flag}) -c -o $@ $<
|
||||
|
||||
#{dep}: #{src}
|
||||
set -e; \
|
||||
$(CC) -I#{dir} -I$(srcdir)/#{dir} $(CPPFLAGS) #{extra_flags} $(#{flag}) $(#{prefix}_#{flag}) -M $< \
|
||||
| sed 's,#{Regexp.quote(fake_obj)}[ :]*,#{obj} $@ : ,g' > $@; \
|
||||
[ -s $@ ] || rm -f $@
|
||||
|
||||
-include #{dep}
|
||||
|
||||
"
|
||||
end.join('')
|
||||
end
|
||||
end
|
||||
|
||||
# Use PModule instead Module, to avoid name conflicting.
|
||||
class PModule
|
||||
def initialize(dir, name)
|
||||
@dir = dir
|
||||
@name = name
|
||||
end
|
||||
attr_reader :dir, :name
|
||||
|
||||
def rule(sources)
|
||||
prefix = @name.to_var
|
||||
objs = sources.collect do |src|
|
||||
raise "unknown source file `#{src}'" if /\.[cS]$/ !~ src
|
||||
prefix + '-' + src.to_obj
|
||||
end
|
||||
objs_str = objs.join(' ')
|
||||
deps = objs.collect {|obj| obj.suffix('d')}
|
||||
deps_str = deps.join(' ')
|
||||
pre_obj = 'pre-' + @name.suffix('o')
|
||||
mod_src = 'mod-' + @name.suffix('c')
|
||||
mod_obj = mod_src.suffix('o')
|
||||
defsym = 'def-' + @name.suffix('lst')
|
||||
undsym = 'und-' + @name.suffix('lst')
|
||||
mod_name = File.basename(@name, '.mod')
|
||||
|
||||
"CLEANFILES += #{@name} #{mod_obj} #{mod_src} #{pre_obj} #{objs_str} #{defsym} #{undsym}
|
||||
MOSTLYCLEANFILES += #{deps_str}
|
||||
DEFSYMFILES += #{defsym}
|
||||
UNDSYMFILES += #{undsym}
|
||||
|
||||
#{@name}: #{pre_obj} #{mod_obj}
|
||||
-rm -f $@
|
||||
$(LD) -r -o $@ $^
|
||||
$(STRIP) --strip-unneeded -K pupa_mod_init -K pupa_mod_fini -R .note -R .comment $@
|
||||
|
||||
#{pre_obj}: #{objs_str}
|
||||
-rm -f $@
|
||||
$(LD) -r -o $@ $^
|
||||
|
||||
#{mod_obj}: #{mod_src}
|
||||
$(CC) $(CPPFLAGS) $(CFLAGS) -c -o $@ $<
|
||||
|
||||
#{mod_src}: moddep.lst genmodsrc.sh
|
||||
sh $(srcdir)/genmodsrc.sh '#{mod_name}' $< > $@ || (rm -f $@; exit 1)
|
||||
|
||||
#{defsym}: #{pre_obj}
|
||||
$(NM) -g --defined-only -P -p $< | sed 's/^\\([^ ]*\\).*/\\1 #{mod_name}/' > $@
|
||||
|
||||
#{undsym}: #{pre_obj}
|
||||
echo '#{mod_name}' > $@
|
||||
$(NM) -u -P -p $< >> $@
|
||||
|
||||
" + objs.collect_with_index do |obj, i|
|
||||
src = sources[i]
|
||||
fake_obj = File.basename(src).suffix('o')
|
||||
dep = deps[i]
|
||||
flag = if /\.c$/ =~ src then 'CFLAGS' else 'ASFLAGS' end
|
||||
dir = File.dirname(src)
|
||||
|
||||
"#{obj}: #{src}
|
||||
$(CC) -I#{dir} -I$(srcdir)/#{dir} $(CPPFLAGS) $(#{flag}) $(#{prefix}_#{flag}) -c -o $@ $<
|
||||
|
||||
#{dep}: #{src}
|
||||
set -e; \
|
||||
$(CC) -I#{dir} -I$(srcdir)/#{dir} $(CPPFLAGS) $(#{flag}) $(#{prefix}_#{flag}) -M $< \
|
||||
| sed 's,#{Regexp.quote(fake_obj)}[ :]*,#{obj} $@ : ,g' > $@; \
|
||||
[ -s $@ ] || rm -f $@
|
||||
|
||||
-include #{dep}
|
||||
|
||||
"
|
||||
end.join('')
|
||||
end
|
||||
end
|
||||
|
||||
class Utility
|
||||
def initialize(dir, name)
|
||||
@dir = dir
|
||||
@name = name
|
||||
end
|
||||
attr_reader :dir, :name
|
||||
|
||||
def rule(sources)
|
||||
prefix = @name.to_var
|
||||
objs = sources.collect do |src|
|
||||
raise "unknown source file `#{src}'" if /\.c$/ !~ src
|
||||
prefix + '-' + src.to_obj
|
||||
end
|
||||
objs_str = objs.join(' ');
|
||||
deps = objs.collect {|obj| obj.suffix('d')}
|
||||
deps_str = deps.join(' ');
|
||||
|
||||
"CLEANFILES += #{@name} #{objs_str}
|
||||
MOSTLYCLEANFILES += #{deps_str}
|
||||
|
||||
#{@name}: #{objs_str}
|
||||
$(BUILD_CC) $(BUILD_LDFLAGS) $(#{prefix}_LDFLAGS) -o $@ $^
|
||||
|
||||
" + objs.collect_with_index do |obj, i|
|
||||
src = sources[i]
|
||||
fake_obj = File.basename(src).suffix('o')
|
||||
dep = deps[i]
|
||||
dir = File.dirname(src)
|
||||
|
||||
"#{obj}: #{src}
|
||||
$(BUILD_CC) -I#{dir} -I$(srcdir)/#{dir} $(BUILD_CPPFLAGS) -DPUPA_UTIL=1 $(#{prefix}_CFLAGS) -c -o $@ $<
|
||||
|
||||
#{dep}: #{src}
|
||||
set -e; \
|
||||
$(BUILD_CC) -I#{dir} -I$(srcdir)/#{dir} $(BUILD_CPPFLAGS) -DPUPA_UTIL=1 $(#{prefix}_CFLAGS) -M $< \
|
||||
| sed 's,#{Regexp.quote(fake_obj)}[ :]*,#{obj} $@ : ,g' > $@; \
|
||||
[ -s $@ ] || rm -f $@
|
||||
|
||||
-include #{dep}
|
||||
|
||||
"
|
||||
end.join('')
|
||||
end
|
||||
end
|
||||
|
||||
images = []
|
||||
utils = []
|
||||
pmodules = []
|
||||
|
||||
cont = false
|
||||
s = nil
|
||||
while l = gets
|
||||
if cont
|
||||
s += l
|
||||
else
|
||||
s = l
|
||||
end
|
||||
|
||||
print l
|
||||
cont = (/\\$/ =~ l)
|
||||
unless cont
|
||||
s.gsub!(/\\\n/, ' ')
|
||||
|
||||
if /^([a-zA-Z0-9_]+)\s*=\s*(.*?)\s*$/ =~ s
|
||||
var, args = $1, $2
|
||||
|
||||
if var =~ /^([a-zA-Z0-9_]+)_([A-Z]+)$/
|
||||
prefix, type = $1, $2
|
||||
|
||||
case type
|
||||
when 'IMAGES'
|
||||
images += args.split(/\s+/).collect do |img|
|
||||
Image.new(prefix, img)
|
||||
end
|
||||
|
||||
when 'MODULES'
|
||||
pmodules += args.split(/\s+/).collect do |pmod|
|
||||
PModule.new(prefix, pmod)
|
||||
end
|
||||
|
||||
when 'UTILITIES'
|
||||
utils += args.split(/\s+/).collect do |util|
|
||||
Utility.new(prefix, util)
|
||||
end
|
||||
|
||||
when 'SOURCES'
|
||||
if img = images.detect() {|i| i.name.to_var == prefix}
|
||||
print img.rule(args.split(/\s+/))
|
||||
elsif pmod = pmodules.detect() {|m| m.name.to_var == prefix}
|
||||
print pmod.rule(args.split(/\s+/))
|
||||
elsif util = utils.detect() {|u| u.name.to_var == prefix}
|
||||
print util.rule(args.split(/\s+/))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
puts "CLEANFILES += moddep.lst"
|
||||
puts "pkgdata_DATA += moddep.lst"
|
||||
puts "moddep.lst: $(DEFSYMFILES) $(UNDSYMFILES) genmoddep"
|
||||
puts " cat $(DEFSYMFILES) /dev/null | ./genmoddep $(UNDSYMFILES) > $@ \\"
|
||||
puts " || (rm -f $@; exit 1)"
|
48
genmodsrc.sh
Normal file
48
genmodsrc.sh
Normal file
|
@ -0,0 +1,48 @@
|
|||
#! /bin/sh
|
||||
#
|
||||
# Copyright (C) 2002 Yoshinori K. Okuji <okuji@enbug.org>
|
||||
#
|
||||
# This genmodsrc.sh is free software; the author
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
# with or without modifications, as long as this notice is preserved.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
|
||||
# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||
# PARTICULAR PURPOSE.
|
||||
|
||||
set -e
|
||||
|
||||
mod_name="$1"
|
||||
deps="$2"
|
||||
|
||||
cat <<EOF
|
||||
/* This file is automatically generated by genmodsrc.sh. DO NOT EDIT! */
|
||||
/*
|
||||
* PUPA -- Preliminary Universal Programming Architecture for GRUB
|
||||
* Copyright (C) 2002 Yoshinori K. Okuji <okuji@enbug.org>
|
||||
*
|
||||
* PUPA is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with PUPA; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <pupa/dl.h>
|
||||
|
||||
EOF
|
||||
|
||||
echo "PUPA_MOD_NAME(${mod_name});"
|
||||
|
||||
for mod in `grep "^${mod_name}:" ${deps} | sed 's/^[^:]*://'`; do
|
||||
echo "PUPA_MOD_DEP(${mod});"
|
||||
done
|
65
gensymlist.sh
Normal file
65
gensymlist.sh
Normal file
|
@ -0,0 +1,65 @@
|
|||
#! /bin/sh
|
||||
#
|
||||
# Copyright (C) 2002 Yoshinori K. Okuji <okuji@enbug.org>
|
||||
#
|
||||
# This gensymlist.sh is free software; the author
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
# with or without modifications, as long as this notice is preserved.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
|
||||
# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||
# PARTICULAR PURPOSE.
|
||||
|
||||
cat <<EOF
|
||||
/* This file is automatically generated by gensymlist.sh. DO NOT EDIT! */
|
||||
/*
|
||||
* PUPA -- Preliminary Universal Programming Architecture for GRUB
|
||||
* Copyright (C) 2002 Yoshinori K. Okuji <okuji@enbug.org>
|
||||
*
|
||||
* PUPA is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with PUPA; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
EOF
|
||||
|
||||
for i in $*; do
|
||||
echo "#include <$i>"
|
||||
done
|
||||
|
||||
cat <<EOF
|
||||
|
||||
void
|
||||
pupa_register_exported_symbols (void)
|
||||
{
|
||||
EOF
|
||||
|
||||
cat <<EOF
|
||||
struct symtab { const char *name; void *addr; };
|
||||
struct symtab *p;
|
||||
static struct symtab tab[] =
|
||||
{
|
||||
EOF
|
||||
|
||||
cat $* | grep -v '^#' | sed -n '/EXPORT_FUNC *([a-zA-Z0-9_]*)/{s/.*EXPORT_FUNC *(\([a-zA-Z0-9_]*\)).*/ {"\1", \1},/;p;}'
|
||||
cat $* | grep -v '^#' | sed -n '/EXPORT_VAR *([a-zA-Z0-9_]*)/{s/.*EXPORT_VAR *(\([a-zA-Z0-9_]*\)).*/ {"\1", \&\1},/;p;}'
|
||||
|
||||
cat <<EOF
|
||||
{0, 0}
|
||||
};
|
||||
|
||||
for (p = tab; p->name; p++)
|
||||
pupa_dl_register_symbol (p->name, p->addr, 0);
|
||||
}
|
||||
EOF
|
28
include/grub/boot.h
Normal file
28
include/grub/boot.h
Normal file
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* PUPA -- Preliminary Universal Programming Architecture for GRUB
|
||||
* Copyright (C) 2002 Yoshinori K. Okuji <okuji@enbug.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#ifndef PUPA_BOOT_HEADER
|
||||
#define PUPA_BOOT_HEADER 1
|
||||
|
||||
#define PUPA_BOOT_VERSION_MAJOR 4
|
||||
#define PUPA_BOOT_VERSION_MINOR 0
|
||||
#define PUPA_BOOT_VERSION ((PUPA_BOOT_VERSION_MINOR << 8) \
|
||||
| PUPA_BOOT_VERSION_MAJOR)
|
||||
|
||||
#endif /* ! PUPA_BOOT_HEADER */
|
44
include/grub/device.h
Normal file
44
include/grub/device.h
Normal file
|
@ -0,0 +1,44 @@
|
|||
/* device.h - device manager */
|
||||
/*
|
||||
* PUPA -- Preliminary Universal Programming Architecture for GRUB
|
||||
* Copyright (C) 2002 Yoshinori K. Okuji <okuji@enbug.org>
|
||||
*
|
||||
* PUPA is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with PUPA; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#ifndef PUPA_DEVICE_HEADER
|
||||
#define PUPA_DEVICE_HEADER 1
|
||||
|
||||
#include <pupa/symbol.h>
|
||||
#include <pupa/err.h>
|
||||
|
||||
struct pupa_disk;
|
||||
struct pupa_net;
|
||||
struct pupa_fs;
|
||||
|
||||
struct pupa_device
|
||||
{
|
||||
struct pupa_disk *disk;
|
||||
struct pupa_net *net;
|
||||
};
|
||||
typedef struct pupa_device *pupa_device_t;
|
||||
|
||||
pupa_device_t EXPORT_FUNC(pupa_device_open) (const char *name);
|
||||
pupa_err_t EXPORT_FUNC(pupa_device_close) (pupa_device_t device);
|
||||
|
||||
pupa_err_t EXPORT_FUNC(pupa_device_set_root) (const char *name);
|
||||
const char *EXPORT_FUNC(pupa_device_get_root) (void);
|
||||
|
||||
#endif /* ! PUPA_DEVICE_HEADER */
|
119
include/grub/disk.h
Normal file
119
include/grub/disk.h
Normal file
|
@ -0,0 +1,119 @@
|
|||
/*
|
||||
* PUPA -- Preliminary Universal Programming Architecture for GRUB
|
||||
* Copyright (C) 2002 Yoshinori K. Okuji <okuji@enbug.org>
|
||||
*
|
||||
* PUPA is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with PUPA; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#ifndef PUPA_DISK_HEADER
|
||||
#define PUPA_DISK_HEADER 1
|
||||
|
||||
#include <pupa/symbol.h>
|
||||
#include <pupa/err.h>
|
||||
#include <pupa/types.h>
|
||||
|
||||
struct pupa_disk;
|
||||
|
||||
/* Disk device. */
|
||||
struct pupa_disk_dev
|
||||
{
|
||||
/* The device name. */
|
||||
const char *name;
|
||||
|
||||
/* Call HOOK with each device name, until HOOK returns non-zero. */
|
||||
int (*iterate) (int (*hook) (const char *name));
|
||||
|
||||
/* Open the device named NAME, and set up DISK. */
|
||||
pupa_err_t (*open) (const char *name, struct pupa_disk *disk);
|
||||
|
||||
/* Close the disk DISK. */
|
||||
void (*close) (struct pupa_disk *disk);
|
||||
|
||||
/* Read SIZE sectors from the sector SECTOR of the disk DISK into BUF. */
|
||||
pupa_err_t (*read) (struct pupa_disk *disk, unsigned long sector,
|
||||
unsigned long size, char *buf);
|
||||
|
||||
/* Write SIZE sectors from BUF into the sector SECTOR of the disk DISK. */
|
||||
pupa_err_t (*write) (struct pupa_disk *disk, unsigned long sector,
|
||||
unsigned long size, const char *buf);
|
||||
|
||||
/* The next disk device. */
|
||||
struct pupa_disk_dev *next;
|
||||
};
|
||||
typedef struct pupa_disk_dev *pupa_disk_dev_t;
|
||||
|
||||
struct pupa_partition;
|
||||
|
||||
/* Disk. */
|
||||
struct pupa_disk
|
||||
{
|
||||
/* The disk name. */
|
||||
const char *name;
|
||||
|
||||
/* The underlying disk device. */
|
||||
pupa_disk_dev_t dev;
|
||||
|
||||
/* The total number of sectors. */
|
||||
unsigned long total_sectors;
|
||||
|
||||
/* If partitions can be stored. */
|
||||
int has_partitions;
|
||||
|
||||
/* The id used by the disk cache manager. */
|
||||
unsigned long id;
|
||||
|
||||
/* The partition information. This is machine-specific. */
|
||||
struct pupa_partition *partition;
|
||||
|
||||
/* Called when a sector was read. */
|
||||
void (*read_hook) (unsigned long sector, unsigned offset, unsigned length);
|
||||
|
||||
/* Device-specific data. */
|
||||
void *data;
|
||||
};
|
||||
typedef struct pupa_disk *pupa_disk_t;
|
||||
|
||||
/* The sector size. */
|
||||
#define PUPA_DISK_SECTOR_SIZE 0x200
|
||||
#define PUPA_DISK_SECTOR_BITS 9
|
||||
|
||||
/* The maximum number of disk caches. */
|
||||
#define PUPA_DISK_CACHE_NUM 1021
|
||||
|
||||
/* The size of a disk cache in sector units. */
|
||||
#define PUPA_DISK_CACHE_SIZE 8
|
||||
#define PUPA_DISK_CACHE_BITS 3
|
||||
|
||||
/* This is called from the memory manager. */
|
||||
void pupa_disk_cache_invalidate_all (void);
|
||||
|
||||
void EXPORT_FUNC(pupa_disk_dev_register) (pupa_disk_dev_t dev);
|
||||
void EXPORT_FUNC(pupa_disk_dev_unregister) (pupa_disk_dev_t dev);
|
||||
void EXPORT_FUNC(pupa_disk_dev_iterate) (int (*hook) (const char *name));
|
||||
|
||||
pupa_disk_t EXPORT_FUNC(pupa_disk_open) (const char *name);
|
||||
void EXPORT_FUNC(pupa_disk_close) (pupa_disk_t disk);
|
||||
pupa_err_t EXPORT_FUNC(pupa_disk_read) (pupa_disk_t disk,
|
||||
unsigned long sector,
|
||||
unsigned long offset,
|
||||
unsigned long size,
|
||||
char *buf);
|
||||
pupa_err_t EXPORT_FUNC(pupa_disk_write) (pupa_disk_t disk,
|
||||
unsigned long sector,
|
||||
unsigned long offset,
|
||||
unsigned long size,
|
||||
const char *buf);
|
||||
|
||||
#endif /* ! PUPA_DISK_HEADER */
|
86
include/grub/dl.h
Normal file
86
include/grub/dl.h
Normal file
|
@ -0,0 +1,86 @@
|
|||
/* dl.h - types and prototypes for loadable module support */
|
||||
/*
|
||||
* PUPA -- Preliminary Universal Programming Architecture for GRUB
|
||||
* Copyright (C) 2002 Yoshinori K. Okuji <okuji@enbug.org>
|
||||
*
|
||||
* PUPA is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with PUPA; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#ifndef PUPA_DL_H
|
||||
#define PUPA_DL_H 1
|
||||
|
||||
#include <pupa/symbol.h>
|
||||
#include <pupa/err.h>
|
||||
#include <pupa/types.h>
|
||||
|
||||
#define PUPA_MOD_INIT \
|
||||
static void pupa_mod_init (void) __attribute__ ((unused)); \
|
||||
static void \
|
||||
pupa_mod_init (void)
|
||||
|
||||
#define PUPA_MOD_FINI \
|
||||
static void pupa_mod_fini (void) __attribute__ ((unused)); \
|
||||
static void \
|
||||
pupa_mod_fini (void)
|
||||
|
||||
#define PUPA_MOD_NAME(name) \
|
||||
__asm__ (".section .modname,\"S\"\n.string \"" #name "\"\n.previous")
|
||||
|
||||
#define PUPA_MOD_DEP(name) \
|
||||
__asm__ (".section .moddeps,\"S\"\n.string \"" #name "\"\n.previous")
|
||||
|
||||
struct pupa_dl_segment
|
||||
{
|
||||
struct pupa_dl_segment *next;
|
||||
void *addr;
|
||||
pupa_size_t size;
|
||||
unsigned section;
|
||||
};
|
||||
typedef struct pupa_dl_segment *pupa_dl_segment_t;
|
||||
|
||||
struct pupa_dl;
|
||||
|
||||
struct pupa_dl_dep
|
||||
{
|
||||
struct pupa_dl_dep *next;
|
||||
struct pupa_dl *mod;
|
||||
};
|
||||
typedef struct pupa_dl_dep *pupa_dl_dep_t;
|
||||
|
||||
struct pupa_dl
|
||||
{
|
||||
char *name;
|
||||
int ref_count;
|
||||
pupa_dl_dep_t dep;
|
||||
pupa_dl_segment_t segment;
|
||||
void (*init) (void);
|
||||
void (*fini) (void);
|
||||
};
|
||||
typedef struct pupa_dl *pupa_dl_t;
|
||||
|
||||
pupa_dl_t EXPORT_FUNC(pupa_dl_load_file) (const char *filename);
|
||||
pupa_dl_t EXPORT_FUNC(pupa_dl_load) (const char *name);
|
||||
pupa_dl_t pupa_dl_load_core (void *addr, pupa_size_t size);
|
||||
void EXPORT_FUNC(pupa_dl_unload) (pupa_dl_t mod);
|
||||
pupa_dl_t EXPORT_FUNC(pupa_dl_get) (const char *name);
|
||||
pupa_err_t EXPORT_FUNC(pupa_dl_register_symbol) (const char *name, void *addr,
|
||||
pupa_dl_t mod);
|
||||
void *EXPORT_FUNC(pupa_dl_resolve_symbol) (const char *name);
|
||||
void pupa_dl_init (const char *dir);
|
||||
|
||||
int pupa_arch_dl_check_header (void *ehdr, pupa_size_t size);
|
||||
pupa_err_t pupa_arch_dl_relocate_symbols (pupa_dl_t mod, void *ehdr);
|
||||
|
||||
#endif /* ! PUPA_DL_H */
|
2314
include/grub/elf.h
Normal file
2314
include/grub/elf.h
Normal file
File diff suppressed because it is too large
Load diff
59
include/grub/err.h
Normal file
59
include/grub/err.h
Normal file
|
@ -0,0 +1,59 @@
|
|||
/* err.h - error numbers and prototypes */
|
||||
/*
|
||||
* PUPA -- Preliminary Universal Programming Architecture for GRUB
|
||||
* Copyright (C) 2002 Yoshinori K. Okuji <okuji@enbug.org>
|
||||
*
|
||||
* PUPA is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with PUPA; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#ifndef PUPA_ERR_HEADER
|
||||
#define PUPA_ERR_HEADER 1
|
||||
|
||||
#include <pupa/symbol.h>
|
||||
|
||||
typedef enum
|
||||
{
|
||||
PUPA_ERR_NONE = 0,
|
||||
PUPA_ERR_BAD_MODULE,
|
||||
PUPA_ERR_OUT_OF_MEMORY,
|
||||
PUPA_ERR_BAD_FILE_TYPE,
|
||||
PUPA_ERR_FILE_NOT_FOUND,
|
||||
PUPA_ERR_FILE_READ_ERROR,
|
||||
PUPA_ERR_BAD_FILENAME,
|
||||
PUPA_ERR_UNKNOWN_FS,
|
||||
PUPA_ERR_BAD_FS,
|
||||
PUPA_ERR_BAD_NUMBER,
|
||||
PUPA_ERR_OUT_OF_RANGE,
|
||||
PUPA_ERR_UNKNOWN_DEVICE,
|
||||
PUPA_ERR_BAD_DEVICE,
|
||||
PUPA_ERR_READ_ERROR,
|
||||
PUPA_ERR_WRITE_ERROR,
|
||||
PUPA_ERR_BAD_ARGUMENT,
|
||||
PUPA_ERR_BAD_PART_TABLE,
|
||||
PUPA_ERR_UNKNOWN_OS,
|
||||
PUPA_ERR_BAD_OS,
|
||||
PUPA_ERR_NO_KERNEL,
|
||||
PUPA_ERR_NOT_IMPLEMENTED_YET,
|
||||
}
|
||||
pupa_err_t;
|
||||
|
||||
extern pupa_err_t EXPORT_VAR(pupa_errno);
|
||||
extern char EXPORT_VAR(pupa_errmsg)[];
|
||||
|
||||
pupa_err_t EXPORT_FUNC(pupa_error) (pupa_err_t n, const char *fmt, ...);
|
||||
void EXPORT_FUNC(pupa_fatal) (const char *fmt, ...) __attribute__ ((noreturn));
|
||||
void EXPORT_FUNC(pupa_print_error) (void);
|
||||
|
||||
#endif /* ! PUPA_ERR_HEADER */
|
73
include/grub/file.h
Normal file
73
include/grub/file.h
Normal file
|
@ -0,0 +1,73 @@
|
|||
/*
|
||||
* PUPA -- Preliminary Universal Programming Architecture for GRUB
|
||||
* Copyright (C) 2002 Yoshinori K. Okuji <okuji@enbug.org>
|
||||
*
|
||||
* PUPA is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with PUPA; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#ifndef PUPA_FILE_HEADER
|
||||
#define PUPA_FILE_HEADER 1
|
||||
|
||||
#include <pupa/types.h>
|
||||
#include <pupa/err.h>
|
||||
#include <pupa/device.h>
|
||||
#include <pupa/fs.h>
|
||||
|
||||
/* File description. */
|
||||
struct pupa_file
|
||||
{
|
||||
/* The underlying device. */
|
||||
pupa_device_t device;
|
||||
|
||||
/* The underlying filesystem. */
|
||||
pupa_fs_t fs;
|
||||
|
||||
/* The current offset. */
|
||||
pupa_ssize_t offset;
|
||||
|
||||
/* The file size. */
|
||||
pupa_ssize_t size;
|
||||
|
||||
/* Filesystem-specific data. */
|
||||
void *data;
|
||||
|
||||
/* This is called when a sector is read. Used only for a disk device. */
|
||||
void (*read_hook) (unsigned long sector, unsigned offset, unsigned length);
|
||||
};
|
||||
typedef struct pupa_file *pupa_file_t;
|
||||
|
||||
/* Get a device name from NAME. */
|
||||
char *EXPORT_FUNC(pupa_file_get_device_name) (const char *name);
|
||||
|
||||
pupa_file_t EXPORT_FUNC(pupa_file_open) (const char *name);
|
||||
pupa_ssize_t EXPORT_FUNC(pupa_file_read) (pupa_file_t file, char *buf,
|
||||
pupa_ssize_t len);
|
||||
pupa_ssize_t EXPORT_FUNC(pupa_file_seek) (pupa_file_t file,
|
||||
pupa_ssize_t offset);
|
||||
pupa_err_t EXPORT_FUNC(pupa_file_close) (pupa_file_t file);
|
||||
|
||||
static inline pupa_ssize_t
|
||||
pupa_file_size (const pupa_file_t file)
|
||||
{
|
||||
return file->size;
|
||||
}
|
||||
|
||||
static inline pupa_ssize_t
|
||||
pupa_file_tell (const pupa_file_t file)
|
||||
{
|
||||
return file->offset;
|
||||
}
|
||||
|
||||
#endif /* ! PUPA_FILE_HEADER */
|
63
include/grub/fs.h
Normal file
63
include/grub/fs.h
Normal file
|
@ -0,0 +1,63 @@
|
|||
/* fs.h - filesystem manager */
|
||||
/*
|
||||
* PUPA -- Preliminary Universal Programming Architecture for GRUB
|
||||
* Copyright (C) 2002 Yoshinori K. Okuji <okuji@enbug.org>
|
||||
*
|
||||
* PUPA is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with PUPA; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#ifndef PUPA_FS_HEADER
|
||||
#define PUPA_FS_HEADER 1
|
||||
|
||||
#include <pupa/device.h>
|
||||
#include <pupa/symbol.h>
|
||||
#include <pupa/types.h>
|
||||
|
||||
/* Forward declaration is required, because of mutual reference. */
|
||||
struct pupa_file;
|
||||
|
||||
/* Filesystem descriptor. */
|
||||
struct pupa_fs
|
||||
{
|
||||
/* My name. */
|
||||
const char *name;
|
||||
|
||||
/* Call HOOK with each file under DIR. */
|
||||
pupa_err_t (*dir) (pupa_device_t device, const char *path,
|
||||
int (*hook) (const char *filename, int dir));
|
||||
|
||||
/* Open a file named NAME and initialize FILE. */
|
||||
pupa_err_t (*open) (struct pupa_file *file, const char *name);
|
||||
|
||||
/* Read LEN bytes data from FILE into BUF. */
|
||||
pupa_ssize_t (*read) (struct pupa_file *file, char *buf, pupa_ssize_t len);
|
||||
|
||||
/* Close the file FILE. */
|
||||
pupa_err_t (*close) (struct pupa_file *file);
|
||||
|
||||
/* The next filesystem. */
|
||||
struct pupa_fs *next;
|
||||
};
|
||||
typedef struct pupa_fs *pupa_fs_t;
|
||||
|
||||
/* This is special, because block lists are not files in usual sense. */
|
||||
extern struct pupa_fs pupa_fs_blocklist;
|
||||
|
||||
void EXPORT_FUNC(pupa_fs_register) (pupa_fs_t fs);
|
||||
void EXPORT_FUNC(pupa_fs_unregister) (pupa_fs_t fs);
|
||||
void EXPORT_FUNC(pupa_fs_iterate) (int (*hook) (const pupa_fs_t fs));
|
||||
pupa_fs_t EXPORT_FUNC(pupa_fs_probe) (pupa_device_t device);
|
||||
|
||||
#endif /* ! PUPA_FS_HEADER */
|
47
include/grub/i386/pc/biosdisk.h
Normal file
47
include/grub/i386/pc/biosdisk.h
Normal file
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* PUPA -- Preliminary Universal Programming Architecture for GRUB
|
||||
* Copyright (C) 2002 Yoshinori K. Okuji <okuji@enbug.org>
|
||||
*
|
||||
* PUPA is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with PUPA; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#ifndef PUPA_BIOSDISK_MACHINE_HEADER
|
||||
#define PUPA_BIOSDISK_MACHINE_HEADER 1
|
||||
|
||||
#define PUPA_BIOSDISK_FLAG_LBA 1
|
||||
|
||||
struct pupa_biosdisk_data
|
||||
{
|
||||
int drive;
|
||||
unsigned long cylinders;
|
||||
unsigned long heads;
|
||||
unsigned long sectors;
|
||||
unsigned long flags;
|
||||
};
|
||||
|
||||
int pupa_biosdisk_rw_int13_extensions (int ah, int drive, void *dap);
|
||||
int pupa_biosdisk_rw_standard (int ah, int drive, int coff, int hoff,
|
||||
int soff, int nsec, int segment);
|
||||
int pupa_biosdisk_check_int13_extensions (int drive);
|
||||
int pupa_biosdisk_get_diskinfo_int13_extensions (int drive, void *drp);
|
||||
int pupa_biosdisk_get_diskinfo_standard (int drive,
|
||||
unsigned long *cylinders,
|
||||
unsigned long *heads,
|
||||
unsigned long *sectors);
|
||||
int pupa_biosdisk_get_num_floppies (void);
|
||||
|
||||
void pupa_biosdisk_init (void);
|
||||
|
||||
#endif /* ! PUPA_BIOSDISK_MACHINE_HEADER */
|
83
include/grub/i386/pc/boot.h
Normal file
83
include/grub/i386/pc/boot.h
Normal file
|
@ -0,0 +1,83 @@
|
|||
/*
|
||||
* PUPA -- Preliminary Universal Programming Architecture for GRUB
|
||||
* Copyright (C) 1999, 2000 Free Software Foundation, Inc.
|
||||
* Copyright (C) 2002 Yoshinori K. Okuji <okuji@enbug.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#ifndef PUPA_BOOT_MACHINE_HEADER
|
||||
#define PUPA_BOOT_MACHINE_HEADER 1
|
||||
|
||||
/* The signature for bootloader. */
|
||||
#define PUPA_BOOT_MACHINE_SIGNATURE 0xaa55
|
||||
|
||||
/* The offset of the end of BPB (BIOS Parameter Block). */
|
||||
#define PUPA_BOOT_MACHINE_BPBEND 0x3e
|
||||
|
||||
/* The offset of the major version. */
|
||||
#define PUPA_BOOT_MACHINE_VER_MAJ 0x3e
|
||||
|
||||
/* The offset of BOOT_DRIVE. */
|
||||
#define PUPA_BOOT_MACHINE_BOOT_DRIVE 0x40
|
||||
|
||||
/* The offset of FORCE_LBA. */
|
||||
#define PUPA_BOOT_MACHINE_FORCE_LBA 0x41
|
||||
|
||||
/* The offset of KERNEL_ADDRESS. */
|
||||
#define PUPA_BOOT_MACHINE_KERNEL_ADDRESS 0x42
|
||||
|
||||
/* The offset of KERNEL_SECTOR. */
|
||||
#define PUPA_BOOT_MACHINE_KERNEL_SECTOR 0x44
|
||||
|
||||
/* The offset of KERNEL_SEGMENT. */
|
||||
#define PUPA_BOOT_MACHINE_KERNEL_SEGMENT 0x48
|
||||
|
||||
/* The offset of a magic number used by Windows NT. */
|
||||
#define PUPA_BOOT_MACHINE_WINDOWS_NT_MAGIC 0x1b8
|
||||
|
||||
/* The offset of the start of the partition table. */
|
||||
#define PUPA_BOOT_MACHINE_PART_START 0x1be
|
||||
|
||||
/* The offset of the end of the partition table. */
|
||||
#define PUPA_BOOT_MACHINE_PART_END 0x1fe
|
||||
|
||||
/* The stack segment. */
|
||||
#define PUPA_BOOT_MACHINE_STACK_SEG 0x2000
|
||||
|
||||
/* The segment of disk buffer. The disk buffer MUST be 32K long and
|
||||
cannot straddle a 64K boundary. */
|
||||
#define PUPA_BOOT_MACHINE_BUFFER_SEG 0x7000
|
||||
|
||||
/* The address of drive parameters. */
|
||||
#define PUPA_BOOT_MACHINE_DRP_ADDR 0x7f00
|
||||
|
||||
/* The size of drive parameters. */
|
||||
#define PUPA_BOOT_MACHINE_DRP_SIZE 0x42
|
||||
|
||||
/* The flag for BIOS drive number to designate a hard disk vs. a
|
||||
floppy. */
|
||||
#define PUPA_BOOT_MACHINE_BIOS_HD_FLAG 0x80
|
||||
|
||||
/* The segment where the kernel is loaded. */
|
||||
#define PUPA_BOOT_MACHINE_KERNEL_SEG 0x800
|
||||
|
||||
/* The address where the kernel is loaded. */
|
||||
#define PUPA_BOOT_MACHINE_KERNEL_ADDR (PUPA_BOOT_MACHINE_KERNEL_SEG << 4)
|
||||
|
||||
/* The size of a block list used in the kernel startup code. */
|
||||
#define PUPA_BOOT_MACHINE_LIST_SIZE 8
|
||||
|
||||
#endif /* ! BOOT_MACHINE_HEADER */
|
55
include/grub/i386/pc/console.h
Normal file
55
include/grub/i386/pc/console.h
Normal file
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
* PUPA -- Preliminary Universal Programming Architecture for GRUB
|
||||
* Copyright (C) 2002 Yoshinori K. Okuji <okuji@enbug.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#ifndef PUPA_CONSOLE_MACHINE_HEADER
|
||||
#define PUPA_CONSOLE_MACHINE_HEADER 1
|
||||
|
||||
/* Define scan codes. */
|
||||
#define PUPA_CONSOLE_KEY_LEFT 0x4B00
|
||||
#define PUPA_CONSOLE_KEY_RIGHT 0x4D00
|
||||
#define PUPA_CONSOLE_KEY_UP 0x4800
|
||||
#define PUPA_CONSOLE_KEY_DOWN 0x5000
|
||||
#define PUPA_CONSOLE_KEY_IC 0x5200
|
||||
#define PUPA_CONSOLE_KEY_DC 0x5300
|
||||
#define PUPA_CONSOLE_KEY_BACKSPACE 0x0008
|
||||
#define PUPA_CONSOLE_KEY_HOME 0x4700
|
||||
#define PUPA_CONSOLE_KEY_END 0x4F00
|
||||
#define PUPA_CONSOLE_KEY_NPAGE 0x4900
|
||||
#define PUPA_CONSOLE_KEY_PPAGE 0x5100
|
||||
|
||||
#ifndef ASM_FILE
|
||||
|
||||
#include <pupa/types.h>
|
||||
|
||||
/* These are global to share code between C and asm. */
|
||||
extern pupa_uint8_t pupa_console_cur_color;
|
||||
void pupa_console_putchar (int c);
|
||||
int pupa_console_checkkey (void);
|
||||
int pupa_console_getkey (void);
|
||||
pupa_uint16_t pupa_console_getxy (void);
|
||||
void pupa_console_gotoxy (pupa_uint8_t x, pupa_uint8_t y);
|
||||
void pupa_console_cls (void);
|
||||
void pupa_console_setcursor (int on);
|
||||
|
||||
/* Initialize the console system. */
|
||||
void pupa_console_init (void);
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* ! PUPA_CONSOLE_MACHINE_HEADER */
|
50
include/grub/i386/pc/init.h
Normal file
50
include/grub/i386/pc/init.h
Normal file
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* PUPA -- Preliminary Universal Programming Architecture for GRUB
|
||||
* Copyright (C) 2002 Yoshinori K. Okuji <okuji@enbug.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#ifndef PUPA_INIT_MACHINE_HEADER
|
||||
#define PUPA_INIT_MACHINE_HEADER 1
|
||||
|
||||
#include <pupa/types.h>
|
||||
#include <pupa/symbol.h>
|
||||
|
||||
/* Get the memory size in KB. If EXTENDED is zero, return conventional
|
||||
memory, otherwise return extended memory. */
|
||||
pupa_uint16_t pupa_get_memsize (int extended);
|
||||
|
||||
/* Get a packed EISA memory map. Lower 16 bits are between 1MB and 16MB
|
||||
in 1KB parts, and upper 16 bits are above 16MB in 64KB parts. */
|
||||
pupa_uint32_t pupa_get_eisa_mmap (void);
|
||||
|
||||
struct pupa_machine_mmap_entry
|
||||
{
|
||||
pupa_uint32_t size;
|
||||
pupa_uint64_t addr;
|
||||
pupa_uint64_t len;
|
||||
pupa_uint32_t type;
|
||||
};
|
||||
|
||||
/* Get a memory map entry. Return next continuation value. Zero means
|
||||
the end. */
|
||||
pupa_uint32_t pupa_get_mmap_entry (struct pupa_machine_mmap_entry *entry,
|
||||
pupa_uint32_t cont);
|
||||
|
||||
/* Turn on/off Gate A20. */
|
||||
void EXPORT_FUNC(pupa_gate_a20) (int on);
|
||||
|
||||
#endif /* ! PUPA_INIT_MACHINE_HEADER */
|
29
include/grub/i386/pc/kernel.h
Normal file
29
include/grub/i386/pc/kernel.h
Normal file
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* PUPA -- Preliminary Universal Programming Architecture for GRUB
|
||||
* Copyright (C) 2002 Yoshinori K. Okuji <okuji@enbug.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#ifndef KERNEL_MACHINE_HEADER
|
||||
#define KERNEL_MACHINE_HEADER 1
|
||||
|
||||
/* The offset of PUPA_TOTAL_MODULE_SIZE. */
|
||||
#define PUPA_KERNEL_MACHINE_TOTAL_MODULE_SIZE 0x8
|
||||
|
||||
/* The offset of PUPA_KERNEL_IMAGE_SIZE. */
|
||||
#define PUPA_KERNEL_MACHINE_KERNEL_IMAGE_SIZE 0xc
|
||||
|
||||
#endif /* ! KERNEL_MACHINE_HEADER */
|
29
include/grub/i386/pc/loader.h
Normal file
29
include/grub/i386/pc/loader.h
Normal file
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* PUPA -- Preliminary Universal Programming Architecture for GRUB
|
||||
* Copyright (C) 2002 Yoshinori K. Okuji <okuji@enbug.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#ifndef PUPA_LOADER_MACHINE_HEADER
|
||||
#define PUPA_LOADER_MACHINE_HEADER 1
|
||||
|
||||
#include <pupa/types.h>
|
||||
#include <pupa/symbol.h>
|
||||
|
||||
/* This is an asm part of the chainloader. */
|
||||
void EXPORT_FUNC(pupa_chainloader_real_boot) (int drive, void *part_addr) __attribute__ ((noreturn));
|
||||
|
||||
#endif /* ! PUPA_LOADER_MACHINE_HEADER */
|
67
include/grub/i386/pc/memory.h
Normal file
67
include/grub/i386/pc/memory.h
Normal file
|
@ -0,0 +1,67 @@
|
|||
/* memory.h - describe the memory map */
|
||||
/*
|
||||
* PUPA -- Preliminary Universal Programming Architecture for GRUB
|
||||
* Copyright (C) 2002 Yoshinori K. Okuji <okuji@enbug.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#ifndef PUPA_MEMORY_MACHINE_HEADER
|
||||
#define PUPA_MEMORY_MACHINE_HEADER 1
|
||||
|
||||
/* The scratch buffer used in real mode code. */
|
||||
#define PUPA_MEMORY_MACHINE_SCRATCH_ADDR 0x68000
|
||||
#define PUPA_MEMORY_MACHINE_SCRATCH_SEG (PUPA_MEMORY_MACHINE_SCRATCH_ADDR >> 4)
|
||||
#define PUPA_MEMORY_MACHINE_SCRATCH_SIZE 0x10000
|
||||
|
||||
/* The real mode stack. */
|
||||
#define PUPA_MEMORY_MACHINE_REAL_STACK (0x2000 - 0x10)
|
||||
|
||||
/* The size of the protect mode stack. */
|
||||
#define PUPA_MEMORY_MACHINE_PROT_STACK_SIZE 0x8000
|
||||
|
||||
/* The protected mode stack. */
|
||||
#define PUPA_MEMORY_MACHINE_PROT_STACK \
|
||||
(PUPA_MEMORY_MACHINE_SCRATCH_ADDR + PUPA_MEMORY_MACHINE_SCRATCH_SIZE \
|
||||
+ PUPA_MEMORY_MACHINE_PROT_STACK_SIZE - 0x10)
|
||||
|
||||
/* The memory area where PUPA uses its own purpose. */
|
||||
#define PUPA_MEMORY_MACHINE_RESERVED_START \
|
||||
PUPA_MEMORY_MACHINE_SCRATCH_ADDR
|
||||
#define PUPA_MEMORY_MACHINE_RESERVED_END \
|
||||
(PUPA_MEMORY_MACHINE_PROT_STACK + 0x10)
|
||||
|
||||
/* The address of a partition table passed to another boot loader. */
|
||||
#define PUPA_MEMORY_MACHINE_PART_TABLE_ADDR 0x7be
|
||||
|
||||
/* The address where another boot loader is loaded. */
|
||||
#define PUPA_MEMORY_MACHINE_BOOT_LOADER_ADDR 0x7c00
|
||||
|
||||
/* The flag for protected mode. */
|
||||
#define PUPA_MEMORY_MACHINE_CR0_PE_ON 0x1
|
||||
|
||||
/* The code segment of the protected mode. */
|
||||
#define PUPA_MEMORY_MACHINE_PROT_MODE_CSEG 0x8
|
||||
|
||||
/* The data segment of the protected mode. */
|
||||
#define PUPA_MEMORY_MACHINE_PROT_MODE_DSEG 0x10
|
||||
|
||||
/* The code segment of the pseudo real mode. */
|
||||
#define PUPA_MEMORY_MACHINE_PSEUDO_REAL_CSEG 0x18
|
||||
|
||||
/* The data segment of the pseudo real mode. */
|
||||
#define PUPA_MEMORY_MACHINE_PSEUDO_REAL_DSEG 0x20
|
||||
|
||||
#endif /* ! PUPA_MEMORY_MACHINE_HEADER */
|
243
include/grub/i386/pc/partition.h
Normal file
243
include/grub/i386/pc/partition.h
Normal file
|
@ -0,0 +1,243 @@
|
|||
/*
|
||||
* PUPA -- Preliminary Universal Programming Architecture for GRUB
|
||||
* Copyright (C) 1999,2000,2001 Free Software Foundation, Inc.
|
||||
* Copyright (C) 2002 Yoshinori K. Okuji <okuji@enbug.org>
|
||||
*
|
||||
* PUPA is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with PUPA; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#ifndef PUPA_PARTITION_HEADER
|
||||
#define PUPA_PARTITION_HEADER 1
|
||||
|
||||
#include <pupa/symbol.h>
|
||||
#include <pupa/types.h>
|
||||
#include <pupa/err.h>
|
||||
|
||||
/* The signature. */
|
||||
#define PUPA_PARTITION_SIGNATURE 0xaa55
|
||||
|
||||
/* This is not a flag actually, but used as if it were a flag. */
|
||||
#define PUPA_PARTITION_TYPE_HIDDEN_FLAG 0x10
|
||||
|
||||
/* DOS partition types. */
|
||||
#define PUPA_PARTITION_TYPE_NONE 0
|
||||
#define PUPA_PARTITION_TYPE_FAT12 1
|
||||
#define PUPA_PARTITION_TYPE_FAT16_LT32M 4
|
||||
#define PUPA_PARTITION_TYPE_EXTENDED 5
|
||||
#define PUPA_PARTITION_TYPE_FAT16_GT32M 6
|
||||
#define PUPA_PARTITION_TYPE_FAT32 0xb
|
||||
#define PUPA_PARTITION_TYPE_FAT32_LBA 0xc
|
||||
#define PUPA_PARTITION_TYPE_FAT16_LBA 0xe
|
||||
#define PUPA_PARTITION_TYPE_WIN95_EXTENDED 0xf
|
||||
#define PUPA_PARTITION_TYPE_EZD 0x55
|
||||
#define PUPA_PARTITION_TYPE_MINIX 0x80
|
||||
#define PUPA_PARTITION_TYPE_LINUX_MINIX 0x81
|
||||
#define PUPA_PARTITION_TYPE_EXT2FS 0x83
|
||||
#define PUPA_PARTITION_TYPE_LINUX_EXTENDED 0x85
|
||||
#define PUPA_PARTITION_TYPE_VSTAFS 0x9e
|
||||
#define PUPA_PARTITION_TYPE_FREEBSD 0xa5
|
||||
#define PUPA_PARTITION_TYPE_OPENBSD 0xa6
|
||||
#define PUPA_PARTITION_TYPE_NETBSD 0xa9
|
||||
#define PUPA_PARTITION_TYPE_LINUX_RAID 0xfd
|
||||
|
||||
/* Constants for BSD disk label. */
|
||||
#define PUPA_PARTITION_BSD_LABEL_SECTOR 1
|
||||
#define PUPA_PARTITION_BSD_LABEL_MAGIC 0x82564557
|
||||
#define PUPA_PARTITION_BSD_MAX_ENTRIES 8
|
||||
|
||||
/* BSD partition types. */
|
||||
#define PUPA_PARTITION_BSD_TYPE_UNUSED 0
|
||||
#define PUPA_PARTITION_BSD_TYPE_SWAP 1
|
||||
#define PUPA_PARTITION_BSD_TYPE_V6 2
|
||||
#define PUPA_PARTITION_BSD_TYPE_V7 3
|
||||
#define PUPA_PARTITION_BSD_TYPE_SYSV 4
|
||||
#define PUPA_PARTITION_BSD_TYPE_V71K 5
|
||||
#define PUPA_PARTITION_BSD_TYPE_V8 6
|
||||
#define PUPA_PARTITION_BSD_TYPE_BSDFFS 7
|
||||
#define PUPA_PARTITION_BSD_TYPE_MSDOS 8
|
||||
#define PUPA_PARTITION_BSD_TYPE_BSDLFS 9
|
||||
#define PUPA_PARTITION_BSD_TYPE_OTHER 10
|
||||
#define PUPA_PARTITION_BSD_TYPE_HPFS 11
|
||||
#define PUPA_PARTITION_BSD_TYPE_ISO9660 12
|
||||
#define PUPA_PARTITION_BSD_TYPE_BOOT 13
|
||||
|
||||
/* FreeBSD-specific types. */
|
||||
#define PUPA_PARTITION_FREEBSD_TYPE_VINUM 14
|
||||
#define PUPA_PARTITION_FREEBSD_TYPE_RAID 15
|
||||
#define PUPA_PARTITION_FREEBSD_TYPE_JFS2 21
|
||||
|
||||
/* NetBSD-specific types. */
|
||||
#define PUPA_PARTITION_NETBSD_TYPE_ADOS 14
|
||||
#define PUPA_PARTITION_NETBSD_TYPE_HFS 15
|
||||
#define PUPA_PARTITION_NETBSD_TYPE_FILECORE 16
|
||||
#define PUPA_PARTITION_NETBSD_TYPE_EXT2FS 17
|
||||
#define PUPA_PARTITION_NETBSD_TYPE_NTFS 18
|
||||
#define PUPA_PARTITION_NETBSD_TYPE_RAID 19
|
||||
#define PUPA_PARTITION_NETBSD_TYPE_CCD 20
|
||||
#define PUPA_PARTITION_NETBSD_TYPE_JFS2 21
|
||||
#define PUPA_PARTITION_NETBSD_TYPE_APPLEUFS 22
|
||||
|
||||
/* OpenBSD-specific types. */
|
||||
#define PUPA_PARTITION_OPENBSD_TYPE_ADOS 14
|
||||
#define PUPA_PARTITION_OPENBSD_TYPE_HFS 15
|
||||
#define PUPA_PARTITION_OPENBSD_TYPE_FILECORE 16
|
||||
#define PUPA_PARTITION_OPENBSD_TYPE_EXT2FS 17
|
||||
#define PUPA_PARTITION_OPENBSD_TYPE_NTFS 18
|
||||
#define PUPA_PARTITION_OPENBSD_TYPE_RAID 19
|
||||
|
||||
/* The BSD partition entry. */
|
||||
struct pupa_partition_bsd_entry
|
||||
{
|
||||
pupa_uint32_t size;
|
||||
pupa_uint32_t offset;
|
||||
pupa_uint32_t fragment_size;
|
||||
pupa_uint8_t fs_type;
|
||||
pupa_uint8_t fs_fragments;
|
||||
pupa_uint16_t fs_cylinders;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/* The BSD disk label. Only define members useful for PUPA. */
|
||||
struct pupa_partition_disk_label
|
||||
{
|
||||
pupa_uint32_t magic;
|
||||
pupa_uint8_t padding[128];
|
||||
pupa_uint32_t magic2;
|
||||
pupa_uint16_t checksum;
|
||||
pupa_uint16_t num_partitions;
|
||||
pupa_uint32_t boot_size;
|
||||
pupa_uint32_t superblock_size;
|
||||
struct pupa_partition_bsd_entry entries[PUPA_PARTITION_BSD_MAX_ENTRIES];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/* The partition entry. */
|
||||
struct pupa_partition_entry
|
||||
{
|
||||
/* If active, 0x80, otherwise, 0x00. */
|
||||
pupa_uint8_t flag;
|
||||
|
||||
/* The head of the start. */
|
||||
pupa_uint8_t start_head;
|
||||
|
||||
/* (S | ((C >> 2) & 0xC0)) where S is the sector of the start and C
|
||||
is the cylinder of the start. Note that S is counted from one. */
|
||||
pupa_uint8_t start_sector;
|
||||
|
||||
/* (C & 0xFF) where C is the cylinder of the start. */
|
||||
pupa_uint8_t start_cylinder;
|
||||
|
||||
/* The partition type. */
|
||||
pupa_uint8_t type;
|
||||
|
||||
/* The end versions of start_head, start_sector and start_cylinder,
|
||||
respectively. */
|
||||
pupa_uint8_t end_head;
|
||||
pupa_uint8_t end_sector;
|
||||
pupa_uint8_t end_cylinder;
|
||||
|
||||
/* The start sector. Note that this is counted from zero. */
|
||||
pupa_uint32_t start;
|
||||
|
||||
/* The length in sector units. */
|
||||
pupa_uint32_t length;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/* The structure of MBR. */
|
||||
struct pupa_partition_mbr
|
||||
{
|
||||
/* The code area (actually, including BPB). */
|
||||
pupa_uint8_t code[446];
|
||||
|
||||
/* Four partition entries. */
|
||||
struct pupa_partition_entry entries[4];
|
||||
|
||||
/* The signature 0xaa55. */
|
||||
pupa_uint16_t signature;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/* Partition description. */
|
||||
struct pupa_partition
|
||||
{
|
||||
/* The start sector. */
|
||||
unsigned long start;
|
||||
|
||||
/* The length in sector units. */
|
||||
unsigned long len;
|
||||
|
||||
/* The offset of the partition table. */
|
||||
unsigned long offset;
|
||||
|
||||
/* The offset of the extended partition. */
|
||||
unsigned long ext_offset;
|
||||
|
||||
/* The index of this partition in the partition table. */
|
||||
int index;
|
||||
|
||||
/* The DOS partition number. */
|
||||
int dos_part;
|
||||
|
||||
/* The BSD partition number (a == 0). */
|
||||
int bsd_part;
|
||||
|
||||
/* The DOS partition type. */
|
||||
int dos_type;
|
||||
|
||||
/* The BSD partition type. */
|
||||
int bsd_type;
|
||||
};
|
||||
typedef struct pupa_partition *pupa_partition_t;
|
||||
|
||||
struct pupa_disk;
|
||||
|
||||
pupa_partition_t EXPORT_FUNC(pupa_partition_probe) (struct pupa_disk *disk,
|
||||
const char *str);
|
||||
pupa_err_t EXPORT_FUNC(pupa_partition_iterate) (struct pupa_disk *disk,
|
||||
int (*hook) (const pupa_partition_t partition));
|
||||
char *EXPORT_FUNC(pupa_partition_get_name) (const pupa_partition_t partition);
|
||||
|
||||
static inline unsigned long
|
||||
pupa_partition_get_start (const pupa_partition_t p)
|
||||
{
|
||||
return p->start;
|
||||
}
|
||||
|
||||
static inline unsigned long
|
||||
pupa_partition_get_len (const pupa_partition_t p)
|
||||
{
|
||||
return p->len;
|
||||
}
|
||||
|
||||
static inline int
|
||||
pupa_partition_is_empty (int type)
|
||||
{
|
||||
return (type == PUPA_PARTITION_TYPE_NONE);
|
||||
}
|
||||
|
||||
static inline int
|
||||
pupa_partition_is_extended (int type)
|
||||
{
|
||||
return (type == PUPA_PARTITION_TYPE_EXTENDED
|
||||
|| type == PUPA_PARTITION_TYPE_WIN95_EXTENDED
|
||||
|| type == PUPA_PARTITION_TYPE_LINUX_EXTENDED);
|
||||
}
|
||||
|
||||
static inline int
|
||||
pupa_partition_is_bsd (int type)
|
||||
{
|
||||
return (type == PUPA_PARTITION_TYPE_FREEBSD
|
||||
|| type == PUPA_PARTITION_TYPE_OPENBSD
|
||||
|| type == PUPA_PARTITION_TYPE_NETBSD);
|
||||
}
|
||||
|
||||
#endif /* ! PUPA_PARTITION_HEADER */
|
32
include/grub/i386/types.h
Normal file
32
include/grub/i386/types.h
Normal file
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* PUPA -- Preliminary Universal Programming Architecture for GRUB
|
||||
* Copyright (C) 2002 Yoshinori K. Okuji <okuji@enbug.org>
|
||||
*
|
||||
* PUPA is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with PUPA; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#ifndef PUPA_TYPES_CPU_HEADER
|
||||
#define PUPA_TYPES_CPU_HEADER 1
|
||||
|
||||
/* The size of void *. */
|
||||
#define PUPA_HOST_SIZEOF_VOID_P 4
|
||||
|
||||
/* The size of long. */
|
||||
#define PUPA_HOST_SIZEOF_LONG 4
|
||||
|
||||
/* i386 is little-endian. */
|
||||
#undef PUPA_HOST_WORDS_BIGENDIAN
|
||||
|
||||
#endif /* ! PUPA_TYPES_CPU_HEADER */
|
61
include/grub/kernel.h
Normal file
61
include/grub/kernel.h
Normal file
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
* PUPA -- Preliminary Universal Programming Architecture for GRUB
|
||||
* Copyright (C) 2002 Yoshinori K. Okuji <okuji@enbug.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#ifndef PUPA_KERNEL_HEADER
|
||||
#define PUPA_KERNEL_HEADER 1
|
||||
|
||||
#include <pupa/types.h>
|
||||
|
||||
/* The module header. */
|
||||
struct pupa_module_header
|
||||
{
|
||||
/* The offset of object code. */
|
||||
pupa_off_t offset;
|
||||
/* The size of object code plus this header. */
|
||||
pupa_size_t size;
|
||||
};
|
||||
|
||||
/* The start address of the kernel. */
|
||||
extern pupa_addr_t pupa_start_addr;
|
||||
|
||||
/* The end address of the kernel. */
|
||||
extern pupa_addr_t pupa_end_addr;
|
||||
|
||||
/* The total size of modules including their headers. */
|
||||
extern pupa_size_t pupa_total_module_size;
|
||||
|
||||
/* The size of the kernel image. */
|
||||
extern pupa_size_t pupa_kernel_image_size;
|
||||
|
||||
/* The start point of the C code. */
|
||||
void pupa_main (void);
|
||||
|
||||
/* The machine-specific initialization. This must initialize memory. */
|
||||
void pupa_machine_init (void);
|
||||
|
||||
/* Return the end address of the core image. */
|
||||
pupa_addr_t pupa_get_end_addr (void);
|
||||
|
||||
/* Register all the exported symbols. This is automatically generated. */
|
||||
void pupa_register_exported_symbols (void);
|
||||
|
||||
/* Enter normal mode. */
|
||||
void pupa_enter_normal_mode (void);
|
||||
|
||||
#endif /* ! PUPA_KERNEL_HEADER */
|
37
include/grub/loader.h
Normal file
37
include/grub/loader.h
Normal file
|
@ -0,0 +1,37 @@
|
|||
/* loader.h - OS loaders */
|
||||
/*
|
||||
* PUPA -- Preliminary Universal Programming Architecture for GRUB
|
||||
* Copyright (C) 2002 Yoshinori K. Okuji <okuji@enbug.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#ifndef PUPA_LOADER_HEADER
|
||||
#define PUPA_LOADER_HEADER 1
|
||||
|
||||
#include <pupa/file.h>
|
||||
#include <pupa/symbol.h>
|
||||
#include <pupa/err.h>
|
||||
#include <pupa/types.h>
|
||||
|
||||
void EXPORT_FUNC(pupa_loader_set) (pupa_err_t (*load_module) (int argc,
|
||||
char *argv[]),
|
||||
pupa_err_t (*boot) (void),
|
||||
pupa_err_t (*unload) (void));
|
||||
|
||||
pupa_err_t EXPORT_FUNC(pupa_loader_load_module) (int argc, char *argv[]);
|
||||
pupa_err_t EXPORT_FUNC(pupa_loader_boot) (void);
|
||||
|
||||
#endif /* ! PUPA_LOADER_HEADER */
|
47
include/grub/misc.h
Normal file
47
include/grub/misc.h
Normal file
|
@ -0,0 +1,47 @@
|
|||
/* misc.h - prototypes for misc functions */
|
||||
/*
|
||||
* PUPA -- Preliminary Universal Programming Architecture for GRUB
|
||||
* Copyright (C) 2002 Yoshinori K. Okuji <okuji@enbug.org>
|
||||
*
|
||||
* PUPA is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with PUPA; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#ifndef PUPA_MISC_HEADER
|
||||
#define PUPA_MISC_HEADER 1
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <pupa/types.h>
|
||||
#include <pupa/symbol.h>
|
||||
|
||||
void *EXPORT_FUNC(pupa_memcpy) (void *dest, const void *src, pupa_size_t n);
|
||||
int EXPORT_FUNC(pupa_memcmp) (const void *s1, const void *s2, pupa_size_t n);
|
||||
int EXPORT_FUNC(pupa_strcmp) (const char *s1, const char *s2);
|
||||
char *EXPORT_FUNC(pupa_strchr) (const char *s, int c);
|
||||
char *EXPORT_FUNC(pupa_strrchr) (const char *s, int c);
|
||||
int EXPORT_FUNC(pupa_isspace) (int c);
|
||||
int EXPORT_FUNC(pupa_isprint) (int c);
|
||||
int EXPORT_FUNC(pupa_isalpha) (int c);
|
||||
int EXPORT_FUNC(pupa_tolower) (int c);
|
||||
unsigned long EXPORT_FUNC(pupa_strtoul) (const char *str, char **end, int base);
|
||||
char *EXPORT_FUNC(pupa_strdup) (const char *s);
|
||||
void *EXPORT_FUNC(pupa_memset) (void *s, int c, pupa_size_t n);
|
||||
pupa_size_t EXPORT_FUNC(pupa_strlen) (const char *s);
|
||||
int EXPORT_FUNC(pupa_printf) (const char *fmt, ...) __attribute__ ((format (printf, 1, 2)));
|
||||
int EXPORT_FUNC(pupa_vprintf) (const char *fmt, va_list args);
|
||||
int EXPORT_FUNC(pupa_sprintf) (char *str, const char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
|
||||
int EXPORT_FUNC(pupa_vsprintf) (char *str, const char *fmt, va_list args);
|
||||
void EXPORT_FUNC(pupa_stop) (void) __attribute__ ((noreturn));
|
||||
|
||||
#endif /* ! PUPA_MISC_HEADER */
|
39
include/grub/mm.h
Normal file
39
include/grub/mm.h
Normal file
|
@ -0,0 +1,39 @@
|
|||
/* mm.h - prototypes and declarations for memory manager */
|
||||
/*
|
||||
* PUPA -- Preliminary Universal Programming Architecture for GRUB
|
||||
* Copyright (C) 2002 Yoshinori K. Okuji <okuji@enbug.org>
|
||||
*
|
||||
* PUPA is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with PUPA; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#ifndef PUPA_MM_H
|
||||
#define PUPA_MM_H 1
|
||||
|
||||
#include <pupa/types.h>
|
||||
#include <pupa/symbol.h>
|
||||
|
||||
void pupa_mm_init_region (void *addr, unsigned size);
|
||||
void *EXPORT_FUNC(pupa_malloc) (unsigned size);
|
||||
void EXPORT_FUNC(pupa_free) (void *ptr);
|
||||
void *EXPORT_FUNC(pupa_realloc) (void *ptr, unsigned size);
|
||||
void *EXPORT_FUNC(pupa_memalign) (unsigned align, unsigned size);
|
||||
|
||||
/* For debugging. */
|
||||
#define MM_DEBUG 1
|
||||
#if MM_DEBUG
|
||||
void pupa_mm_dump (unsigned lineno);
|
||||
#endif
|
||||
|
||||
#endif /* ! PUPA_MM_H */
|
73
include/grub/net.h
Normal file
73
include/grub/net.h
Normal file
|
@ -0,0 +1,73 @@
|
|||
/*
|
||||
* PUPA -- Preliminary Universal Programming Architecture for GRUB
|
||||
* Copyright (C) 2002 Yoshinori K. Okuji <okuji@enbug.org>
|
||||
*
|
||||
* PUPA is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with PUPA; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#ifndef PUPA_NET_HEADER
|
||||
#define PUPA_NET_HEADER 1
|
||||
|
||||
#include <pupa/symbol.h>
|
||||
#include <pupa/err.h>
|
||||
#include <pupa/types.h>
|
||||
|
||||
struct pupa_net;
|
||||
|
||||
struct pupa_net_dev
|
||||
{
|
||||
/* The device name. */
|
||||
const char *name;
|
||||
|
||||
/* FIXME: Just a template. */
|
||||
int (*probe) (struct pupa_net *net, const void *addr);
|
||||
void (*reset) (struct pupa_net *net);
|
||||
int (*poll) (struct pupa_net *net);
|
||||
void (*transmit) (struct pupa_net *net, const void *destip,
|
||||
unsigned srcsock, unsigned destsock, const void *packet);
|
||||
void (*disable) (struct pupa_net *net);
|
||||
|
||||
/* The next net device. */
|
||||
struct pupa_net_dev *next;
|
||||
};
|
||||
typedef struct pupa_net_dev *pupa_net_dev_t;
|
||||
|
||||
struct pupa_fs;
|
||||
|
||||
struct pupa_net
|
||||
{
|
||||
/* The net name. */
|
||||
const char *name;
|
||||
|
||||
/* The underlying disk device. */
|
||||
pupa_net_dev_t dev;
|
||||
|
||||
/* The binding filesystem. */
|
||||
struct pupa_fs *fs;
|
||||
|
||||
/* FIXME: More data would be required, such as an IP address, a mask,
|
||||
a gateway, etc. */
|
||||
|
||||
/* Device-specific data. */
|
||||
void *data;
|
||||
};
|
||||
typedef struct pupa_net *pupa_net_t;
|
||||
|
||||
/* FIXME: How to abstract networks? More consideration is necessary. */
|
||||
|
||||
/* Note: Networks are very different from disks, because networks must
|
||||
be initialized before used, and the status is persistent. */
|
||||
|
||||
#endif /* ! PUPA_NET_HEADER */
|
37
include/grub/rescue.h
Normal file
37
include/grub/rescue.h
Normal file
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* PUPA -- Preliminary Universal Programming Architecture for GRUB
|
||||
* Copyright (C) 2002 Yoshinori K. Okuji <okuji@enbug.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#ifndef PUPA_RESCUE_HEADER
|
||||
#define PUPA_RESCUE_HEADER 1
|
||||
|
||||
#include <pupa/symbol.h>
|
||||
|
||||
/* Enter rescue mode. */
|
||||
void pupa_enter_rescue_mode (void);
|
||||
|
||||
/* Register a rescue mode command. */
|
||||
void EXPORT_FUNC(pupa_rescue_register_command) (const char *name,
|
||||
void (*func) (int argc,
|
||||
char *argv[]),
|
||||
const char *message);
|
||||
|
||||
/* Unregister a rescue mode command. */
|
||||
void EXPORT_FUNC(pupa_rescue_unregister_command) (const char *name);
|
||||
|
||||
#endif /* ! PUPA_RESCUE_HEADER */
|
40
include/grub/symbol.h
Normal file
40
include/grub/symbol.h
Normal file
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* PUPA -- Preliminary Universal Programming Architecture for GRUB
|
||||
* Copyright (C) 1999,2000,2001,2002 Free Software Foundation, Inc.
|
||||
* Copyright (C) 2002 Yoshinori K. Okuji <okuji@enbug.org>
|
||||
*
|
||||
* PUPA is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with PUPA; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#ifndef PUPA_SYMBOL_HEADER
|
||||
#define PUPA_SYMBOL_HEADER 1
|
||||
|
||||
#include <config.h>
|
||||
|
||||
/* Add an underscore to a C symbol in assembler code if needed. */
|
||||
#ifdef HAVE_ASM_USCORE
|
||||
# define EXT_C(sym) _ ## sym
|
||||
#else
|
||||
# define EXT_C(sym) sym
|
||||
#endif
|
||||
|
||||
#define FUNCTION(x) .globl EXT_C(x) ; EXT_C(x):
|
||||
#define VARIABLE(x) FUNCTION(x)
|
||||
|
||||
/* Mark an exported symbol. */
|
||||
#define EXPORT_FUNC(x) x
|
||||
#define EXPORT_VAR(x) x
|
||||
|
||||
#endif /* ! PUPA_SYMBOL_HEADER */
|
120
include/grub/term.h
Normal file
120
include/grub/term.h
Normal file
|
@ -0,0 +1,120 @@
|
|||
/*
|
||||
* PUPA -- Preliminary Universal Programming Architecture for GRUB
|
||||
* Copyright (C) 2002 Free Software Foundation, Inc.
|
||||
* Copyright (C) 2002 Yoshinori K. Okuji <okuji@enbug.org>
|
||||
*
|
||||
* PUPA is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with PUPA; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#ifndef PUPA_TERM_HEADER
|
||||
#define PUPA_TERM_HEADER 1
|
||||
|
||||
#include <pupa/symbol.h>
|
||||
#include <pupa/types.h>
|
||||
|
||||
/* These are used to represent the various color states we use. */
|
||||
typedef enum
|
||||
{
|
||||
/* The color used to display all text that does not use the
|
||||
user defined colors below. */
|
||||
PUPA_TERM_COLOR_STANDARD,
|
||||
/* The user defined colors for normal text. */
|
||||
PUPA_TERM_COLOR_NORMAL,
|
||||
/* The user defined colors for highlighted text. */
|
||||
PUPA_TERM_COLOR_HIGHLIGHT
|
||||
}
|
||||
pupa_term_color_state;
|
||||
|
||||
/* Flags for representing the capabilities of a terminal. */
|
||||
/* Some notes about the flags:
|
||||
- These flags are used by higher-level functions but not terminals
|
||||
themselves.
|
||||
- If a terminal is dumb, you may assume that only putchar, getkey and
|
||||
checkkey are called.
|
||||
- Some fancy features (setcolorstate, setcolor and setcursor) can be set
|
||||
to NULL. */
|
||||
|
||||
/* Set when input characters shouldn't be echoed back. */
|
||||
#define PUPA_TERM_NO_ECHO (1 << 0)
|
||||
/* Set when the editing feature should be disabled. */
|
||||
#define PUPA_TERM_NO_EDIT (1 << 1)
|
||||
/* Set when the terminal cannot do fancy things. */
|
||||
#define PUPA_TERM_DUMB (1 << 2)
|
||||
/* Set when the terminal needs to be initialized. */
|
||||
#define PUPA_TERM_NEED_INIT (1 << 16)
|
||||
|
||||
struct pupa_term
|
||||
{
|
||||
/* The terminal name. */
|
||||
const char *name;
|
||||
|
||||
/* Put a character. */
|
||||
void (*putchar) (int c);
|
||||
|
||||
/* Check if any input character is available. */
|
||||
int (*checkkey) (void);
|
||||
|
||||
/* Get a character. */
|
||||
int (*getkey) (void);
|
||||
|
||||
/* Get the cursor position. The return value is ((X << 8) | Y). */
|
||||
pupa_uint16_t (*getxy) (void);
|
||||
|
||||
/* Go to the position (X, Y). */
|
||||
void (*gotoxy) (pupa_uint8_t x, pupa_uint8_t y);
|
||||
|
||||
/* Clear the screen. */
|
||||
void (*cls) (void);
|
||||
|
||||
/* Set the current color to be used */
|
||||
void (*setcolorstate) (pupa_term_color_state state);
|
||||
|
||||
/* Set the normal color and the highlight color. The format of each
|
||||
color is VGA's. */
|
||||
void (*setcolor) (pupa_uint8_t normal_color, pupa_uint8_t highlight_color);
|
||||
|
||||
/* Turn on/off the cursor. */
|
||||
void (*setcursor) (int on);
|
||||
|
||||
/* The feature flags defined above. */
|
||||
pupa_uint32_t flags;
|
||||
|
||||
/* The next terminal. */
|
||||
struct pupa_term *next;
|
||||
};
|
||||
typedef struct pupa_term *pupa_term_t;
|
||||
|
||||
void EXPORT_FUNC(pupa_term_register) (pupa_term_t term);
|
||||
void EXPORT_FUNC(pupa_term_unregister) (pupa_term_t term);
|
||||
void EXPORT_FUNC(pupa_term_iterate) (int (*hook) (pupa_term_t term));
|
||||
|
||||
void EXPORT_FUNC(pupa_term_set_current) (pupa_term_t term);
|
||||
pupa_term_t EXPORT_FUNC(pupa_term_get_current) (void);
|
||||
|
||||
void EXPORT_FUNC(pupa_putchar) (int c);
|
||||
int EXPORT_FUNC(pupa_getkey) (void);
|
||||
int EXPORT_FUNC(pupa_checkkey) (void);
|
||||
pupa_uint16_t EXPORT_FUNC(pupa_getxy) (void);
|
||||
void EXPORT_FUNC(pupa_gotoxy) (pupa_uint8_t x, pupa_uint8_t y);
|
||||
void EXPORT_FUNC(pupa_cls) (void);
|
||||
void EXPORT_FUNC(pupa_setcolorstate) (pupa_term_color_state state);
|
||||
void EXPORT_FUNC(pupa_setcolor) (pupa_uint8_t normal_color,
|
||||
pupa_uint8_t highlight_color);
|
||||
int EXPORT_FUNC(pupa_setcursor) (int on);
|
||||
|
||||
/* For convenience. */
|
||||
#define PUPA_TERM_ASCII_CHAR(c) ((c) & 0xff)
|
||||
|
||||
#endif /* ! PUPA_TERM_HEADER */
|
141
include/grub/types.h
Normal file
141
include/grub/types.h
Normal file
|
@ -0,0 +1,141 @@
|
|||
/*
|
||||
* PUPA -- Preliminary Universal Programming Architecture for GRUB
|
||||
* Copyright (C) 2002 Yoshinori K. Okuji <okuji@enbug.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#ifndef PUPA_TYPES_HEADER
|
||||
#define PUPA_TYPES_HEADER 1
|
||||
|
||||
#include <config.h>
|
||||
#include <pupa/cpu/types.h>
|
||||
|
||||
#ifdef PUPA_UTIL
|
||||
# define PUPA_CPU_SIZEOF_VOID_P SIZEOF_VOID_P
|
||||
# define PUPA_CPU_SIZEOF_LONG SIZEOF_LONG
|
||||
# ifdef WORDS_BIGENDIAN
|
||||
# define PUPA_CPU_WORDS_BIGENDIAN 1
|
||||
# else
|
||||
# undef PUPA_CPU_WORDS_BIGENDIAN
|
||||
# endif
|
||||
#else /* ! PUPA_UTIL */
|
||||
# define PUPA_CPU_SIZEOF_VOID_P PUPA_HOST_SIZEOF_VOID_P
|
||||
# define PUPA_CPU_SIZEOF_LONG PUPA_HOST_SIZEOF_LONG
|
||||
# ifdef PUPA_HOST_WORDS_BIGENDIAN
|
||||
# define PUPA_CPU_WORDS_BIGENDIAN 1
|
||||
# else
|
||||
# undef PUPA_CPU_WORDS_BIGENDIAN
|
||||
# endif
|
||||
#endif /* ! PUPA_UTIL */
|
||||
|
||||
#if PUPA_CPU_SIZEOF_VOID_P != PUPA_CPU_SIZEOF_LONG
|
||||
# error "This architecture is not supported because sizeof(void *) != sizeof(long)"
|
||||
#endif
|
||||
|
||||
#if PUPA_CPU_SIZEOF_VOID_P != 4 && PUPA_CPU_SIZEOF_VOID_P != 8
|
||||
# error "This architecture is not supported because sizeof(void *) != 4 and sizeof(void *) != 8"
|
||||
#endif
|
||||
|
||||
/* Define various wide integers. */
|
||||
typedef signed char pupa_int8_t;
|
||||
typedef short pupa_int16_t;
|
||||
typedef int pupa_int32_t;
|
||||
#if PUPA_CPU_SIZEOF_VOID_P == 8
|
||||
typedef long pupa_int64_t;
|
||||
#else
|
||||
typedef long long pupa_int64_t;
|
||||
#endif
|
||||
|
||||
typedef unsigned char pupa_uint8_t;
|
||||
typedef unsigned short pupa_uint16_t;
|
||||
typedef unsigned pupa_uint32_t;
|
||||
#if PUPA_CPU_SIZEOF_VOID_P == 8
|
||||
typedef unsigned long pupa_uint64_t;
|
||||
#else
|
||||
typedef unsigned long long pupa_uint64_t;
|
||||
#endif
|
||||
|
||||
/* Misc types. */
|
||||
#if PUPA_HOST_SIZE_OF_VOID_P == 8
|
||||
typedef pupa_uint64_t pupa_addr_t;
|
||||
typedef pupa_uint64_t pupa_off_t;
|
||||
typedef pupa_uint64_t pupa_size_t;
|
||||
typedef pupa_int64_t pupa_ssize_t;
|
||||
#else
|
||||
typedef pupa_uint32_t pupa_addr_t;
|
||||
typedef pupa_uint32_t pupa_off_t;
|
||||
typedef pupa_uint32_t pupa_size_t;
|
||||
typedef pupa_int32_t pupa_ssize_t;
|
||||
#endif
|
||||
|
||||
/* Byte-orders. */
|
||||
#define pupa_swap_bytes16(x) \
|
||||
({ \
|
||||
pupa_uint16_t _x = (x); \
|
||||
(_x << 8) | (_x >> 8); \
|
||||
})
|
||||
|
||||
#define pupa_swap_bytes32(x) \
|
||||
({ \
|
||||
pupa_uint32_t _x = (x); \
|
||||
(pupa_uint32_t) ((_x << 24) \
|
||||
| ((_x & (pupa_uint32_t) 0xFF00UL) << 8) \
|
||||
| ((_x & (pupa_uint32_t) 0xFF0000UL) >> 8) \
|
||||
| (_x >> 24)); \
|
||||
})
|
||||
|
||||
#define pupa_swap_bytes64(x) \
|
||||
({ \
|
||||
pupa_uint64_t _x = (x); \
|
||||
(pupa_uint64_t) ((_x << 56) \
|
||||
| ((_x & (pupa_uint64_t) 0xFF00ULL) << 40) \
|
||||
| ((_x & (pupa_uint64_t) 0xFF0000ULL) << 24) \
|
||||
| ((_x & (pupa_uint64_t) 0xFF000000ULL) << 8) \
|
||||
| ((_x & (pupa_uint64_t) 0xFF00000000ULL) >> 8) \
|
||||
| ((_x & (pupa_uint64_t) 0xFF0000000000ULL) >> 24) \
|
||||
| ((_x & (pupa_uint64_t) 0xFF000000000000ULL) >> 40) \
|
||||
| (_x >> 56)); \
|
||||
})
|
||||
|
||||
#ifdef PUPA_CPU_WORDS_BIGENDIAN
|
||||
# define pupa_cpu_to_le16(x) pupa_swap_bytes16(x)
|
||||
# define pupa_cpu_to_le32(x) pupa_swap_bytes32(x)
|
||||
# define pupa_cpu_to_le64(x) pupa_swap_bytes64(x)
|
||||
# define pupa_le_to_cpu16(x) pupa_swap_bytes16(x)
|
||||
# define pupa_le_to_cpu32(x) pupa_swap_bytes32(x)
|
||||
# define pupa_le_to_cpu64(x) pupa_swap_bytes64(x)
|
||||
# define pupa_cpu_to_be16(x) ((pupa_uint16_t) (x))
|
||||
# define pupa_cpu_to_be32(x) ((pupa_uint32_t) (x))
|
||||
# define pupa_cpu_to_be64(x) ((pupa_uint64_t) (x))
|
||||
# define pupa_be_to_cpu16(x) ((pupa_uint16_t) (x))
|
||||
# define pupa_be_to_cpu32(x) ((pupa_uint32_t) (x))
|
||||
# define pupa_be_to_cpu64(x) ((pupa_uint64_t) (x))
|
||||
#else /* ! WORDS_BIGENDIAN */
|
||||
# define pupa_cpu_to_le16(x) ((pupa_uint16_t) (x))
|
||||
# define pupa_cpu_to_le32(x) ((pupa_uint32_t) (x))
|
||||
# define pupa_cpu_to_le64(x) ((pupa_uint64_t) (x))
|
||||
# define pupa_le_to_cpu16(x) ((pupa_uint16_t) (x))
|
||||
# define pupa_le_to_cpu32(x) ((pupa_uint32_t) (x))
|
||||
# define pupa_le_to_cpu64(x) ((pupa_uint64_t) (x))
|
||||
# define pupa_cpu_to_be16(x) pupa_swap_bytes16(x)
|
||||
# define pupa_cpu_to_be32(x) pupa_swap_bytes32(x)
|
||||
# define pupa_cpu_to_be64(x) pupa_swap_bytes64(x)
|
||||
# define pupa_be_to_cpu16(x) pupa_swap_bytes16(x)
|
||||
# define pupa_be_to_cpu32(x) pupa_swap_bytes32(x)
|
||||
# define pupa_be_to_cpu64(x) pupa_swap_bytes64(x)
|
||||
#endif /* ! WORDS_BIGENDIAN */
|
||||
|
||||
#endif /* ! PUPA_TYPES_HEADER */
|
40
include/grub/util/misc.h
Normal file
40
include/grub/util/misc.h
Normal file
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* PUPA -- Preliminary Universal Programming Architecture for GRUB
|
||||
* Copyright (C) 2002 Yoshinori K. Okuji <okuji@enbug.org>
|
||||
*
|
||||
* PUPA is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with PUPA; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#ifndef PUPA_UTIL_MISC_HEADER
|
||||
#define PUPA_UTIL_MISC_HEADER 1
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
extern char *progname;
|
||||
extern int verbosity;
|
||||
|
||||
void pupa_util_info (const char *fmt, ...);
|
||||
void pupa_util_error (const char *fmt, ...) __attribute__ ((noreturn));
|
||||
|
||||
void *xmalloc (size_t size);
|
||||
char *xstrdup (const char *str);
|
||||
|
||||
char *pupa_util_get_path (const char *dir, const char *file);
|
||||
size_t pupa_util_get_image_size (const char *path);
|
||||
char *pupa_util_read_image (const char *path);
|
||||
void pupa_util_write_image (const char *img, size_t size, FILE *out);
|
||||
|
||||
#endif /* ! PUPA_UTIL_MISC_HEADER */
|
36
include/grub/util/resolve.h
Normal file
36
include/grub/util/resolve.h
Normal file
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* PUPA -- Preliminary Universal Programming Architecture for GRUB
|
||||
* Copyright (C) 2002 Yoshinori K. Okuji <okuji@enbug.org>
|
||||
*
|
||||
* PUPA is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with PUPA; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#ifndef PUPA_UTIL_RESOLVE_HEADER
|
||||
#define PUPA_UTIL_RESOLVE_HEADER 1
|
||||
|
||||
struct pupa_util_path_list
|
||||
{
|
||||
const char *name;
|
||||
struct pupa_util_path_list *next;
|
||||
};
|
||||
|
||||
/* Resolve the dependencies of the modules MODULES using the information
|
||||
in the file DEP_LIST_FILE. The directory PREFIX is used to find files. */
|
||||
struct pupa_util_path_list *
|
||||
pupa_util_resolve_dependencies (const char *prefix,
|
||||
const char *dep_list_file,
|
||||
char *modules[]);
|
||||
|
||||
#endif /* ! PUPA_UTIL_RESOLVE_HEADER */
|
251
install-sh
Normal file
251
install-sh
Normal file
|
@ -0,0 +1,251 @@
|
|||
#!/bin/sh
|
||||
#
|
||||
# install - install a program, script, or datafile
|
||||
# This comes from X11R5 (mit/util/scripts/install.sh).
|
||||
#
|
||||
# Copyright 1991 by the Massachusetts Institute of Technology
|
||||
#
|
||||
# Permission to use, copy, modify, distribute, and sell this software and its
|
||||
# documentation for any purpose is hereby granted without fee, provided that
|
||||
# the above copyright notice appear in all copies and that both that
|
||||
# copyright notice and this permission notice appear in supporting
|
||||
# documentation, and that the name of M.I.T. not be used in advertising or
|
||||
# publicity pertaining to distribution of the software without specific,
|
||||
# written prior permission. M.I.T. makes no representations about the
|
||||
# suitability of this software for any purpose. It is provided "as is"
|
||||
# without express or implied warranty.
|
||||
#
|
||||
# Calling this script install-sh is preferred over install.sh, to prevent
|
||||
# `make' implicit rules from creating a file called install from it
|
||||
# when there is no Makefile.
|
||||
#
|
||||
# This script is compatible with the BSD install script, but was written
|
||||
# from scratch. It can only install one file at a time, a restriction
|
||||
# shared with many OS's install programs.
|
||||
|
||||
|
||||
# set DOITPROG to echo to test this script
|
||||
|
||||
# Don't use :- since 4.3BSD and earlier shells don't like it.
|
||||
doit="${DOITPROG-}"
|
||||
|
||||
|
||||
# put in absolute paths if you don't have them in your path; or use env. vars.
|
||||
|
||||
mvprog="${MVPROG-mv}"
|
||||
cpprog="${CPPROG-cp}"
|
||||
chmodprog="${CHMODPROG-chmod}"
|
||||
chownprog="${CHOWNPROG-chown}"
|
||||
chgrpprog="${CHGRPPROG-chgrp}"
|
||||
stripprog="${STRIPPROG-strip}"
|
||||
rmprog="${RMPROG-rm}"
|
||||
mkdirprog="${MKDIRPROG-mkdir}"
|
||||
|
||||
transformbasename=""
|
||||
transform_arg=""
|
||||
instcmd="$mvprog"
|
||||
chmodcmd="$chmodprog 0755"
|
||||
chowncmd=""
|
||||
chgrpcmd=""
|
||||
stripcmd=""
|
||||
rmcmd="$rmprog -f"
|
||||
mvcmd="$mvprog"
|
||||
src=""
|
||||
dst=""
|
||||
dir_arg=""
|
||||
|
||||
while [ x"$1" != x ]; do
|
||||
case $1 in
|
||||
-c) instcmd="$cpprog"
|
||||
shift
|
||||
continue;;
|
||||
|
||||
-d) dir_arg=true
|
||||
shift
|
||||
continue;;
|
||||
|
||||
-m) chmodcmd="$chmodprog $2"
|
||||
shift
|
||||
shift
|
||||
continue;;
|
||||
|
||||
-o) chowncmd="$chownprog $2"
|
||||
shift
|
||||
shift
|
||||
continue;;
|
||||
|
||||
-g) chgrpcmd="$chgrpprog $2"
|
||||
shift
|
||||
shift
|
||||
continue;;
|
||||
|
||||
-s) stripcmd="$stripprog"
|
||||
shift
|
||||
continue;;
|
||||
|
||||
-t=*) transformarg=`echo $1 | sed 's/-t=//'`
|
||||
shift
|
||||
continue;;
|
||||
|
||||
-b=*) transformbasename=`echo $1 | sed 's/-b=//'`
|
||||
shift
|
||||
continue;;
|
||||
|
||||
*) if [ x"$src" = x ]
|
||||
then
|
||||
src=$1
|
||||
else
|
||||
# this colon is to work around a 386BSD /bin/sh bug
|
||||
:
|
||||
dst=$1
|
||||
fi
|
||||
shift
|
||||
continue;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [ x"$src" = x ]
|
||||
then
|
||||
echo "install: no input file specified"
|
||||
exit 1
|
||||
else
|
||||
true
|
||||
fi
|
||||
|
||||
if [ x"$dir_arg" != x ]; then
|
||||
dst=$src
|
||||
src=""
|
||||
|
||||
if [ -d $dst ]; then
|
||||
instcmd=:
|
||||
chmodcmd=""
|
||||
else
|
||||
instcmd=mkdir
|
||||
fi
|
||||
else
|
||||
|
||||
# Waiting for this to be detected by the "$instcmd $src $dsttmp" command
|
||||
# might cause directories to be created, which would be especially bad
|
||||
# if $src (and thus $dsttmp) contains '*'.
|
||||
|
||||
if [ -f $src -o -d $src ]
|
||||
then
|
||||
true
|
||||
else
|
||||
echo "install: $src does not exist"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ x"$dst" = x ]
|
||||
then
|
||||
echo "install: no destination specified"
|
||||
exit 1
|
||||
else
|
||||
true
|
||||
fi
|
||||
|
||||
# If destination is a directory, append the input filename; if your system
|
||||
# does not like double slashes in filenames, you may need to add some logic
|
||||
|
||||
if [ -d $dst ]
|
||||
then
|
||||
dst="$dst"/`basename $src`
|
||||
else
|
||||
true
|
||||
fi
|
||||
fi
|
||||
|
||||
## this sed command emulates the dirname command
|
||||
dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`
|
||||
|
||||
# Make sure that the destination directory exists.
|
||||
# this part is taken from Noah Friedman's mkinstalldirs script
|
||||
|
||||
# Skip lots of stat calls in the usual case.
|
||||
if [ ! -d "$dstdir" ]; then
|
||||
defaultIFS='
|
||||
'
|
||||
IFS="${IFS-${defaultIFS}}"
|
||||
|
||||
oIFS="${IFS}"
|
||||
# Some sh's can't handle IFS=/ for some reason.
|
||||
IFS='%'
|
||||
set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'`
|
||||
IFS="${oIFS}"
|
||||
|
||||
pathcomp=''
|
||||
|
||||
while [ $# -ne 0 ] ; do
|
||||
pathcomp="${pathcomp}${1}"
|
||||
shift
|
||||
|
||||
if [ ! -d "${pathcomp}" ] ;
|
||||
then
|
||||
$mkdirprog "${pathcomp}"
|
||||
else
|
||||
true
|
||||
fi
|
||||
|
||||
pathcomp="${pathcomp}/"
|
||||
done
|
||||
fi
|
||||
|
||||
if [ x"$dir_arg" != x ]
|
||||
then
|
||||
$doit $instcmd $dst &&
|
||||
|
||||
if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi &&
|
||||
if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi &&
|
||||
if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi &&
|
||||
if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi
|
||||
else
|
||||
|
||||
# If we're going to rename the final executable, determine the name now.
|
||||
|
||||
if [ x"$transformarg" = x ]
|
||||
then
|
||||
dstfile=`basename $dst`
|
||||
else
|
||||
dstfile=`basename $dst $transformbasename |
|
||||
sed $transformarg`$transformbasename
|
||||
fi
|
||||
|
||||
# don't allow the sed command to completely eliminate the filename
|
||||
|
||||
if [ x"$dstfile" = x ]
|
||||
then
|
||||
dstfile=`basename $dst`
|
||||
else
|
||||
true
|
||||
fi
|
||||
|
||||
# Make a temp file name in the proper directory.
|
||||
|
||||
dsttmp=$dstdir/#inst.$$#
|
||||
|
||||
# Move or copy the file name to the temp name
|
||||
|
||||
$doit $instcmd $src $dsttmp &&
|
||||
|
||||
trap "rm -f ${dsttmp}" 0 &&
|
||||
|
||||
# and set any options; do chmod last to preserve setuid bits
|
||||
|
||||
# If any of these fail, we abort the whole thing. If we want to
|
||||
# ignore errors from any of these, just make sure not to ignore
|
||||
# errors from the above "$doit $instcmd $src $dsttmp" command.
|
||||
|
||||
if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi &&
|
||||
if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi &&
|
||||
if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi &&
|
||||
if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi &&
|
||||
|
||||
# Now rename the file to the real destination.
|
||||
|
||||
$doit $rmcmd -f $dstdir/$dstfile &&
|
||||
$doit $mvcmd $dsttmp $dstdir/$dstfile
|
||||
|
||||
fi &&
|
||||
|
||||
|
||||
exit 0
|
99
kern/device.c
Normal file
99
kern/device.c
Normal file
|
@ -0,0 +1,99 @@
|
|||
/* device.c - device manager */
|
||||
/*
|
||||
* PUPA -- Preliminary Universal Programming Architecture for GRUB
|
||||
* Copyright (C) 2002 Yoshinori K. Okuji <okuji@enbug.org>
|
||||
*
|
||||
* PUPA is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with PUPA; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <pupa/device.h>
|
||||
#include <pupa/disk.h>
|
||||
#include <pupa/net.h>
|
||||
#include <pupa/fs.h>
|
||||
#include <pupa/mm.h>
|
||||
#include <pupa/misc.h>
|
||||
|
||||
static char *pupa_device_root;
|
||||
|
||||
pupa_err_t
|
||||
pupa_device_set_root (const char *name)
|
||||
{
|
||||
pupa_free (pupa_device_root);
|
||||
pupa_device_root = pupa_strdup (name);
|
||||
return pupa_errno;
|
||||
}
|
||||
|
||||
const char *
|
||||
pupa_device_get_root (void)
|
||||
{
|
||||
if (! pupa_device_root)
|
||||
pupa_error (PUPA_ERR_BAD_DEVICE, "no root device");
|
||||
|
||||
return pupa_device_root;
|
||||
}
|
||||
|
||||
pupa_device_t
|
||||
pupa_device_open (const char *name)
|
||||
{
|
||||
pupa_disk_t disk = 0;
|
||||
pupa_device_t dev = 0;
|
||||
|
||||
if (! name)
|
||||
{
|
||||
if (! pupa_device_root)
|
||||
{
|
||||
pupa_error (PUPA_ERR_BAD_DEVICE, "no device is set");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
name = pupa_device_root;
|
||||
}
|
||||
|
||||
dev = pupa_malloc (sizeof (*dev));
|
||||
if (! dev)
|
||||
goto fail;
|
||||
|
||||
/* Try to open a disk. */
|
||||
disk = pupa_disk_open (name);
|
||||
if (! disk)
|
||||
{
|
||||
pupa_error (PUPA_ERR_BAD_DEVICE, "unknown device");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
dev->disk = disk;
|
||||
dev->net = 0; /* FIXME */
|
||||
|
||||
return dev;
|
||||
|
||||
fail:
|
||||
if (disk)
|
||||
pupa_disk_close (disk);
|
||||
|
||||
pupa_free (dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
pupa_err_t
|
||||
pupa_device_close (pupa_device_t device)
|
||||
{
|
||||
if (device->disk)
|
||||
pupa_disk_close (device->disk);
|
||||
|
||||
pupa_free (device);
|
||||
|
||||
return pupa_errno;
|
||||
}
|
474
kern/disk.c
Normal file
474
kern/disk.c
Normal file
|
@ -0,0 +1,474 @@
|
|||
/*
|
||||
* PUPA -- Preliminary Universal Programming Architecture for GRUB
|
||||
* Copyright (C) 2002 Yoshinori K. Okuji <okuji@enbug.org>
|
||||
*
|
||||
* PUPA is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with PUPA; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <pupa/disk.h>
|
||||
#include <pupa/err.h>
|
||||
#include <pupa/mm.h>
|
||||
#include <pupa/types.h>
|
||||
#include <pupa/machine/partition.h>
|
||||
#include <pupa/misc.h>
|
||||
|
||||
/* Disk cache. */
|
||||
struct pupa_disk_cache
|
||||
{
|
||||
unsigned long id;
|
||||
unsigned long sector;
|
||||
char *data;
|
||||
int lock;
|
||||
};
|
||||
|
||||
static struct pupa_disk_cache pupa_disk_cache_table[PUPA_DISK_CACHE_NUM];
|
||||
|
||||
#if 0
|
||||
static unsigned long pupa_disk_cache_hits;
|
||||
static unsigned long pupa_disk_cache_misses;
|
||||
|
||||
void
|
||||
pupa_disk_cache_get_performance (unsigned long *hits, unsigned long *misses)
|
||||
{
|
||||
*hits = pupa_disk_cache_hits;
|
||||
*misses = pupa_disk_cache_misses;
|
||||
}
|
||||
#endif
|
||||
|
||||
static unsigned
|
||||
pupa_disk_cache_get_index (unsigned long id, unsigned long sector)
|
||||
{
|
||||
return ((id * 2606459 + (sector >> PUPA_DISK_CACHE_BITS))
|
||||
% PUPA_DISK_CACHE_NUM);
|
||||
}
|
||||
|
||||
static void
|
||||
pupa_disk_cache_invalidate (unsigned long id, unsigned long sector)
|
||||
{
|
||||
unsigned index;
|
||||
struct pupa_disk_cache *cache;
|
||||
|
||||
sector &= ~(PUPA_DISK_CACHE_SIZE - 1);
|
||||
index = pupa_disk_cache_get_index (id, sector);
|
||||
cache = pupa_disk_cache_table + index;
|
||||
|
||||
if (cache->id == id && cache->sector == sector && cache->data)
|
||||
{
|
||||
cache->lock = 1;
|
||||
pupa_free (cache->data);
|
||||
cache->data = 0;
|
||||
cache->lock = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
pupa_disk_cache_invalidate_all (void)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < PUPA_DISK_CACHE_NUM; i++)
|
||||
{
|
||||
struct pupa_disk_cache *cache = pupa_disk_cache_table + i;
|
||||
|
||||
if (cache->data && ! cache->lock)
|
||||
{
|
||||
pupa_free (cache->data);
|
||||
cache->data = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static char *
|
||||
pupa_disk_cache_fetch (unsigned long id, unsigned long sector)
|
||||
{
|
||||
struct pupa_disk_cache *cache;
|
||||
unsigned index;
|
||||
|
||||
index = pupa_disk_cache_get_index (id, sector);
|
||||
cache = pupa_disk_cache_table + index;
|
||||
|
||||
if (cache->id == id && cache->sector == sector)
|
||||
{
|
||||
cache->lock = 1;
|
||||
#if 0
|
||||
pupa_disk_cache_hits++;
|
||||
#endif
|
||||
return cache->data;
|
||||
}
|
||||
|
||||
#if 0
|
||||
pupa_disk_cache_misses++;
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
pupa_disk_cache_unlock (unsigned long id, unsigned long sector)
|
||||
{
|
||||
struct pupa_disk_cache *cache;
|
||||
unsigned index;
|
||||
|
||||
index = pupa_disk_cache_get_index (id, sector);
|
||||
cache = pupa_disk_cache_table + index;
|
||||
|
||||
if (cache->id == id && cache->sector == sector)
|
||||
cache->lock = 0;
|
||||
}
|
||||
|
||||
static pupa_err_t
|
||||
pupa_disk_cache_store (unsigned long id, unsigned long sector,
|
||||
const char *data)
|
||||
{
|
||||
unsigned index;
|
||||
struct pupa_disk_cache *cache;
|
||||
|
||||
pupa_disk_cache_invalidate (id, sector);
|
||||
|
||||
index = pupa_disk_cache_get_index (id, sector);
|
||||
cache = pupa_disk_cache_table + index;
|
||||
|
||||
cache->data = pupa_malloc (PUPA_DISK_SECTOR_SIZE << PUPA_DISK_CACHE_BITS);
|
||||
if (! cache->data)
|
||||
return pupa_errno;
|
||||
|
||||
pupa_memcpy (cache->data, data,
|
||||
PUPA_DISK_SECTOR_SIZE << PUPA_DISK_CACHE_BITS);
|
||||
cache->id = id;
|
||||
cache->sector = sector;
|
||||
|
||||
return PUPA_ERR_NONE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static pupa_disk_dev_t pupa_disk_dev_list;
|
||||
|
||||
void
|
||||
pupa_disk_dev_register (pupa_disk_dev_t dev)
|
||||
{
|
||||
dev->next = pupa_disk_dev_list;
|
||||
pupa_disk_dev_list = dev;
|
||||
}
|
||||
|
||||
void
|
||||
pupa_disk_dev_unregister (pupa_disk_dev_t dev)
|
||||
{
|
||||
pupa_disk_dev_t *p, q;
|
||||
|
||||
for (p = &pupa_disk_dev_list, q = *p; q; p = &(q->next), q = q->next)
|
||||
if (q == dev)
|
||||
{
|
||||
*p = q->next;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
pupa_disk_dev_iterate (int (*hook) (const char *name))
|
||||
{
|
||||
pupa_disk_dev_t p;
|
||||
|
||||
for (p = pupa_disk_dev_list; p; p = p->next)
|
||||
if ((p->iterate) (hook))
|
||||
break;
|
||||
}
|
||||
|
||||
pupa_disk_t
|
||||
pupa_disk_open (const char *name)
|
||||
{
|
||||
char *p;
|
||||
pupa_disk_t disk;
|
||||
pupa_disk_dev_t dev;
|
||||
char *raw = (char *) name;
|
||||
|
||||
disk = (pupa_disk_t) pupa_malloc (sizeof (*disk));
|
||||
if (! disk)
|
||||
return 0;
|
||||
|
||||
disk->dev = 0;
|
||||
disk->read_hook = 0;
|
||||
disk->partition = 0;
|
||||
disk->data = 0;
|
||||
disk->name = pupa_strdup (name);
|
||||
if (! disk->name)
|
||||
goto fail;
|
||||
|
||||
p = pupa_strchr (name, ',');
|
||||
if (p)
|
||||
{
|
||||
pupa_size_t len = p - name;
|
||||
|
||||
raw = pupa_malloc (len + 1);
|
||||
if (! raw)
|
||||
goto fail;
|
||||
|
||||
pupa_memcpy (raw, name, len);
|
||||
raw[len] = '\0';
|
||||
}
|
||||
|
||||
for (dev = pupa_disk_dev_list; dev; dev = dev->next)
|
||||
{
|
||||
if ((dev->open) (raw, disk) == PUPA_ERR_NONE)
|
||||
break;
|
||||
else if (pupa_errno == PUPA_ERR_UNKNOWN_DEVICE)
|
||||
pupa_errno = PUPA_ERR_NONE;
|
||||
else
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (! dev)
|
||||
{
|
||||
pupa_error (PUPA_ERR_UNKNOWN_DEVICE, "no such disk");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (p && ! disk->has_partitions)
|
||||
{
|
||||
pupa_error (PUPA_ERR_BAD_DEVICE, "no partition on this disk");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
disk->dev = dev;
|
||||
|
||||
if (p)
|
||||
disk->partition = pupa_partition_probe (disk, p + 1);
|
||||
|
||||
fail:
|
||||
|
||||
if (raw && raw != name)
|
||||
pupa_free (raw);
|
||||
|
||||
if (pupa_errno != PUPA_ERR_NONE)
|
||||
{
|
||||
pupa_disk_close (disk);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return disk;
|
||||
}
|
||||
|
||||
void
|
||||
pupa_disk_close (pupa_disk_t disk)
|
||||
{
|
||||
if (disk->dev && disk->dev->close)
|
||||
(disk->dev->close) (disk);
|
||||
|
||||
pupa_free (disk->partition);
|
||||
pupa_free ((void *) disk->name);
|
||||
pupa_free (disk);
|
||||
}
|
||||
|
||||
static pupa_err_t
|
||||
pupa_disk_check_range (pupa_disk_t disk, unsigned long *sector,
|
||||
unsigned long *offset, pupa_ssize_t size)
|
||||
{
|
||||
*sector += *offset >> PUPA_DISK_SECTOR_BITS;
|
||||
*offset &= PUPA_DISK_SECTOR_SIZE - 1;
|
||||
|
||||
if (disk->partition)
|
||||
{
|
||||
unsigned long start, len;
|
||||
|
||||
start = pupa_partition_get_start (disk->partition);
|
||||
len = pupa_partition_get_len (disk->partition);
|
||||
|
||||
if (*sector >= len
|
||||
|| len - *sector < ((*offset + size + PUPA_DISK_SECTOR_SIZE - 1)
|
||||
>> PUPA_DISK_SECTOR_BITS))
|
||||
return pupa_error (PUPA_ERR_OUT_OF_RANGE, "out of partition");
|
||||
|
||||
*sector += start;
|
||||
}
|
||||
|
||||
if (disk->total_sectors <= *sector
|
||||
|| ((*offset + size + PUPA_DISK_SECTOR_SIZE - 1)
|
||||
>> PUPA_DISK_SECTOR_BITS) > disk->total_sectors - *sector)
|
||||
return pupa_error (PUPA_ERR_OUT_OF_RANGE, "out of disk");
|
||||
|
||||
return PUPA_ERR_NONE;
|
||||
}
|
||||
|
||||
/* Read data from the disk. */
|
||||
pupa_err_t
|
||||
pupa_disk_read (pupa_disk_t disk, unsigned long sector,
|
||||
unsigned long offset, unsigned long size, char *buf)
|
||||
{
|
||||
char *tmp_buf;
|
||||
|
||||
/* First of all, check if the region is within the disk. */
|
||||
if (pupa_disk_check_range (disk, §or, &offset, size) != PUPA_ERR_NONE)
|
||||
return pupa_errno;
|
||||
|
||||
/* Allocate a temporary buffer. */
|
||||
tmp_buf = pupa_malloc (PUPA_DISK_SECTOR_SIZE << PUPA_DISK_CACHE_BITS);
|
||||
if (! tmp_buf)
|
||||
return pupa_errno;
|
||||
|
||||
/* Until SIZE is zero... */
|
||||
while (size)
|
||||
{
|
||||
char *data;
|
||||
unsigned long start_sector;
|
||||
unsigned long len;
|
||||
unsigned long pos;
|
||||
|
||||
/* For reading bulk data. */
|
||||
start_sector = sector & ~(PUPA_DISK_CACHE_SIZE - 1);
|
||||
pos = (sector - start_sector) << PUPA_DISK_SECTOR_BITS;
|
||||
len = (PUPA_DISK_SECTOR_SIZE << PUPA_DISK_CACHE_BITS) - pos - offset;
|
||||
if (len > size)
|
||||
len = size;
|
||||
|
||||
/* Fetch the cache. */
|
||||
data = pupa_disk_cache_fetch (disk->id, start_sector);
|
||||
if (data)
|
||||
{
|
||||
/* Just copy it! */
|
||||
pupa_memcpy (buf, data + pos + offset, len);
|
||||
pupa_disk_cache_unlock (disk->id, start_sector);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Otherwise read data from the disk actually. */
|
||||
if ((disk->dev->read) (disk, start_sector,
|
||||
PUPA_DISK_CACHE_SIZE, tmp_buf)
|
||||
!= PUPA_ERR_NONE)
|
||||
{
|
||||
/* Uggh... Failed. Instead, just read necessary data. */
|
||||
unsigned num;
|
||||
|
||||
/* If more data is required, no way. */
|
||||
if (pos + size
|
||||
>= (PUPA_DISK_SECTOR_SIZE << PUPA_DISK_CACHE_BITS))
|
||||
goto finish;
|
||||
|
||||
num = ((size + PUPA_DISK_SECTOR_SIZE - 1)
|
||||
>> PUPA_DISK_SECTOR_BITS);
|
||||
if ((disk->dev->read) (disk, sector, num, tmp_buf))
|
||||
goto finish;
|
||||
|
||||
pupa_memcpy (buf, tmp_buf + offset, size);
|
||||
|
||||
/* Call the read hook, if any. */
|
||||
if (disk->read_hook)
|
||||
while (size)
|
||||
{
|
||||
(disk->read_hook) (sector, offset,
|
||||
((size > PUPA_DISK_SECTOR_SIZE)
|
||||
? PUPA_DISK_SECTOR_SIZE
|
||||
: size));
|
||||
sector++;
|
||||
size -= PUPA_DISK_SECTOR_SIZE - offset;
|
||||
offset = 0;
|
||||
}
|
||||
|
||||
/* This must be the end. */
|
||||
goto finish;
|
||||
}
|
||||
|
||||
/* Copy it and store it in the disk cache. */
|
||||
pupa_memcpy (buf, tmp_buf + pos + offset, len);
|
||||
pupa_disk_cache_store (disk->id, start_sector, tmp_buf);
|
||||
}
|
||||
|
||||
/* Call the read hook, if any. */
|
||||
if (disk->read_hook)
|
||||
{
|
||||
unsigned long s = sector;
|
||||
unsigned long l = len;
|
||||
|
||||
while (l)
|
||||
{
|
||||
(disk->read_hook) (s, offset,
|
||||
((l > PUPA_DISK_SECTOR_SIZE)
|
||||
? PUPA_DISK_SECTOR_SIZE
|
||||
: l));
|
||||
s++;
|
||||
l -= PUPA_DISK_SECTOR_SIZE - offset;
|
||||
offset = 0;
|
||||
}
|
||||
}
|
||||
|
||||
sector = start_sector + PUPA_DISK_CACHE_SIZE;
|
||||
buf += len;
|
||||
size -= len;
|
||||
offset = 0;
|
||||
}
|
||||
|
||||
finish:
|
||||
|
||||
pupa_free (tmp_buf);
|
||||
|
||||
return pupa_errno;
|
||||
}
|
||||
|
||||
pupa_err_t
|
||||
pupa_disk_write (pupa_disk_t disk, unsigned long sector,
|
||||
unsigned long offset, unsigned long size, const char *buf)
|
||||
{
|
||||
if (pupa_disk_check_range (disk, §or, &offset, size) != PUPA_ERR_NONE)
|
||||
return -1;
|
||||
|
||||
while (size)
|
||||
{
|
||||
if (offset != 0 || (size < PUPA_DISK_SECTOR_SIZE && size != 0))
|
||||
{
|
||||
char tmp_buf[PUPA_DISK_SECTOR_SIZE];
|
||||
unsigned long len;
|
||||
|
||||
if (pupa_disk_read (disk, sector, 0, PUPA_DISK_SECTOR_SIZE, tmp_buf)
|
||||
!= PUPA_ERR_NONE)
|
||||
goto finish;
|
||||
|
||||
len = PUPA_DISK_SECTOR_SIZE - offset;
|
||||
if (len > size)
|
||||
len = size;
|
||||
|
||||
pupa_memcpy (tmp_buf + offset, buf, len);
|
||||
|
||||
pupa_disk_cache_invalidate (disk->id, sector);
|
||||
|
||||
if ((disk->dev->write) (disk, sector, 1, tmp_buf) != PUPA_ERR_NONE)
|
||||
goto finish;
|
||||
|
||||
sector++;
|
||||
buf += len;
|
||||
size -= len;
|
||||
offset = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned long len;
|
||||
unsigned long n;
|
||||
|
||||
len = size & ~(PUPA_DISK_SECTOR_SIZE - 1);
|
||||
n = size >> PUPA_DISK_SECTOR_BITS;
|
||||
|
||||
if ((disk->dev->write) (disk, sector, n, buf) != PUPA_ERR_NONE)
|
||||
goto finish;
|
||||
|
||||
while (n--)
|
||||
pupa_disk_cache_invalidate (disk->id, sector++);
|
||||
|
||||
buf += len;
|
||||
size -= len;
|
||||
}
|
||||
}
|
||||
|
||||
finish:
|
||||
|
||||
return pupa_errno;
|
||||
}
|
599
kern/dl.c
Normal file
599
kern/dl.c
Normal file
|
@ -0,0 +1,599 @@
|
|||
/* dl.c - loadable module support */
|
||||
/*
|
||||
* PUPA -- Preliminary Universal Programming Architecture for GRUB
|
||||
* Copyright (C) 2002 Yoshinori K. Okuji <okuji@enbug.org>
|
||||
*
|
||||
* PUPA is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with PUPA; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <pupa/elf.h>
|
||||
#include <pupa/dl.h>
|
||||
#include <pupa/misc.h>
|
||||
#include <pupa/mm.h>
|
||||
#include <pupa/err.h>
|
||||
#include <pupa/types.h>
|
||||
#include <pupa/symbol.h>
|
||||
#include <pupa/file.h>
|
||||
|
||||
#if PUPA_HOST_SIZEOF_VOID_P == 4
|
||||
|
||||
typedef Elf32_Word Elf_Word;
|
||||
typedef Elf32_Addr Elf_Addr;
|
||||
typedef Elf32_Ehdr Elf_Ehdr;
|
||||
typedef Elf32_Shdr Elf_Shdr;
|
||||
typedef Elf32_Sym Elf_Sym;
|
||||
|
||||
# define ELF_ST_BIND(val) ELF32_ST_BIND (val)
|
||||
# define ELF_ST_TYPE(val) ELF32_ST_TYPE (val)
|
||||
|
||||
#elif PUPA_HOST_SIZEOF_VOID_P == 8
|
||||
|
||||
typedef Elf64_Word Elf_Word;
|
||||
typedef Elf64_Addr Elf_Addr;
|
||||
typedef Elf64_Ehdr Elf_Ehdr;
|
||||
typedef Elf64_Shdr Elf_Shdr;
|
||||
typedef Elf64_Sym Elf_Sym;
|
||||
|
||||
# define ELF_ST_BIND(val) ELF64_ST_BIND (val)
|
||||
# define ELF_ST_TYPE(val) ELF64_ST_TYPE (val)
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
struct pupa_dl_list
|
||||
{
|
||||
struct pupa_dl_list *next;
|
||||
pupa_dl_t mod;
|
||||
};
|
||||
typedef struct pupa_dl_list *pupa_dl_list_t;
|
||||
|
||||
static pupa_dl_list_t pupa_dl_head;
|
||||
|
||||
static pupa_err_t
|
||||
pupa_dl_add (pupa_dl_t mod)
|
||||
{
|
||||
pupa_dl_list_t l;
|
||||
|
||||
if (pupa_dl_get (mod->name))
|
||||
return pupa_error (PUPA_ERR_BAD_MODULE,
|
||||
"`%s' is already loaded", mod->name);
|
||||
|
||||
l = (pupa_dl_list_t) pupa_malloc (sizeof (*l));
|
||||
if (! l)
|
||||
return pupa_errno;
|
||||
|
||||
l->mod = mod;
|
||||
l->next = pupa_dl_head;
|
||||
pupa_dl_head = l;
|
||||
|
||||
return PUPA_ERR_NONE;
|
||||
}
|
||||
|
||||
static void
|
||||
pupa_dl_remove (pupa_dl_t mod)
|
||||
{
|
||||
pupa_dl_list_t *p, q;
|
||||
|
||||
for (p = &pupa_dl_head, q = *p; q; p = &q->next, q = *p)
|
||||
if (q->mod == mod)
|
||||
{
|
||||
*p = q->next;
|
||||
pupa_free (q);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
pupa_dl_t
|
||||
pupa_dl_get (const char *name)
|
||||
{
|
||||
pupa_dl_list_t l;
|
||||
|
||||
for (l = pupa_dl_head; l; l = l->next)
|
||||
if (pupa_strcmp (name, l->mod->name) == 0)
|
||||
return l->mod;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
struct pupa_symbol
|
||||
{
|
||||
struct pupa_symbol *next;
|
||||
const char *name;
|
||||
void *addr;
|
||||
pupa_dl_t mod; /* The module to which this symbol belongs. */
|
||||
};
|
||||
typedef struct pupa_symbol *pupa_symbol_t;
|
||||
|
||||
/* The size of the symbol table. */
|
||||
#define PUPA_SYMTAB_SIZE 509
|
||||
|
||||
/* The symbol table (using an open-hash). */
|
||||
static struct pupa_symbol *pupa_symtab[PUPA_SYMTAB_SIZE];
|
||||
|
||||
/* Simple hash function. */
|
||||
static unsigned
|
||||
pupa_symbol_hash (const char *s)
|
||||
{
|
||||
unsigned key = 0;
|
||||
|
||||
while (*s)
|
||||
key = key * 65599 + *s++;
|
||||
|
||||
return (key + (key >> 5)) % PUPA_SYMTAB_SIZE;
|
||||
}
|
||||
|
||||
/* Resolve the symbol name NAME and return the address.
|
||||
Return NULL, if not found. */
|
||||
void *
|
||||
pupa_dl_resolve_symbol (const char *name)
|
||||
{
|
||||
pupa_symbol_t sym;
|
||||
|
||||
for (sym = pupa_symtab[pupa_symbol_hash (name)]; sym; sym = sym->next)
|
||||
if (pupa_strcmp (sym->name, name) == 0)
|
||||
return sym->addr;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Register a symbol with the name NAME and the address ADDR. */
|
||||
pupa_err_t
|
||||
pupa_dl_register_symbol (const char *name, void *addr, pupa_dl_t mod)
|
||||
{
|
||||
pupa_symbol_t sym;
|
||||
unsigned k;
|
||||
|
||||
sym = (pupa_symbol_t) pupa_malloc (sizeof (*sym));
|
||||
if (! sym)
|
||||
return pupa_errno;
|
||||
|
||||
if (mod)
|
||||
{
|
||||
sym->name = pupa_strdup (name);
|
||||
if (! sym->name)
|
||||
{
|
||||
pupa_free (sym);
|
||||
return pupa_errno;
|
||||
}
|
||||
}
|
||||
else
|
||||
sym->name = name;
|
||||
|
||||
sym->addr = addr;
|
||||
sym->mod = mod;
|
||||
|
||||
k = pupa_symbol_hash (name);
|
||||
sym->next = pupa_symtab[k];
|
||||
pupa_symtab[k] = sym;
|
||||
|
||||
return PUPA_ERR_NONE;
|
||||
}
|
||||
|
||||
/* Unregister all the symbols defined in the module MOD. */
|
||||
static void
|
||||
pupa_dl_unregister_symbols (pupa_dl_t mod)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
if (! mod)
|
||||
pupa_fatal ("core symbols cannot be unregistered");
|
||||
|
||||
for (i = 0; i < PUPA_SYMTAB_SIZE; i++)
|
||||
{
|
||||
pupa_symbol_t sym, *p, q;
|
||||
|
||||
for (p = &pupa_symtab[i], sym = *p; sym; sym = q)
|
||||
{
|
||||
q = sym->next;
|
||||
if (sym->mod == mod)
|
||||
{
|
||||
*p = q;
|
||||
pupa_free ((void *) sym->name);
|
||||
pupa_free (sym);
|
||||
}
|
||||
else
|
||||
p = &sym->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Return the address of a section whose index is N. */
|
||||
static void *
|
||||
pupa_dl_get_section_addr (pupa_dl_t mod, unsigned n)
|
||||
{
|
||||
pupa_dl_segment_t seg;
|
||||
|
||||
for (seg = mod->segment; seg; seg = seg->next)
|
||||
if (seg->section == n)
|
||||
return seg->addr;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Load all segments from memory specified by E. */
|
||||
static pupa_err_t
|
||||
pupa_dl_load_segments (pupa_dl_t mod, const Elf_Ehdr *e)
|
||||
{
|
||||
unsigned i;
|
||||
Elf_Shdr *s;
|
||||
|
||||
for (i = 0, s = (Elf_Shdr *)((char *) e + e->e_shoff);
|
||||
i < e->e_shnum;
|
||||
i++, s = (Elf_Shdr *)((char *) s + e->e_shentsize))
|
||||
{
|
||||
if (s->sh_flags & SHF_ALLOC)
|
||||
{
|
||||
pupa_dl_segment_t seg;
|
||||
|
||||
seg = (pupa_dl_segment_t) pupa_malloc (sizeof (*seg));
|
||||
if (! seg)
|
||||
return pupa_errno;
|
||||
|
||||
if (s->sh_size)
|
||||
{
|
||||
void *addr;
|
||||
|
||||
addr = pupa_memalign (s->sh_addralign, s->sh_size);
|
||||
if (! addr)
|
||||
{
|
||||
pupa_free (seg);
|
||||
return pupa_errno;
|
||||
}
|
||||
|
||||
switch (s->sh_type)
|
||||
{
|
||||
case SHT_PROGBITS:
|
||||
pupa_memcpy (addr, (char *) e + s->sh_offset, s->sh_size);
|
||||
break;
|
||||
case SHT_NOBITS:
|
||||
pupa_memset (addr, 0, s->sh_size);
|
||||
break;
|
||||
}
|
||||
|
||||
seg->addr = addr;
|
||||
}
|
||||
else
|
||||
seg->addr = 0;
|
||||
|
||||
seg->size = s->sh_size;
|
||||
seg->section = i;
|
||||
seg->next = mod->segment;
|
||||
mod->segment = seg;
|
||||
}
|
||||
}
|
||||
|
||||
return PUPA_ERR_NONE;
|
||||
}
|
||||
|
||||
static pupa_err_t
|
||||
pupa_dl_resolve_symbols (pupa_dl_t mod, Elf_Ehdr *e)
|
||||
{
|
||||
unsigned i;
|
||||
Elf_Shdr *s;
|
||||
Elf_Sym *sym;
|
||||
const char *str;
|
||||
Elf_Word size, entsize;
|
||||
|
||||
for (i = 0, s = (Elf_Shdr *) ((char *) e + e->e_shoff);
|
||||
i < e->e_shnum;
|
||||
i++, s = (Elf_Shdr *) ((char *) s + e->e_shentsize))
|
||||
if (s->sh_type == SHT_SYMTAB)
|
||||
break;
|
||||
|
||||
if (i == e->e_shnum)
|
||||
return pupa_error (PUPA_ERR_BAD_MODULE, "no symbol table");
|
||||
|
||||
sym = (Elf_Sym *) ((char *) e + s->sh_offset);
|
||||
size = s->sh_size;
|
||||
entsize = s->sh_entsize;
|
||||
|
||||
s = (Elf_Shdr *) ((char *) e + e->e_shoff + e->e_shentsize * s->sh_link);
|
||||
str = (char *) e + s->sh_offset;
|
||||
|
||||
for (i = 0;
|
||||
i < size / entsize;
|
||||
i++, sym = (Elf_Sym *) ((char *) sym + entsize))
|
||||
{
|
||||
unsigned char type = ELF_ST_TYPE (sym->st_info);
|
||||
unsigned char bind = ELF_ST_BIND (sym->st_info);
|
||||
const char *name = str + sym->st_name;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case STT_NOTYPE:
|
||||
/* Resolve a global symbol. */
|
||||
if (sym->st_name != 0 && sym->st_shndx == 0)
|
||||
{
|
||||
sym->st_value = (Elf_Addr) pupa_dl_resolve_symbol (name);
|
||||
if (! sym->st_value)
|
||||
return pupa_error (PUPA_ERR_BAD_MODULE,
|
||||
"the symbol `%s' not found", name);
|
||||
}
|
||||
else
|
||||
sym->st_value = 0;
|
||||
break;
|
||||
|
||||
case STT_OBJECT:
|
||||
sym->st_value += (Elf_Addr) pupa_dl_get_section_addr (mod,
|
||||
sym->st_shndx);
|
||||
if (bind != STB_LOCAL)
|
||||
if (pupa_dl_register_symbol (name, (void *) sym->st_value, mod))
|
||||
return pupa_errno;
|
||||
break;
|
||||
|
||||
case STT_FUNC:
|
||||
sym->st_value += (Elf_Addr) pupa_dl_get_section_addr (mod,
|
||||
sym->st_shndx);
|
||||
if (bind != STB_LOCAL)
|
||||
if (pupa_dl_register_symbol (name, (void *) sym->st_value, mod))
|
||||
return pupa_errno;
|
||||
|
||||
if (pupa_strcmp (name, "pupa_mod_init") == 0)
|
||||
mod->init = (void (*) ()) sym->st_value;
|
||||
else if (pupa_strcmp (name, "pupa_mod_fini") == 0)
|
||||
mod->fini = (void (*) ()) sym->st_value;
|
||||
break;
|
||||
|
||||
case STT_SECTION:
|
||||
sym->st_value = (Elf_Addr) pupa_dl_get_section_addr (mod,
|
||||
sym->st_shndx);
|
||||
break;
|
||||
|
||||
case STT_FILE:
|
||||
sym->st_value = 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
return pupa_error (PUPA_ERR_BAD_MODULE,
|
||||
"unknown symbol type `%d'", (int) type);
|
||||
}
|
||||
}
|
||||
|
||||
return PUPA_ERR_NONE;
|
||||
}
|
||||
|
||||
static void
|
||||
pupa_dl_call_init (pupa_dl_t mod)
|
||||
{
|
||||
if (mod->init)
|
||||
(mod->init) ();
|
||||
}
|
||||
|
||||
static pupa_err_t
|
||||
pupa_dl_resolve_name (pupa_dl_t mod, Elf_Ehdr *e)
|
||||
{
|
||||
Elf_Shdr *s;
|
||||
const char *str;
|
||||
unsigned i;
|
||||
|
||||
s = (Elf_Shdr *) ((char *) e + e->e_shoff + e->e_shstrndx * e->e_shentsize);
|
||||
str = (char *) e + s->sh_offset;
|
||||
|
||||
for (i = 0, s = (Elf_Shdr *) ((char *) e + e->e_shoff);
|
||||
i < e->e_shnum;
|
||||
i++, s = (Elf_Shdr *) ((char *) s + e->e_shentsize))
|
||||
if (pupa_strcmp (str + s->sh_name, ".modname") == 0)
|
||||
{
|
||||
mod->name = pupa_strdup ((char *) e + s->sh_offset);
|
||||
if (! mod->name)
|
||||
return pupa_errno;
|
||||
break;
|
||||
}
|
||||
|
||||
if (i == e->e_shnum)
|
||||
return pupa_error (PUPA_ERR_BAD_MODULE, "no module name found");
|
||||
|
||||
return PUPA_ERR_NONE;
|
||||
}
|
||||
|
||||
static pupa_err_t
|
||||
pupa_dl_resolve_dependencies (pupa_dl_t mod, Elf_Ehdr *e)
|
||||
{
|
||||
Elf_Shdr *s;
|
||||
const char *str;
|
||||
unsigned i;
|
||||
|
||||
s = (Elf_Shdr *) ((char *) e + e->e_shoff + e->e_shstrndx * e->e_shentsize);
|
||||
str = (char *) e + s->sh_offset;
|
||||
|
||||
for (i = 0, s = (Elf_Shdr *) ((char *) e + e->e_shoff);
|
||||
i < e->e_shnum;
|
||||
i++, s = (Elf_Shdr *) ((char *) s + e->e_shentsize))
|
||||
if (pupa_strcmp (str + s->sh_name, ".moddeps") == 0)
|
||||
{
|
||||
const char *name = (char *) e + s->sh_offset;
|
||||
const char *max = name + s->sh_size;
|
||||
|
||||
while (name < max)
|
||||
{
|
||||
pupa_dl_t m;
|
||||
pupa_dl_dep_t dep;
|
||||
|
||||
m = pupa_dl_load (name);
|
||||
if (! m)
|
||||
return pupa_errno;
|
||||
|
||||
dep = (pupa_dl_dep_t) pupa_malloc (sizeof (*dep));
|
||||
if (! dep)
|
||||
return pupa_errno;
|
||||
|
||||
dep->mod = m;
|
||||
dep->next = mod->dep;
|
||||
mod->dep = dep;
|
||||
|
||||
name += pupa_strlen (name) + 1;
|
||||
}
|
||||
}
|
||||
|
||||
return PUPA_ERR_NONE;
|
||||
}
|
||||
|
||||
/* Load a module from core memory. */
|
||||
pupa_dl_t
|
||||
pupa_dl_load_core (void *addr, pupa_size_t size)
|
||||
{
|
||||
Elf_Ehdr *e;
|
||||
pupa_dl_t mod;
|
||||
|
||||
e = addr;
|
||||
if (! pupa_arch_dl_check_header (e, size))
|
||||
{
|
||||
pupa_error (PUPA_ERR_BAD_MODULE, "invalid ELF header");
|
||||
return 0;
|
||||
}
|
||||
|
||||
mod = (pupa_dl_t) pupa_malloc (sizeof (*mod));
|
||||
if (! mod)
|
||||
return 0;
|
||||
|
||||
mod->name = 0;
|
||||
mod->ref_count = 1;
|
||||
mod->dep = 0;
|
||||
mod->segment = 0;
|
||||
mod->init = 0;
|
||||
mod->fini = 0;
|
||||
|
||||
if (pupa_dl_resolve_name (mod, e)
|
||||
|| pupa_dl_resolve_dependencies (mod, e)
|
||||
|| pupa_dl_load_segments (mod, e)
|
||||
|| pupa_dl_resolve_symbols (mod, e)
|
||||
|| pupa_arch_dl_relocate_symbols (mod, e))
|
||||
{
|
||||
mod->fini = 0;
|
||||
pupa_dl_unload (mod);
|
||||
return 0;
|
||||
}
|
||||
|
||||
pupa_dl_call_init (mod);
|
||||
|
||||
if (pupa_dl_add (mod))
|
||||
{
|
||||
pupa_dl_unload (mod);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return mod;
|
||||
}
|
||||
|
||||
/* Load a module from the file FILENAME. */
|
||||
pupa_dl_t
|
||||
pupa_dl_load_file (const char *filename)
|
||||
{
|
||||
pupa_file_t file;
|
||||
pupa_ssize_t size;
|
||||
void *core = 0;
|
||||
pupa_dl_t mod = 0;
|
||||
|
||||
file = pupa_file_open (filename);
|
||||
if (! file)
|
||||
return 0;
|
||||
|
||||
size = pupa_file_size (file);
|
||||
core = pupa_malloc (size);
|
||||
if (! core)
|
||||
goto failed;
|
||||
|
||||
if (pupa_file_read (file, core, size) != (int) size)
|
||||
goto failed;
|
||||
|
||||
mod = pupa_dl_load_core (core, size);
|
||||
|
||||
failed:
|
||||
pupa_file_close (file);
|
||||
pupa_free (core);
|
||||
|
||||
return mod;
|
||||
}
|
||||
|
||||
static char *pupa_dl_dir;
|
||||
|
||||
/* Load a module using a symbolic name. */
|
||||
pupa_dl_t
|
||||
pupa_dl_load (const char *name)
|
||||
{
|
||||
char *filename;
|
||||
pupa_dl_t mod;
|
||||
|
||||
mod = pupa_dl_get (name);
|
||||
if (mod)
|
||||
{
|
||||
mod->ref_count++;
|
||||
return mod;
|
||||
}
|
||||
|
||||
if (! pupa_dl_dir)
|
||||
pupa_fatal ("module dir is not initialized yet");
|
||||
|
||||
filename = (char *) pupa_malloc (pupa_strlen (pupa_dl_dir) + 1
|
||||
+ pupa_strlen (name) + 3);
|
||||
if (! filename)
|
||||
return 0;
|
||||
|
||||
pupa_sprintf (filename, "%s/%s.o", pupa_dl_dir, name);
|
||||
mod = pupa_dl_load_file (filename);
|
||||
pupa_free (filename);
|
||||
|
||||
if (! mod)
|
||||
return 0;
|
||||
|
||||
if (pupa_strcmp (mod->name, name) != 0)
|
||||
pupa_error (PUPA_ERR_BAD_MODULE, "mismatched names");
|
||||
|
||||
return mod;
|
||||
}
|
||||
|
||||
/* Unload the module MOD. */
|
||||
void
|
||||
pupa_dl_unload (pupa_dl_t mod)
|
||||
{
|
||||
pupa_dl_dep_t dep, depn;
|
||||
pupa_dl_segment_t seg, segn;
|
||||
|
||||
if (--mod->ref_count > 0)
|
||||
return;
|
||||
|
||||
if (mod->fini)
|
||||
(mod->fini) ();
|
||||
|
||||
pupa_dl_remove (mod);
|
||||
pupa_dl_unregister_symbols (mod);
|
||||
|
||||
for (dep = mod->dep; dep; dep = depn)
|
||||
{
|
||||
depn = dep->next;
|
||||
pupa_dl_unload (dep->mod);
|
||||
pupa_free (dep);
|
||||
}
|
||||
|
||||
for (seg = mod->segment; seg; seg = segn)
|
||||
{
|
||||
segn = seg->next;
|
||||
pupa_free (seg->addr);
|
||||
pupa_free (seg);
|
||||
}
|
||||
|
||||
pupa_free (mod->name);
|
||||
pupa_free (mod);
|
||||
}
|
||||
|
||||
void
|
||||
pupa_dl_init (const char *dir)
|
||||
{
|
||||
pupa_dl_dir = (char *) dir;
|
||||
}
|
61
kern/err.c
Normal file
61
kern/err.c
Normal file
|
@ -0,0 +1,61 @@
|
|||
/* err.c - error handling routines */
|
||||
/*
|
||||
* PUPA -- Preliminary Universal Programming Architecture for GRUB
|
||||
* Copyright (C) 2002 Yoshinori K. Okuji <okuji@enbug.org>
|
||||
*
|
||||
* PUPA is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with PUPA; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <pupa/err.h>
|
||||
#include <pupa/misc.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#define PUPA_MAX_ERRMSG 256
|
||||
|
||||
pupa_err_t pupa_errno;
|
||||
char pupa_errmsg[PUPA_MAX_ERRMSG];
|
||||
|
||||
pupa_err_t
|
||||
pupa_error (pupa_err_t n, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
pupa_errno = n;
|
||||
|
||||
va_start (ap, fmt);
|
||||
pupa_vsprintf (pupa_errmsg, fmt, ap);
|
||||
va_end (ap);
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
void
|
||||
pupa_fatal (const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start (ap, fmt);
|
||||
pupa_vprintf (fmt, ap);
|
||||
va_end (ap);
|
||||
|
||||
pupa_stop ();
|
||||
}
|
||||
|
||||
void
|
||||
pupa_print_error (void)
|
||||
{
|
||||
if (pupa_errno != PUPA_ERR_NONE)
|
||||
pupa_printf ("error: %s\n", pupa_errmsg);
|
||||
}
|
158
kern/file.c
Normal file
158
kern/file.c
Normal file
|
@ -0,0 +1,158 @@
|
|||
/* file.c - file I/O functions */
|
||||
/*
|
||||
* PUPA -- Preliminary Universal Programming Architecture for GRUB
|
||||
* Copyright (C) 2002 Yoshinori K. Okuji <okuji@enbug.org>
|
||||
*
|
||||
* PUPA is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with PUPA; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <pupa/misc.h>
|
||||
#include <pupa/err.h>
|
||||
#include <pupa/file.h>
|
||||
#include <pupa/mm.h>
|
||||
#include <pupa/fs.h>
|
||||
#include <pupa/device.h>
|
||||
|
||||
/* Get the device part of the filename NAME. It is enclosed by parentheses. */
|
||||
char *
|
||||
pupa_file_get_device_name (const char *name)
|
||||
{
|
||||
if (name[0] == '(')
|
||||
{
|
||||
char *p = pupa_strchr (name, ')');
|
||||
char *ret;
|
||||
|
||||
if (! p)
|
||||
{
|
||||
pupa_error (PUPA_ERR_BAD_FILENAME, "missing `)'");
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = (char *) pupa_malloc (p - name);
|
||||
if (! ret)
|
||||
return 0;
|
||||
|
||||
pupa_memcpy (ret, name + 1, p - name - 1);
|
||||
ret[p - name - 1] = '\0';
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
pupa_file_t
|
||||
pupa_file_open (const char *name)
|
||||
{
|
||||
pupa_device_t device;
|
||||
pupa_file_t file = 0;
|
||||
char *device_name;
|
||||
char *file_name;
|
||||
|
||||
device_name = pupa_file_get_device_name (name);
|
||||
if (pupa_errno)
|
||||
return 0;
|
||||
|
||||
/* Get the file part of NAME. */
|
||||
file_name = pupa_strchr (name, ')');
|
||||
if (file_name)
|
||||
file_name++;
|
||||
else
|
||||
file_name = (char *) name;
|
||||
|
||||
device = pupa_device_open (device_name);
|
||||
pupa_free (device_name);
|
||||
if (! device)
|
||||
goto fail;
|
||||
|
||||
file = (pupa_file_t) pupa_malloc (sizeof (*file));
|
||||
if (! file)
|
||||
goto fail;
|
||||
|
||||
file->device = device;
|
||||
file->offset = 0;
|
||||
file->data = 0;
|
||||
file->read_hook = 0;
|
||||
|
||||
if (device->disk && file_name[0] != '/')
|
||||
/* This is a block list. */
|
||||
file->fs = &pupa_fs_blocklist;
|
||||
else
|
||||
{
|
||||
file->fs = pupa_fs_probe (device);
|
||||
if (! file->fs)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if ((file->fs->open) (file, file_name) != PUPA_ERR_NONE)
|
||||
goto fail;
|
||||
|
||||
return file;
|
||||
|
||||
fail:
|
||||
if (device)
|
||||
pupa_device_close (device);
|
||||
|
||||
/* if (net) pupa_net_close (net); */
|
||||
|
||||
pupa_free (file);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
pupa_ssize_t
|
||||
pupa_file_read (pupa_file_t file, char *buf, pupa_ssize_t len)
|
||||
{
|
||||
pupa_ssize_t res;
|
||||
|
||||
if (len == 0 || len > file->size - file->offset)
|
||||
len = file->size - file->offset;
|
||||
|
||||
if (len == 0)
|
||||
return 0;
|
||||
|
||||
res = (file->fs->read) (file, buf, len);
|
||||
if (res > 0)
|
||||
file->offset += res;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
pupa_err_t
|
||||
pupa_file_close (pupa_file_t file)
|
||||
{
|
||||
if (file->fs->close)
|
||||
(file->fs->close) (file);
|
||||
|
||||
pupa_device_close (file->device);
|
||||
pupa_free (file);
|
||||
return pupa_errno;
|
||||
}
|
||||
|
||||
pupa_ssize_t
|
||||
pupa_file_seek (pupa_file_t file, pupa_ssize_t offset)
|
||||
{
|
||||
pupa_ssize_t old;
|
||||
|
||||
if (offset < 0 || offset >= file->size)
|
||||
{
|
||||
pupa_error (PUPA_ERR_OUT_OF_RANGE,
|
||||
"attempt to seek outside of the file");
|
||||
return -1;
|
||||
}
|
||||
|
||||
old = file->offset;
|
||||
file->offset = offset;
|
||||
return old;
|
||||
}
|
224
kern/fs.c
Normal file
224
kern/fs.c
Normal file
|
@ -0,0 +1,224 @@
|
|||
/* fs.c - filesystem manager */
|
||||
/*
|
||||
* PUPA -- Preliminary Universal Programming Architecture for GRUB
|
||||
* Copyright (C) 2002 Yoshinori K. Okuji <okuji@enbug.org>
|
||||
*
|
||||
* PUPA is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with PUPA; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <pupa/disk.h>
|
||||
#include <pupa/net.h>
|
||||
#include <pupa/fs.h>
|
||||
#include <pupa/file.h>
|
||||
#include <pupa/err.h>
|
||||
#include <pupa/misc.h>
|
||||
#include <pupa/types.h>
|
||||
#include <pupa/mm.h>
|
||||
#include <pupa/term.h>
|
||||
|
||||
static pupa_fs_t pupa_fs_list;
|
||||
|
||||
void
|
||||
pupa_fs_register (pupa_fs_t fs)
|
||||
{
|
||||
fs->next = pupa_fs_list;
|
||||
pupa_fs_list = fs;
|
||||
}
|
||||
|
||||
void
|
||||
pupa_fs_unregister (pupa_fs_t fs)
|
||||
{
|
||||
pupa_fs_t *p, q;
|
||||
|
||||
for (p = &pupa_fs_list, q = *p; q; p = &(q->next), q = q->next)
|
||||
if (q == fs)
|
||||
{
|
||||
*p = q->next;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
pupa_fs_iterate (int (*hook) (const pupa_fs_t fs))
|
||||
{
|
||||
pupa_fs_t p;
|
||||
|
||||
for (p = pupa_fs_list; p; p = p->next)
|
||||
if (hook (p))
|
||||
break;
|
||||
}
|
||||
|
||||
pupa_fs_t
|
||||
pupa_fs_probe (pupa_device_t device)
|
||||
{
|
||||
pupa_fs_t p;
|
||||
auto int dummy_func (const char *filename, int dir);
|
||||
|
||||
int dummy_func (const char *filename __attribute__ ((unused)),
|
||||
int dir __attribute__ ((unused)))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (device->disk)
|
||||
{
|
||||
for (p = pupa_fs_list; p; p = p->next)
|
||||
{
|
||||
(p->dir) (device, "/", dummy_func);
|
||||
if (pupa_errno == PUPA_ERR_NONE)
|
||||
return p;
|
||||
|
||||
if (pupa_errno != PUPA_ERR_BAD_FS)
|
||||
return 0;
|
||||
|
||||
pupa_errno = PUPA_ERR_NONE;
|
||||
}
|
||||
}
|
||||
else if (device->net->fs)
|
||||
return device->net->fs;
|
||||
|
||||
pupa_error (PUPA_ERR_UNKNOWN_FS, "unknown filesystem");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Block list support routines. */
|
||||
|
||||
struct pupa_fs_block
|
||||
{
|
||||
unsigned long offset;
|
||||
unsigned long length;
|
||||
};
|
||||
|
||||
static pupa_err_t
|
||||
pupa_fs_blocklist_open (pupa_file_t file, const char *name)
|
||||
{
|
||||
char *p = (char *) name;
|
||||
unsigned num = 0;
|
||||
unsigned i;
|
||||
pupa_disk_t disk = file->device->disk;
|
||||
struct pupa_fs_block *blocks;
|
||||
|
||||
/* First, count the number of blocks. */
|
||||
do
|
||||
{
|
||||
num++;
|
||||
p = pupa_strchr (p, ',');
|
||||
}
|
||||
while (p);
|
||||
|
||||
/* Allocate a block list. */
|
||||
blocks = pupa_malloc (sizeof (struct pupa_fs_block) * (num + 1));
|
||||
if (! blocks)
|
||||
return 0;
|
||||
|
||||
file->size = 0;
|
||||
p = (char *) name;
|
||||
for (i = 0; i < num; i++)
|
||||
{
|
||||
if (*p != '+')
|
||||
{
|
||||
blocks[i].offset = pupa_strtoul (p, &p, 0);
|
||||
if (pupa_errno != PUPA_ERR_NONE || *p != '+')
|
||||
{
|
||||
pupa_error (PUPA_ERR_BAD_FILENAME,
|
||||
"invalid file name `%s'", name);
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
else
|
||||
blocks[i].offset = 0;
|
||||
|
||||
p++;
|
||||
blocks[i].length = pupa_strtoul (p, &p, 0);
|
||||
if (pupa_errno != PUPA_ERR_NONE
|
||||
|| blocks[i].length == 0
|
||||
|| (*p && *p != ',' && ! pupa_isspace (*p)))
|
||||
{
|
||||
pupa_error (PUPA_ERR_BAD_FILENAME,
|
||||
"invalid file name `%s'", name);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (disk->total_sectors < blocks[i].offset + blocks[i].length)
|
||||
{
|
||||
pupa_error (PUPA_ERR_BAD_FILENAME, "beyond the total sectors");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
file->size += (blocks[i].length << PUPA_DISK_SECTOR_BITS);
|
||||
p++;
|
||||
}
|
||||
|
||||
blocks[i].length = 0;
|
||||
file->data = blocks;
|
||||
|
||||
return PUPA_ERR_NONE;
|
||||
|
||||
fail:
|
||||
pupa_free (blocks);
|
||||
return pupa_errno;
|
||||
}
|
||||
|
||||
static pupa_ssize_t
|
||||
pupa_fs_blocklist_read (pupa_file_t file, char *buf, pupa_ssize_t len)
|
||||
{
|
||||
struct pupa_fs_block *p;
|
||||
unsigned long sector;
|
||||
unsigned long offset;
|
||||
pupa_ssize_t ret = 0;
|
||||
|
||||
if (len > file->size - file->offset)
|
||||
len = file->size - file->offset;
|
||||
|
||||
sector = (file->offset >> PUPA_DISK_SECTOR_BITS);
|
||||
offset = (file->offset & (PUPA_DISK_SECTOR_SIZE - 1));
|
||||
for (p = file->data; p->length && len > 0; p++)
|
||||
{
|
||||
if (sector < p->length)
|
||||
{
|
||||
pupa_ssize_t size;
|
||||
|
||||
size = len;
|
||||
if (((size + offset + PUPA_DISK_SECTOR_SIZE - 1)
|
||||
>> PUPA_DISK_SECTOR_BITS) > p->length - sector)
|
||||
size = ((p->length - sector) << PUPA_DISK_SECTOR_BITS) - offset;
|
||||
|
||||
if (pupa_disk_read (file->device->disk, p->offset + sector, offset,
|
||||
size, buf) != PUPA_ERR_NONE)
|
||||
return -1;
|
||||
|
||||
ret += size;
|
||||
len -= size;
|
||||
sector -= ((size + offset) >> PUPA_DISK_SECTOR_BITS);
|
||||
offset = ((size + offset) & (PUPA_DISK_SECTOR_SIZE - 1));
|
||||
}
|
||||
else
|
||||
sector -= p->length;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct pupa_fs pupa_fs_blocklist =
|
||||
{
|
||||
.name = "blocklist",
|
||||
.dir = 0,
|
||||
.open = pupa_fs_blocklist_open,
|
||||
.read = pupa_fs_blocklist_read,
|
||||
.close = 0,
|
||||
.next = 0
|
||||
};
|
126
kern/i386/dl.c
Normal file
126
kern/i386/dl.c
Normal file
|
@ -0,0 +1,126 @@
|
|||
/* dl-386.c - arch-dependent part of loadable module support */
|
||||
/*
|
||||
* PUPA -- Preliminary Universal Programming Architecture for GRUB
|
||||
* Copyright (C) 2002 Yoshinori K. Okuji <okuji@enbug.org>
|
||||
*
|
||||
* PUPA is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with PUPA; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <pupa/dl.h>
|
||||
#include <pupa/elf.h>
|
||||
#include <pupa/misc.h>
|
||||
#include <pupa/err.h>
|
||||
|
||||
/* Check if EHDR is a valid ELF header. */
|
||||
int
|
||||
pupa_arch_dl_check_header (void *ehdr, unsigned size)
|
||||
{
|
||||
Elf32_Ehdr *e = ehdr;
|
||||
|
||||
/* Check the header size. */
|
||||
if (size < sizeof (Elf32_Ehdr))
|
||||
return 0;
|
||||
|
||||
/* Check the magic numbers. */
|
||||
if (e->e_ident[EI_MAG0] != ELFMAG0
|
||||
|| e->e_ident[EI_MAG1] != ELFMAG1
|
||||
|| e->e_ident[EI_MAG2] != ELFMAG2
|
||||
|| e->e_ident[EI_MAG3] != ELFMAG3
|
||||
|| e->e_version != EV_CURRENT
|
||||
|| e->e_ident[EI_CLASS] != ELFCLASS32
|
||||
|| e->e_ident[EI_DATA] != ELFDATA2LSB
|
||||
|| e->e_machine != EM_386
|
||||
|| e->e_type != ET_REL)
|
||||
return 0;
|
||||
|
||||
/* Make sure that every section is within the core. */
|
||||
if (size < e->e_shoff + e->e_shentsize * e->e_shnum)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Relocate symbols. */
|
||||
pupa_err_t
|
||||
pupa_arch_dl_relocate_symbols (pupa_dl_t mod, void *ehdr)
|
||||
{
|
||||
Elf32_Ehdr *e = ehdr;
|
||||
Elf32_Shdr *s;
|
||||
Elf32_Sym *symtab;
|
||||
Elf32_Word entsize;
|
||||
unsigned i;
|
||||
|
||||
/* Find a symbol table. */
|
||||
for (i = 0, s = (Elf32_Shdr *) ((char *) e + e->e_shoff);
|
||||
i < e->e_shnum;
|
||||
i++, s = (Elf32_Shdr *) ((char *) s + e->e_shentsize))
|
||||
if (s->sh_type == SHT_SYMTAB)
|
||||
break;
|
||||
|
||||
if (i == e->e_shnum)
|
||||
return pupa_error (PUPA_ERR_BAD_MODULE, "no symtab found");
|
||||
|
||||
symtab = (Elf32_Sym *) ((char *) e + s->sh_offset);
|
||||
entsize = s->sh_entsize;
|
||||
|
||||
for (i = 0, s = (Elf32_Shdr *) ((char *) e + e->e_shoff);
|
||||
i < e->e_shnum;
|
||||
i++, s = (Elf32_Shdr *) ((char *) s + e->e_shentsize))
|
||||
if (s->sh_type == SHT_REL)
|
||||
{
|
||||
pupa_dl_segment_t seg;
|
||||
|
||||
/* Find the target segment. */
|
||||
for (seg = mod->segment; seg; seg = seg->next)
|
||||
if (seg->section == s->sh_info)
|
||||
break;
|
||||
|
||||
if (seg)
|
||||
{
|
||||
Elf32_Rel *rel, *max;
|
||||
|
||||
for (rel = (Elf32_Rel *) ((char *) e + s->sh_offset),
|
||||
max = rel + s->sh_size / s->sh_entsize;
|
||||
rel < max;
|
||||
rel++)
|
||||
{
|
||||
Elf32_Word *addr;
|
||||
Elf32_Sym *sym;
|
||||
|
||||
if (seg->size < rel->r_offset)
|
||||
return pupa_error (PUPA_ERR_BAD_MODULE,
|
||||
"reloc offset is out of the segment");
|
||||
|
||||
addr = (Elf32_Word *) ((char *) seg->addr + rel->r_offset);
|
||||
sym = (Elf32_Sym *) ((char *) symtab
|
||||
+ entsize * ELF32_R_SYM (rel->r_info));
|
||||
|
||||
switch (ELF32_R_TYPE (rel->r_info))
|
||||
{
|
||||
case R_386_32:
|
||||
*addr += sym->st_value;
|
||||
break;
|
||||
|
||||
case R_386_PC32:
|
||||
*addr += (sym->st_value - (Elf32_Word) seg->addr
|
||||
- rel->r_offset);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return PUPA_ERR_NONE;
|
||||
}
|
114
kern/i386/pc/init.c
Normal file
114
kern/i386/pc/init.c
Normal file
|
@ -0,0 +1,114 @@
|
|||
/*
|
||||
* PUPA -- Preliminary Universal Programming Architecture for GRUB
|
||||
* Copyright (C) 2002 Yoshinori K. Okuji <okuji@enbug.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <pupa/kernel.h>
|
||||
#include <pupa/mm.h>
|
||||
#include <pupa/machine/init.h>
|
||||
#include <pupa/machine/memory.h>
|
||||
#include <pupa/machine/console.h>
|
||||
#include <pupa/machine/biosdisk.h>
|
||||
#include <pupa/types.h>
|
||||
#include <pupa/err.h>
|
||||
|
||||
void
|
||||
pupa_machine_init (void)
|
||||
{
|
||||
pupa_uint32_t cont;
|
||||
struct pupa_machine_mmap_entry entry;
|
||||
pupa_size_t lower_mem = (pupa_get_memsize (0) << 10);
|
||||
pupa_addr_t end_addr = pupa_get_end_addr ();
|
||||
|
||||
/* Initialize the console as early as possible. */
|
||||
pupa_console_init ();
|
||||
|
||||
/* Sanity check. */
|
||||
if (lower_mem < PUPA_MEMORY_MACHINE_RESERVED_END)
|
||||
pupa_fatal ("too small memory");
|
||||
|
||||
/* Turn on Gate A20 to access >1MB. */
|
||||
pupa_gate_a20 (1);
|
||||
|
||||
/* Add the lower memory into free memory. */
|
||||
if (lower_mem >= PUPA_MEMORY_MACHINE_RESERVED_END)
|
||||
pupa_mm_init_region ((void *) PUPA_MEMORY_MACHINE_RESERVED_END,
|
||||
lower_mem - PUPA_MEMORY_MACHINE_RESERVED_END);
|
||||
|
||||
pupa_mm_init_region ((void *) end_addr,
|
||||
PUPA_MEMORY_MACHINE_RESERVED_START - end_addr);
|
||||
|
||||
/* Check if pupa_get_mmap_entry works. */
|
||||
cont = pupa_get_mmap_entry (&entry, 0);
|
||||
|
||||
if (entry.size)
|
||||
do
|
||||
{
|
||||
/* Avoid the lower memory. */
|
||||
if (entry.addr < 0x100000)
|
||||
{
|
||||
if (entry.len <= 0x100000 - entry.addr)
|
||||
goto next;
|
||||
|
||||
entry.len -= 0x100000 - entry.addr;
|
||||
entry.addr = 0x100000;
|
||||
}
|
||||
|
||||
/* Ignore >4GB. */
|
||||
if (entry.addr <= 0xFFFFFFFF && entry.type == 1)
|
||||
{
|
||||
pupa_addr_t addr;
|
||||
pupa_size_t len;
|
||||
|
||||
addr = (pupa_addr_t) entry.addr;
|
||||
len = ((addr + entry.len > 0xFFFFFFFF)
|
||||
? 0xFFFFFFFF - addr
|
||||
: (pupa_size_t) entry.len);
|
||||
pupa_mm_init_region ((void *) addr, len);
|
||||
}
|
||||
|
||||
next:
|
||||
if (! cont)
|
||||
break;
|
||||
|
||||
cont = pupa_get_mmap_entry (&entry, cont);
|
||||
}
|
||||
while (entry.size);
|
||||
else
|
||||
{
|
||||
pupa_uint32_t eisa_mmap = pupa_get_eisa_mmap ();
|
||||
|
||||
if (eisa_mmap)
|
||||
{
|
||||
if ((eisa_mmap & 0xFFFF) == 0x3C00)
|
||||
pupa_mm_init_region ((void *) 0x100000,
|
||||
(eisa_mmap << 16) + 0x100000 * 15);
|
||||
else
|
||||
{
|
||||
pupa_mm_init_region ((void *) 0x100000,
|
||||
(eisa_mmap & 0xFFFF) << 10);
|
||||
pupa_mm_init_region ((void *) 0x1000000, eisa_mmap << 16);
|
||||
}
|
||||
}
|
||||
else
|
||||
pupa_mm_init_region ((void *) 0x100000,
|
||||
(pupa_size_t) pupa_get_memsize (1) << 10);
|
||||
}
|
||||
|
||||
/* The memory system was initialized, thus register built-in devices. */
|
||||
pupa_biosdisk_init ();
|
||||
}
|
1377
kern/i386/pc/startup.S
Normal file
1377
kern/i386/pc/startup.S
Normal file
File diff suppressed because it is too large
Load diff
67
kern/loader.c
Normal file
67
kern/loader.c
Normal file
|
@ -0,0 +1,67 @@
|
|||
/*
|
||||
* PUPA -- Preliminary Universal Programming Architecture for GRUB
|
||||
* Copyright (C) 2002 Yoshinori K. Okuji <okuji@enbug.org>
|
||||
*
|
||||
* PUPA is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with PUPA; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <pupa/loader.h>
|
||||
#include <pupa/misc.h>
|
||||
#include <pupa/mm.h>
|
||||
#include <pupa/err.h>
|
||||
|
||||
static pupa_err_t (*pupa_loader_load_module_func) (int argc, char *argv[]);
|
||||
static pupa_err_t (*pupa_loader_boot_func) (void);
|
||||
static pupa_err_t (*pupa_loader_unload_func) (void);
|
||||
|
||||
static int pupa_loader_loaded;
|
||||
|
||||
void
|
||||
pupa_loader_set (pupa_err_t (*load_module) (int argc, char *argv[]),
|
||||
pupa_err_t (*boot) (void),
|
||||
pupa_err_t (*unload) (void))
|
||||
{
|
||||
if (pupa_loader_loaded && pupa_loader_unload_func)
|
||||
if (pupa_loader_unload_func () != PUPA_ERR_NONE)
|
||||
return;
|
||||
|
||||
pupa_loader_load_module_func = load_module;
|
||||
pupa_loader_boot_func = boot;
|
||||
pupa_loader_unload_func = unload;
|
||||
|
||||
pupa_loader_loaded = 1;
|
||||
}
|
||||
|
||||
pupa_err_t
|
||||
pupa_loader_load_module (int argc, char *argv[])
|
||||
{
|
||||
if (! pupa_loader_loaded)
|
||||
return pupa_error (PUPA_ERR_NO_KERNEL, "no loaded kernel");
|
||||
|
||||
if (! pupa_loader_load_module_func)
|
||||
return pupa_error (PUPA_ERR_BAD_OS, "module not supported");
|
||||
|
||||
return pupa_loader_load_module_func (argc, argv);
|
||||
}
|
||||
|
||||
pupa_err_t
|
||||
pupa_loader_boot (void)
|
||||
{
|
||||
if (! pupa_loader_loaded)
|
||||
return pupa_error (PUPA_ERR_NO_KERNEL, "no loaded kernel");
|
||||
|
||||
return (pupa_loader_boot_func) ();
|
||||
}
|
||||
|
86
kern/main.c
Normal file
86
kern/main.c
Normal file
|
@ -0,0 +1,86 @@
|
|||
/*
|
||||
* PUPA -- Preliminary Universal Programming Architecture for GRUB
|
||||
* Copyright (C) 2002 Yoshinori K. Okuji <okuji@enbug.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <pupa/kernel.h>
|
||||
#include <pupa/misc.h>
|
||||
#include <pupa/mm.h>
|
||||
#include <pupa/symbol.h>
|
||||
#include <pupa/dl.h>
|
||||
#include <pupa/term.h>
|
||||
#include <pupa/rescue.h>
|
||||
|
||||
/* Return the end of the core image. */
|
||||
pupa_addr_t
|
||||
pupa_get_end_addr (void)
|
||||
{
|
||||
return pupa_total_module_size + pupa_end_addr;
|
||||
}
|
||||
|
||||
/* Load all modules in core. */
|
||||
static void
|
||||
pupa_load_modules (void)
|
||||
{
|
||||
struct pupa_module_header *header;
|
||||
|
||||
for (header = (struct pupa_module_header *) pupa_end_addr;
|
||||
header < (struct pupa_module_header *) pupa_get_end_addr ();
|
||||
header = (struct pupa_module_header *) ((char *) header + header->size))
|
||||
{
|
||||
if (! pupa_dl_load_core ((char *) header + header->offset,
|
||||
(header->size - header->offset)))
|
||||
pupa_fatal ("%s", pupa_errmsg);
|
||||
}
|
||||
}
|
||||
|
||||
/* Add the region where modules reside into dynamic memory. */
|
||||
static void
|
||||
pupa_add_unused_region (void)
|
||||
{
|
||||
if (pupa_total_module_size)
|
||||
pupa_mm_init_region ((void *) pupa_end_addr, pupa_total_module_size);
|
||||
}
|
||||
|
||||
/* The main routine. */
|
||||
void
|
||||
pupa_main (void)
|
||||
{
|
||||
void (*normal_func) (void);
|
||||
|
||||
/* First of all, initialize the machine. */
|
||||
pupa_machine_init ();
|
||||
|
||||
/* Hello. */
|
||||
pupa_setcolorstate (PUPA_TERM_COLOR_HIGHLIGHT);
|
||||
pupa_printf ("Welcome to PUPA!");
|
||||
pupa_setcolorstate (PUPA_TERM_COLOR_STANDARD);
|
||||
pupa_printf ("\n\n");
|
||||
|
||||
pupa_register_exported_symbols ();
|
||||
pupa_load_modules ();
|
||||
pupa_add_unused_region ();
|
||||
|
||||
/* If the function pupa_enter_normal_mode is present, call it. */
|
||||
normal_func = pupa_dl_resolve_symbol ("pupa_enter_normal_mode");
|
||||
if (normal_func)
|
||||
(*normal_func) ();
|
||||
|
||||
/* If pupa_enter_normal_mode fails or doesn't exist, enter rescue mode. */
|
||||
pupa_printf ("Entering into rescue mode...\n");
|
||||
pupa_enter_rescue_mode ();
|
||||
}
|
377
kern/misc.c
Normal file
377
kern/misc.c
Normal file
|
@ -0,0 +1,377 @@
|
|||
/* misc.c - definitions of misc functions */
|
||||
/*
|
||||
* PUPA -- Preliminary Universal Programming Architecture for GRUB
|
||||
* Copyright (C) 1999,2000,2001,2002 Free Software Foundation, Inc.
|
||||
* Copyright (C) 2002 Yoshinori K. Okuji <okuji@enbug.org>
|
||||
*
|
||||
* PUPA is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with PUPA; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <pupa/misc.h>
|
||||
#include <pupa/err.h>
|
||||
#include <pupa/mm.h>
|
||||
#include <stdarg.h>
|
||||
#include <pupa/term.h>
|
||||
|
||||
void *
|
||||
pupa_memcpy (void *dest, const void *src, pupa_size_t n)
|
||||
{
|
||||
char *d = (char *) dest;
|
||||
char *s = (char *) src;
|
||||
|
||||
while (n--)
|
||||
*d++ = *s++;
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
int
|
||||
pupa_printf (const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
int ret;
|
||||
|
||||
va_start (ap, fmt);
|
||||
ret = pupa_vprintf (fmt, ap);
|
||||
va_end (ap);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
pupa_vprintf (const char *fmt, va_list args)
|
||||
{
|
||||
return pupa_vsprintf (0, fmt, args);
|
||||
}
|
||||
|
||||
int
|
||||
pupa_memcmp (const void *s1, const void *s2, pupa_size_t n)
|
||||
{
|
||||
const char *t1 = s1;
|
||||
const char *t2 = s2;
|
||||
|
||||
while (n--)
|
||||
{
|
||||
if (*t1 != *t2)
|
||||
return (int) *t1 - (int) *t2;
|
||||
|
||||
t1++;
|
||||
t2++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
pupa_strcmp (const char *s1, const char *s2)
|
||||
{
|
||||
while (*s1 && *s2)
|
||||
{
|
||||
if (*s1 != *s2)
|
||||
return (int) *s1 - (int) *s2;
|
||||
|
||||
s1++;
|
||||
s2++;
|
||||
}
|
||||
|
||||
return (int) *s1 - (int) *s2;
|
||||
}
|
||||
|
||||
char *
|
||||
pupa_strchr (const char *s, int c)
|
||||
{
|
||||
while (*s)
|
||||
{
|
||||
if (*s == c)
|
||||
return (char *) s;
|
||||
s++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
char *
|
||||
pupa_strrchr (const char *s, int c)
|
||||
{
|
||||
char *p = 0;
|
||||
|
||||
while (*s)
|
||||
{
|
||||
if (*s == c)
|
||||
p = (char *) s;
|
||||
s++;
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
int
|
||||
pupa_isspace (int c)
|
||||
{
|
||||
return (c == '\n' || c == '\r' || c == ' ' || c == '\t');
|
||||
}
|
||||
|
||||
int
|
||||
pupa_isprint (int c)
|
||||
{
|
||||
return (c >= ' ' && c <= '~');
|
||||
}
|
||||
|
||||
int
|
||||
pupa_isalpha (int c)
|
||||
{
|
||||
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
|
||||
}
|
||||
|
||||
int
|
||||
pupa_tolower (int c)
|
||||
{
|
||||
if (c >= 'A' && c <= 'Z')
|
||||
return c - 'A' + 'a';
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
unsigned long
|
||||
pupa_strtoul (const char *str, char **end, int base)
|
||||
{
|
||||
unsigned long num = 0;
|
||||
int found = 0;
|
||||
|
||||
/* Skip white spaces. */
|
||||
while (*str && pupa_isspace (*str))
|
||||
str++;
|
||||
|
||||
/* Guess the base, if not specified. The prefix `0x' means 16, and
|
||||
the prefix `0' means 8. */
|
||||
if (str[0] == '0')
|
||||
{
|
||||
if (str[1] == 'x')
|
||||
{
|
||||
if (base == 0 || base == 16)
|
||||
{
|
||||
base = 16;
|
||||
str += 2;
|
||||
}
|
||||
}
|
||||
else if (str[1] >= '0' && str[1] <= '7')
|
||||
base = 8;
|
||||
}
|
||||
|
||||
if (base == 0)
|
||||
base = 10;
|
||||
|
||||
while (*str)
|
||||
{
|
||||
unsigned long digit;
|
||||
|
||||
digit = pupa_tolower (*str) - '0';
|
||||
if (digit > 9)
|
||||
{
|
||||
digit += '0' - 'a' + 10;
|
||||
if (digit >= (unsigned long) base)
|
||||
break;
|
||||
}
|
||||
|
||||
found = 1;
|
||||
|
||||
if (num > (~0UL - digit) / base)
|
||||
{
|
||||
pupa_error (PUPA_ERR_OUT_OF_RANGE, "overflow is detected");
|
||||
return 0;
|
||||
}
|
||||
|
||||
num += num * base + digit;
|
||||
str++;
|
||||
}
|
||||
|
||||
if (! found)
|
||||
{
|
||||
pupa_error (PUPA_ERR_BAD_NUMBER, "unrecognized number");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (end)
|
||||
*end = (char *) str;
|
||||
|
||||
return num;
|
||||
}
|
||||
|
||||
char *
|
||||
pupa_strdup (const char *s)
|
||||
{
|
||||
pupa_size_t len;
|
||||
char *p;
|
||||
|
||||
len = pupa_strlen (s) + 1;
|
||||
p = (char *) pupa_malloc (len);
|
||||
if (! p)
|
||||
return 0;
|
||||
|
||||
return pupa_memcpy (p, s, len);
|
||||
}
|
||||
|
||||
void *
|
||||
pupa_memset (void *s, int c, pupa_size_t n)
|
||||
{
|
||||
unsigned char *p = (unsigned char *) s;
|
||||
|
||||
while (n--)
|
||||
*p++ = (unsigned char) c;
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
pupa_size_t
|
||||
pupa_strlen (const char *s)
|
||||
{
|
||||
char *p = (char *) s;
|
||||
|
||||
while (*p)
|
||||
p++;
|
||||
|
||||
return p - s;
|
||||
}
|
||||
|
||||
static inline void
|
||||
pupa_reverse (char *str)
|
||||
{
|
||||
char *p = str + pupa_strlen (str) - 1;
|
||||
|
||||
while (str < p)
|
||||
{
|
||||
char tmp;
|
||||
|
||||
tmp = *str;
|
||||
*str = *p;
|
||||
*p = tmp;
|
||||
str++;
|
||||
p--;
|
||||
}
|
||||
}
|
||||
|
||||
char *
|
||||
pupa_itoa (char *str, int c, unsigned n)
|
||||
{
|
||||
unsigned base = (c == 'x') ? 16 : 10;
|
||||
char *p;
|
||||
|
||||
if ((int) n < 0 && c == 'd')
|
||||
{
|
||||
n = (unsigned) (-((int) n));
|
||||
*str++ = '-';
|
||||
}
|
||||
|
||||
p = str;
|
||||
do
|
||||
{
|
||||
unsigned d = n % base;
|
||||
*p++ = (d > 9) ? d + 'a' - 10 : d + '0';
|
||||
}
|
||||
while (n /= base);
|
||||
*p = 0;
|
||||
|
||||
pupa_reverse (str);
|
||||
return p;
|
||||
}
|
||||
|
||||
int
|
||||
pupa_vsprintf (char *str, const char *fmt, va_list args)
|
||||
{
|
||||
char c;
|
||||
int count = 0;
|
||||
auto void write_char (char c);
|
||||
auto void write_str (const char *s);
|
||||
|
||||
void write_char (char c)
|
||||
{
|
||||
if (str)
|
||||
*str++ = c;
|
||||
else
|
||||
pupa_putchar (c);
|
||||
|
||||
count++;
|
||||
}
|
||||
|
||||
void write_str (const char *s)
|
||||
{
|
||||
while (*s)
|
||||
write_char (*s++);
|
||||
}
|
||||
|
||||
while ((c = *fmt++) != 0)
|
||||
{
|
||||
if (c != '%')
|
||||
write_char (c);
|
||||
else
|
||||
{
|
||||
char tmp[16];
|
||||
char *p;
|
||||
int n;
|
||||
|
||||
c = *fmt++;
|
||||
|
||||
switch (c)
|
||||
{
|
||||
case 'p':
|
||||
write_str ("0x");
|
||||
c = 'x';
|
||||
/* fall through */
|
||||
case 'x':
|
||||
case 'u':
|
||||
case 'd':
|
||||
n = va_arg (args, int);
|
||||
pupa_itoa (tmp, c, n);
|
||||
write_str (tmp);
|
||||
break;
|
||||
|
||||
case 'c':
|
||||
n = va_arg (args, int);
|
||||
write_char (n);
|
||||
break;
|
||||
|
||||
case 's':
|
||||
p = va_arg (args, char *);
|
||||
if (p)
|
||||
write_str (p);
|
||||
else
|
||||
write_str ("(null)");
|
||||
break;
|
||||
|
||||
default:
|
||||
write_char (c);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (str)
|
||||
*str = '\0';
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
int
|
||||
pupa_sprintf (char *str, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
int ret;
|
||||
|
||||
va_start (ap, fmt);
|
||||
ret = pupa_vsprintf (str, fmt, ap);
|
||||
va_end (ap);
|
||||
|
||||
return ret;
|
||||
}
|
352
kern/mm.c
Normal file
352
kern/mm.c
Normal file
|
@ -0,0 +1,352 @@
|
|||
/* mm.c - functions for memory manager */
|
||||
/*
|
||||
* PUPA -- Preliminary Universal Programming Architecture for GRUB
|
||||
* Copyright (C) 2002 Yoshinori K. Okuji <okuji@enbug.org>
|
||||
*
|
||||
* PUPA is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with PUPA; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <pupa/mm.h>
|
||||
#include <pupa/misc.h>
|
||||
#include <pupa/err.h>
|
||||
#include <pupa/types.h>
|
||||
#include <pupa/disk.h>
|
||||
|
||||
/* Magic words. */
|
||||
#define PUPA_MM_FREE_MAGIC 0x2d3c2808
|
||||
#define PUPA_MM_ALLOC_MAGIC 0x6db08fa4
|
||||
|
||||
typedef struct pupa_mm_header
|
||||
{
|
||||
struct pupa_mm_header *next;
|
||||
pupa_size_t size;
|
||||
pupa_size_t magic;
|
||||
#if PUPA_CPU_SIZEOF_VOID_P == 4
|
||||
char padding[4];
|
||||
#elif PUPA_CPU_SIZEOF_VOID_P == 8
|
||||
char padding[8];
|
||||
#else
|
||||
# error "unknown word size"
|
||||
#endif
|
||||
}
|
||||
*pupa_mm_header_t;
|
||||
|
||||
#if PUPA_CPU_SIZEOF_VOID_P == 4
|
||||
# define PUPA_MM_ALIGN_LOG2 4
|
||||
#elif PUPA_CPU_SIZEOF_VOID_P == 8
|
||||
# define PUPA_MM_ALIGN_LOG2 8
|
||||
#endif
|
||||
|
||||
#define PUPA_MM_ALIGN (1 << PUPA_MM_ALIGN_LOG2)
|
||||
|
||||
typedef struct pupa_mm_region
|
||||
{
|
||||
struct pupa_mm_header *first;
|
||||
struct pupa_mm_region *next;
|
||||
pupa_addr_t addr;
|
||||
pupa_size_t size;
|
||||
}
|
||||
*pupa_mm_region_t;
|
||||
|
||||
|
||||
|
||||
static pupa_mm_region_t base;
|
||||
|
||||
/* Get a header from the pointer PTR, and set *P and *R to a pointer
|
||||
to the header and a pointer to its region, respectively. PTR must
|
||||
be allocated. */
|
||||
static void
|
||||
get_header_from_pointer (void *ptr, pupa_mm_header_t *p, pupa_mm_region_t *r)
|
||||
{
|
||||
if ((unsigned) ptr & (PUPA_MM_ALIGN - 1))
|
||||
pupa_fatal ("unaligned pointer %p", ptr);
|
||||
|
||||
for (*r = base; *r; *r = (*r)->next)
|
||||
if ((unsigned) ptr > (*r)->addr
|
||||
&& (unsigned) ptr <= (*r)->addr + (*r)->size)
|
||||
break;
|
||||
|
||||
if (! *r)
|
||||
pupa_fatal ("out of range pointer %p", ptr);
|
||||
|
||||
*p = (pupa_mm_header_t) ptr - 1;
|
||||
if ((*p)->magic != PUPA_MM_ALLOC_MAGIC)
|
||||
pupa_fatal ("alloc magic is broken at %p", *p);
|
||||
}
|
||||
|
||||
/* Initialize a region starting from ADDR and whose size is SIZE,
|
||||
to use it as free space. */
|
||||
void
|
||||
pupa_mm_init_region (void *addr, pupa_size_t size)
|
||||
{
|
||||
pupa_mm_header_t h;
|
||||
pupa_mm_region_t r, *p, q;
|
||||
|
||||
/* If this region is too small, ignore it. */
|
||||
if (size < PUPA_MM_ALIGN * 2)
|
||||
return;
|
||||
|
||||
/* Allocate a region from the head. */
|
||||
r = (pupa_mm_region_t) (((pupa_addr_t) addr + PUPA_MM_ALIGN - 1)
|
||||
& (~(PUPA_MM_ALIGN - 1)));
|
||||
size -= (char *) r - (char *) addr + sizeof (*r);
|
||||
|
||||
h = (pupa_mm_header_t) ((char *) r + PUPA_MM_ALIGN);
|
||||
h->next = h;
|
||||
h->magic = PUPA_MM_FREE_MAGIC;
|
||||
h->size = (size >> PUPA_MM_ALIGN_LOG2);
|
||||
|
||||
r->first = h;
|
||||
r->addr = (pupa_addr_t) h;
|
||||
r->size = (h->size << PUPA_MM_ALIGN_LOG2);
|
||||
|
||||
/* Find where to insert this region. Put a smaller one before bigger ones,
|
||||
to prevent fragmentations. */
|
||||
for (p = &base, q = *p; q; p = &(q->next), q = *p)
|
||||
if (q->size > r->size)
|
||||
break;
|
||||
|
||||
*p = r;
|
||||
r->next = q;
|
||||
}
|
||||
|
||||
/* Allocate the number of units N with the alignment ALIGN from the ring
|
||||
buffer starting from *FIRST. ALIGN must be a power of two. Return a
|
||||
non-NULL if successful, otherwise return NULL. */
|
||||
static void *
|
||||
pupa_real_malloc (pupa_mm_header_t *first, pupa_size_t n, pupa_size_t align)
|
||||
{
|
||||
pupa_mm_header_t p, q;
|
||||
|
||||
if ((*first)->magic == PUPA_MM_ALLOC_MAGIC)
|
||||
return 0;
|
||||
|
||||
for (q = *first, p = q->next; ; q = p, p = p->next)
|
||||
{
|
||||
pupa_off_t extra;
|
||||
|
||||
extra = ((pupa_addr_t) (p + 1) >> PUPA_MM_ALIGN_LOG2) % align;
|
||||
if (extra)
|
||||
extra = align - extra;
|
||||
|
||||
if (! p)
|
||||
pupa_fatal ("null in the ring");
|
||||
|
||||
if (p->magic != PUPA_MM_FREE_MAGIC)
|
||||
pupa_fatal ("free magic is broken at %p", p);
|
||||
|
||||
if (p->size >= n + extra)
|
||||
{
|
||||
if (extra == 0 && p->size == n)
|
||||
{
|
||||
q->next = p->next;
|
||||
p->magic = PUPA_MM_ALLOC_MAGIC;
|
||||
}
|
||||
else if (extra == 0 || p->size == n + extra)
|
||||
{
|
||||
p->size -= n;
|
||||
p += p->size;
|
||||
p->size = n;
|
||||
p->magic = PUPA_MM_ALLOC_MAGIC;
|
||||
}
|
||||
else
|
||||
{
|
||||
pupa_mm_header_t r;
|
||||
|
||||
r = p + extra + n;
|
||||
r->magic = PUPA_MM_FREE_MAGIC;
|
||||
r->size = p->size - extra - n;
|
||||
r->next = p->next;
|
||||
|
||||
p->size = extra;
|
||||
p->next = r;
|
||||
p += extra;
|
||||
p->size = n;
|
||||
p->magic = PUPA_MM_ALLOC_MAGIC;
|
||||
}
|
||||
|
||||
*first = q;
|
||||
return p + 1;
|
||||
}
|
||||
|
||||
if (p == *first)
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Allocate SIZE bytes with the alignment ALIGN and return the pointer. */
|
||||
void *
|
||||
pupa_memalign (pupa_size_t align, pupa_size_t size)
|
||||
{
|
||||
pupa_mm_region_t r;
|
||||
pupa_size_t n = ((size + PUPA_MM_ALIGN - 1) >> PUPA_MM_ALIGN_LOG2) + 1;
|
||||
int first = 1;
|
||||
|
||||
align = (align >> PUPA_MM_ALIGN_LOG2);
|
||||
if (align == 0)
|
||||
align = 1;
|
||||
|
||||
again:
|
||||
|
||||
for (r = base; r; r = r->next)
|
||||
{
|
||||
void *p;
|
||||
|
||||
p = pupa_real_malloc (&(r->first), n, align);
|
||||
if (p)
|
||||
return p;
|
||||
}
|
||||
|
||||
/* If failed, invalidate disk caches to increase free memory. */
|
||||
if (first)
|
||||
{
|
||||
pupa_disk_cache_invalidate_all ();
|
||||
first = 0;
|
||||
goto again;
|
||||
}
|
||||
|
||||
pupa_error (PUPA_ERR_OUT_OF_MEMORY, "out of memory");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Allocate SIZE bytes and return the pointer. */
|
||||
void *
|
||||
pupa_malloc (pupa_size_t size)
|
||||
{
|
||||
return pupa_memalign (0, size);
|
||||
}
|
||||
|
||||
/* Deallocate the pointer PTR. */
|
||||
void
|
||||
pupa_free (void *ptr)
|
||||
{
|
||||
pupa_mm_header_t p;
|
||||
pupa_mm_region_t r;
|
||||
|
||||
if (! ptr)
|
||||
return;
|
||||
|
||||
get_header_from_pointer (ptr, &p, &r);
|
||||
|
||||
if (p == r->first)
|
||||
{
|
||||
p->magic = PUPA_MM_FREE_MAGIC;
|
||||
p->next = p;
|
||||
}
|
||||
else
|
||||
{
|
||||
pupa_mm_header_t q;
|
||||
|
||||
for (q = r->first; q >= p || q->next <= p; q = q->next)
|
||||
{
|
||||
if (q->magic != PUPA_MM_FREE_MAGIC)
|
||||
pupa_fatal ("free magic is broken at %p", q);
|
||||
|
||||
if (q >= q->next && (q < p || q->next > p))
|
||||
break;
|
||||
}
|
||||
|
||||
p->magic = PUPA_MM_FREE_MAGIC;
|
||||
p->next = q->next;
|
||||
q->next = p;
|
||||
|
||||
if (p + p->size == p->next)
|
||||
{
|
||||
p->next->magic = 0;
|
||||
p->size += p->next->size;
|
||||
p->next = p->next->next;
|
||||
}
|
||||
|
||||
if (q + q->size == p)
|
||||
{
|
||||
p->magic = 0;
|
||||
q->size += p->size;
|
||||
q->next = p->next;
|
||||
}
|
||||
|
||||
r->first = q;
|
||||
}
|
||||
}
|
||||
|
||||
/* Reallocate SIZE bytes and return the pointer. The contents will be
|
||||
the same as that of PTR. */
|
||||
void *
|
||||
pupa_realloc (void *ptr, pupa_size_t size)
|
||||
{
|
||||
pupa_mm_header_t p;
|
||||
pupa_mm_region_t r;
|
||||
void *q;
|
||||
pupa_size_t n;
|
||||
|
||||
if (! ptr)
|
||||
return pupa_malloc (size);
|
||||
|
||||
if (! size)
|
||||
{
|
||||
pupa_free (ptr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* FIXME: Not optimal. */
|
||||
n = ((size + PUPA_MM_ALIGN - 1) >> PUPA_MM_ALIGN_LOG2) + 1;
|
||||
get_header_from_pointer (ptr, &p, &r);
|
||||
|
||||
if (p->size >= n)
|
||||
return p;
|
||||
|
||||
q = pupa_malloc (size);
|
||||
if (! q)
|
||||
return q;
|
||||
|
||||
pupa_memcpy (q, ptr, size);
|
||||
pupa_free (ptr);
|
||||
return q;
|
||||
}
|
||||
|
||||
#if MM_DEBUG
|
||||
void
|
||||
pupa_mm_dump (unsigned lineno)
|
||||
{
|
||||
pupa_mm_region_t r;
|
||||
|
||||
pupa_printf ("called at line %u\n", lineno);
|
||||
for (r = base; r; r = r->next)
|
||||
{
|
||||
pupa_mm_header_t p;
|
||||
|
||||
for (p = (pupa_mm_header_t) ((r->addr + PUPA_MM_ALIGN - 1)
|
||||
& (~(PUPA_MM_ALIGN - 1)));
|
||||
(pupa_addr_t) p < r->addr + r->size;
|
||||
p++)
|
||||
{
|
||||
switch (p->magic)
|
||||
{
|
||||
case PUPA_MM_FREE_MAGIC:
|
||||
pupa_printf ("F:%p:%u:%p\n",
|
||||
p, p->size << PUPA_MM_ALIGN_LOG2, p->next);
|
||||
break;
|
||||
case PUPA_MM_ALLOC_MAGIC:
|
||||
pupa_printf ("A:%p:%u\n", p, p->size << PUPA_MM_ALIGN_LOG2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pupa_printf ("\n");
|
||||
}
|
||||
#endif /* MM_DEBUG */
|
576
kern/rescue.c
Normal file
576
kern/rescue.c
Normal file
|
@ -0,0 +1,576 @@
|
|||
/* rescue.c - rescue mode */
|
||||
/*
|
||||
* PUPA -- Preliminary Universal Programming Architecture for GRUB
|
||||
* Copyright (C) 2002 Yoshinori K. Okuji <okuji@enbug.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <pupa/kernel.h>
|
||||
#include <pupa/term.h>
|
||||
#include <pupa/misc.h>
|
||||
#include <pupa/disk.h>
|
||||
#include <pupa/file.h>
|
||||
#include <pupa/mm.h>
|
||||
#include <pupa/err.h>
|
||||
#include <pupa/loader.h>
|
||||
#include <pupa/machine/partition.h>
|
||||
|
||||
#define PUPA_RESCUE_BUF_SIZE 256
|
||||
#define PUPA_RESCUE_MAX_ARGS 20
|
||||
|
||||
struct pupa_rescue_command
|
||||
{
|
||||
const char *name;
|
||||
void (*func) (int argc, char *argv[]);
|
||||
const char *message;
|
||||
struct pupa_rescue_command *next;
|
||||
};
|
||||
typedef struct pupa_rescue_command *pupa_rescue_command_t;
|
||||
|
||||
static char buf[PUPA_RESCUE_BUF_SIZE];
|
||||
|
||||
static pupa_rescue_command_t pupa_rescue_command_list;
|
||||
|
||||
void
|
||||
pupa_rescue_register_command (const char *name,
|
||||
void (*func) (int argc, char *argv[]),
|
||||
const char *message)
|
||||
{
|
||||
pupa_rescue_command_t cmd;
|
||||
|
||||
cmd = (pupa_rescue_command_t) pupa_malloc (sizeof (*cmd));
|
||||
if (! cmd)
|
||||
return;
|
||||
|
||||
cmd->name = name;
|
||||
cmd->func = func;
|
||||
cmd->message = message;
|
||||
|
||||
cmd->next = pupa_rescue_command_list;
|
||||
pupa_rescue_command_list = cmd;
|
||||
}
|
||||
|
||||
void
|
||||
pupa_rescue_unregister_command (const char *name)
|
||||
{
|
||||
pupa_rescue_command_t *p, q;
|
||||
|
||||
for (p = &pupa_rescue_command_list, q = *p; q; p = &(q->next), q = q->next)
|
||||
if (pupa_strcmp (name, q->name) == 0)
|
||||
{
|
||||
*p = q->next;
|
||||
pupa_free (q);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Prompt to input a command and read the line. */
|
||||
static void
|
||||
pupa_rescue_get_command_line (const char *prompt)
|
||||
{
|
||||
int c;
|
||||
int pos = 0;
|
||||
|
||||
pupa_printf (prompt);
|
||||
pupa_memset (buf, 0, PUPA_RESCUE_BUF_SIZE);
|
||||
|
||||
while ((c = PUPA_TERM_ASCII_CHAR (pupa_getkey ())) != '\n' && c != '\r')
|
||||
{
|
||||
if (pupa_isprint (c))
|
||||
{
|
||||
if (pos < PUPA_RESCUE_BUF_SIZE - 1)
|
||||
{
|
||||
buf[pos++] = c;
|
||||
pupa_putchar (c);
|
||||
}
|
||||
}
|
||||
else if (c == '\b')
|
||||
{
|
||||
if (pos > 0)
|
||||
{
|
||||
buf[--pos] = 0;
|
||||
pupa_putchar (c);
|
||||
pupa_putchar (' ');
|
||||
pupa_putchar (c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pupa_putchar ('\n');
|
||||
}
|
||||
|
||||
/* Get the next word in STR and return a next pointer. */
|
||||
static char *
|
||||
next_word (char **str)
|
||||
{
|
||||
char *word;
|
||||
char *p = *str;
|
||||
|
||||
/* Skip spaces. */
|
||||
while (*p && pupa_isspace (*p))
|
||||
p++;
|
||||
|
||||
word = p;
|
||||
|
||||
/* Find a space. */
|
||||
while (*p && ! pupa_isspace (*p))
|
||||
p++;
|
||||
|
||||
*p = '\0';
|
||||
*str = p + 1;
|
||||
|
||||
return word;
|
||||
}
|
||||
|
||||
/* boot */
|
||||
static void
|
||||
pupa_rescue_cmd_boot (int argc __attribute__ ((unused)),
|
||||
char *argv[] __attribute__ ((unused)))
|
||||
{
|
||||
pupa_loader_boot ();
|
||||
}
|
||||
|
||||
/* cat FILE */
|
||||
static void
|
||||
pupa_rescue_cmd_cat (int argc, char *argv[])
|
||||
{
|
||||
pupa_file_t file;
|
||||
char buf[PUPA_DISK_SECTOR_SIZE];
|
||||
pupa_ssize_t size;
|
||||
|
||||
if (argc < 1)
|
||||
{
|
||||
pupa_error (PUPA_ERR_BAD_ARGUMENT, "no file specified");
|
||||
return;
|
||||
}
|
||||
|
||||
file = pupa_file_open (argv[0]);
|
||||
if (! file)
|
||||
return;
|
||||
|
||||
while ((size = pupa_file_read (file, buf, sizeof (buf))) > 0)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < size; i++)
|
||||
{
|
||||
unsigned char c = buf[i];
|
||||
|
||||
if (pupa_isprint (c) || pupa_isspace (c))
|
||||
pupa_putchar (c);
|
||||
else
|
||||
{
|
||||
pupa_setcolorstate (PUPA_TERM_COLOR_HIGHLIGHT);
|
||||
pupa_printf ("<%x>", (int) c);
|
||||
pupa_setcolorstate (PUPA_TERM_COLOR_STANDARD);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pupa_putchar ('\n');
|
||||
pupa_file_close (file);
|
||||
}
|
||||
|
||||
static int
|
||||
pupa_rescue_print_disks (const char *name)
|
||||
{
|
||||
pupa_device_t dev;
|
||||
auto int print_partition (const pupa_partition_t p);
|
||||
|
||||
int print_partition (const pupa_partition_t p)
|
||||
{
|
||||
char *pname = pupa_partition_get_name (p);
|
||||
|
||||
if (pname)
|
||||
{
|
||||
pupa_printf ("(%s,%s) ", name, pname);
|
||||
pupa_free (pname);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
dev = pupa_device_open (name);
|
||||
pupa_errno = PUPA_ERR_NONE;
|
||||
|
||||
if (dev)
|
||||
{
|
||||
pupa_printf ("(%s) ", name);
|
||||
|
||||
if (dev->disk && dev->disk->has_partitions)
|
||||
{
|
||||
pupa_partition_iterate (dev->disk, print_partition);
|
||||
pupa_errno = PUPA_ERR_NONE;
|
||||
}
|
||||
|
||||
pupa_device_close (dev);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
pupa_rescue_print_files (const char *filename, int dir)
|
||||
{
|
||||
pupa_printf ("%s%s ", filename, dir ? "/" : "");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ls [ARG] */
|
||||
static void
|
||||
pupa_rescue_cmd_ls (int argc, char *argv[])
|
||||
{
|
||||
if (argc < 1)
|
||||
{
|
||||
pupa_disk_dev_iterate (pupa_rescue_print_disks);
|
||||
pupa_putchar ('\n');
|
||||
}
|
||||
else
|
||||
{
|
||||
char *device_name;
|
||||
pupa_device_t dev;
|
||||
pupa_fs_t fs;
|
||||
char *path;
|
||||
|
||||
device_name = pupa_file_get_device_name (argv[0]);
|
||||
dev = pupa_device_open (device_name);
|
||||
if (! dev)
|
||||
goto fail;
|
||||
|
||||
fs = pupa_fs_probe (dev);
|
||||
path = pupa_strchr (argv[0], '/');
|
||||
|
||||
if (! path && ! device_name)
|
||||
{
|
||||
pupa_error (PUPA_ERR_BAD_ARGUMENT, "invalid argument");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (! path)
|
||||
{
|
||||
if (pupa_errno == PUPA_ERR_UNKNOWN_FS)
|
||||
pupa_errno = PUPA_ERR_NONE;
|
||||
|
||||
pupa_printf ("(%s): Filesystem is %s.\n",
|
||||
device_name, fs ? fs->name : "unknown");
|
||||
}
|
||||
else if (fs)
|
||||
{
|
||||
(fs->dir) (dev, path, pupa_rescue_print_files);
|
||||
pupa_putchar ('\n');
|
||||
}
|
||||
|
||||
fail:
|
||||
if (dev)
|
||||
pupa_device_close (dev);
|
||||
|
||||
pupa_free (device_name);
|
||||
}
|
||||
}
|
||||
|
||||
/* help */
|
||||
static void
|
||||
pupa_rescue_cmd_help (int argc __attribute__ ((unused)),
|
||||
char *argv[] __attribute__ ((unused)))
|
||||
{
|
||||
pupa_rescue_command_t p, q;
|
||||
|
||||
/* Sort the commands. This is not a good algorithm, but this is enough,
|
||||
because rescue mode has a small number of commands. */
|
||||
for (p = pupa_rescue_command_list; p; p = p->next)
|
||||
for (q = p->next; q; q = q->next)
|
||||
if (pupa_strcmp (p->name, q->name) > 0)
|
||||
{
|
||||
struct pupa_rescue_command tmp;
|
||||
|
||||
tmp.name = p->name;
|
||||
tmp.func = p->func;
|
||||
tmp.message = p->message;
|
||||
|
||||
p->name = q->name;
|
||||
p->func = q->func;
|
||||
p->message = q->message;
|
||||
|
||||
q->name = tmp.name;
|
||||
q->func = tmp.func;
|
||||
q->message = tmp.message;
|
||||
}
|
||||
|
||||
/* Print them. */
|
||||
for (p = pupa_rescue_command_list; p; p = p->next)
|
||||
pupa_printf ("%s\t%s\n", p->name, p->message);
|
||||
}
|
||||
|
||||
#if 0
|
||||
static void
|
||||
pupa_rescue_cmd_info (void)
|
||||
{
|
||||
extern void pupa_disk_cache_get_performance (unsigned long *,
|
||||
unsigned long *);
|
||||
unsigned long hits, misses;
|
||||
|
||||
pupa_disk_cache_get_performance (&hits, &misses);
|
||||
pupa_printf ("Disk cache: hits = %u, misses = %u ", hits, misses);
|
||||
if (hits + misses)
|
||||
{
|
||||
unsigned long ratio = hits * 10000 / (hits + misses);
|
||||
pupa_printf ("(%u.%u%%)\n", ratio / 100, ratio % 100);
|
||||
}
|
||||
else
|
||||
pupa_printf ("(N/A)\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
/* (module|initrd) FILE [ARGS] */
|
||||
static void
|
||||
pupa_rescue_cmd_module (int argc, char *argv[])
|
||||
{
|
||||
pupa_loader_load_module (argc, argv);
|
||||
}
|
||||
|
||||
/* root [DEVICE] */
|
||||
static void
|
||||
pupa_rescue_cmd_root (int argc, char *argv[])
|
||||
{
|
||||
pupa_device_t dev;
|
||||
pupa_fs_t fs;
|
||||
|
||||
if (argc > 0)
|
||||
{
|
||||
char *device_name = pupa_file_get_device_name (argv[0]);
|
||||
if (! device_name)
|
||||
return;
|
||||
|
||||
pupa_device_set_root (device_name);
|
||||
pupa_free (device_name);
|
||||
}
|
||||
|
||||
dev = pupa_device_open (0);
|
||||
if (! dev)
|
||||
return;
|
||||
|
||||
fs = pupa_fs_probe (dev);
|
||||
if (pupa_errno == PUPA_ERR_UNKNOWN_FS)
|
||||
pupa_errno = PUPA_ERR_NONE;
|
||||
|
||||
pupa_printf ("(%s): Filesystem is %s.\n",
|
||||
pupa_device_get_root (), fs ? fs->name : "unknown");
|
||||
|
||||
pupa_device_close (dev);
|
||||
}
|
||||
|
||||
#if 0
|
||||
static void
|
||||
pupa_rescue_cmd_testload (int argc, char *argv[])
|
||||
{
|
||||
pupa_file_t file;
|
||||
char *buf;
|
||||
pupa_ssize_t size;
|
||||
pupa_ssize_t pos;
|
||||
auto void read_func (unsigned long sector, unsigned offset, unsigned len);
|
||||
|
||||
void read_func (unsigned long sector __attribute__ ((unused)),
|
||||
unsigned offset __attribute__ ((unused)),
|
||||
unsigned len __attribute__ ((unused)))
|
||||
{
|
||||
pupa_putchar ('.');
|
||||
}
|
||||
|
||||
if (argc < 1)
|
||||
{
|
||||
pupa_error (PUPA_ERR_BAD_ARGUMENT, "no file specified");
|
||||
return;
|
||||
}
|
||||
|
||||
file = pupa_file_open (argv[0]);
|
||||
if (! file)
|
||||
return;
|
||||
|
||||
size = pupa_file_size (file) & ~(PUPA_DISK_SECTOR_SIZE - 1);
|
||||
if (size == 0)
|
||||
{
|
||||
pupa_file_close (file);
|
||||
return;
|
||||
}
|
||||
|
||||
buf = pupa_malloc (size);
|
||||
if (! buf)
|
||||
goto fail;
|
||||
|
||||
pupa_printf ("Reading %s sequentially", argv[0]);
|
||||
file->read_hook = read_func;
|
||||
if (pupa_file_read (file, buf, size) != size)
|
||||
goto fail;
|
||||
pupa_printf (" Done.\n");
|
||||
|
||||
/* Read sequentially again. */
|
||||
pupa_printf ("Reading %s sequentially again", argv[0]);
|
||||
if (pupa_file_seek (file, 0) < 0)
|
||||
goto fail;
|
||||
|
||||
for (pos = 0; pos < size; pos += PUPA_DISK_SECTOR_SIZE)
|
||||
{
|
||||
char sector[PUPA_DISK_SECTOR_SIZE];
|
||||
|
||||
if (pupa_file_read (file, sector, PUPA_DISK_SECTOR_SIZE)
|
||||
!= PUPA_DISK_SECTOR_SIZE)
|
||||
goto fail;
|
||||
|
||||
if (pupa_memcmp (sector, buf + pos, PUPA_DISK_SECTOR_SIZE) != 0)
|
||||
{
|
||||
pupa_printf ("\nDiffers in %d\n", pos);
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
pupa_printf (" Done.\n");
|
||||
|
||||
/* Read backwards and compare. */
|
||||
pupa_printf ("Reading %s backwards", argv[0]);
|
||||
pos = size;
|
||||
while (pos > 0)
|
||||
{
|
||||
char sector[PUPA_DISK_SECTOR_SIZE];
|
||||
|
||||
pos -= PUPA_DISK_SECTOR_SIZE;
|
||||
|
||||
if (pupa_file_seek (file, pos) < 0)
|
||||
goto fail;
|
||||
|
||||
if (pupa_file_read (file, sector, PUPA_DISK_SECTOR_SIZE)
|
||||
!= PUPA_DISK_SECTOR_SIZE)
|
||||
goto fail;
|
||||
|
||||
if (pupa_memcmp (sector, buf + pos, PUPA_DISK_SECTOR_SIZE) != 0)
|
||||
{
|
||||
int i;
|
||||
|
||||
pupa_printf ("\nDiffers in %d\n", pos);
|
||||
|
||||
for (i = 0; i < PUPA_DISK_SECTOR_SIZE; i++)
|
||||
pupa_putchar (buf[pos + i]);
|
||||
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
pupa_printf (" Done.\n");
|
||||
|
||||
fail:
|
||||
|
||||
pupa_file_close (file);
|
||||
pupa_free (buf);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void
|
||||
pupa_rescue_cmd_dump (int argc, char *argv[])
|
||||
{
|
||||
pupa_uint8_t *addr;
|
||||
pupa_size_t size = 4;
|
||||
|
||||
if (argc == 0)
|
||||
{
|
||||
pupa_error (PUPA_ERR_BAD_ARGUMENT, "no address specified");
|
||||
return;
|
||||
}
|
||||
|
||||
addr = (pupa_uint8_t *) pupa_strtoul (argv[0], 0, 0);
|
||||
if (pupa_errno)
|
||||
return;
|
||||
|
||||
if (argc > 1)
|
||||
size = (pupa_size_t) pupa_strtoul (argv[1], 0, 0);
|
||||
|
||||
while (size--)
|
||||
{
|
||||
pupa_printf ("%x%x ", *addr >> 4, *addr & 0xf);
|
||||
addr++;
|
||||
}
|
||||
}
|
||||
|
||||
/* Enter the rescue mode. */
|
||||
void
|
||||
pupa_enter_rescue_mode (void)
|
||||
{
|
||||
pupa_rescue_register_command ("boot", pupa_rescue_cmd_boot,
|
||||
"boot an operating system");
|
||||
pupa_rescue_register_command ("cat", pupa_rescue_cmd_cat,
|
||||
"show the contents of a file");
|
||||
pupa_rescue_register_command ("help", pupa_rescue_cmd_help,
|
||||
"show this message");
|
||||
pupa_rescue_register_command ("initrd", pupa_rescue_cmd_module,
|
||||
"load an initrd");
|
||||
pupa_rescue_register_command ("ls", pupa_rescue_cmd_ls,
|
||||
"list devices or files");
|
||||
pupa_rescue_register_command ("module", pupa_rescue_cmd_module,
|
||||
"load an OS module");
|
||||
pupa_rescue_register_command ("root", pupa_rescue_cmd_root,
|
||||
"set a root device");
|
||||
pupa_rescue_register_command ("dump", pupa_rescue_cmd_dump,
|
||||
"dump memory");
|
||||
|
||||
while (1)
|
||||
{
|
||||
char *line = buf;
|
||||
char *name;
|
||||
int n;
|
||||
pupa_rescue_command_t cmd;
|
||||
char *args[PUPA_RESCUE_MAX_ARGS + 1];
|
||||
|
||||
/* Get a command line. */
|
||||
pupa_rescue_get_command_line ("pupa rescue> ");
|
||||
|
||||
/* Get the command name. */
|
||||
name = next_word (&line);
|
||||
|
||||
/* If nothing is specified, restart. */
|
||||
if (*name == '\0')
|
||||
continue;
|
||||
|
||||
/* Get arguments. */
|
||||
for (n = 0; n <= PUPA_RESCUE_MAX_ARGS; n++)
|
||||
{
|
||||
char *arg = next_word (&line);
|
||||
|
||||
if (*arg)
|
||||
args[n] = arg;
|
||||
else
|
||||
break;
|
||||
}
|
||||
args[n] = 0;
|
||||
|
||||
/* Find the command and execute it. */
|
||||
for (cmd = pupa_rescue_command_list; cmd; cmd = cmd->next)
|
||||
{
|
||||
if (pupa_strcmp (name, cmd->name) == 0)
|
||||
{
|
||||
(cmd->func) (n, args);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* If not found, print an error message. */
|
||||
if (! cmd)
|
||||
{
|
||||
pupa_printf ("Unknown command `%s'\n", name);
|
||||
pupa_printf ("Try `help' for usage\n");
|
||||
}
|
||||
|
||||
/* Print an error, if any. */
|
||||
pupa_print_error ();
|
||||
pupa_errno = PUPA_ERR_NONE;
|
||||
}
|
||||
}
|
153
kern/term.c
Normal file
153
kern/term.c
Normal file
|
@ -0,0 +1,153 @@
|
|||
/*
|
||||
* PUPA -- Preliminary Universal Programming Architecture for GRUB
|
||||
* Copyright (C) 2002 Free Software Foundation, Inc.
|
||||
* Copyright (C) 2002 Yoshinori K. Okuji <okuji@enbug.org>
|
||||
*
|
||||
* PUPA is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with PUPA; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <pupa/term.h>
|
||||
#include <pupa/err.h>
|
||||
#include <pupa/mm.h>
|
||||
|
||||
/* The list of terminals. */
|
||||
static pupa_term_t pupa_term_list;
|
||||
|
||||
/* The current terminal. */
|
||||
static pupa_term_t pupa_cur_term;
|
||||
|
||||
void
|
||||
pupa_term_register (pupa_term_t term)
|
||||
{
|
||||
term->next = pupa_term_list;
|
||||
pupa_term_list = term;
|
||||
}
|
||||
|
||||
void
|
||||
pupa_term_unregister (pupa_term_t term)
|
||||
{
|
||||
pupa_term_t *p, q;
|
||||
|
||||
for (p = &pupa_term_list, q = *p; q; p = &(q->next), q = q->next)
|
||||
if (q == term)
|
||||
{
|
||||
*p = q->next;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
pupa_term_iterate (int (*hook) (pupa_term_t term))
|
||||
{
|
||||
pupa_term_t p;
|
||||
|
||||
for (p = pupa_term_list; p; p = p->next)
|
||||
if (hook (p))
|
||||
break;
|
||||
}
|
||||
|
||||
void
|
||||
pupa_term_set_current (pupa_term_t term)
|
||||
{
|
||||
pupa_cur_term = term;
|
||||
}
|
||||
|
||||
pupa_term_t
|
||||
pupa_term_get_current (void)
|
||||
{
|
||||
return pupa_cur_term;
|
||||
}
|
||||
|
||||
void
|
||||
pupa_putchar (int c)
|
||||
{
|
||||
if (c == '\n')
|
||||
pupa_putchar ('\r');
|
||||
else if (c == '\t' && pupa_cur_term->getxy)
|
||||
{
|
||||
int n;
|
||||
|
||||
n = 8 - ((pupa_getxy () >> 8) & 7);
|
||||
while (n--)
|
||||
pupa_putchar (' ');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
(pupa_cur_term->putchar) (c);
|
||||
}
|
||||
|
||||
int
|
||||
pupa_getkey (void)
|
||||
{
|
||||
return (pupa_cur_term->getkey) ();
|
||||
}
|
||||
|
||||
int
|
||||
pupa_checkkey (void)
|
||||
{
|
||||
return (pupa_cur_term->checkkey) ();
|
||||
}
|
||||
|
||||
pupa_uint16_t
|
||||
pupa_getxy (void)
|
||||
{
|
||||
return (pupa_cur_term->getxy) ();
|
||||
}
|
||||
|
||||
void
|
||||
pupa_gotoxy (pupa_uint8_t x, pupa_uint8_t y)
|
||||
{
|
||||
(pupa_cur_term->gotoxy) (x, y);
|
||||
}
|
||||
|
||||
void
|
||||
pupa_cls (void)
|
||||
{
|
||||
if (pupa_cur_term->flags & PUPA_TERM_DUMB)
|
||||
pupa_putchar ('\n');
|
||||
else
|
||||
(pupa_cur_term->cls) ();
|
||||
}
|
||||
|
||||
void
|
||||
pupa_setcolorstate (pupa_term_color_state state)
|
||||
{
|
||||
if (pupa_cur_term->setcolorstate)
|
||||
(pupa_cur_term->setcolorstate) (state);
|
||||
}
|
||||
|
||||
void
|
||||
pupa_setcolor (pupa_uint8_t normal_color, pupa_uint8_t highlight_color)
|
||||
{
|
||||
if (pupa_cur_term->setcolor)
|
||||
(pupa_cur_term->setcolor) (normal_color, highlight_color);
|
||||
}
|
||||
|
||||
int
|
||||
pupa_setcursor (int on)
|
||||
{
|
||||
static int prev = 1;
|
||||
int ret = prev;
|
||||
|
||||
if (pupa_cur_term->setcursor)
|
||||
{
|
||||
(pupa_cur_term->setcursor) (on);
|
||||
prev = on;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
137
loader/i386/pc/chainloader.c
Normal file
137
loader/i386/pc/chainloader.c
Normal file
|
@ -0,0 +1,137 @@
|
|||
/* chainloader.c - boot another boot loader */
|
||||
/*
|
||||
* PUPA -- Preliminary Universal Programming Architecture for GRUB
|
||||
* Copyright (C) 2002 Yoshinori K. Okuji <okuji@enbug.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <pupa/loader.h>
|
||||
#include <pupa/machine/loader.h>
|
||||
#include <pupa/file.h>
|
||||
#include <pupa/err.h>
|
||||
#include <pupa/device.h>
|
||||
#include <pupa/disk.h>
|
||||
#include <pupa/misc.h>
|
||||
#include <pupa/types.h>
|
||||
#include <pupa/machine/init.h>
|
||||
#include <pupa/machine/partition.h>
|
||||
#include <pupa/machine/memory.h>
|
||||
#include <pupa/rescue.h>
|
||||
#include <pupa/dl.h>
|
||||
|
||||
/* Allocate space statically, because this is very small anyway. */
|
||||
static char pupa_chainloader_boot_sector[PUPA_DISK_SECTOR_SIZE];
|
||||
|
||||
static pupa_err_t
|
||||
pupa_chainloader_boot (void)
|
||||
{
|
||||
pupa_device_t dev;
|
||||
int drive = -1;
|
||||
void *part_addr = 0;
|
||||
|
||||
/* Open the root device. */
|
||||
dev = pupa_device_open (0);
|
||||
if (dev)
|
||||
{
|
||||
pupa_disk_t disk = dev->disk;
|
||||
|
||||
if (disk)
|
||||
{
|
||||
pupa_partition_t p = disk->partition;
|
||||
|
||||
/* In i386-pc, the id is equal to the BIOS drive number. */
|
||||
drive = (int) disk->id;
|
||||
|
||||
if (p)
|
||||
{
|
||||
pupa_disk_read (disk, p->offset, 446, 64,
|
||||
(char *) PUPA_MEMORY_MACHINE_PART_TABLE_ADDR);
|
||||
|
||||
/* Ignore errors. Perhaps it's not fatal. */
|
||||
part_addr = (void *) (PUPA_MEMORY_MACHINE_PART_TABLE_ADDR
|
||||
+ (p->index << 4));
|
||||
}
|
||||
}
|
||||
|
||||
pupa_device_close (dev);
|
||||
}
|
||||
|
||||
pupa_chainloader_real_boot (drive, part_addr);
|
||||
|
||||
/* Never reach here. */
|
||||
return PUPA_ERR_NONE;
|
||||
}
|
||||
|
||||
static void
|
||||
pupa_rescue_cmd_chainloader (int argc, char *argv[])
|
||||
{
|
||||
pupa_file_t file;
|
||||
pupa_uint16_t signature;
|
||||
int force = 0;
|
||||
|
||||
if (argc > 0 && pupa_strcmp (argv[0], "--force") == 0)
|
||||
{
|
||||
force = 1;
|
||||
argc--;
|
||||
argv++;
|
||||
}
|
||||
|
||||
if (argc == 0)
|
||||
{
|
||||
pupa_error (PUPA_ERR_BAD_ARGUMENT, "no file specified");
|
||||
return;
|
||||
}
|
||||
|
||||
file = pupa_file_open (argv[0]);
|
||||
if (! file)
|
||||
return;
|
||||
|
||||
/* Read the first block. */
|
||||
if (pupa_file_read (file, pupa_chainloader_boot_sector,
|
||||
PUPA_DISK_SECTOR_SIZE) != PUPA_DISK_SECTOR_SIZE)
|
||||
{
|
||||
if (pupa_errno == PUPA_ERR_NONE)
|
||||
pupa_error (PUPA_ERR_BAD_OS, "too small");
|
||||
|
||||
pupa_file_close (file);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Check the signature. */
|
||||
signature = *((pupa_uint16_t *) (pupa_chainloader_boot_sector
|
||||
+ PUPA_DISK_SECTOR_SIZE - 2));
|
||||
if (signature != pupa_le_to_cpu16 (0xaa55) && ! force)
|
||||
pupa_error (PUPA_ERR_BAD_OS, "invalid signature");
|
||||
|
||||
pupa_file_close (file);
|
||||
|
||||
if (pupa_errno == PUPA_ERR_NONE)
|
||||
pupa_loader_set (0, pupa_chainloader_boot, 0);
|
||||
}
|
||||
|
||||
static const char loader_name[] = "chainloader";
|
||||
|
||||
PUPA_MOD_INIT
|
||||
{
|
||||
pupa_rescue_register_command (loader_name,
|
||||
pupa_rescue_cmd_chainloader,
|
||||
"load another boot loader");
|
||||
}
|
||||
|
||||
PUPA_MOD_FINI
|
||||
{
|
||||
pupa_rescue_unregister_command (loader_name);
|
||||
}
|
40
mkinstalldirs
Normal file
40
mkinstalldirs
Normal file
|
@ -0,0 +1,40 @@
|
|||
#! /bin/sh
|
||||
# mkinstalldirs --- make directory hierarchy
|
||||
# Author: Noah Friedman <friedman@prep.ai.mit.edu>
|
||||
# Created: 1993-05-16
|
||||
# Public domain
|
||||
|
||||
# $Id$
|
||||
|
||||
errstatus=0
|
||||
|
||||
for file
|
||||
do
|
||||
set fnord `echo ":$file" | sed -ne 's/^:\//#/;s/^://;s/\// /g;s/^#/\//;p'`
|
||||
shift
|
||||
|
||||
pathcomp=
|
||||
for d
|
||||
do
|
||||
pathcomp="$pathcomp$d"
|
||||
case "$pathcomp" in
|
||||
-* ) pathcomp=./$pathcomp ;;
|
||||
esac
|
||||
|
||||
if test ! -d "$pathcomp"; then
|
||||
echo "mkdir $pathcomp"
|
||||
|
||||
mkdir "$pathcomp" || lasterr=$?
|
||||
|
||||
if test ! -d "$pathcomp"; then
|
||||
errstatus=$lasterr
|
||||
fi
|
||||
fi
|
||||
|
||||
pathcomp="$pathcomp/"
|
||||
done
|
||||
done
|
||||
|
||||
exit $errstatus
|
||||
|
||||
# mkinstalldirs ends here
|
1
stamp-h.in
Normal file
1
stamp-h.in
Normal file
|
@ -0,0 +1 @@
|
|||
timestamp
|
76
term/i386/pc/console.c
Normal file
76
term/i386/pc/console.c
Normal file
|
@ -0,0 +1,76 @@
|
|||
/*
|
||||
* PUPA -- Preliminary Universal Programming Architecture for GRUB
|
||||
* Copyright (C) 2002 Free Software Foundation, Inc.
|
||||
* Copyright (C) 2002 Yoshinori K. Okuji <okuji@enbug.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <pupa/machine/console.h>
|
||||
#include <pupa/term.h>
|
||||
#include <pupa/types.h>
|
||||
|
||||
pupa_uint8_t pupa_console_cur_color = 0x7;
|
||||
static pupa_uint8_t pupa_console_standard_color = 0x7;
|
||||
static pupa_uint8_t pupa_console_normal_color = 0x7;
|
||||
static pupa_uint8_t pupa_console_highlight_color = 0x70;
|
||||
|
||||
static void
|
||||
pupa_console_setcolorstate (pupa_term_color_state state)
|
||||
{
|
||||
switch (state) {
|
||||
case PUPA_TERM_COLOR_STANDARD:
|
||||
pupa_console_cur_color = pupa_console_standard_color;
|
||||
break;
|
||||
case PUPA_TERM_COLOR_NORMAL:
|
||||
pupa_console_cur_color = pupa_console_normal_color;
|
||||
break;
|
||||
case PUPA_TERM_COLOR_HIGHLIGHT:
|
||||
pupa_console_cur_color = pupa_console_highlight_color;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pupa_console_setcolor (pupa_uint8_t normal_color, pupa_uint8_t highlight_color)
|
||||
{
|
||||
pupa_console_normal_color = normal_color;
|
||||
pupa_console_highlight_color = highlight_color;
|
||||
}
|
||||
|
||||
static struct pupa_term pupa_console_term =
|
||||
{
|
||||
.name = "console",
|
||||
.putchar = pupa_console_putchar,
|
||||
.checkkey = pupa_console_checkkey,
|
||||
.getkey = pupa_console_getkey,
|
||||
.getxy = pupa_console_getxy,
|
||||
.gotoxy = pupa_console_gotoxy,
|
||||
.cls = pupa_console_cls,
|
||||
.setcolorstate = pupa_console_setcolorstate,
|
||||
.setcolor = pupa_console_setcolor,
|
||||
.setcursor = pupa_console_setcursor,
|
||||
.flags = 0,
|
||||
.next = 0
|
||||
};
|
||||
|
||||
void
|
||||
pupa_console_init (void)
|
||||
{
|
||||
pupa_term_register (&pupa_console_term);
|
||||
pupa_term_set_current (&pupa_console_term);
|
||||
}
|
279
util/genmoddep.c
Normal file
279
util/genmoddep.c
Normal file
|
@ -0,0 +1,279 @@
|
|||
/*
|
||||
* PUPA -- Preliminary Universal Programming Architecture for GRUB
|
||||
* Copyright (C) 2002 Yoshinori K. Okuji <okuji@enbug.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#define BUF_SIZE 1024
|
||||
#define SYMTAB_SIZE 509
|
||||
|
||||
struct symbol
|
||||
{
|
||||
const char *name;
|
||||
const char *mod;
|
||||
struct symbol *next;
|
||||
};
|
||||
|
||||
struct module
|
||||
{
|
||||
const char *name;
|
||||
struct module *next;
|
||||
};
|
||||
|
||||
static char buf[BUF_SIZE];
|
||||
static struct symbol *symtab[SYMTAB_SIZE];
|
||||
|
||||
static void
|
||||
err (const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
fprintf (stderr, "genmoddep: error: ");
|
||||
|
||||
va_start (ap, fmt);
|
||||
vfprintf (stderr, fmt, ap);
|
||||
va_end (ap);
|
||||
|
||||
fputc ('\n', stderr);
|
||||
exit (1);
|
||||
}
|
||||
|
||||
static void *
|
||||
xmalloc (size_t size)
|
||||
{
|
||||
void *p;
|
||||
|
||||
p = malloc (size);
|
||||
if (! p)
|
||||
err ("out of memory");
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
static char *
|
||||
xstrdup (const char *str)
|
||||
{
|
||||
char *s;
|
||||
size_t len;
|
||||
|
||||
len = strlen (str);
|
||||
s = (char *) xmalloc (len + 1);
|
||||
memcpy (s, str, len + 1);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
static void
|
||||
chomp (char *str)
|
||||
{
|
||||
int end;
|
||||
|
||||
end = strlen (str) - 1;
|
||||
if (end < 0)
|
||||
err ("empty string");
|
||||
|
||||
if (str[end] == '\n')
|
||||
str[end] = '\0';
|
||||
}
|
||||
|
||||
static unsigned
|
||||
symbol_hash (const char *s)
|
||||
{
|
||||
unsigned key = 0;
|
||||
|
||||
while (*s)
|
||||
key = key * 65599 + *s++;
|
||||
|
||||
return (key + (key >> 5)) % SYMTAB_SIZE;
|
||||
}
|
||||
|
||||
static struct symbol *
|
||||
get_symbol (const char *name)
|
||||
{
|
||||
unsigned k;
|
||||
struct symbol *sym;
|
||||
|
||||
k = symbol_hash (name);
|
||||
for (sym = symtab[k]; sym; sym = sym->next)
|
||||
if (strcmp (sym->name, name) == 0)
|
||||
return sym;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
add_symbol (const char *name, const char *mod)
|
||||
{
|
||||
unsigned k;
|
||||
struct symbol *sym;
|
||||
|
||||
if (get_symbol (name))
|
||||
err ("duplicated symbol: %s", name);
|
||||
|
||||
sym = (struct symbol *) xmalloc (sizeof (*sym));
|
||||
sym->name = xstrdup (name);
|
||||
sym->mod = xstrdup (mod);
|
||||
|
||||
k = symbol_hash (name);
|
||||
sym->next = symtab[k];
|
||||
symtab[k] = sym;
|
||||
}
|
||||
|
||||
static void
|
||||
free_symbols (void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < SYMTAB_SIZE; i++)
|
||||
{
|
||||
struct symbol *p, *q;
|
||||
|
||||
p = symtab[i];
|
||||
while (p)
|
||||
{
|
||||
q = p->next;
|
||||
free ((void *) p->name);
|
||||
free ((void *) p->mod);
|
||||
free (p);
|
||||
p = q;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
read_defined_symbols (FILE *fp)
|
||||
{
|
||||
while (fgets (buf, sizeof (buf), fp))
|
||||
{
|
||||
char *p;
|
||||
|
||||
if (! *buf)
|
||||
err ("empty symbol name: %s", buf);
|
||||
|
||||
p = strchr (buf, ' ');
|
||||
if (! p)
|
||||
err ("invalid line format: %s", buf);
|
||||
|
||||
p++;
|
||||
|
||||
if (! *p)
|
||||
err ("empty module name: %s", buf);
|
||||
|
||||
*(p - 1) = '\0';
|
||||
chomp (p);
|
||||
|
||||
add_symbol (buf, p);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
add_module (struct module **head, const char *name)
|
||||
{
|
||||
struct module *mod;
|
||||
|
||||
for (mod = *head; mod; mod = mod->next)
|
||||
if (strcmp (mod->name, name) == 0)
|
||||
return;
|
||||
|
||||
mod = (struct module *) xmalloc (sizeof (*mod));
|
||||
mod->name = xstrdup (name);
|
||||
|
||||
mod->next = *head;
|
||||
*head = mod;
|
||||
}
|
||||
|
||||
static void
|
||||
free_modules (struct module *head)
|
||||
{
|
||||
struct module *next;
|
||||
|
||||
while (head)
|
||||
{
|
||||
next = head->next;
|
||||
free ((void *) head->name);
|
||||
free (head);
|
||||
head = next;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
find_dependencies (FILE *fp)
|
||||
{
|
||||
char *mod_name;
|
||||
struct module *mod_list = 0;
|
||||
struct module *mod;
|
||||
|
||||
if (! fgets (buf, sizeof (buf), fp) || buf[0] == '\n' || buf[0] == '\0')
|
||||
err ("no module name");
|
||||
|
||||
chomp (buf);
|
||||
mod_name = xstrdup (buf);
|
||||
|
||||
while (fgets (buf, sizeof (buf), fp))
|
||||
{
|
||||
struct symbol *sym;
|
||||
|
||||
chomp (buf);
|
||||
sym = get_symbol (buf);
|
||||
if (! sym)
|
||||
err ("%s in %s is not defined", buf, mod_name);
|
||||
|
||||
add_module (&mod_list, sym->mod);
|
||||
}
|
||||
|
||||
printf ("%s:", mod_name);
|
||||
|
||||
for (mod = mod_list; mod; mod = mod->next)
|
||||
if (strcmp (mod->name, "kernel") != 0)
|
||||
printf (" %s", mod->name);
|
||||
|
||||
putchar ('\n');
|
||||
|
||||
free_modules (mod_list);
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
int i;
|
||||
|
||||
/* First, get defined symbols. */
|
||||
read_defined_symbols (stdin);
|
||||
|
||||
/* Second, find the dependecies. */
|
||||
for (i = 1; i < argc; i++)
|
||||
{
|
||||
FILE *fp;
|
||||
|
||||
fp = fopen (argv[i], "r");
|
||||
if (! fp)
|
||||
err ("cannot open %s", argv[i]);
|
||||
|
||||
find_dependencies (fp);
|
||||
|
||||
fclose (fp);
|
||||
}
|
||||
|
||||
/* Last, free memory. */
|
||||
free_symbols ();
|
||||
|
||||
return 0;
|
||||
}
|
223
util/i386/pc/grub-mkimage.c
Normal file
223
util/i386/pc/grub-mkimage.c
Normal file
|
@ -0,0 +1,223 @@
|
|||
/* pupa-mkimage.c - make a bootable image */
|
||||
/*
|
||||
* PUPA -- Preliminary Universal Programming Architecture for GRUB
|
||||
* Copyright (C) 2002 Yoshinori K. Okuji <okuji@enbug.org>
|
||||
*
|
||||
* PUPA is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with PUPA; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <pupa/types.h>
|
||||
#include <pupa/machine/boot.h>
|
||||
#include <pupa/machine/kernel.h>
|
||||
#include <pupa/kernel.h>
|
||||
#include <pupa/disk.h>
|
||||
#include <pupa/util/misc.h>
|
||||
#include <pupa/util/resolve.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define _GNU_SOURCE 1
|
||||
#include <getopt.h>
|
||||
|
||||
static void
|
||||
generate_image (const char *dir, FILE *out, char *mods[])
|
||||
{
|
||||
pupa_addr_t module_addr = 0;
|
||||
char *kernel_img, *boot_img;
|
||||
size_t kernel_size, boot_size, total_module_size;
|
||||
char *kernel_path, *boot_path;
|
||||
unsigned num;
|
||||
struct pupa_util_path_list *path_list, *p, *next;
|
||||
|
||||
path_list = pupa_util_resolve_dependencies (dir, "moddep.lst", mods);
|
||||
|
||||
kernel_path = pupa_util_get_path (dir, "kernel.img");
|
||||
kernel_size = pupa_util_get_image_size (kernel_path);
|
||||
|
||||
total_module_size = 0;
|
||||
for (p = path_list; p; p = p->next)
|
||||
total_module_size += (pupa_util_get_image_size (p->name)
|
||||
+ sizeof (struct pupa_module_header));
|
||||
|
||||
pupa_util_info ("the total module size is 0x%x", total_module_size);
|
||||
|
||||
num = ((kernel_size + total_module_size + PUPA_DISK_SECTOR_SIZE - 1)
|
||||
>> PUPA_DISK_SECTOR_BITS);
|
||||
if (num > 0xffff)
|
||||
pupa_util_error ("the core image is too big");
|
||||
|
||||
boot_path = pupa_util_get_path (dir, "diskboot.img");
|
||||
boot_size = pupa_util_get_image_size (boot_path);
|
||||
if (boot_size != PUPA_DISK_SECTOR_SIZE)
|
||||
pupa_util_error ("diskboot.img is not one sector size");
|
||||
|
||||
boot_img = pupa_util_read_image (boot_path);
|
||||
|
||||
/* i386 is a little endian architecture. */
|
||||
*((pupa_uint16_t *) (boot_img + PUPA_DISK_SECTOR_SIZE
|
||||
- PUPA_BOOT_MACHINE_LIST_SIZE + 4))
|
||||
= pupa_cpu_to_le16 (num);
|
||||
|
||||
pupa_util_write_image (boot_img, boot_size, out);
|
||||
free (boot_img);
|
||||
free (boot_path);
|
||||
|
||||
kernel_img = pupa_util_read_image (kernel_path);
|
||||
module_addr = (path_list
|
||||
? (PUPA_BOOT_MACHINE_KERNEL_ADDR + PUPA_DISK_SECTOR_SIZE
|
||||
+ kernel_size)
|
||||
: 0);
|
||||
|
||||
pupa_util_info ("the first module address is 0x%x", module_addr);
|
||||
*((pupa_uint32_t *) (kernel_img + PUPA_KERNEL_MACHINE_TOTAL_MODULE_SIZE))
|
||||
= pupa_cpu_to_le32 (total_module_size);
|
||||
*((pupa_uint32_t *) (kernel_img + PUPA_KERNEL_MACHINE_KERNEL_IMAGE_SIZE))
|
||||
= pupa_cpu_to_le32 (kernel_size);
|
||||
|
||||
pupa_util_write_image (kernel_img, kernel_size, out);
|
||||
free (kernel_img);
|
||||
free (kernel_path);
|
||||
|
||||
while (path_list)
|
||||
{
|
||||
struct pupa_module_header header;
|
||||
size_t mod_size;
|
||||
char *mod_img;
|
||||
|
||||
next = path_list->next;
|
||||
|
||||
mod_size = pupa_util_get_image_size (path_list->name);
|
||||
|
||||
header.offset = pupa_cpu_to_le32 (sizeof (header));
|
||||
header.size = pupa_cpu_to_le32 (mod_size + sizeof (header));
|
||||
|
||||
pupa_util_info ("offset=0x%x, size=0x%x", header.offset, header.size);
|
||||
pupa_util_write_image ((char *) &header, sizeof (header), out);
|
||||
|
||||
mod_img = pupa_util_read_image (path_list->name);
|
||||
pupa_util_write_image (mod_img, mod_size, out);
|
||||
free (mod_img);
|
||||
|
||||
free ((void *) path_list->name);
|
||||
free (path_list);
|
||||
path_list = next;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static struct option options[] =
|
||||
{
|
||||
{"directory", required_argument, 0, 'd'},
|
||||
{"output", required_argument, 0, 'o'},
|
||||
{"help", no_argument, 0, 'h'},
|
||||
{"version", no_argument, 0, 'V'},
|
||||
{"verbose", no_argument, 0, 'v'},
|
||||
{0, 0, 0, 0}
|
||||
};
|
||||
|
||||
static void
|
||||
usage (int status)
|
||||
{
|
||||
if (status)
|
||||
fprintf (stderr, "Try ``pupa-mkimage --help'' for more information.\n");
|
||||
else
|
||||
printf ("\
|
||||
Usage: pupa-mkimage [OPTION]... [MODULES]\n\
|
||||
\n\
|
||||
Make a bootable image of PUPA.\n\
|
||||
\n\
|
||||
-d, --directory=DIR use images and modules under DIR [default=%s]\n\
|
||||
-o, --output=FILE output a generated image to FILE [default=stdout]\n\
|
||||
-h, --help display this image and exit\n\
|
||||
-V, --version print version information and exit\n\
|
||||
-v, --verbose print verbose messages\n\
|
||||
\n\
|
||||
Report bugs to <okuji@enbug.org>.\n\
|
||||
", PUPA_DATADIR);
|
||||
|
||||
exit (status);
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
char *output = 0;
|
||||
char *dir = 0;
|
||||
FILE *fp = stdout;
|
||||
|
||||
progname = "pupa-mkimage";
|
||||
|
||||
while (1)
|
||||
{
|
||||
int c = getopt_long (argc, argv, "d:o:hVv", options, 0);
|
||||
|
||||
if (c == -1)
|
||||
break;
|
||||
else
|
||||
switch (c)
|
||||
{
|
||||
case 'o':
|
||||
if (output)
|
||||
free (output);
|
||||
|
||||
output = xstrdup (optarg);
|
||||
break;
|
||||
|
||||
case 'd':
|
||||
if (dir)
|
||||
free (dir);
|
||||
|
||||
dir = xstrdup (optarg);
|
||||
break;
|
||||
|
||||
case 'h':
|
||||
usage (0);
|
||||
break;
|
||||
|
||||
case 'V':
|
||||
printf ("pupa-mkimage (%s) %s\n", PACKAGE_NAME, PACKAGE_VERSION);
|
||||
return 0;
|
||||
|
||||
case 'v':
|
||||
verbosity++;
|
||||
break;
|
||||
|
||||
default:
|
||||
usage (1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (output)
|
||||
{
|
||||
fp = fopen (output, "wb");
|
||||
if (! fp)
|
||||
pupa_util_error ("cannot open %s", output);
|
||||
}
|
||||
|
||||
generate_image (dir ? : PUPA_DATADIR, fp, argv + optind);
|
||||
|
||||
fclose (fp);
|
||||
|
||||
if (dir)
|
||||
free (dir);
|
||||
|
||||
return 0;
|
||||
}
|
137
util/misc.c
Normal file
137
util/misc.c
Normal file
|
@ -0,0 +1,137 @@
|
|||
/*
|
||||
* PUPA -- Preliminary Universal Programming Architecture for GRUB
|
||||
* Copyright (C) 2002 Yoshinori K. Okuji <okuji@enbug.org>
|
||||
*
|
||||
* PUPA is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with PUPA; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <pupa/util/misc.h>
|
||||
|
||||
char *progname = 0;
|
||||
int verbosity = 0;
|
||||
|
||||
void
|
||||
pupa_util_info (const char *fmt, ...)
|
||||
{
|
||||
if (verbosity > 0)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
fprintf (stderr, "%s: info: ", progname);
|
||||
va_start (ap, fmt);
|
||||
vfprintf (stderr, fmt, ap);
|
||||
va_end (ap);
|
||||
fputc ('\n', stderr);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
pupa_util_error (const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
fprintf (stderr, "%s: error: ", progname);
|
||||
va_start (ap, fmt);
|
||||
vfprintf (stderr, fmt, ap);
|
||||
va_end (ap);
|
||||
fputc ('\n', stderr);
|
||||
exit (1);
|
||||
}
|
||||
|
||||
void *
|
||||
xmalloc (size_t size)
|
||||
{
|
||||
void *p;
|
||||
|
||||
p = malloc (size);
|
||||
if (! p)
|
||||
pupa_util_error ("out of memory");
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
char *
|
||||
xstrdup (const char *str)
|
||||
{
|
||||
size_t len;
|
||||
char *dup;
|
||||
|
||||
len = strlen (str);
|
||||
dup = (char *) xmalloc (len + 1);
|
||||
memcpy (dup, str, len + 1);
|
||||
|
||||
return dup;
|
||||
}
|
||||
|
||||
char *
|
||||
pupa_util_get_path (const char *dir, const char *file)
|
||||
{
|
||||
char *path;
|
||||
|
||||
path = (char *) xmalloc (strlen (dir) + 1 + strlen (file) + 1);
|
||||
sprintf (path, "%s/%s", dir, file);
|
||||
return path;
|
||||
}
|
||||
|
||||
size_t
|
||||
pupa_util_get_image_size (const char *path)
|
||||
{
|
||||
struct stat st;
|
||||
|
||||
pupa_util_info ("getting the size of %s", path);
|
||||
|
||||
if (stat (path, &st) == -1)
|
||||
pupa_util_error ("cannot stat %s", path);
|
||||
|
||||
return st.st_size;
|
||||
}
|
||||
|
||||
char *
|
||||
pupa_util_read_image (const char *path)
|
||||
{
|
||||
char *img;
|
||||
FILE *fp;
|
||||
size_t size;
|
||||
|
||||
pupa_util_info ("reading %s", path);
|
||||
|
||||
size = pupa_util_get_image_size (path);
|
||||
img = (char *) xmalloc (size);
|
||||
|
||||
fp = fopen (path, "rb");
|
||||
if (! fp)
|
||||
pupa_util_error ("cannot open %s", path);
|
||||
|
||||
if (fread (img, 1, size, fp) != size)
|
||||
pupa_util_error ("cannot read %s", path);
|
||||
|
||||
return img;
|
||||
}
|
||||
|
||||
void
|
||||
pupa_util_write_image (const char *img, size_t size, FILE *out)
|
||||
{
|
||||
pupa_util_info ("writing 0x%x bytes", size);
|
||||
if (fwrite (img, 1, size, out) != size)
|
||||
pupa_util_error ("write failed");
|
||||
}
|
||||
|
257
util/resolve.c
Normal file
257
util/resolve.c
Normal file
|
@ -0,0 +1,257 @@
|
|||
/*
|
||||
* PUPA -- Preliminary Universal Programming Architecture for GRUB
|
||||
* Copyright (C) 2002 Yoshinori K. Okuji <okuji@enbug.org>
|
||||
*
|
||||
* PUPA is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with PUPA; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include <pupa/util/resolve.h>
|
||||
#include <pupa/util/misc.h>
|
||||
|
||||
/* Module. */
|
||||
struct mod_list
|
||||
{
|
||||
const char *name;
|
||||
struct mod_list *next;
|
||||
};
|
||||
|
||||
/* Dependency. */
|
||||
struct dep_list
|
||||
{
|
||||
const char *name;
|
||||
struct mod_list *list;
|
||||
struct dep_list *next;
|
||||
};
|
||||
|
||||
static char buf[1024];
|
||||
|
||||
static void
|
||||
free_mod_list (struct mod_list *head)
|
||||
{
|
||||
while (head)
|
||||
{
|
||||
struct mod_list *next;
|
||||
|
||||
next = head->next;
|
||||
free ((void *) head->name);
|
||||
free (head);
|
||||
head = next;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
free_dep_list (struct dep_list *head)
|
||||
{
|
||||
while (head)
|
||||
{
|
||||
struct dep_list *next;
|
||||
|
||||
next = head->next;
|
||||
free ((void *) head->name);
|
||||
free_mod_list (head->list);
|
||||
free (head);
|
||||
head = next;
|
||||
}
|
||||
}
|
||||
|
||||
/* Read the list of dependencies. */
|
||||
static struct dep_list *
|
||||
read_dep_list (FILE *fp)
|
||||
{
|
||||
struct dep_list *dep_list = 0;
|
||||
|
||||
while (fgets (buf, sizeof (buf), fp))
|
||||
{
|
||||
char *p;
|
||||
struct dep_list *dep;
|
||||
|
||||
/* Get the target name. */
|
||||
p = strchr (buf, ':');
|
||||
if (! p)
|
||||
pupa_util_error ("invalid line format: %s", buf);
|
||||
|
||||
*p++ = '\0';
|
||||
|
||||
dep = xmalloc (sizeof (*dep));
|
||||
dep->name = xstrdup (buf);
|
||||
dep->list = 0;
|
||||
|
||||
dep->next = dep_list;
|
||||
dep_list = dep;
|
||||
|
||||
/* Add dependencies. */
|
||||
while (*p)
|
||||
{
|
||||
struct mod_list *mod;
|
||||
char *name;
|
||||
|
||||
/* Skip white spaces. */
|
||||
while (*p && isspace (*p))
|
||||
p++;
|
||||
|
||||
if (! *p)
|
||||
break;
|
||||
|
||||
name = p;
|
||||
|
||||
/* Skip non-WSPs. */
|
||||
while (*p && ! isspace (*p))
|
||||
p++;
|
||||
|
||||
*p++ = '\0';
|
||||
|
||||
mod = (struct mod_list *) xmalloc (sizeof (*mod));
|
||||
mod->name = xstrdup (name);
|
||||
mod->next = dep->list;
|
||||
dep->list = mod;
|
||||
}
|
||||
}
|
||||
|
||||
return dep_list;
|
||||
}
|
||||
|
||||
static char *
|
||||
get_module_name (const char *str)
|
||||
{
|
||||
char *base;
|
||||
char *ext;
|
||||
|
||||
base = strrchr (str, '/');
|
||||
if (! base)
|
||||
base = (char *) str;
|
||||
else
|
||||
base++;
|
||||
|
||||
ext = strrchr (base, '.');
|
||||
if (ext && strcmp (ext, ".mod") == 0)
|
||||
{
|
||||
char *name;
|
||||
|
||||
name = xmalloc (ext - base + 1);
|
||||
memcpy (name, base, ext - base);
|
||||
name[ext - base] = '\0';
|
||||
return name;
|
||||
}
|
||||
|
||||
return xstrdup (base);
|
||||
}
|
||||
|
||||
static char *
|
||||
get_module_path (const char *prefix, const char *str)
|
||||
{
|
||||
char *dir;
|
||||
char *base;
|
||||
char *ext;
|
||||
char *ret;
|
||||
|
||||
ext = strrchr (str, '.');
|
||||
if (ext && strcmp (ext, ".mod") == 0)
|
||||
base = xstrdup (str);
|
||||
else
|
||||
{
|
||||
base = xmalloc (strlen (str) + 4 + 1);
|
||||
sprintf (base, "%s.mod", str);
|
||||
}
|
||||
|
||||
dir = strchr (str, '/');
|
||||
if (dir)
|
||||
return base;
|
||||
|
||||
ret = pupa_util_get_path (prefix, base);
|
||||
free (base);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
add_module (const char *dir,
|
||||
struct dep_list *dep_list,
|
||||
struct mod_list **mod_head,
|
||||
struct pupa_util_path_list **path_head,
|
||||
const char *name)
|
||||
{
|
||||
char *mod_name;
|
||||
struct pupa_util_path_list *path;
|
||||
struct mod_list *mod;
|
||||
struct dep_list *dep;
|
||||
|
||||
mod_name = get_module_name (name);
|
||||
|
||||
/* Check if the module has already been added. */
|
||||
for (mod = *mod_head; mod; mod = mod->next)
|
||||
if (strcmp (mod->name, mod_name) == 0)
|
||||
{
|
||||
free (mod_name);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Resolve dependencies. */
|
||||
for (dep = dep_list; dep; dep = dep->next)
|
||||
if (strcmp (dep->name, mod_name) == 0)
|
||||
{
|
||||
for (mod = dep->list; mod; mod = mod->next)
|
||||
add_module (dir, dep_list, mod_head, path_head, mod->name);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
/* Add this module. */
|
||||
mod = (struct mod_list *) xmalloc (sizeof (*mod));
|
||||
mod->name = mod_name;
|
||||
mod->next = *mod_head;
|
||||
*mod_head = mod;
|
||||
|
||||
/* Add this path. */
|
||||
path = (struct pupa_util_path_list *) xmalloc (sizeof (*path));
|
||||
path->name = get_module_path (dir, name);
|
||||
path->next = *path_head;
|
||||
*path_head = path;
|
||||
}
|
||||
|
||||
struct pupa_util_path_list *
|
||||
pupa_util_resolve_dependencies (const char *prefix,
|
||||
const char *dep_list_file,
|
||||
char *modules[])
|
||||
{
|
||||
char *path;
|
||||
FILE *fp;
|
||||
struct dep_list *dep_list;
|
||||
struct mod_list *mod_list = 0;
|
||||
struct pupa_util_path_list *path_list = 0;
|
||||
|
||||
path = pupa_util_get_path (prefix, dep_list_file);
|
||||
fp = fopen (path, "r");
|
||||
if (! fp)
|
||||
pupa_util_error ("cannot open %s", path);
|
||||
|
||||
free (path);
|
||||
dep_list = read_dep_list (fp);
|
||||
fclose (fp);
|
||||
|
||||
while (*modules)
|
||||
{
|
||||
add_module (prefix, dep_list, &mod_list, &path_list, *modules);
|
||||
modules++;
|
||||
}
|
||||
|
||||
free_dep_list (dep_list);
|
||||
free_mod_list (mod_list);
|
||||
|
||||
return path_list;
|
||||
}
|
Loading…
Reference in a new issue