Initial revision

This commit is contained in:
okuji 2002-12-27 08:53:07 +00:00
commit 6a161fa938
80 changed files with 23264 additions and 0 deletions

8
.cvsignore Normal file
View file

@ -0,0 +1,8 @@
Makefile
config.cache
config.h
config.log
config.status
stamp-h
stamp-h1
autom4te.cache

1
AUTHORS Normal file
View file

@ -0,0 +1 @@
Yoshinori K. Okuji designed and implemented everything.

340
COPYING Normal file
View 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
View file

@ -0,0 +1,4 @@
2002-12-27 Yoshinori K. Okuji <okuji@enbug.org>
* Changelog: New file.

157
INSTALL Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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

File diff suppressed because it is too large Load diff

78
config.h.in Normal file
View 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

File diff suppressed because it is too large Load diff

5745
configure vendored Normal file

File diff suppressed because it is too large Load diff

124
configure.ac Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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

File diff suppressed because it is too large Load diff

59
include/grub/err.h Normal file
View 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
View 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
View 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 */

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

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

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

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

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

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

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

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

View 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
View 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
View 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
View 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, &sector, &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, &sector, &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
View 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
View 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
View 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
View 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
View 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
View 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

File diff suppressed because it is too large Load diff

67
kern/loader.c Normal file
View 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
View 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
View 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
View 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
View 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
View 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;
}

View 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
View 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
View file

@ -0,0 +1 @@
timestamp

76
term/i386/pc/console.c Normal file
View 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
View 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
View 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
View 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
View 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;
}